Current File : /home/mmdealscpanel/yummmdeals.com/doc.tar
nghttp2/README.rst000064400000140676150340533010007631 0ustar00nghttp2 - HTTP/2 C Library
==========================

This is an implementation of the Hypertext Transfer Protocol version 2
in C.

The framing layer of HTTP/2 is implemented as a reusable C library.
On top of that, we have implemented an HTTP/2 client, server and
proxy.  We have also developed load test and benchmarking tools for
HTTP/2.

An HPACK encoder and decoder are available as a public API.

Development Status
------------------

nghttp2 was originally developed based on `RFC 7540
<https://tools.ietf.org/html/rfc7540>`_ HTTP/2 and `RFC 7541
<https://tools.ietf.org/html/rfc7541>`_ HPACK - Header Compression for
HTTP/2.  Now we are updating our code to implement `RFC 9113
<https://datatracker.ietf.org/doc/html/rfc9113>`_.

The nghttp2 code base was forked from the spdylay
(https://github.com/tatsuhiro-t/spdylay) project.

Public Test Server
------------------

The following endpoints are available to try out our nghttp2
implementation.

* https://nghttp2.org/ (TLS + ALPN and HTTP/3)

  This endpoint supports ``h2``, ``h2-16``, ``h2-14``, and
  ``http/1.1`` via ALPN and requires TLSv1.2 for HTTP/2
  connection.

  It also supports HTTP/3.

* http://nghttp2.org/ (HTTP Upgrade and HTTP/2 Direct)

  ``h2c`` and ``http/1.1``.

Requirements
------------

The following package is required to build the libnghttp2 library:

* pkg-config >= 0.20

To build the documentation, you need to install:

* sphinx (http://sphinx-doc.org/)

If you need libnghttp2 (C library) only, then the above packages are
all you need.  Use ``--enable-lib-only`` to ensure that only
libnghttp2 is built.  This avoids potential build error related to
building bundled applications.

To build and run the application programs (``nghttp``, ``nghttpd``,
``nghttpx`` and ``h2load``) in the ``src`` directory, the following packages
are required:

* OpenSSL >= 1.1.1; or wolfSSL >= 5.7.0; or LibreSSL >= 3.8.1; or
  aws-lc >= 1.19.0; or BoringSSL
* libev >= 4.11
* zlib >= 1.2.3
* libc-ares >= 1.7.5

To enable ``-a`` option (getting linked assets from the downloaded
resource) in ``nghttp``, the following package is required:

* libxml2 >= 2.6.26

To enable systemd support in nghttpx, the following package is
required:

* libsystemd-dev >= 209

The HPACK tools require the following package:

* jansson >= 2.5

To build sources under the examples directory, libevent is required:

* libevent-openssl >= 2.0.8

To mitigate heap fragmentation in long running server programs
(``nghttpd`` and ``nghttpx``), jemalloc is recommended:

* jemalloc

  .. note::

     Alpine Linux currently does not support malloc replacement
     due to musl limitations. See details in issue `#762 <https://github.com/nghttp2/nghttp2/issues/762>`_.

For BoringSSL or aws-lc build, to enable :rfc:`8879` TLS Certificate
Compression in applications, the following library is required:

* libbrotli-dev >= 1.0.9

To enable mruby support for nghttpx, `mruby
<https://github.com/mruby/mruby>`_ is required.  We need to build
mruby with C++ ABI explicitly turned on, and probably need other
mrgems, mruby is managed by git submodule under third-party/mruby
directory.  Currently, mruby support for nghttpx is disabled by
default.  To enable mruby support, use ``--with-mruby`` configure
option.  Note that at the time of this writing, libmruby-dev and mruby
packages in Debian/Ubuntu are not usable for nghttp2, since they do
not enable C++ ABI.  To build mruby, the following packages are
required:

* ruby
* bison

nghttpx supports `neverbleed <https://github.com/h2o/neverbleed>`_,
privilege separation engine for OpenSSL.  In short, it minimizes the
risk of private key leakage when serious bug like Heartbleed is
exploited.  The neverbleed is disabled by default.  To enable it, use
``--with-neverbleed`` configure option.

To enable the experimental HTTP/3 support for h2load and nghttpx, the
following libraries are required:

* `OpenSSL with QUIC support
  <https://github.com/quictls/openssl/tree/OpenSSL_1_1_1w+quic>`_; or
  wolfSSL; or LibreSSL (does not support 0RTT); or aws-lc; or
  `BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit
  294ab9730c570213b496cfc2fc14b3c0bfcd4bcc)
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 1.4.0
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 1.1.0

Use ``--enable-http3`` configure option to enable HTTP/3 feature for
h2load and nghttpx.

In order to build optional eBPF program to direct an incoming QUIC UDP
datagram to a correct socket for nghttpx, the following libraries are
required:

* libbpf-dev >= 0.7.0

Use ``--with-libbpf`` configure option to build eBPF program.
libelf-dev is needed to build libbpf.

For Ubuntu 20.04, you can build libbpf from `the source code
<https://github.com/libbpf/libbpf/releases>`_.  nghttpx requires eBPF
program for reloading its configuration and hot swapping its
executable.

Compiling libnghttp2 C source code requires a C99 compiler.  gcc 4.8
is known to be adequate.  In order to compile the C++ source code,
C++20 compliant compiler is required.  At least g++ >= 12 and
clang++ >= 15 are known to work.

.. note::

   To enable mruby support in nghttpx, and use ``--with-mruby``
   configure option.

.. note::

   Mac OS X users may need the ``--disable-threads`` configure option to
   disable multi-threading in nghttpd, nghttpx and h2load to prevent
   them from crashing. A patch is welcome to make multi threading work
   on Mac OS X platform.

.. note::

   To compile the associated applications (nghttp, nghttpd, nghttpx
   and h2load), you must use the ``--enable-app`` configure option and
   ensure that the specified requirements above are met.  Normally,
   configure script checks required dependencies to build these
   applications, and enable ``--enable-app`` automatically, so you
   don't have to use it explicitly.  But if you found that
   applications were not built, then using ``--enable-app`` may find
   that cause, such as the missing dependency.

.. note::

   In order to detect third party libraries, pkg-config is used
   (however we don't use pkg-config for some libraries (e.g., libev)).
   By default, pkg-config searches ``*.pc`` file in the standard
   locations (e.g., /usr/lib/pkgconfig).  If it is necessary to use
   ``*.pc`` file in the custom location, specify paths to
   ``PKG_CONFIG_PATH`` environment variable, and pass it to configure
   script, like so:

   .. code-block:: text

       $ ./configure PKG_CONFIG_PATH=/path/to/pkgconfig

   For pkg-config managed libraries, ``*_CFLAG`` and ``*_LIBS``
   environment variables are defined (e.g., ``OPENSSL_CFLAGS``,
   ``OPENSSL_LIBS``).  Specifying non-empty string to these variables
   completely overrides pkg-config.  In other words, if they are
   specified, pkg-config is not used for detection, and user is
   responsible to specify the correct values to these variables.  For
   complete list of these variables, run ``./configure -h``.

If you are using Ubuntu 22.04 LTS, run the following to install the
required packages:

.. code-block:: text

    sudo apt-get install g++ clang make binutils autoconf automake \
      autotools-dev libtool pkg-config \
      zlib1g-dev libssl-dev libxml2-dev libev-dev \
      libevent-dev libjansson-dev \
      libc-ares-dev libjemalloc-dev libsystemd-dev \
      ruby-dev bison libelf-dev

Building nghttp2 from release tar archive
-----------------------------------------

The nghttp2 project regularly releases tar archives which includes
nghttp2 source code, and generated build files.  They can be
downloaded from `Releases
<https://github.com/nghttp2/nghttp2/releases>`_ page.

Building nghttp2 from git requires autotools development packages.
Building from tar archives does not require them, and thus it is much
easier.  The usual build step is as follows:

.. code-block:: text

    $ tar xf nghttp2-X.Y.Z.tar.bz2
    $ cd nghttp2-X.Y.Z
    $ ./configure
    $ make

Building from git
-----------------

Building from git is easy, but please be sure that at least autoconf 2.68 is
used:

.. code-block:: text

    $ git submodule update --init
    $ autoreconf -i
    $ automake
    $ autoconf
    $ ./configure
    $ make

Notes for building on Windows (MSVC)
------------------------------------

The easiest way to build native Windows nghttp2 dll is use `cmake
<https://cmake.org/>`_.  The free version of `Visual C++ Build Tools
<http://landinghub.visualstudio.com/visual-cpp-build-tools>`_ works
fine.

1. Install cmake for windows
2. Open "Visual C++ ... Native Build Tool Command Prompt", and inside
   nghttp2 directly, run ``cmake``.
3. Then run ``cmake --build`` to build library.
4. nghttp2.dll, nghttp2.lib, nghttp2.exp are placed under lib directory.

Note that the above steps most likely produce nghttp2 library only.
No bundled applications are compiled.

Notes for building on Windows (Mingw/Cygwin)
--------------------------------------------

Under Mingw environment, you can only compile the library, it's
``libnghttp2-X.dll`` and ``libnghttp2.a``.

If you want to compile the applications(``h2load``, ``nghttp``,
``nghttpx``, ``nghttpd``), you need to use the Cygwin environment.

Under Cygwin environment, to compile the applications you need to
compile and install the libev first.

Secondly, you need to undefine the macro ``__STRICT_ANSI__``, if you
not, the functions ``fdopen``, ``fileno`` and ``strptime`` will not
available.

the sample command like this:

.. code-block:: text

    $ export CFLAGS="-U__STRICT_ANSI__ -I$libev_PREFIX/include -L$libev_PREFIX/lib"
    $ export CXXFLAGS=$CFLAGS
    $ ./configure
    $ make

If you want to compile the applications under ``examples/``, you need
to remove or rename the ``event.h`` from libev's installation, because
it conflicts with libevent's installation.

Notes for installation on Linux systems
--------------------------------------------
After installing nghttp2 tool suite with ``make install`` one might experience a similar error:

.. code-block:: text

    nghttpx: error while loading shared libraries: libnghttp2.so.14: cannot open shared object file: No such file or directory

This means that the tool is unable to locate the ``libnghttp2.so`` shared library.

To update the shared library cache run ``sudo ldconfig``.

Building the documentation
--------------------------

.. note::

   Documentation is still incomplete.

To build the documentation, run:

.. code-block:: text

    $ make html

The documents will be generated under ``doc/manual/html/``.

The generated documents will not be installed with ``make install``.

The online documentation is available at
https://nghttp2.org/documentation/

Build HTTP/3 enabled h2load and nghttpx
---------------------------------------

To build h2load and nghttpx with HTTP/3 feature enabled, run the
configure script with ``--enable-http3``.

For nghttpx to reload configurations and swapping its executable while
gracefully terminating old worker processes, eBPF is required.  Run
the configure script with ``--enable-http3 --with-libbpf`` to build
eBPF program.  The QUIC keying material must be set with
``--frontend-quic-secret-file`` in order to keep the existing
connections alive during reload.

The detailed steps to build HTTP/3 enabled h2load and nghttpx follow.

Build aws-lc:

.. code-block:: text

   $ git clone --depth 1 -b v1.46.1 https://github.com/aws/aws-lc
   $ cd aws-lc
   $ cmake -B build -DDISABLE_GO=ON --install-prefix=$PWD/opt
   $ make -j$(nproc) -C build
   $ cmake --install build
   $ cd ..

Build nghttp3:

.. code-block:: text

   $ git clone --depth 1 -b v1.8.0 https://github.com/ngtcp2/nghttp3
   $ cd nghttp3
   $ git submodule update --init --depth 1
   $ autoreconf -i
   $ ./configure --prefix=$PWD/build --enable-lib-only
   $ make -j$(nproc)
   $ make install
   $ cd ..

Build ngtcp2:

.. code-block:: text

   $ git clone --depth 1 -b v1.11.0 https://github.com/ngtcp2/ngtcp2
   $ cd ngtcp2
   $ git submodule update --init --depth 1
   $ autoreconf -i
   $ ./configure --prefix=$PWD/build --enable-lib-only --with-boringssl \
         BORINGSSL_CFLAGS="-I$PWD/../aws-lc/opt/include" \
         BORINGSSL_LIBS="-L$PWD/../aws-lc/opt/lib -lssl -lcrypto"
   $ make -j$(nproc)
   $ make install
   $ cd ..

If your Linux distribution does not have libbpf-dev >= 0.7.0, build
from source:

.. code-block:: text

   $ git clone --depth 1 -b v1.5.0 https://github.com/libbpf/libbpf
   $ cd libbpf
   $ PREFIX=$PWD/build make -C src install
   $ cd ..

Build nghttp2:

.. code-block:: text

   $ git clone https://github.com/nghttp2/nghttp2
   $ cd nghttp2
   $ git submodule update --init
   $ autoreconf -i
   $ ./configure --with-mruby --enable-http3 --with-libbpf \
         CC=clang-15 CXX=clang++-15 \
         PKG_CONFIG_PATH="$PWD/../aws-lc/opt/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../ngtcp2/build/lib/pkgconfig:$PWD/../libbpf/build/lib64/pkgconfig" \
         LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../aws-lc/opt/lib -Wl,-rpath,$PWD/../libbpf/build/lib64"
   $ make -j$(nproc)

The eBPF program ``reuseport_kern.o`` should be found under bpf
directory.  Pass ``--quic-bpf-program-file=bpf/reuseport_kern.o``
option to nghttpx to load it.  See also `HTTP/3 section in nghttpx -
HTTP/2 proxy - HOW-TO
<https://nghttp2.org/documentation/nghttpx-howto.html#http-3>`_.

Unit tests
----------

Unit tests are done by simply running ``make check``.

Integration tests
-----------------

We have the integration tests for the nghttpx proxy server.  The tests are
written in the `Go programming language <http://golang.org/>`_ and uses
its testing framework.  We depend on the following libraries:

* golang.org/x/net/http2
* golang.org/x/net/websocket
* https://github.com/tatsuhiro-t/go-nghttp2

Go modules will download these dependencies automatically.

To run the tests, run the following command under
``integration-tests`` directory:

.. code-block:: text

    $ make it

Inside the tests, we use port 3009 to run the test subject server.

Migration from v0.7.15 or earlier
---------------------------------

nghttp2 v1.0.0 introduced several backward incompatible changes.  In
this section, we describe these changes and how to migrate to v1.0.0.

ALPN protocol ID is now ``h2`` and ``h2c``
++++++++++++++++++++++++++++++++++++++++++

Previously we announced ``h2-14`` and ``h2c-14``.  v1.0.0 implements
final protocol version, and we changed ALPN ID to ``h2`` and ``h2c``.
The macros ``NGHTTP2_PROTO_VERSION_ID``,
``NGHTTP2_PROTO_VERSION_ID_LEN``,
``NGHTTP2_CLEARTEXT_PROTO_VERSION_ID``, and
``NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN`` have been updated to
reflect this change.

Basically, existing applications do not have to do anything, just
recompiling is enough for this change.

Use word "client magic" where we use "client connection preface"
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

We use "client connection preface" to mean first 24 bytes of client
connection preface.  This is technically not correct, since client
connection preface is composed of 24 bytes client magic byte string
followed by SETTINGS frame.  For clarification, we call "client magic"
for this 24 bytes byte string and updated API.

* ``NGHTTP2_CLIENT_CONNECTION_PREFACE`` was replaced with
  ``NGHTTP2_CLIENT_MAGIC``.
* ``NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN`` was replaced with
  ``NGHTTP2_CLIENT_MAGIC_LEN``.
* ``NGHTTP2_BAD_PREFACE`` was renamed as ``NGHTTP2_BAD_CLIENT_MAGIC``

The already deprecated ``NGHTTP2_CLIENT_CONNECTION_HEADER`` and
``NGHTTP2_CLIENT_CONNECTION_HEADER_LEN`` were removed.

If application uses these macros, just replace old ones with new ones.
Since v1.0.0, client magic is sent by library (see next subsection),
so client application may just remove these macro use.

Client magic is sent by library
+++++++++++++++++++++++++++++++

Previously nghttp2 library did not send client magic, which is first
24 bytes byte string of client connection preface, and client
applications have to send it by themselves.  Since v1.0.0, client
magic is sent by library via first call of ``nghttp2_session_send()``
or ``nghttp2_session_mem_send2()``.

The client applications which send client magic must remove the
relevant code.

Remove HTTP Alternative Services (Alt-Svc) related code
+++++++++++++++++++++++++++++++++++++++++++++++++++++++

Alt-Svc specification is not finalized yet.  To make our API stable,
we have decided to remove all Alt-Svc related API from nghttp2.

* ``NGHTTP2_EXT_ALTSVC`` was removed.
* ``nghttp2_ext_altsvc`` was removed.

We have already removed the functionality of Alt-Svc in v0.7 series
and they have been essentially noop.  The application using these
macro and struct, remove those lines.

Use nghttp2_error in nghttp2_on_invalid_frame_recv_callback
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Previously ``nghttp2_on_invalid_frame_recv_cb_called`` took the
``error_code``, defined in ``nghttp2_error_code``, as parameter.  But
they are not detailed enough to debug.  Therefore, we decided to use
more detailed ``nghttp2_error`` values instead.

The application using this callback should update the callback
signature.  If it treats ``error_code`` as HTTP/2 error code, update
the code so that it is treated as ``nghttp2_error``.

Receive client magic by default
+++++++++++++++++++++++++++++++

Previously nghttp2 did not process client magic (24 bytes byte
string).  To make it deal with it, we had to use
``nghttp2_option_set_recv_client_preface()``.  Since v1.0.0, nghttp2
processes client magic by default and
``nghttp2_option_set_recv_client_preface()`` was removed.

Some application may want to disable this behaviour, so we added
``nghttp2_option_set_no_recv_client_magic()`` to achieve this.

The application using ``nghttp2_option_set_recv_client_preface()``
with nonzero value, just remove it.

The application using ``nghttp2_option_set_recv_client_preface()``
with zero value or not using it must use
``nghttp2_option_set_no_recv_client_magic()`` with nonzero value.

Client, Server and Proxy programs
---------------------------------

The ``src`` directory contains the HTTP/2 client, server and proxy programs.

nghttp - client
+++++++++++++++

``nghttp`` is a HTTP/2 client.  It can connect to the HTTP/2 server
with prior knowledge, HTTP Upgrade and ALPN TLS extension.

It has verbose output mode for framing information.  Here is sample
output from ``nghttp`` client:

.. code-block:: text

    $ nghttp -nv https://nghttp2.org
    [  0.190] Connected
    The negotiated protocol: h2
    [  0.212] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
	      (niv=2)
	      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
	      [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
    [  0.212] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
	      (niv=2)
	      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
	      [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
    [  0.212] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
	      ; ACK
	      (niv=0)
    [  0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
	      (dep_stream_id=0, weight=201, exclusive=0)
    [  0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
	      (dep_stream_id=0, weight=101, exclusive=0)
    [  0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
	      (dep_stream_id=0, weight=1, exclusive=0)
    [  0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
	      (dep_stream_id=7, weight=1, exclusive=0)
    [  0.212] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
	      (dep_stream_id=3, weight=1, exclusive=0)
    [  0.212] send HEADERS frame <length=39, flags=0x25, stream_id=13>
	      ; END_STREAM | END_HEADERS | PRIORITY
	      (padlen=0, dep_stream_id=11, weight=16, exclusive=0)
	      ; Open new stream
	      :method: GET
	      :path: /
	      :scheme: https
	      :authority: nghttp2.org
	      accept: */*
	      accept-encoding: gzip, deflate
	      user-agent: nghttp2/1.0.1-DEV
    [  0.221] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
	      ; ACK
	      (niv=0)
    [  0.221] recv (stream_id=13) :method: GET
    [  0.221] recv (stream_id=13) :scheme: https
    [  0.221] recv (stream_id=13) :path: /stylesheets/screen.css
    [  0.221] recv (stream_id=13) :authority: nghttp2.org
    [  0.221] recv (stream_id=13) accept-encoding: gzip, deflate
    [  0.222] recv (stream_id=13) user-agent: nghttp2/1.0.1-DEV
    [  0.222] recv PUSH_PROMISE frame <length=50, flags=0x04, stream_id=13>
	      ; END_HEADERS
	      (padlen=0, promised_stream_id=2)
    [  0.222] recv (stream_id=13) :status: 200
    [  0.222] recv (stream_id=13) date: Thu, 21 May 2015 16:38:14 GMT
    [  0.222] recv (stream_id=13) content-type: text/html
    [  0.222] recv (stream_id=13) last-modified: Fri, 15 May 2015 15:38:06 GMT
    [  0.222] recv (stream_id=13) etag: W/"555612de-19f6"
    [  0.222] recv (stream_id=13) link: </stylesheets/screen.css>; rel=preload; as=stylesheet
    [  0.222] recv (stream_id=13) content-encoding: gzip
    [  0.222] recv (stream_id=13) server: nghttpx nghttp2/1.0.1-DEV
    [  0.222] recv (stream_id=13) via: 1.1 nghttpx
    [  0.222] recv (stream_id=13) strict-transport-security: max-age=31536000
    [  0.222] recv HEADERS frame <length=166, flags=0x04, stream_id=13>
	      ; END_HEADERS
	      (padlen=0)
	      ; First response header
    [  0.222] recv DATA frame <length=2601, flags=0x01, stream_id=13>
	      ; END_STREAM
    [  0.222] recv (stream_id=2) :status: 200
    [  0.222] recv (stream_id=2) date: Thu, 21 May 2015 16:38:14 GMT
    [  0.222] recv (stream_id=2) content-type: text/css
    [  0.222] recv (stream_id=2) last-modified: Fri, 15 May 2015 15:38:06 GMT
    [  0.222] recv (stream_id=2) etag: W/"555612de-9845"
    [  0.222] recv (stream_id=2) content-encoding: gzip
    [  0.222] recv (stream_id=2) server: nghttpx nghttp2/1.0.1-DEV
    [  0.222] recv (stream_id=2) via: 1.1 nghttpx
    [  0.222] recv (stream_id=2) strict-transport-security: max-age=31536000
    [  0.222] recv HEADERS frame <length=32, flags=0x04, stream_id=2>
	      ; END_HEADERS
	      (padlen=0)
	      ; First push response header
    [  0.228] recv DATA frame <length=8715, flags=0x01, stream_id=2>
	      ; END_STREAM
    [  0.228] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
	      (last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])

The HTTP Upgrade is performed like so:

.. code-block:: text

    $ nghttp -nvu http://nghttp2.org
    [  0.011] Connected
    [  0.011] HTTP Upgrade request
    GET / HTTP/1.1
    Host: nghttp2.org
    Connection: Upgrade, HTTP2-Settings
    Upgrade: h2c
    HTTP2-Settings: AAMAAABkAAQAAP__
    Accept: */*
    User-Agent: nghttp2/1.0.1-DEV


    [  0.018] HTTP Upgrade response
    HTTP/1.1 101 Switching Protocols
    Connection: Upgrade
    Upgrade: h2c


    [  0.018] HTTP Upgrade success
    [  0.018] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
	      (niv=2)
	      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
	      [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
    [  0.018] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
	      (niv=2)
	      [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
	      [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
    [  0.018] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
	      ; ACK
	      (niv=0)
    [  0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
	      (dep_stream_id=0, weight=201, exclusive=0)
    [  0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
	      (dep_stream_id=0, weight=101, exclusive=0)
    [  0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
	      (dep_stream_id=0, weight=1, exclusive=0)
    [  0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
	      (dep_stream_id=7, weight=1, exclusive=0)
    [  0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
	      (dep_stream_id=3, weight=1, exclusive=0)
    [  0.018] send PRIORITY frame <length=5, flags=0x00, stream_id=1>
	      (dep_stream_id=11, weight=16, exclusive=0)
    [  0.019] recv (stream_id=1) :method: GET
    [  0.019] recv (stream_id=1) :scheme: http
    [  0.019] recv (stream_id=1) :path: /stylesheets/screen.css
    [  0.019] recv (stream_id=1) host: nghttp2.org
    [  0.019] recv (stream_id=1) user-agent: nghttp2/1.0.1-DEV
    [  0.019] recv PUSH_PROMISE frame <length=49, flags=0x04, stream_id=1>
	      ; END_HEADERS
	      (padlen=0, promised_stream_id=2)
    [  0.019] recv (stream_id=1) :status: 200
    [  0.019] recv (stream_id=1) date: Thu, 21 May 2015 16:39:16 GMT
    [  0.019] recv (stream_id=1) content-type: text/html
    [  0.019] recv (stream_id=1) content-length: 6646
    [  0.019] recv (stream_id=1) last-modified: Fri, 15 May 2015 15:38:06 GMT
    [  0.019] recv (stream_id=1) etag: "555612de-19f6"
    [  0.019] recv (stream_id=1) link: </stylesheets/screen.css>; rel=preload; as=stylesheet
    [  0.019] recv (stream_id=1) accept-ranges: bytes
    [  0.019] recv (stream_id=1) server: nghttpx nghttp2/1.0.1-DEV
    [  0.019] recv (stream_id=1) via: 1.1 nghttpx
    [  0.019] recv HEADERS frame <length=157, flags=0x04, stream_id=1>
	      ; END_HEADERS
	      (padlen=0)
	      ; First response header
    [  0.019] recv DATA frame <length=6646, flags=0x01, stream_id=1>
	      ; END_STREAM
    [  0.019] recv (stream_id=2) :status: 200
    [  0.019] recv (stream_id=2) date: Thu, 21 May 2015 16:39:16 GMT
    [  0.019] recv (stream_id=2) content-type: text/css
    [  0.019] recv (stream_id=2) content-length: 38981
    [  0.019] recv (stream_id=2) last-modified: Fri, 15 May 2015 15:38:06 GMT
    [  0.019] recv (stream_id=2) etag: "555612de-9845"
    [  0.019] recv (stream_id=2) accept-ranges: bytes
    [  0.019] recv (stream_id=2) server: nghttpx nghttp2/1.0.1-DEV
    [  0.019] recv (stream_id=2) via: 1.1 nghttpx
    [  0.019] recv HEADERS frame <length=36, flags=0x04, stream_id=2>
	      ; END_HEADERS
	      (padlen=0)
	      ; First push response header
    [  0.026] recv DATA frame <length=16384, flags=0x00, stream_id=2>
    [  0.027] recv DATA frame <length=7952, flags=0x00, stream_id=2>
    [  0.027] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
	      (window_size_increment=33343)
    [  0.032] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=2>
	      (window_size_increment=33707)
    [  0.032] recv DATA frame <length=14645, flags=0x01, stream_id=2>
	      ; END_STREAM
    [  0.032] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
	      ; ACK
	      (niv=0)
    [  0.032] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
	      (last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])

Using the ``-s`` option, ``nghttp`` prints out some timing information for
requests, sorted by completion time:

.. code-block:: text

    $ nghttp -nas https://nghttp2.org/
    ***** Statistics *****

    Request timing:
      responseEnd: the  time  when  last  byte of  response  was  received
                   relative to connectEnd
     requestStart: the time  just before  first byte  of request  was sent
                   relative  to connectEnd.   If  '*' is  shown, this  was
                   pushed by server.
          process: responseEnd - requestStart
             code: HTTP status code
             size: number  of  bytes  received as  response  body  without
                   inflation.
              URI: request URI

    see http://www.w3.org/TR/resource-timing/#processing-model

    sorted by 'complete'

    id  responseEnd requestStart  process code size request path
     13    +37.19ms       +280us  36.91ms  200   2K /
      2    +72.65ms *   +36.38ms  36.26ms  200   8K /stylesheets/screen.css
     17    +77.43ms     +38.67ms  38.75ms  200   3K /javascripts/octopress.js
     15    +78.12ms     +38.66ms  39.46ms  200   3K /javascripts/modernizr-2.0.js

Using the ``-r`` option, ``nghttp`` writes more detailed timing data to
the given file in HAR format.

nghttpd - server
++++++++++++++++

``nghttpd`` is a multi-threaded static web server.

By default, it uses SSL/TLS connection.  Use ``--no-tls`` option to
disable it.

``nghttpd`` only accepts HTTP/2 connections via ALPN or direct HTTP/2
connections.  No HTTP Upgrade is supported.

The ``-p`` option allows users to configure server push.

Just like ``nghttp``, it has a verbose output mode for framing
information.  Here is sample output from ``nghttpd``:

.. code-block:: text

    $ nghttpd --no-tls -v 8080
    IPv4: listen 0.0.0.0:8080
    IPv6: listen :::8080
    [id=1] [  1.521] send SETTINGS frame <length=6, flags=0x00, stream_id=0>
              (niv=1)
              [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
    [id=1] [  1.521] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
              (niv=2)
              [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
              [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
    [id=1] [  1.521] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
              ; ACK
              (niv=0)
    [id=1] [  1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=3>
              (dep_stream_id=0, weight=201, exclusive=0)
    [id=1] [  1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=5>
              (dep_stream_id=0, weight=101, exclusive=0)
    [id=1] [  1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=7>
              (dep_stream_id=0, weight=1, exclusive=0)
    [id=1] [  1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=9>
              (dep_stream_id=7, weight=1, exclusive=0)
    [id=1] [  1.521] recv PRIORITY frame <length=5, flags=0x00, stream_id=11>
              (dep_stream_id=3, weight=1, exclusive=0)
    [id=1] [  1.521] recv (stream_id=13) :method: GET
    [id=1] [  1.521] recv (stream_id=13) :path: /
    [id=1] [  1.521] recv (stream_id=13) :scheme: http
    [id=1] [  1.521] recv (stream_id=13) :authority: localhost:8080
    [id=1] [  1.521] recv (stream_id=13) accept: */*
    [id=1] [  1.521] recv (stream_id=13) accept-encoding: gzip, deflate
    [id=1] [  1.521] recv (stream_id=13) user-agent: nghttp2/1.0.0-DEV
    [id=1] [  1.521] recv HEADERS frame <length=41, flags=0x25, stream_id=13>
              ; END_STREAM | END_HEADERS | PRIORITY
              (padlen=0, dep_stream_id=11, weight=16, exclusive=0)
              ; Open new stream
    [id=1] [  1.521] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
              ; ACK
              (niv=0)
    [id=1] [  1.521] send HEADERS frame <length=86, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0)
              ; First response header
              :status: 200
              server: nghttpd nghttp2/1.0.0-DEV
              content-length: 10
              cache-control: max-age=3600
              date: Fri, 15 May 2015 14:49:04 GMT
              last-modified: Tue, 30 Sep 2014 12:40:52 GMT
    [id=1] [  1.522] send DATA frame <length=10, flags=0x01, stream_id=13>
              ; END_STREAM
    [id=1] [  1.522] stream_id=13 closed
    [id=1] [  1.522] recv GOAWAY frame <length=8, flags=0x00, stream_id=0>
              (last_stream_id=0, error_code=NO_ERROR(0x00), opaque_data(0)=[])
    [id=1] [  1.522] closed

nghttpx - proxy
+++++++++++++++

``nghttpx`` is a multi-threaded reverse proxy for HTTP/3, HTTP/2, and
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server
push.

We reworked ``nghttpx`` command-line interface, and as a result, there
are several incompatibles from 1.8.0 or earlier.  This is necessary to
extend its capability, and secure the further feature enhancements in
the future release.  Please read `Migration from nghttpx v1.8.0 or
earlier
<https://nghttp2.org/documentation/nghttpx-howto.html#migration-from-nghttpx-v1-8-0-or-earlier>`_
to know how to migrate from earlier releases.

``nghttpx`` implements `important performance-oriented features
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
session IDs, session tickets (with automatic key rotation), OCSP
stapling, dynamic record sizing, ALPN, forward secrecy and HTTP/2.
``nghttpx`` also offers the functionality to share session cache and
ticket keys among multiple ``nghttpx`` instances via memcached.

``nghttpx`` has 2 operation modes:

================== ======================== ================ =============
Mode option        Frontend                 Backend          Note
================== ======================== ================ =============
default mode       HTTP/3, HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Reverse proxy
``--http2-proxy``  HTTP/3, HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Forward proxy
================== ======================== ================ =============

The interesting mode at the moment is the default mode.  It works like
a reverse proxy and listens for HTTP/3, HTTP/2, and HTTP/1.1 and can
be deployed as a SSL/TLS terminator for existing web server.

In all modes, the frontend connections are encrypted by SSL/TLS by
default.  To disable encryption, use the ``no-tls`` keyword in
``--frontend`` option.  If encryption is disabled, incoming HTTP/1.1
connections can be upgraded to HTTP/2 through HTTP Upgrade.  On the
other hard, backend connections are not encrypted by default.  To
encrypt backend connections, use ``tls`` keyword in ``--backend``
option.

``nghttpx`` supports a configuration file.  See the ``--conf`` option and
sample configuration file ``nghttpx.conf.sample``.

In the default mode, ``nghttpx`` works as reverse proxy to the backend
server:

.. code-block:: text

    Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Web Server
                                            [reverse proxy]

With the ``--http2-proxy`` option, it works as forward proxy, and it
is so called secure HTTP/2 proxy:

.. code-block:: text

    Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
                                             [secure proxy]          (e.g., Squid, ATS)

The ``Client`` in the above example needs to be configured to use
``nghttpx`` as secure proxy.

At the time of this writing, both Chrome and Firefox support secure
HTTP/2 proxy.  One way to configure Chrome to use a secure proxy is to
create a proxy.pac script like this:

.. code-block:: javascript

    function FindProxyForURL(url, host) {
        return "HTTPS SERVERADDR:PORT";
    }

``SERVERADDR`` and ``PORT`` is the hostname/address and port of the
machine nghttpx is running on.  Please note that Chrome requires a valid
certificate for secure proxy.

Then run Chrome with the following arguments:

.. code-block:: text

    $ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn

The backend HTTP/2 connections can be tunneled through an HTTP proxy.
The proxy is specified using ``--backend-http-proxy-uri``.  The
following figure illustrates how nghttpx talks to the outside HTTP/2
proxy through an HTTP proxy:

.. code-block:: text

    Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --

            --===================---> HTTP/2 Proxy
              (HTTP proxy tunnel)     (e.g., nghttpx -s)

Benchmarking tool
-----------------

The ``h2load`` program is a benchmarking tool for HTTP/3, HTTP/2, and
HTTP/1.1.  The UI of ``h2load`` is heavily inspired by ``weighttp``
(https://github.com/lighttpd/weighttp).  The typical usage is as
follows:

.. code-block:: text

    $ h2load -n100000 -c100 -m100 https://localhost:8443/
    starting benchmark...
    spawning thread #0: 100 concurrent clients, 100000 total requests
    Protocol: TLSv1.2
    Cipher: ECDHE-RSA-AES128-GCM-SHA256
    Server Temp Key: ECDH P-256 256 bits
    progress: 10% done
    progress: 20% done
    progress: 30% done
    progress: 40% done
    progress: 50% done
    progress: 60% done
    progress: 70% done
    progress: 80% done
    progress: 90% done
    progress: 100% done

    finished in 771.26ms, 129658 req/s, 4.71MB/s
    requests: 100000 total, 100000 started, 100000 done, 100000 succeeded, 0 failed, 0 errored
    status codes: 100000 2xx, 0 3xx, 0 4xx, 0 5xx
    traffic: 3812300 bytes total, 1009900 bytes headers, 1000000 bytes data
                         min         max         mean         sd        +/- sd
    time for request:    25.12ms    124.55ms     51.07ms     15.36ms    84.87%
    time for connect:   208.94ms    254.67ms    241.38ms      7.95ms    63.00%
    time to 1st byte:   209.11ms    254.80ms    241.51ms      7.94ms    63.00%

The above example issued total 100,000 requests, using 100 concurrent
clients (in other words, 100 HTTP/2 sessions), and a maximum of 100 streams
per client.  With the ``-t`` option, ``h2load`` will use multiple native
threads to avoid saturating a single core on client side.

.. warning::

   **Don't use this tool against publicly available servers.** That is
   considered a DOS attack.  Please only use it against your private
   servers.

If the experimental HTTP/3 is enabled, h2load can send requests to
HTTP/3 server.  To do this, specify ``h3`` to ``--alpn-list`` option
like so:

.. code-block:: text

    $ h2load --alpn-list h3 https://127.0.0.1:4433

For nghttp2 v1.58 or earlier, use ``--npn-list`` instead of
``--alpn-list``.

HPACK tools
-----------

The ``src`` directory contains the HPACK tools.  The ``deflatehd`` program is a
command-line header compression tool.  The ``inflatehd`` program is a
command-line header decompression tool.  Both tools read input from
stdin and write output to stdout.  Errors are written to stderr.
They take JSON as input and output.  We  (mostly) use the same JSON data
format described at https://github.com/http2jp/hpack-test-case.

deflatehd - header compressor
+++++++++++++++++++++++++++++

The ``deflatehd`` program reads JSON data or HTTP/1-style header fields from
stdin and outputs compressed header block in JSON.

For the JSON input, the root JSON object must include a ``cases`` key.
Its value has to include the sequence of input header set.  They share
the same compression context and are processed in the order they
appear.  Each item in the sequence is a JSON object and it must
include a ``headers`` key.  Its value is an array of JSON objects,
which includes exactly one name/value pair.

Example:

.. code-block:: json

    {
      "cases":
      [
        {
          "headers": [
            { ":method": "GET" },
            { ":path": "/" }
          ]
        },
        {
          "headers": [
            { ":method": "POST" },
            { ":path": "/" }
          ]
        }
      ]
    }


With the ``-t`` option, the program can accept more familiar HTTP/1 style
header field blocks.  Each header set is delimited by an empty line:

Example:

.. code-block:: text

    :method: GET
    :scheme: https
    :path: /

    :method: POST
    user-agent: nghttp2

The output is in JSON object.  It should include a ``cases`` key and its
value is an array of JSON objects, which has at least the following keys:

seq
    The index of header set in the input.

input_length
    The sum of the length of the name/value pairs in the input.

output_length
    The length of the compressed header block.

percentage_of_original_size
    ``output_length`` / ``input_length`` * 100

wire
    The compressed header block as a hex string.

headers
    The input header set.

header_table_size
    The header table size adjusted before deflating the header set.

Examples:

.. code-block:: json

    {
      "cases":
      [
        {
          "seq": 0,
          "input_length": 66,
          "output_length": 20,
          "percentage_of_original_size": 30.303030303030305,
          "wire": "01881f3468e5891afcbf83868a3d856659c62e3f",
          "headers": [
            {
              ":authority": "example.org"
            },
            {
              ":method": "GET"
            },
            {
              ":path": "/"
            },
            {
              ":scheme": "https"
            },
            {
              "user-agent": "nghttp2"
            }
          ],
          "header_table_size": 4096
        }
        ,
        {
          "seq": 1,
          "input_length": 74,
          "output_length": 10,
          "percentage_of_original_size": 13.513513513513514,
          "wire": "88448504252dd5918485",
          "headers": [
            {
              ":authority": "example.org"
            },
            {
              ":method": "POST"
            },
            {
              ":path": "/account"
            },
            {
              ":scheme": "https"
            },
            {
              "user-agent": "nghttp2"
            }
          ],
          "header_table_size": 4096
        }
      ]
    }


The output can be used as the input for ``inflatehd`` and
``deflatehd``.

With the ``-d`` option, the extra ``header_table`` key is added and its
associated value includes the state of dynamic header table after the
corresponding header set was processed.  The value includes at least
the following keys:

entries
    The entry in the header table.  If ``referenced`` is ``true``, it
    is in the reference set.  The ``size`` includes the overhead (32
    bytes).  The ``index`` corresponds to the index of header table.
    The ``name`` is the header field name and the ``value`` is the
    header field value.

size
    The sum of the spaces entries occupied, this includes the
    entry overhead.

max_size
    The maximum header table size.

deflate_size
    The sum of the spaces entries occupied within
    ``max_deflate_size``.

max_deflate_size
    The maximum header table size the encoder uses.  This can be smaller
    than ``max_size``.  In this case, the encoder only uses up to first
    ``max_deflate_size`` buffer.  Since the header table size is still
    ``max_size``, the encoder has to keep track of entries outside the
    ``max_deflate_size`` but inside the ``max_size`` and make sure
    that they are no longer referenced.

Example:

.. code-block:: json

    {
      "cases":
      [
        {
          "seq": 0,
          "input_length": 66,
          "output_length": 20,
          "percentage_of_original_size": 30.303030303030305,
          "wire": "01881f3468e5891afcbf83868a3d856659c62e3f",
          "headers": [
            {
              ":authority": "example.org"
            },
            {
              ":method": "GET"
            },
            {
              ":path": "/"
            },
            {
              ":scheme": "https"
            },
            {
              "user-agent": "nghttp2"
            }
          ],
          "header_table_size": 4096,
          "header_table": {
            "entries": [
              {
                "index": 1,
                "name": "user-agent",
                "value": "nghttp2",
                "referenced": true,
                "size": 49
              },
              {
                "index": 2,
                "name": ":scheme",
                "value": "https",
                "referenced": true,
                "size": 44
              },
              {
                "index": 3,
                "name": ":path",
                "value": "/",
                "referenced": true,
                "size": 38
              },
              {
                "index": 4,
                "name": ":method",
                "value": "GET",
                "referenced": true,
                "size": 42
              },
              {
                "index": 5,
                "name": ":authority",
                "value": "example.org",
                "referenced": true,
                "size": 53
              }
            ],
            "size": 226,
            "max_size": 4096,
            "deflate_size": 226,
            "max_deflate_size": 4096
          }
        }
        ,
        {
          "seq": 1,
          "input_length": 74,
          "output_length": 10,
          "percentage_of_original_size": 13.513513513513514,
          "wire": "88448504252dd5918485",
          "headers": [
            {
              ":authority": "example.org"
            },
            {
              ":method": "POST"
            },
            {
              ":path": "/account"
            },
            {
              ":scheme": "https"
            },
            {
              "user-agent": "nghttp2"
            }
          ],
          "header_table_size": 4096,
          "header_table": {
            "entries": [
              {
                "index": 1,
                "name": ":method",
                "value": "POST",
                "referenced": true,
                "size": 43
              },
              {
                "index": 2,
                "name": "user-agent",
                "value": "nghttp2",
                "referenced": true,
                "size": 49
              },
              {
                "index": 3,
                "name": ":scheme",
                "value": "https",
                "referenced": true,
                "size": 44
              },
              {
                "index": 4,
                "name": ":path",
                "value": "/",
                "referenced": false,
                "size": 38
              },
              {
                "index": 5,
                "name": ":method",
                "value": "GET",
                "referenced": false,
                "size": 42
              },
              {
                "index": 6,
                "name": ":authority",
                "value": "example.org",
                "referenced": true,
                "size": 53
              }
            ],
            "size": 269,
            "max_size": 4096,
            "deflate_size": 269,
            "max_deflate_size": 4096
          }
        }
      ]
    }

inflatehd - header decompressor
+++++++++++++++++++++++++++++++

The ``inflatehd`` program reads JSON data from stdin and outputs decompressed
name/value pairs in JSON.

The root JSON object must include the ``cases`` key.  Its value has to
include the sequence of compressed header blocks.  They share the same
compression context and are processed in the order they appear.  Each
item in the sequence is a JSON object and it must have at least a
``wire`` key.  Its value is a compressed header block as a hex string.

Example:

.. code-block:: json

    {
      "cases":
      [
        { "wire": "8285" },
        { "wire": "8583" }
      ]
    }

The output is a JSON object.  It should include a ``cases`` key and its
value is an array of JSON objects, which has at least following keys:

seq
    The index of the header set in the input.

headers
    A JSON array that includes decompressed name/value pairs.

wire
    The compressed header block as a hex string.

header_table_size
    The header table size adjusted before inflating compressed header
    block.

Example:

.. code-block:: json

    {
      "cases":
      [
        {
          "seq": 0,
          "wire": "01881f3468e5891afcbf83868a3d856659c62e3f",
          "headers": [
            {
              ":authority": "example.org"
            },
            {
              ":method": "GET"
            },
            {
              ":path": "/"
            },
            {
              ":scheme": "https"
            },
            {
              "user-agent": "nghttp2"
            }
          ],
          "header_table_size": 4096
        }
        ,
        {
          "seq": 1,
          "wire": "88448504252dd5918485",
          "headers": [
            {
              ":method": "POST"
            },
            {
              ":path": "/account"
            },
            {
              "user-agent": "nghttp2"
            },
            {
              ":scheme": "https"
            },
            {
              ":authority": "example.org"
            }
          ],
          "header_table_size": 4096
        }
      ]
    }

The output can be used as the input for ``deflatehd`` and
``inflatehd``.

With the ``-d`` option, the extra ``header_table`` key is added and its
associated value includes the state of the dynamic header table after the
corresponding header set was processed.  The format is the same as
``deflatehd``.

Contribution
------------

[This text was composed based on 1.2. License section of curl/libcurl
project.]

When contributing with code, you agree to put your changes and new
code under the same license nghttp2 is already using unless stated and
agreed otherwise.

When changing existing source code, do not alter the copyright of
the original file(s).  The copyright will still be owned by the
original creator(s) or those who have been assigned copyright by the
original author(s).

By submitting a patch to the nghttp2 project, you (or your employer, as
the case may be) agree to assign the copyright of your submission to us.
.. the above really needs to be reworded to pass legal muster.
We will credit you for your
changes as far as possible, to give credit but also to keep a trace
back to who made what changes.  Please always provide us with your
full real name when contributing!

See `Contribution Guidelines
<https://nghttp2.org/documentation/contribute.html>`_ for more
details.

Versioning
----------

In general, we follow `Semantic Versioning <http://semver.org/>`_.

We may release PATCH releases between the regular releases, mainly for
severe security bug fixes.

We have no plan to break API compatibility changes involving soname
bump, so MAJOR version will stay 1 for the foreseeable future.

License
-------

The MIT License
alt-openssl11/NEWS000064400000133524150404743610007662 0ustar00
  NEWS
  ====

  This file gives a brief overview of the major changes between each OpenSSL
  release. For more details please read the CHANGES file.

  Major changes between OpenSSL 1.1.1v and OpenSSL 1.1.1w [11 Sep 2023]

      o Fix POLY1305 MAC implementation corrupting XMM registers on Windows
        (CVE-2023-4807)

  Major changes between OpenSSL 1.1.1u and OpenSSL 1.1.1v [1 Aug 2023]

      o Fix excessive time spent checking DH q parameter value (CVE-2023-3817)
      o Fix DH_check() excessive time with over sized modulus (CVE-2023-3446)

  Major changes between OpenSSL 1.1.1t and OpenSSL 1.1.1u [30 May 2023]

      o Mitigate for very slow `OBJ_obj2txt()` performance with gigantic
        OBJECT IDENTIFIER sub-identities.  (CVE-2023-2650)
      o Fixed documentation of X509_VERIFY_PARAM_add0_policy() (CVE-2023-0466)
      o Fixed handling of invalid certificate policies in leaf certificates
        (CVE-2023-0465)
      o Limited the number of nodes created in a policy tree ([CVE-2023-0464])

  Major changes between OpenSSL 1.1.1s and OpenSSL 1.1.1t [7 Feb 2023]

      o Fixed X.400 address type confusion in X.509 GeneralName (CVE-2023-0286)
      o Fixed Use-after-free following BIO_new_NDEF (CVE-2023-0215)
      o Fixed Double free after calling PEM_read_bio_ex (CVE-2022-4450)
      o Fixed Timing Oracle in RSA Decryption (CVE-2022-4304)

  Major changes between OpenSSL 1.1.1r and OpenSSL 1.1.1s [1 Nov 2022]

      o Fixed a regression introduced in OpenSSL 1.1.1r not refreshing the
        certificate data to be signed before signing the certificate.

  Major changes between OpenSSL 1.1.1q and OpenSSL 1.1.1r [11 Oct 2022]

      o Added a missing header for memcmp that caused compilation failure on
        some platforms

  Major changes between OpenSSL 1.1.1p and OpenSSL 1.1.1q [5 Jul 2022]

      o Fixed AES OCB failure to encrypt some bytes on 32-bit x86 platforms
        (CVE-2022-2097)

  Major changes between OpenSSL 1.1.1o and OpenSSL 1.1.1p [21 Jun 2022]

      o Fixed additional bugs in the c_rehash script which was not properly
        sanitising shell metacharacters to prevent command injection
        (CVE-2022-2068)

  Major changes between OpenSSL 1.1.1n and OpenSSL 1.1.1o [3 May 2022]

      o Fixed a bug in the c_rehash script which was not properly sanitising
        shell metacharacters to prevent command injection (CVE-2022-1292)

  Major changes between OpenSSL 1.1.1m and OpenSSL 1.1.1n [15 Mar 2022]

      o Fixed a bug in the BN_mod_sqrt() function that can cause it to loop
        forever for non-prime moduli (CVE-2022-0778)

  Major changes between OpenSSL 1.1.1l and OpenSSL 1.1.1m [14 Dec 2021]

      o None

  Major changes between OpenSSL 1.1.1k and OpenSSL 1.1.1l [24 Aug 2021]

      o Fixed an SM2 Decryption Buffer Overflow (CVE-2021-3711)
      o Fixed various read buffer overruns processing ASN.1 strings (CVE-2021-3712)

  Major changes between OpenSSL 1.1.1j and OpenSSL 1.1.1k [25 Mar 2021]

      o Fixed a problem with verifying a certificate chain when using the
        X509_V_FLAG_X509_STRICT flag (CVE-2021-3450)
      o Fixed an issue where an OpenSSL TLS server may crash if sent a
        maliciously crafted renegotiation ClientHello message from a client
        (CVE-2021-3449)

  Major changes between OpenSSL 1.1.1i and OpenSSL 1.1.1j [16 Feb 2021]

      o Fixed a NULL pointer deref in the X509_issuer_and_serial_hash()
        function (CVE-2021-23841)
      o Fixed the RSA_padding_check_SSLv23() function and the RSA_SSLV23_PADDING
        padding mode to correctly check for rollback attacks
      o Fixed an overflow in the EVP_CipherUpdate, EVP_EncryptUpdate and
        EVP_DecryptUpdate functions (CVE-2021-23840)
      o Fixed SRP_Calc_client_key so that it runs in constant time

  Major changes between OpenSSL 1.1.1h and OpenSSL 1.1.1i [8 Dec 2020]

      o Fixed NULL pointer deref in GENERAL_NAME_cmp (CVE-2020-1971)

  Major changes between OpenSSL 1.1.1g and OpenSSL 1.1.1h [22 Sep 2020]

      o Disallow explicit curve parameters in verifications chains when
        X509_V_FLAG_X509_STRICT is used
      o Enable 'MinProtocol' and 'MaxProtocol' to configure both TLS and DTLS
        contexts
      o Oracle Developer Studio will start reporting deprecation warnings

  Major changes between OpenSSL 1.1.1f and OpenSSL 1.1.1g [21 Apr 2020]

      o Fixed segmentation fault in SSL_check_chain() (CVE-2020-1967)

  Major changes between OpenSSL 1.1.1e and OpenSSL 1.1.1f [31 Mar 2020]

      o Revert the unexpected EOF reporting via SSL_ERROR_SSL

  Major changes between OpenSSL 1.1.1d and OpenSSL 1.1.1e [17 Mar 2020]

      o Fixed an overflow bug in the x64_64 Montgomery squaring procedure
        used in exponentiation with 512-bit moduli (CVE-2019-1551)
      o Properly detect unexpected EOF while reading in libssl and report
        it via SSL_ERROR_SSL

  Major changes between OpenSSL 1.1.1c and OpenSSL 1.1.1d [10 Sep 2019]

      o Fixed a fork protection issue (CVE-2019-1549)
      o Fixed a padding oracle in PKCS7_dataDecode and CMS_decrypt_set1_pkey
        (CVE-2019-1563)
      o For built-in EC curves, ensure an EC_GROUP built from the curve name is
        used even when parsing explicit parameters
      o Compute ECC cofactors if not provided during EC_GROUP construction
        (CVE-2019-1547)
      o Early start up entropy quality from the DEVRANDOM seed source has been
        improved for older Linux systems
      o Correct the extended master secret constant on EBCDIC systems
      o Use Windows installation paths in the mingw builds (CVE-2019-1552)
      o Changed DH_check to accept parameters with order q and 2q subgroups
      o Significantly reduce secure memory usage by the randomness pools
      o Revert the DEVRANDOM_WAIT feature for Linux systems

  Major changes between OpenSSL 1.1.1b and OpenSSL 1.1.1c [28 May 2019]

      o Prevent over long nonces in ChaCha20-Poly1305 (CVE-2019-1543)

  Major changes between OpenSSL 1.1.1a and OpenSSL 1.1.1b [26 Feb 2019]

      o Change the info callback signals for the start and end of a post-handshake
        message exchange in TLSv1.3.
      o Fix a bug in DTLS over SCTP. This breaks interoperability with older versions
        of OpenSSL like OpenSSL 1.1.0 and OpenSSL 1.0.2.

  Major changes between OpenSSL 1.1.1 and OpenSSL 1.1.1a [20 Nov 2018]

      o Timing vulnerability in DSA signature generation (CVE-2018-0734)
      o Timing vulnerability in ECDSA signature generation (CVE-2018-0735)

  Major changes between OpenSSL 1.1.0i and OpenSSL 1.1.1 [11 Sep 2018]

      o Support for TLSv1.3 added (see https://wiki.openssl.org/index.php/TLS1.3
        for further important information). The TLSv1.3 implementation includes:
          o Fully compliant implementation of RFC8446 (TLSv1.3) on by default
          o Early data (0-RTT)
          o Post-handshake authentication and key update
          o Middlebox Compatibility Mode
          o TLSv1.3 PSKs
          o Support for all five RFC8446 ciphersuites
          o RSA-PSS signature algorithms (backported to TLSv1.2)
          o Configurable session ticket support
          o Stateless server support
          o Rewrite of the packet construction code for "safer" packet handling
          o Rewrite of the extension handling code
      o Complete rewrite of the OpenSSL random number generator to introduce the
        following capabilities
          o The default RAND method now utilizes an AES-CTR DRBG according to
            NIST standard SP 800-90Ar1.
          o Support for multiple DRBG instances with seed chaining.
          o There is a public and private DRBG instance.
          o The DRBG instances are fork-safe.
          o Keep all global DRBG instances on the secure heap if it is enabled.
          o The public and private DRBG instance are per thread for lock free
            operation
      o Support for various new cryptographic algorithms including:
          o SHA3
          o SHA512/224 and SHA512/256
          o EdDSA (both Ed25519 and Ed448) including X509 and TLS support
          o X448 (adding to the existing X25519 support in 1.1.0)
          o Multi-prime RSA
          o SM2
          o SM3
          o SM4
          o SipHash
          o ARIA (including TLS support)
      o Significant Side-Channel attack security improvements
      o Add a new ClientHello callback to provide the ability to adjust the SSL
        object at an early stage.
      o Add 'Maximum Fragment Length' TLS extension negotiation and support
      o A new STORE module, which implements a uniform and URI based reader of
        stores that can contain keys, certificates, CRLs and numerous other
        objects.
      o Move the display of configuration data to configdata.pm.
      o Allow GNU style "make variables" to be used with Configure.
      o Claim the namespaces OSSL and OPENSSL, represented as symbol prefixes
      o Rewrite of devcrypto engine

  Major changes between OpenSSL 1.1.0h and OpenSSL 1.1.0i [under development]

      o Client DoS due to large DH parameter (CVE-2018-0732)
      o Cache timing vulnerability in RSA Key Generation (CVE-2018-0737)

  Major changes between OpenSSL 1.1.0g and OpenSSL 1.1.0h [under development]

      o Constructed ASN.1 types with a recursive definition could exceed the
        stack (CVE-2018-0739)
      o Incorrect CRYPTO_memcmp on HP-UX PA-RISC (CVE-2018-0733)
      o rsaz_1024_mul_avx2 overflow bug on x86_64 (CVE-2017-3738)

  Major changes between OpenSSL 1.1.0f and OpenSSL 1.1.0g [2 Nov 2017]

      o bn_sqrx8x_internal carry bug on x86_64 (CVE-2017-3736)
      o Malformed X.509 IPAddressFamily could cause OOB read (CVE-2017-3735)

  Major changes between OpenSSL 1.1.0e and OpenSSL 1.1.0f [25 May 2017]

      o config now recognises 64-bit mingw and chooses mingw64 instead of mingw

  Major changes between OpenSSL 1.1.0d and OpenSSL 1.1.0e [16 Feb 2017]

      o Encrypt-Then-Mac renegotiation crash (CVE-2017-3733)

  Major changes between OpenSSL 1.1.0c and OpenSSL 1.1.0d [26 Jan 2017]

      o Truncated packet could crash via OOB read (CVE-2017-3731)
      o Bad (EC)DHE parameters cause a client crash (CVE-2017-3730)
      o BN_mod_exp may produce incorrect results on x86_64 (CVE-2017-3732)

  Major changes between OpenSSL 1.1.0b and OpenSSL 1.1.0c [10 Nov 2016]

      o ChaCha20/Poly1305 heap-buffer-overflow (CVE-2016-7054)
      o CMS Null dereference (CVE-2016-7053)
      o Montgomery multiplication may produce incorrect results (CVE-2016-7055)

  Major changes between OpenSSL 1.1.0a and OpenSSL 1.1.0b [26 Sep 2016]

      o Fix Use After Free for large message sizes (CVE-2016-6309)

  Major changes between OpenSSL 1.1.0 and OpenSSL 1.1.0a [22 Sep 2016]

      o OCSP Status Request extension unbounded memory growth (CVE-2016-6304)
      o SSL_peek() hang on empty record (CVE-2016-6305)
      o Excessive allocation of memory in tls_get_message_header()
       (CVE-2016-6307)
      o Excessive allocation of memory in dtls1_preprocess_fragment()
       (CVE-2016-6308)

  Major changes between OpenSSL 1.0.2h and OpenSSL 1.1.0 [25 Aug 2016]

      o Copyright text was shrunk to a boilerplate that points to the license
      o "shared" builds are now the default when possible
      o Added support for "pipelining"
      o Added the AFALG engine
      o New threading API implemented
      o Support for ChaCha20 and Poly1305 added to libcrypto and libssl
      o Support for extended master secret
      o CCM ciphersuites
      o Reworked test suite, now based on perl, Test::Harness and Test::More
      o *Most* libcrypto and libssl public structures were made opaque,
        including:
        BIGNUM and associated types, EC_KEY and EC_KEY_METHOD,
        DH and DH_METHOD, DSA and DSA_METHOD, RSA and RSA_METHOD,
        BIO and BIO_METHOD, EVP_MD_CTX, EVP_MD, EVP_CIPHER_CTX,
        EVP_CIPHER, EVP_PKEY and associated types, HMAC_CTX,
        X509, X509_CRL, X509_OBJECT, X509_STORE_CTX, X509_STORE,
        X509_LOOKUP, X509_LOOKUP_METHOD
      o libssl internal structures made opaque
      o SSLv2 support removed
      o Kerberos ciphersuite support removed
      o RC4 removed from DEFAULT ciphersuites in libssl
      o 40 and 56 bit cipher support removed from libssl
      o All public header files moved to include/openssl, no more symlinking
      o SSL/TLS state machine, version negotiation and record layer rewritten
      o EC revision: now operations use new EC_KEY_METHOD.
      o Support for OCB mode added to libcrypto
      o Support for asynchronous crypto operations added to libcrypto and libssl
      o Deprecated interfaces can now be disabled at build time either
        relative to the latest release via the "no-deprecated" Configure
        argument, or via the "--api=1.1.0|1.0.0|0.9.8" option.
      o Application software can be compiled with -DOPENSSL_API_COMPAT=version
        to ensure that features deprecated in that version are not exposed.
      o Support for RFC6698/RFC7671 DANE TLSA peer authentication
      o Change of Configure to use --prefix as the main installation
        directory location rather than --openssldir.  The latter becomes
        the directory for certs, private key and openssl.cnf exclusively.
      o Reworked BIO networking library, with full support for IPv6.
      o New "unified" build system
      o New security levels
      o Support for scrypt algorithm
      o Support for X25519
      o Extended SSL_CONF support using configuration files
      o KDF algorithm support. Implement TLS PRF as a KDF.
      o Support for Certificate Transparency
      o HKDF support.

  Major changes between OpenSSL 1.0.2g and OpenSSL 1.0.2h [3 May 2016]

      o Prevent padding oracle in AES-NI CBC MAC check (CVE-2016-2107)
      o Fix EVP_EncodeUpdate overflow (CVE-2016-2105)
      o Fix EVP_EncryptUpdate overflow (CVE-2016-2106)
      o Prevent ASN.1 BIO excessive memory allocation (CVE-2016-2109)
      o EBCDIC overread (CVE-2016-2176)
      o Modify behavior of ALPN to invoke callback after SNI/servername
        callback, such that updates to the SSL_CTX affect ALPN.
      o Remove LOW from the DEFAULT cipher list.  This removes singles DES from
        the default.
      o Only remove the SSLv2 methods with the no-ssl2-method option.

  Major changes between OpenSSL 1.0.2f and OpenSSL 1.0.2g [1 Mar 2016]

      o Disable weak ciphers in SSLv3 and up in default builds of OpenSSL.
      o Disable SSLv2 default build, default negotiation and weak ciphers
        (CVE-2016-0800)
      o Fix a double-free in DSA code (CVE-2016-0705)
      o Disable SRP fake user seed to address a server memory leak
        (CVE-2016-0798)
      o Fix BN_hex2bn/BN_dec2bn NULL pointer deref/heap corruption
        (CVE-2016-0797)
      o Fix memory issues in BIO_*printf functions (CVE-2016-0799)
      o Fix side channel attack on modular exponentiation (CVE-2016-0702)

  Major changes between OpenSSL 1.0.2e and OpenSSL 1.0.2f [28 Jan 2016]

      o DH small subgroups (CVE-2016-0701)
      o SSLv2 doesn't block disabled ciphers (CVE-2015-3197)

  Major changes between OpenSSL 1.0.2d and OpenSSL 1.0.2e [3 Dec 2015]

      o BN_mod_exp may produce incorrect results on x86_64 (CVE-2015-3193)
      o Certificate verify crash with missing PSS parameter (CVE-2015-3194)
      o X509_ATTRIBUTE memory leak (CVE-2015-3195)
      o Rewrite EVP_DecodeUpdate (base64 decoding) to fix several bugs
      o In DSA_generate_parameters_ex, if the provided seed is too short,
        return an error

  Major changes between OpenSSL 1.0.2c and OpenSSL 1.0.2d [9 Jul 2015]

      o Alternate chains certificate forgery (CVE-2015-1793)
      o Race condition handling PSK identify hint (CVE-2015-3196)

  Major changes between OpenSSL 1.0.2b and OpenSSL 1.0.2c [12 Jun 2015]

      o Fix HMAC ABI incompatibility

  Major changes between OpenSSL 1.0.2a and OpenSSL 1.0.2b [11 Jun 2015]

      o Malformed ECParameters causes infinite loop (CVE-2015-1788)
      o Exploitable out-of-bounds read in X509_cmp_time (CVE-2015-1789)
      o PKCS7 crash with missing EnvelopedContent (CVE-2015-1790)
      o CMS verify infinite loop with unknown hash function (CVE-2015-1792)
      o Race condition handling NewSessionTicket (CVE-2015-1791)

  Major changes between OpenSSL 1.0.2 and OpenSSL 1.0.2a [19 Mar 2015]

      o OpenSSL 1.0.2 ClientHello sigalgs DoS fix (CVE-2015-0291)
      o Multiblock corrupted pointer fix (CVE-2015-0290)
      o Segmentation fault in DTLSv1_listen fix (CVE-2015-0207)
      o Segmentation fault in ASN1_TYPE_cmp fix (CVE-2015-0286)
      o Segmentation fault for invalid PSS parameters fix (CVE-2015-0208)
      o ASN.1 structure reuse memory corruption fix (CVE-2015-0287)
      o PKCS7 NULL pointer dereferences fix (CVE-2015-0289)
      o DoS via reachable assert in SSLv2 servers fix (CVE-2015-0293)
      o Empty CKE with client auth and DHE fix (CVE-2015-1787)
      o Handshake with unseeded PRNG fix (CVE-2015-0285)
      o Use After Free following d2i_ECPrivatekey error fix (CVE-2015-0209)
      o X509_to_X509_REQ NULL pointer deref fix (CVE-2015-0288)
      o Removed the export ciphers from the DEFAULT ciphers

  Major changes between OpenSSL 1.0.1l and OpenSSL 1.0.2 [22 Jan 2015]:

      o Suite B support for TLS 1.2 and DTLS 1.2
      o Support for DTLS 1.2
      o TLS automatic EC curve selection.
      o API to set TLS supported signature algorithms and curves
      o SSL_CONF configuration API.
      o TLS Brainpool support.
      o ALPN support.
      o CMS support for RSA-PSS, RSA-OAEP, ECDH and X9.42 DH.

  Major changes between OpenSSL 1.0.1k and OpenSSL 1.0.1l [15 Jan 2015]

      o Build fixes for the Windows and OpenVMS platforms

  Major changes between OpenSSL 1.0.1j and OpenSSL 1.0.1k [8 Jan 2015]

      o Fix for CVE-2014-3571
      o Fix for CVE-2015-0206
      o Fix for CVE-2014-3569
      o Fix for CVE-2014-3572
      o Fix for CVE-2015-0204
      o Fix for CVE-2015-0205
      o Fix for CVE-2014-8275
      o Fix for CVE-2014-3570

  Major changes between OpenSSL 1.0.1i and OpenSSL 1.0.1j [15 Oct 2014]

      o Fix for CVE-2014-3513
      o Fix for CVE-2014-3567
      o Mitigation for CVE-2014-3566 (SSL protocol vulnerability)
      o Fix for CVE-2014-3568

  Major changes between OpenSSL 1.0.1h and OpenSSL 1.0.1i [6 Aug 2014]

      o Fix for CVE-2014-3512
      o Fix for CVE-2014-3511
      o Fix for CVE-2014-3510
      o Fix for CVE-2014-3507
      o Fix for CVE-2014-3506
      o Fix for CVE-2014-3505
      o Fix for CVE-2014-3509
      o Fix for CVE-2014-5139
      o Fix for CVE-2014-3508

  Major changes between OpenSSL 1.0.1g and OpenSSL 1.0.1h [5 Jun 2014]

      o Fix for CVE-2014-0224
      o Fix for CVE-2014-0221
      o Fix for CVE-2014-0198
      o Fix for CVE-2014-0195
      o Fix for CVE-2014-3470
      o Fix for CVE-2010-5298

  Major changes between OpenSSL 1.0.1f and OpenSSL 1.0.1g [7 Apr 2014]

      o Fix for CVE-2014-0160
      o Add TLS padding extension workaround for broken servers.
      o Fix for CVE-2014-0076

  Major changes between OpenSSL 1.0.1e and OpenSSL 1.0.1f [6 Jan 2014]

      o Don't include gmt_unix_time in TLS server and client random values
      o Fix for TLS record tampering bug CVE-2013-4353
      o Fix for TLS version checking bug CVE-2013-6449
      o Fix for DTLS retransmission bug CVE-2013-6450

  Major changes between OpenSSL 1.0.1d and OpenSSL 1.0.1e [11 Feb 2013]:

      o Corrected fix for CVE-2013-0169

  Major changes between OpenSSL 1.0.1c and OpenSSL 1.0.1d [4 Feb 2013]:

      o Fix renegotiation in TLS 1.1, 1.2 by using the correct TLS version.
      o Include the fips configuration module.
      o Fix OCSP bad key DoS attack CVE-2013-0166
      o Fix for SSL/TLS/DTLS CBC plaintext recovery attack CVE-2013-0169
      o Fix for TLS AESNI record handling flaw CVE-2012-2686

  Major changes between OpenSSL 1.0.1b and OpenSSL 1.0.1c [10 May 2012]:

      o Fix TLS/DTLS record length checking bug CVE-2012-2333
      o Don't attempt to use non-FIPS composite ciphers in FIPS mode.

  Major changes between OpenSSL 1.0.1a and OpenSSL 1.0.1b [26 Apr 2012]:

      o Fix compilation error on non-x86 platforms.
      o Make FIPS capable OpenSSL ciphers work in non-FIPS mode.
      o Fix SSL_OP_NO_TLSv1_1 clash with SSL_OP_ALL in OpenSSL 1.0.0

  Major changes between OpenSSL 1.0.1 and OpenSSL 1.0.1a [19 Apr 2012]:

      o Fix for ASN1 overflow bug CVE-2012-2110
      o Workarounds for some servers that hang on long client hellos.
      o Fix SEGV in AES code.

  Major changes between OpenSSL 1.0.0h and OpenSSL 1.0.1 [14 Mar 2012]:

      o TLS/DTLS heartbeat support.
      o SCTP support.
      o RFC 5705 TLS key material exporter.
      o RFC 5764 DTLS-SRTP negotiation.
      o Next Protocol Negotiation.
      o PSS signatures in certificates, requests and CRLs.
      o Support for password based recipient info for CMS.
      o Support TLS v1.2 and TLS v1.1.
      o Preliminary FIPS capability for unvalidated 2.0 FIPS module.
      o SRP support.

  Major changes between OpenSSL 1.0.0g and OpenSSL 1.0.0h [12 Mar 2012]:

      o Fix for CMS/PKCS#7 MMA CVE-2012-0884
      o Corrected fix for CVE-2011-4619
      o Various DTLS fixes.

  Major changes between OpenSSL 1.0.0f and OpenSSL 1.0.0g [18 Jan 2012]:

      o Fix for DTLS DoS issue CVE-2012-0050

  Major changes between OpenSSL 1.0.0e and OpenSSL 1.0.0f [4 Jan 2012]:

      o Fix for DTLS plaintext recovery attack CVE-2011-4108
      o Clear block padding bytes of SSL 3.0 records CVE-2011-4576
      o Only allow one SGC handshake restart for SSL/TLS CVE-2011-4619
      o Check parameters are not NULL in GOST ENGINE CVE-2012-0027
      o Check for malformed RFC3779 data CVE-2011-4577

  Major changes between OpenSSL 1.0.0d and OpenSSL 1.0.0e [6 Sep 2011]:

      o Fix for CRL vulnerability issue CVE-2011-3207
      o Fix for ECDH crashes CVE-2011-3210
      o Protection against EC timing attacks.
      o Support ECDH ciphersuites for certificates using SHA2 algorithms.
      o Various DTLS fixes.

  Major changes between OpenSSL 1.0.0c and OpenSSL 1.0.0d [8 Feb 2011]:

      o Fix for security issue CVE-2011-0014

  Major changes between OpenSSL 1.0.0b and OpenSSL 1.0.0c [2 Dec 2010]:

      o Fix for security issue CVE-2010-4180
      o Fix for CVE-2010-4252
      o Fix mishandling of absent EC point format extension.
      o Fix various platform compilation issues.
      o Corrected fix for security issue CVE-2010-3864.

  Major changes between OpenSSL 1.0.0a and OpenSSL 1.0.0b [16 Nov 2010]:

      o Fix for security issue CVE-2010-3864.
      o Fix for CVE-2010-2939
      o Fix WIN32 build system for GOST ENGINE.

  Major changes between OpenSSL 1.0.0 and OpenSSL 1.0.0a [1 Jun 2010]:

      o Fix for security issue CVE-2010-1633.
      o GOST MAC and CFB fixes.

  Major changes between OpenSSL 0.9.8n and OpenSSL 1.0.0 [29 Mar 2010]:

      o RFC3280 path validation: sufficient to process PKITS tests.
      o Integrated support for PVK files and keyblobs.
      o Change default private key format to PKCS#8.
      o CMS support: able to process all examples in RFC4134
      o Streaming ASN1 encode support for PKCS#7 and CMS.
      o Multiple signer and signer add support for PKCS#7 and CMS.
      o ASN1 printing support.
      o Whirlpool hash algorithm added.
      o RFC3161 time stamp support.
      o New generalised public key API supporting ENGINE based algorithms.
      o New generalised public key API utilities.
      o New ENGINE supporting GOST algorithms.
      o SSL/TLS GOST ciphersuite support.
      o PKCS#7 and CMS GOST support.
      o RFC4279 PSK ciphersuite support.
      o Supported points format extension for ECC ciphersuites.
      o ecdsa-with-SHA224/256/384/512 signature types.
      o dsa-with-SHA224 and dsa-with-SHA256 signature types.
      o Opaque PRF Input TLS extension support.
      o Updated time routines to avoid OS limitations.

  Major changes between OpenSSL 0.9.8m and OpenSSL 0.9.8n [24 Mar 2010]:

      o CFB cipher definition fixes.
      o Fix security issues CVE-2010-0740 and CVE-2010-0433.

  Major changes between OpenSSL 0.9.8l and OpenSSL 0.9.8m [25 Feb 2010]:

      o Cipher definition fixes.
      o Workaround for slow RAND_poll() on some WIN32 versions.
      o Remove MD2 from algorithm tables.
      o SPKAC handling fixes.
      o Support for RFC5746 TLS renegotiation extension.
      o Compression memory leak fixed.
      o Compression session resumption fixed.
      o Ticket and SNI coexistence fixes.
      o Many fixes to DTLS handling.

  Major changes between OpenSSL 0.9.8k and OpenSSL 0.9.8l [5 Nov 2009]:

      o Temporary work around for CVE-2009-3555: disable renegotiation.

  Major changes between OpenSSL 0.9.8j and OpenSSL 0.9.8k [25 Mar 2009]:

      o Fix various build issues.
      o Fix security issues (CVE-2009-0590, CVE-2009-0591, CVE-2009-0789)

  Major changes between OpenSSL 0.9.8i and OpenSSL 0.9.8j [7 Jan 2009]:

      o Fix security issue (CVE-2008-5077)
      o Merge FIPS 140-2 branch code.

  Major changes between OpenSSL 0.9.8g and OpenSSL 0.9.8h [28 May 2008]:

      o CryptoAPI ENGINE support.
      o Various precautionary measures.
      o Fix for bugs affecting certificate request creation.
      o Support for local machine keyset attribute in PKCS#12 files.

  Major changes between OpenSSL 0.9.8f and OpenSSL 0.9.8g [19 Oct 2007]:

      o Backport of CMS functionality to 0.9.8.
      o Fixes for bugs introduced with 0.9.8f.

  Major changes between OpenSSL 0.9.8e and OpenSSL 0.9.8f [11 Oct 2007]:

      o Add gcc 4.2 support.
      o Add support for AES and SSE2 assembly language optimization
        for VC++ build.
      o Support for RFC4507bis and server name extensions if explicitly
        selected at compile time.
      o DTLS improvements.
      o RFC4507bis support.
      o TLS Extensions support.

  Major changes between OpenSSL 0.9.8d and OpenSSL 0.9.8e [23 Feb 2007]:

      o Various ciphersuite selection fixes.
      o RFC3779 support.

  Major changes between OpenSSL 0.9.8c and OpenSSL 0.9.8d [28 Sep 2006]:

      o Introduce limits to prevent malicious key DoS  (CVE-2006-2940)
      o Fix security issues (CVE-2006-2937, CVE-2006-3737, CVE-2006-4343)
      o Changes to ciphersuite selection algorithm

  Major changes between OpenSSL 0.9.8b and OpenSSL 0.9.8c [5 Sep 2006]:

      o Fix Daniel Bleichenbacher forged signature attack, CVE-2006-4339
      o New cipher Camellia

  Major changes between OpenSSL 0.9.8a and OpenSSL 0.9.8b [4 May 2006]:

      o Cipher string fixes.
      o Fixes for VC++ 2005.
      o Updated ECC cipher suite support.
      o New functions EVP_CIPHER_CTX_new() and EVP_CIPHER_CTX_free().
      o Zlib compression usage fixes.
      o Built in dynamic engine compilation support on Win32.
      o Fixes auto dynamic engine loading in Win32.

  Major changes between OpenSSL 0.9.8 and OpenSSL 0.9.8a [11 Oct 2005]:

      o Fix potential SSL 2.0 rollback, CVE-2005-2969
      o Extended Windows CE support

  Major changes between OpenSSL 0.9.7g and OpenSSL 0.9.8 [5 Jul 2005]:

      o Major work on the BIGNUM library for higher efficiency and to
        make operations more streamlined and less contradictory.  This
        is the result of a major audit of the BIGNUM library.
      o Addition of BIGNUM functions for fields GF(2^m) and NIST
        curves, to support the Elliptic Crypto functions.
      o Major work on Elliptic Crypto; ECDH and ECDSA added, including
        the use through EVP, X509 and ENGINE.
      o New ASN.1 mini-compiler that's usable through the OpenSSL
        configuration file.
      o Added support for ASN.1 indefinite length constructed encoding.
      o New PKCS#12 'medium level' API to manipulate PKCS#12 files.
      o Complete rework of shared library construction and linking
        programs with shared or static libraries, through a separate
        Makefile.shared.
      o Rework of the passing of parameters from one Makefile to another.
      o Changed ENGINE framework to load dynamic engine modules
        automatically from specifically given directories.
      o New structure and ASN.1 functions for CertificatePair.
      o Changed the ZLIB compression method to be stateful.
      o Changed the key-generation and primality testing "progress"
        mechanism to take a structure that contains the ticker
        function and an argument.
      o New engine module: GMP (performs private key exponentiation).
      o New engine module: VIA PadLOck ACE extension in VIA C3
        Nehemiah processors.
      o Added support for IPv6 addresses in certificate extensions.
        See RFC 1884, section 2.2.
      o Added support for certificate policy mappings, policy
        constraints and name constraints.
      o Added support for multi-valued AVAs in the OpenSSL
        configuration file.
      o Added support for multiple certificates with the same subject
        in the 'openssl ca' index file.
      o Make it possible to create self-signed certificates using
        'openssl ca -selfsign'.
      o Make it possible to generate a serial number file with
        'openssl ca -create_serial'.
      o New binary search functions with extended functionality.
      o New BUF functions.
      o New STORE structure and library to provide an interface to all
        sorts of data repositories.  Supports storage of public and
        private keys, certificates, CRLs, numbers and arbitrary blobs.
        This library is unfortunately unfinished and unused within
        OpenSSL.
      o New control functions for the error stack.
      o Changed the PKCS#7 library to support one-pass S/MIME
        processing.
      o Added the possibility to compile without old deprecated
        functionality with the OPENSSL_NO_DEPRECATED macro or the
        'no-deprecated' argument to the config and Configure scripts.
      o Constification of all ASN.1 conversion functions, and other
        affected functions.
      o Improved platform support for PowerPC.
      o New FIPS 180-2 algorithms (SHA-224, -256, -384 and -512).
      o New X509_VERIFY_PARAM structure to support parameterisation
        of X.509 path validation.
      o Major overhaul of RC4 performance on Intel P4, IA-64 and
        AMD64.
      o Changed the Configure script to have some algorithms disabled
        by default.  Those can be explicitly enabled with the new
        argument form 'enable-xxx'.
      o Change the default digest in 'openssl' commands from MD5 to
        SHA-1.
      o Added support for DTLS.
      o New BIGNUM blinding.
      o Added support for the RSA-PSS encryption scheme
      o Added support for the RSA X.931 padding.
      o Added support for BSD sockets on NetWare.
      o Added support for files larger than 2GB.
      o Added initial support for Win64.
      o Added alternate pkg-config files.

  Major changes between OpenSSL 0.9.7l and OpenSSL 0.9.7m [23 Feb 2007]:

      o FIPS 1.1.1 module linking.
      o Various ciphersuite selection fixes.

  Major changes between OpenSSL 0.9.7k and OpenSSL 0.9.7l [28 Sep 2006]:

      o Introduce limits to prevent malicious key DoS  (CVE-2006-2940)
      o Fix security issues (CVE-2006-2937, CVE-2006-3737, CVE-2006-4343)

  Major changes between OpenSSL 0.9.7j and OpenSSL 0.9.7k [5 Sep 2006]:

      o Fix Daniel Bleichenbacher forged signature attack, CVE-2006-4339

  Major changes between OpenSSL 0.9.7i and OpenSSL 0.9.7j [4 May 2006]:

      o Visual C++ 2005 fixes.
      o Update Windows build system for FIPS.

  Major changes between OpenSSL 0.9.7h and OpenSSL 0.9.7i [14 Oct 2005]:

      o Give EVP_MAX_MD_SIZE its old value, except for a FIPS build.

  Major changes between OpenSSL 0.9.7g and OpenSSL 0.9.7h [11 Oct 2005]:

      o Fix SSL 2.0 Rollback, CVE-2005-2969
      o Allow use of fixed-length exponent on DSA signing
      o Default fixed-window RSA, DSA, DH private-key operations

  Major changes between OpenSSL 0.9.7f and OpenSSL 0.9.7g [11 Apr 2005]:

      o More compilation issues fixed.
      o Adaptation to more modern Kerberos API.
      o Enhanced or corrected configuration for Solaris64, Mingw and Cygwin.
      o Enhanced x86_64 assembler BIGNUM module.
      o More constification.
      o Added processing of proxy certificates (RFC 3820).

  Major changes between OpenSSL 0.9.7e and OpenSSL 0.9.7f [22 Mar 2005]:

      o Several compilation issues fixed.
      o Many memory allocation failure checks added.
      o Improved comparison of X509 Name type.
      o Mandatory basic checks on certificates.
      o Performance improvements.

  Major changes between OpenSSL 0.9.7d and OpenSSL 0.9.7e [25 Oct 2004]:

      o Fix race condition in CRL checking code.
      o Fixes to PKCS#7 (S/MIME) code.

  Major changes between OpenSSL 0.9.7c and OpenSSL 0.9.7d [17 Mar 2004]:

      o Security: Fix Kerberos ciphersuite SSL/TLS handshaking bug
      o Security: Fix null-pointer assignment in do_change_cipher_spec()
      o Allow multiple active certificates with same subject in CA index
      o Multiple X509 verification fixes
      o Speed up HMAC and other operations

  Major changes between OpenSSL 0.9.7b and OpenSSL 0.9.7c [30 Sep 2003]:

      o Security: fix various ASN1 parsing bugs.
      o New -ignore_err option to OCSP utility.
      o Various interop and bug fixes in S/MIME code.
      o SSL/TLS protocol fix for unrequested client certificates.

  Major changes between OpenSSL 0.9.7a and OpenSSL 0.9.7b [10 Apr 2003]:

      o Security: counter the Klima-Pokorny-Rosa extension of
        Bleichbacher's attack
      o Security: make RSA blinding default.
      o Configuration: Irix fixes, AIX fixes, better mingw support.
      o Support for new platforms: linux-ia64-ecc.
      o Build: shared library support fixes.
      o ASN.1: treat domainComponent correctly.
      o Documentation: fixes and additions.

  Major changes between OpenSSL 0.9.7 and OpenSSL 0.9.7a [19 Feb 2003]:

      o Security: Important security related bugfixes.
      o Enhanced compatibility with MIT Kerberos.
      o Can be built without the ENGINE framework.
      o IA32 assembler enhancements.
      o Support for new platforms: FreeBSD/IA64 and FreeBSD/Sparc64.
      o Configuration: the no-err option now works properly.
      o SSL/TLS: now handles manual certificate chain building.
      o SSL/TLS: certain session ID malfunctions corrected.

  Major changes between OpenSSL 0.9.6 and OpenSSL 0.9.7 [30 Dec 2002]:

      o New library section OCSP.
      o Complete rewrite of ASN1 code.
      o CRL checking in verify code and openssl utility.
      o Extension copying in 'ca' utility.
      o Flexible display options in 'ca' utility.
      o Provisional support for international characters with UTF8.
      o Support for external crypto devices ('engine') is no longer
        a separate distribution.
      o New elliptic curve library section.
      o New AES (Rijndael) library section.
      o Support for new platforms: Windows CE, Tandem OSS, A/UX, AIX 64-bit,
        Linux x86_64, Linux 64-bit on Sparc v9
      o Extended support for some platforms: VxWorks
      o Enhanced support for shared libraries.
      o Now only builds PIC code when shared library support is requested.
      o Support for pkg-config.
      o Lots of new manuals.
      o Makes symbolic links to or copies of manuals to cover all described
        functions.
      o Change DES API to clean up the namespace (some applications link also
        against libdes providing similar functions having the same name).
        Provide macros for backward compatibility (will be removed in the
        future).
      o Unify handling of cryptographic algorithms (software and engine)
        to be available via EVP routines for asymmetric and symmetric ciphers.
      o NCONF: new configuration handling routines.
      o Change API to use more 'const' modifiers to improve error checking
        and help optimizers.
      o Finally remove references to RSAref.
      o Reworked parts of the BIGNUM code.
      o Support for new engines: Broadcom ubsec, Accelerated Encryption
        Processing, IBM 4758.
      o A few new engines added in the demos area.
      o Extended and corrected OID (object identifier) table.
      o PRNG: query at more locations for a random device, automatic query for
        EGD style random sources at several locations.
      o SSL/TLS: allow optional cipher choice according to server's preference.
      o SSL/TLS: allow server to explicitly set new session ids.
      o SSL/TLS: support Kerberos cipher suites (RFC2712).
        Only supports MIT Kerberos for now.
      o SSL/TLS: allow more precise control of renegotiations and sessions.
      o SSL/TLS: add callback to retrieve SSL/TLS messages.
      o SSL/TLS: support AES cipher suites (RFC3268).

  Major changes between OpenSSL 0.9.6j and OpenSSL 0.9.6k [30 Sep 2003]:

      o Security: fix various ASN1 parsing bugs.
      o SSL/TLS protocol fix for unrequested client certificates.

  Major changes between OpenSSL 0.9.6i and OpenSSL 0.9.6j [10 Apr 2003]:

      o Security: counter the Klima-Pokorny-Rosa extension of
        Bleichbacher's attack
      o Security: make RSA blinding default.
      o Build: shared library support fixes.

  Major changes between OpenSSL 0.9.6h and OpenSSL 0.9.6i [19 Feb 2003]:

      o Important security related bugfixes.

  Major changes between OpenSSL 0.9.6g and OpenSSL 0.9.6h [5 Dec 2002]:

      o New configuration targets for Tandem OSS and A/UX.
      o New OIDs for Microsoft attributes.
      o Better handling of SSL session caching.
      o Better comparison of distinguished names.
      o Better handling of shared libraries in a mixed GNU/non-GNU environment.
      o Support assembler code with Borland C.
      o Fixes for length problems.
      o Fixes for uninitialised variables.
      o Fixes for memory leaks, some unusual crashes and some race conditions.
      o Fixes for smaller building problems.
      o Updates of manuals, FAQ and other instructive documents.

  Major changes between OpenSSL 0.9.6f and OpenSSL 0.9.6g [9 Aug 2002]:

      o Important building fixes on Unix.

  Major changes between OpenSSL 0.9.6e and OpenSSL 0.9.6f [8 Aug 2002]:

      o Various important bugfixes.

  Major changes between OpenSSL 0.9.6d and OpenSSL 0.9.6e [30 Jul 2002]:

      o Important security related bugfixes.
      o Various SSL/TLS library bugfixes.

  Major changes between OpenSSL 0.9.6c and OpenSSL 0.9.6d [9 May 2002]:

      o Various SSL/TLS library bugfixes.
      o Fix DH parameter generation for 'non-standard' generators.

  Major changes between OpenSSL 0.9.6b and OpenSSL 0.9.6c [21 Dec 2001]:

      o Various SSL/TLS library bugfixes.
      o BIGNUM library fixes.
      o RSA OAEP and random number generation fixes.
      o Object identifiers corrected and added.
      o Add assembler BN routines for IA64.
      o Add support for OS/390 Unix, UnixWare with gcc, OpenUNIX 8,
        MIPS Linux; shared library support for Irix, HP-UX.
      o Add crypto accelerator support for AEP, Baltimore SureWare,
        Broadcom and Cryptographic Appliance's keyserver
        [in 0.9.6c-engine release].

  Major changes between OpenSSL 0.9.6a and OpenSSL 0.9.6b [9 Jul 2001]:

      o Security fix: PRNG improvements.
      o Security fix: RSA OAEP check.
      o Security fix: Reinsert and fix countermeasure to Bleichbacher's
        attack.
      o MIPS bug fix in BIGNUM.
      o Bug fix in "openssl enc".
      o Bug fix in X.509 printing routine.
      o Bug fix in DSA verification routine and DSA S/MIME verification.
      o Bug fix to make PRNG thread-safe.
      o Bug fix in RAND_file_name().
      o Bug fix in compatibility mode trust settings.
      o Bug fix in blowfish EVP.
      o Increase default size for BIO buffering filter.
      o Compatibility fixes in some scripts.

  Major changes between OpenSSL 0.9.6 and OpenSSL 0.9.6a [5 Apr 2001]:

      o Security fix: change behavior of OpenSSL to avoid using
        environment variables when running as root.
      o Security fix: check the result of RSA-CRT to reduce the
        possibility of deducing the private key from an incorrectly
        calculated signature.
      o Security fix: prevent Bleichenbacher's DSA attack.
      o Security fix: Zero the premaster secret after deriving the
        master secret in DH ciphersuites.
      o Reimplement SSL_peek(), which had various problems.
      o Compatibility fix: the function des_encrypt() renamed to
        des_encrypt1() to avoid clashes with some Unixen libc.
      o Bug fixes for Win32, HP/UX and Irix.
      o Bug fixes in BIGNUM, SSL, PKCS#7, PKCS#12, X.509, CONF and
        memory checking routines.
      o Bug fixes for RSA operations in threaded environments.
      o Bug fixes in misc. openssl applications.
      o Remove a few potential memory leaks.
      o Add tighter checks of BIGNUM routines.
      o Shared library support has been reworked for generality.
      o More documentation.
      o New function BN_rand_range().
      o Add "-rand" option to openssl s_client and s_server.

  Major changes between OpenSSL 0.9.5a and OpenSSL 0.9.6 [10 Oct 2000]:

      o Some documentation for BIO and SSL libraries.
      o Enhanced chain verification using key identifiers.
      o New sign and verify options to 'dgst' application.
      o Support for DER and PEM encoded messages in 'smime' application.
      o New 'rsautl' application, low level RSA utility.
      o MD4 now included.
      o Bugfix for SSL rollback padding check.
      o Support for external crypto devices [1].
      o Enhanced EVP interface.

    [1] The support for external crypto devices is currently a separate
        distribution.  See the file README.ENGINE.

  Major changes between OpenSSL 0.9.5 and OpenSSL 0.9.5a [1 Apr 2000]:

      o Bug fixes for Win32, SuSE Linux, NeXTSTEP and FreeBSD 2.2.8
      o Shared library support for HPUX and Solaris-gcc
      o Support of Linux/IA64
      o Assembler support for Mingw32
      o New 'rand' application
      o New way to check for existence of algorithms from scripts

  Major changes between OpenSSL 0.9.4 and OpenSSL 0.9.5 [25 May 2000]:

      o S/MIME support in new 'smime' command
      o Documentation for the OpenSSL command line application
      o Automation of 'req' application
      o Fixes to make s_client, s_server work under Windows
      o Support for multiple fieldnames in SPKACs
      o New SPKAC command line utility and associated library functions
      o Options to allow passwords to be obtained from various sources
      o New public key PEM format and options to handle it
      o Many other fixes and enhancements to command line utilities
      o Usable certificate chain verification
      o Certificate purpose checking
      o Certificate trust settings
      o Support of authority information access extension
      o Extensions in certificate requests
      o Simplified X509 name and attribute routines
      o Initial (incomplete) support for international character sets
      o New DH_METHOD, DSA_METHOD and enhanced RSA_METHOD
      o Read only memory BIOs and simplified creation function
      o TLS/SSL protocol bugfixes: Accept TLS 'client hello' in SSL 3.0
        record; allow fragmentation and interleaving of handshake and other
        data
      o TLS/SSL code now "tolerates" MS SGC
      o Work around for Netscape client certificate hang bug
      o RSA_NULL option that removes RSA patent code but keeps other
        RSA functionality
      o Memory leak detection now allows applications to add extra information
        via a per-thread stack
      o PRNG robustness improved
      o EGD support
      o BIGNUM library bug fixes
      o Faster DSA parameter generation
      o Enhanced support for Alpha Linux
      o Experimental MacOS support

  Major changes between OpenSSL 0.9.3 and OpenSSL 0.9.4 [9 Aug 1999]:

      o Transparent support for PKCS#8 format private keys: these are used
        by several software packages and are more secure than the standard
        form
      o PKCS#5 v2.0 implementation
      o Password callbacks have a new void * argument for application data
      o Avoid various memory leaks
      o New pipe-like BIO that allows using the SSL library when actual I/O
        must be handled by the application (BIO pair)

  Major changes between OpenSSL 0.9.2b and OpenSSL 0.9.3 [24 May 1999]:
      o Lots of enhancements and cleanups to the Configuration mechanism
      o RSA OEAP related fixes
      o Added `openssl ca -revoke' option for revoking a certificate
      o Source cleanups: const correctness, type-safe stacks and ASN.1 SETs
      o Source tree cleanups: removed lots of obsolete files
      o Thawte SXNet, certificate policies and CRL distribution points
        extension support
      o Preliminary (experimental) S/MIME support
      o Support for ASN.1 UTF8String and VisibleString
      o Full integration of PKCS#12 code
      o Sparc assembler bignum implementation, optimized hash functions
      o Option to disable selected ciphers

  Major changes between OpenSSL 0.9.1c and OpenSSL 0.9.2b [22 Mar 1999]:
      o Fixed a security hole related to session resumption
      o Fixed RSA encryption routines for the p < q case
      o "ALL" in cipher lists now means "everything except NULL ciphers"
      o Support for Triple-DES CBCM cipher
      o Support of Optimal Asymmetric Encryption Padding (OAEP) for RSA
      o First support for new TLSv1 ciphers
      o Added a few new BIOs (syslog BIO, reliable BIO)
      o Extended support for DSA certificate/keys.
      o Extended support for Certificate Signing Requests (CSR)
      o Initial support for X.509v3 extensions
      o Extended support for compression inside the SSL record layer
      o Overhauled Win32 builds
      o Cleanups and fixes to the Big Number (BN) library
      o Support for ASN.1 GeneralizedTime
      o Splitted ASN.1 SETs from SEQUENCEs
      o ASN1 and PEM support for Netscape Certificate Sequences
      o Overhauled Perl interface
      o Lots of source tree cleanups.
      o Lots of memory leak fixes.
      o Lots of bug fixes.

  Major changes between SSLeay 0.9.0b and OpenSSL 0.9.1c [23 Dec 1998]:
      o Integration of the popular NO_RSA/NO_DSA patches
      o Initial support for compression inside the SSL record layer
      o Added BIO proxy and filtering functionality
      o Extended Big Number (BN) library
      o Added RIPE MD160 message digest
      o Added support for RC2/64bit cipher
      o Extended ASN.1 parser routines
      o Adjustments of the source tree for CVS
      o Support for various new platforms
alt-openssl11/README000064400000006126150404743610010040 0ustar00
 OpenSSL 1.1.1w 11 Sep 2023

 Copyright (c) 1998-2023 The OpenSSL Project
 Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson
 All rights reserved.

 DESCRIPTION
 -----------

 The OpenSSL Project is a collaborative effort to develop a robust,
 commercial-grade, fully featured, and Open Source toolkit implementing the
 Transport Layer Security (TLS) protocols (including SSLv3) as well as a
 full-strength general purpose cryptographic library.

 OpenSSL is descended from the SSLeay library developed by Eric A. Young
 and Tim J. Hudson.  The OpenSSL toolkit is licensed under a dual-license (the
 OpenSSL license plus the SSLeay license), which means that you are free to
 get and use it for commercial and non-commercial purposes as long as you
 fulfill the conditions of both licenses.

 OVERVIEW
 --------

 The OpenSSL toolkit includes:

 libssl (with platform specific naming):
     Provides the client and server-side implementations for SSLv3 and TLS.

 libcrypto (with platform specific naming):
     Provides general cryptographic and X.509 support needed by SSL/TLS but
     not logically part of it.

 openssl:
     A command line tool that can be used for:
        Creation of key parameters
        Creation of X.509 certificates, CSRs and CRLs
        Calculation of message digests
        Encryption and decryption
        SSL/TLS client and server tests
        Handling of S/MIME signed or encrypted mail
        And more...

 INSTALLATION
 ------------

 See the appropriate file:
        INSTALL         Linux, Unix, Windows, OpenVMS, ...
        NOTES.*         INSTALL addendums for different platforms

 SUPPORT
 -------

 See the OpenSSL website www.openssl.org for details on how to obtain
 commercial technical support. Free community support is available through the
 openssl-users email list (see
 https://www.openssl.org/community/mailinglists.html for further details).

 If you have any problems with OpenSSL then please take the following steps
 first:

    - Download the latest version from the repository
      to see if the problem has already been addressed
    - Configure with no-asm
    - Remove compiler optimization flags

 If you wish to report a bug then please include the following information
 and create an issue on GitHub:

    - OpenSSL version: output of 'openssl version -a'
    - Configuration data: output of 'perl configdata.pm --dump'
    - OS Name, Version, Hardware platform
    - Compiler Details (name, version)
    - Application Details (name, version)
    - Problem Description (steps that will reproduce the problem, if known)
    - Stack Traceback (if the application dumps core)

 Just because something doesn't work the way you expect does not mean it
 is necessarily a bug in OpenSSL. Use the openssl-users email list for this type
 of query.

 HOW TO CONTRIBUTE TO OpenSSL
 ----------------------------

 See CONTRIBUTING

 LEGALITIES
 ----------

 A number of nations restrict the use or export of cryptography. If you
 are potentially subject to such restrictions you should seek competent
 professional legal advice before attempting to develop or distribute
 cryptographic code.
alt-openssl11/FAQ000064400000000124150404743610007502 0ustar00The FAQ is now maintained on the web:
        https://www.openssl.org/docs/faq.html
alt-python312-pip/README.rst000064400000004352150410147340011351 0ustar00pip - The Python Package Installer
==================================

.. image:: https://img.shields.io/pypi/v/pip.svg
   :target: https://pypi.org/project/pip/
   :alt: PyPI

.. image:: https://img.shields.io/pypi/pyversions/pip
   :target: https://pypi.org/project/pip
   :alt: PyPI - Python Version

.. image:: https://readthedocs.org/projects/pip/badge/?version=latest
   :target: https://pip.pypa.io/en/latest
   :alt: Documentation

pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.

Please take a look at our documentation for how to install and use pip:

* `Installation`_
* `Usage`_

We release updates regularly, with a new version every 3 months. Find more details in our documentation:

* `Release notes`_
* `Release process`_

If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:

* `Issue tracking`_
* `Discourse channel`_
* `User IRC`_

If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:

* `GitHub page`_
* `Development documentation`_
* `Development IRC`_

Code of Conduct
---------------

Everyone interacting in the pip project's codebases, issue trackers, chat
rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.

.. _package installer: https://packaging.python.org/guides/tool-recommendations/
.. _Python Package Index: https://pypi.org
.. _Installation: https://pip.pypa.io/en/stable/installation/
.. _Usage: https://pip.pypa.io/en/stable/
.. _Release notes: https://pip.pypa.io/en/stable/news.html
.. _Release process: https://pip.pypa.io/en/latest/development/release-process/
.. _GitHub page: https://github.com/pypa/pip
.. _Development documentation: https://pip.pypa.io/en/latest/development
.. _Issue tracking: https://github.com/pypa/pip/issues
.. _Discourse channel: https://discuss.python.org/c/packaging
.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa
.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev
.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md
alt-python312-setuptools/zpl.txt000064400000004026150410147340012657 0ustar00Zope Public License (ZPL) Version 2.1

A copyright notice accompanies this license document that identifies the
copyright holders.

This license has been certified as open source. It has also been designated as
GPL compatible by the Free Software Foundation (FSF).

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions in source code must retain the accompanying copyright
notice, this list of conditions, and the following disclaimer.

2. Redistributions in binary form must reproduce the accompanying copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3. Names of the copyright holders must not be used to endorse or promote
products derived from this software without prior written permission from the
copyright holders.

4. The right to distribute this software or to use it for any purpose does not
give you the right to use Servicemarks (sm) or Trademarks (tm) of the
copyright
holders. Use of them is covered by separate agreement with the copyright
holders.

5. If any files are modified, you must cause the modified files to carry
prominent notices stating that you changed the files and the date of any
change.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
alt-python312-setuptools/psfl.txt000064400000030737150410147340013026 0ustar00A. HISTORY OF THE SOFTWARE
==========================

Python was created in the early 1990s by Guido van Rossum at Stichting
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
as a successor of a language called ABC.  Guido remains Python's
principal author, although it includes many contributions from others.

In 1995, Guido continued his work on Python at the Corporation for
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
in Reston, Virginia where he released several versions of the
software.

In May 2000, Guido and the Python core development team moved to
BeOpen.com to form the BeOpen PythonLabs team.  In October of the same
year, the PythonLabs team moved to Digital Creations (now Zope
Corporation, see http://www.zope.com).  In 2001, the Python Software
Foundation (PSF, see http://www.python.org/psf/) was formed, a
non-profit organization created specifically to own Python-related
Intellectual Property.  Zope Corporation is a sponsoring member of
the PSF.

All Python releases are Open Source (see http://www.opensource.org for
the Open Source Definition).  Historically, most, but not all, Python
releases have also been GPL-compatible; the table below summarizes
the various releases.

    Release         Derived     Year        Owner       GPL-
                    from                                compatible? (1)

    0.9.0 thru 1.2              1991-1995   CWI         yes
    1.3 thru 1.5.2  1.2         1995-1999   CNRI        yes
    1.6             1.5.2       2000        CNRI        no
    2.0             1.6         2000        BeOpen.com  no
    1.6.1           1.6         2001        CNRI        yes (2)
    2.1             2.0+1.6.1   2001        PSF         no
    2.0.1           2.0+1.6.1   2001        PSF         yes
    2.1.1           2.1+2.0.1   2001        PSF         yes
    2.1.2           2.1.1       2002        PSF         yes
    2.1.3           2.1.2       2002        PSF         yes
    2.2 and above   2.1.1       2001-now    PSF         yes

Footnotes:

(1) GPL-compatible doesn't mean that we're distributing Python under
    the GPL.  All Python licenses, unlike the GPL, let you distribute
    a modified version without making your changes open source.  The
    GPL-compatible licenses make it possible to combine Python with
    other software that is released under the GPL; the others don't.

(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
    because its license has a choice of law clause.  According to
    CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
    is "not incompatible" with the GPL.

Thanks to the many outside volunteers who have worked under Guido's
direction to make these releases possible.


B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
===============================================================

PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------

1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") in source or binary form and
its associated documentation.

2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016 Python Software Foundation; All Rights
Reserved" are retained in Python alone or in any derivative version prepared by
Licensee.

3. In the event Licensee prepares a derivative work that is based on
or incorporates Python or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python.

4. PSF is making Python available to Licensee on an "AS IS"
basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.

5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.

7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee.  This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.

8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.


BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
-------------------------------------------

BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1

1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
Individual or Organization ("Licensee") accessing and otherwise using
this software in source or binary form and its associated
documentation ("the Software").

2. Subject to the terms and conditions of this BeOpen Python License
Agreement, BeOpen hereby grants Licensee a non-exclusive,
royalty-free, world-wide license to reproduce, analyze, test, perform
and/or display publicly, prepare derivative works, distribute, and
otherwise use the Software alone or in any derivative version,
provided, however, that the BeOpen Python License is retained in the
Software, alone or in any derivative version prepared by Licensee.

3. BeOpen is making the Software available to Licensee on an "AS IS"
basis.  BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.

4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

5. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.

6. This License Agreement shall be governed by and interpreted in all
respects by the law of the State of California, excluding conflict of
law provisions.  Nothing in this License Agreement shall be deemed to
create any relationship of agency, partnership, or joint venture
between BeOpen and Licensee.  This License Agreement does not grant
permission to use BeOpen trademarks or trade names in a trademark
sense to endorse or promote products or services of Licensee, or any
third party.  As an exception, the "BeOpen Python" logos available at
http://www.pythonlabs.com/logos.html may be used according to the
permissions granted on that web page.

7. By copying, installing or otherwise using the software, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.


CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
---------------------------------------

1. This LICENSE AGREEMENT is between the Corporation for National
Research Initiatives, having an office at 1895 Preston White Drive,
Reston, VA 20191 ("CNRI"), and the Individual or Organization
("Licensee") accessing and otherwise using Python 1.6.1 software in
source or binary form and its associated documentation.

2. Subject to the terms and conditions of this License Agreement, CNRI
hereby grants Licensee a nonexclusive, royalty-free, world-wide
license to reproduce, analyze, test, perform and/or display publicly,
prepare derivative works, distribute, and otherwise use Python 1.6.1
alone or in any derivative version, provided, however, that CNRI's
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
1995-2001 Corporation for National Research Initiatives; All Rights
Reserved" are retained in Python 1.6.1 alone or in any derivative
version prepared by Licensee.  Alternately, in lieu of CNRI's License
Agreement, Licensee may substitute the following text (omitting the
quotes): "Python 1.6.1 is made available subject to the terms and
conditions in CNRI's License Agreement.  This Agreement together with
Python 1.6.1 may be located on the Internet using the following
unique, persistent identifier (known as a handle): 1895.22/1013.  This
Agreement may also be obtained from a proxy server on the Internet
using the following URL: http://hdl.handle.net/1895.22/1013".

3. In the event Licensee prepares a derivative work that is based on
or incorporates Python 1.6.1 or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python 1.6.1.

4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
basis.  CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.

5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.

7. This License Agreement shall be governed by the federal
intellectual property law of the United States, including without
limitation the federal copyright law, and, to the extent such
U.S. federal law does not apply, by the law of the Commonwealth of
Virginia, excluding Virginia's conflict of law provisions.
Notwithstanding the foregoing, with regard to derivative works based
on Python 1.6.1 that incorporate non-separable material that was
previously distributed under the GNU General Public License (GPL), the
law of the Commonwealth of Virginia shall govern this License
Agreement only as to issues arising under or with respect to
Paragraphs 4, 5, and 7 of this License Agreement.  Nothing in this
License Agreement shall be deemed to create any relationship of
agency, partnership, or joint venture between CNRI and Licensee.  This
License Agreement does not grant permission to use CNRI trademarks or
trade name in a trademark sense to endorse or promote products or
services of Licensee, or any third party.

8. By clicking on the "ACCEPT" button where indicated, or by copying,
installing or otherwise using Python 1.6.1, Licensee agrees to be
bound by the terms and conditions of this License Agreement.

        ACCEPT


CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
--------------------------------------------------

Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
The Netherlands.  All rights reserved.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.

STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
alt-python312-setuptools/LICENSE000064400000001777150410147340012330 0ustar00Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
alt-python312-setuptools/docs/python 2 sunset.rst000064400000006722150410147340015745 0ustar00:orphan:

Python 2 Sunset
===============

Since January 2020 and the release of Setuptools 45, Python 2 is no longer
supported by the most current release (`discussion
<https://github.com/pypa/setuptools/issues/1458>`_). Setuptools as a project
continues to support Python 2 with bugfixes and important features on
Setuptools 44.x.

By design, most users will be unaffected by this change. That's because
Setuptools 45 declares its supported Python versions to exclude Python 2.7,
and installers such as pip 9 or later will honor this declaration and prevent
installation of Setuptools 45 or later in Python 2 environments.

Users that do import any portion of Setuptools 45 or later on Python 2 are
directed to this documentation to provide guidance on how to work around the
issues.

Workarounds
-----------

The best recommendation is to avoid Python 2 and move to Python 3 where
possible. This project acknowledges that not all environments can drop Python
2 support, so provides other options.

In less common scenarios, later versions of Setuptools can be installed on
unsupported Python versions. In these environments, the installer is advised
to first install ``setuptools<45`` to "pin Setuptools" to a compatible
version.

- When using older versions of pip (before 9.0), the ``Requires-Python``
  directive is not honored and invalid versions can be installed. Users are
  advised first to upgrade pip and retry or to pin Setuptools. Use ``pip
  --version`` to determine the version of pip.
- When using ``easy_install``, ``Requires-Python`` is not honored and later
  versions can be installed. In this case, users are advised to pin
  Setuptools. This applies to ``setup.py install`` invocations as well, as
  they use Setuptools under the hood.

It's still not working
----------------------

If after trying the above steps, the Python environment still has incompatible
versions of Setuptools installed, here are some things to try.

1. Uninstall and reinstall Setuptools. Run ``pip uninstall -y setuptools`` for
   the relevant environment. Repeat until there is no Setuptools installed.
   Then ``pip install setuptools``.
2. If possible, attempt to replicate the problem in a second environment
   (virtual machine, friend's computer, etc). If the issue is isolated to just
   one unique environment, first determine what is different about those
   environments (or reinstall/reset the failing one to defaults).
3. End users who are not themselves the maintainers for the package they are
   trying to install should contact the support channels for the relevant
   application. Please be considerate of those projects by searching for
   existing issues and following the latest guidance before reaching out for
   support. When filing an issue, be sure to give as much detail as possible
   to help the maintainers understand what factors led to the issue after
   following their recommended guidance.
4. Reach out to your local support groups. There's a good chance someone
   nearby has the expertise and willingness to help.
5. If all else fails, `file this template
   <https://github.com/pypa/setuptools/issues/new?assignees=&labels=Python+2&template=setuptools-warns-about-python-2-incompatibility.md&title=Incompatible+install+in+(summarize+your+environment)>`_
   with Setuptools. Please complete the whole template, providing as much
   detail about what factors led to the issue. Setuptools maintainers will
   summarily close tickets filed without any meaningful detail or engagement
   with the issue.
alt-python312-setuptools/docs/artwork.rst000064400000011103150410147340014456 0ustar00=======
Artwork
=======

.. figure:: images/logo-over-white.svg
   :align: center

   Setuptools logo, designed in 2021 by `Anderson Bravalheri`_

Elements of Design
==================

The main colours of the design are a dark pastel azure (``#336790``) and a pale
orange (``#E5B62F``), referred in this document simply as "blue" and "yellow"
respectively. The text uses the *Monoid* typeface, an open source webfont that
was developed by Andreas Larsen and contributors in 2015 and is distributed
under the MIT or SIL licenses (more information at
https://github.com/larsenwork/monoid)


Usage
=====

The preferred way of using the setuptools logo is over a white (or light)
background. Alternatively, the following options can be considered, depending
on the circumstances:

- *"negative"* design - for dark backgrounds (e.g. website displayed in "dark
  mode"): the white colour (``#FFFFFF``) of the background and the "blue"
  (``#336790``) colour of the design can be swapped.
- *"monochrome"* - when colours are not available (e.g. black and white printed
  media): a completely black or white version of the logo can also be used.
- *"banner"* mode: the symbol and text can be used alongside depending on the
  available space.

The following image illustrate these alternatives:

.. image:: images/logo-demo.svg
   :align: center

Please refer to the SVG files in the `setuptools repository`_ for the specific
shapes and proportions between the elements of the design.


Working with the Design
=======================

The `setuptools repository`_ contains a series of vector representations of the
design under the ``docs/images`` directory. These representations can be
manipulated via any graphic editor that support SVG files,
however the free and open-source software Inkscape_ is recommended for maximum
compatibility.

When selecting the right file to work with, file names including
``editable-inkscape`` indicate "more editable" elements (e.g. editable text),
while the others prioritise SVG paths for maximum reproducibility.

Also notice that you might have to `install the correct fonts`_ to be able to
visualise or edit some of the designs.


Inspiration
===========

This design was inspired by :user:`cajhne`'s `original proposal`_ and the
ancient symbol of the ouroboros_.
It features a snake moving in a circular trajectory not only as a reference to
the Python programming language but also to the :pep:`wheel package format <427>` as one
of the distribution formats supported by setuptools.
The shape of the snake also resembles a cog, which together with the hammer is
a nod to the two words that compose the name of the project.


License
=======


This logo, design variations or a modified version may be used by anyone to
refer to setuptools, but does not indicate endorsement by the project.

Redistribution, usage and derivative works are permitted under the same license
used by the setuptools software (MIT):

.. code-block:: text

   Copyright (c) Anderson Bravalheri

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to
   deal in the Software without restriction, including without limitation the
   rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   sell copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.

   THE USAGE OF THIS LOGO AND ARTWORK DOES NOT INDICATE ENDORSEMENT BY THE
   SETUPTOOLS PROJECT.

Whenever possible, please make the image a link to
https://github.com/pypa/setuptools or https://setuptools.pypa.io.


.. _Anderson Bravalheri: https://github.com/abravalheri
.. _Inkscape: https://inkscape.org
.. _setuptools repository: https://github.com/pypa/setuptools
.. _install the correct fonts: https://wiki.inkscape.org/wiki/Installing_fonts
.. _original proposal: https://github.com/pypa/setuptools/issues/2227#issuecomment-653628344
.. _ouroboros: https://en.wikipedia.org/wiki/Ouroboros
alt-python312-setuptools/docs/build_meta.rst000064400000015422150410147340015102 0ustar00=======================================
Build System Support
=======================================

What is it?
-------------

Python packaging has come `a long way <https://bernat.tech/posts/pep-517-518/>`_.

The traditional ``setuptools`` way of packaging Python modules
uses a ``setup()`` function within the ``setup.py`` script. Commands such as
``python setup.py bdist`` or ``python setup.py bdist_wheel`` generate a
distribution bundle and ``python setup.py install`` installs the distribution.
This interface makes it difficult to choose other packaging tools without an
overhaul. Because ``setup.py`` scripts allow for arbitrary execution, it
is difficult to provide a reliable user experience across environments
and history.

:pep:`517` came to
the rescue and specified a new standard for packaging and distributing Python
modules. Under PEP 517:

    A ``pyproject.toml`` file is used to specify which program to use
    to generate the distribution.

    Two functions provided by the program, ``build_wheel(directory: str)``
    and ``build_sdist(directory: str)``, create the distribution bundle in the
    specified ``directory``.

    The program may use its own configuration file or extend the ``.toml`` file.

    The actual installation is done with ``pip install *.whl`` or
    ``pip install *.tar.gz``. If ``*.whl`` is available, ``pip`` will go ahead and copy
    its files into the ``site-packages`` directory. If not, ``pip`` will look at
    ``pyproject.toml`` and decide which program to use to 'build from source'.
    (Note that if there is no ``pyproject.toml`` file or the ``build-backend``
    parameter is not defined, then the fall-back behaviour is to use ``setuptools``.)

With this standard, switching between packaging tools is a lot easier.

How to use it?
--------------

Start with a package that you want to distribute. You will need your source
files, a ``pyproject.toml`` file and a ``setup.cfg`` file::

    ~/meowpkg/
        pyproject.toml
        setup.cfg
        meowpkg/
            __init__.py
            module.py

The ``pyproject.toml`` file specifies the build system (i.e. what is
being used to package your scripts and install from source). To use it with
``setuptools`` the content would be::

    [build-system]
    requires = ["setuptools"]
    build-backend = "setuptools.build_meta"

``build_meta`` implements ``setuptools``' build system support.
The ``setuptools`` package implements the ``build_sdist``
command and the ``wheel`` package implements the ``build_wheel``
command; the latter is a dependency of the former
exposed via :pep:`517` hooks.

Use ``setuptools``' :ref:`declarative config <declarative config>` to
specify the package information in ``setup.cfg``::

    [metadata]
    name = meowpkg
    version = 0.0.1
    description = a package that meows

    [options]
    packages = find:

.. _building:

Now generate the distribution. To build the package, use
`PyPA build <https://pypa-build.readthedocs.io/en/latest/>`_::

    $ pip install -q build
    $ python -m build

And now it's done! The ``.whl`` file  and ``.tar.gz`` can then be distributed
and installed::

    dist/
        meowpkg-0.0.1.whl
        meowpkg-0.0.1.tar.gz

    $ pip install dist/meowpkg-0.0.1.whl

or::

    $ pip install dist/meowpkg-0.0.1.tar.gz


.. _backend-wrapper:

Dynamic build dependencies and other ``build_meta`` tweaks
----------------------------------------------------------

With the changes introduced by :pep:`517` and :pep:`518`, the
``setup_requires`` configuration field was deprecated in ``setup.cfg`` and
``setup.py``, in favour of directly listing build dependencies in the
``requires`` field of the ``build-system`` table of ``pyproject.toml``.
This approach has a series of advantages and gives package managers and
installers the ability to inspect the build requirements in advance and
perform a series of optimisations.

However, some package authors might still need to dynamically inspect the final
user's machine before deciding these requirements. One way of doing that, as
specified by :pep:`517`, is to "tweak" ``setuptools.build_meta`` by using an
:pep:`in-tree backend <517#in-tree-build-backends>`.

.. tip:: Before implementing an *in-tree* backend, have a look at
   :pep:`PEP 508 <508#environment-markers>`. Most of the time, dependencies
   with **environment markers** are enough to differentiate operating systems
   and platforms.

If you put the following configuration in your ``pyproject.toml``:

.. code-block:: toml

    [build-system]
    requires = ["setuptools"]
    build-backend = "backend"
    backend-path = ["_custom_build"]


then you can implement a thin wrapper around ``build_meta`` in
the ``_custom_build/backend.py`` file, as shown in the following example:

.. code-block:: python

    from setuptools import build_meta as _orig
    from setuptools.build_meta import *


    def get_requires_for_build_wheel(config_settings=None):
        return _orig.get_requires_for_build_wheel(config_settings) + [...]


    def get_requires_for_build_sdist(config_settings=None):
        return _orig.get_requires_for_build_sdist(config_settings) + [...]


.. note::

   You can override any of the functions specified in :pep:`PEP 517
   <517#build-backend-interface>`, not only the ones responsible for gathering
   requirements. It is important to ``import *`` so that the hooks that you
   choose not to reimplement would be inherited from the setuptools' backend
   automatically. This will also cover hooks that might be added in the future
   like the ones that :pep:`660` declares.


.. important:: Make sure your backend script is included in the :doc:`source
   distribution </userguide/distribution>`, otherwise the build will fail.
   This can be done by using a SCM_/VCS_ plugin (like :pypi:`setuptools-scm`
   and :pypi:`setuptools-svn`), or by correctly setting up :ref:`MANIFEST.in
   <manifest>`.

   The generated ``.tar.gz`` and ``.whl`` files are compressed archives that
   can be inspected as follows:
   On POSIX systems, this can be done with ``tar -tf dist/*.tar.gz``
   and ``unzip -l dist/*.whl``.
   On Windows systems, you can rename the ``.whl`` to ``.zip`` to be able to
   inspect it from File Explorer. You can also use the above ``tar`` command in a
   command prompt to inspect the ``.tar.gz`` file. Alternatively, there are GUI programs
   like `7-zip`_ that handle ``.tar.gz`` and ``.whl`` files.

   In general, the backend script should be present in the ``.tar.gz`` (so the
   project can be built from the source) but not in the ``.whl`` (otherwise the
   backend script would end up being distributed alongside your package).
   See ":doc:`/userguide/package_discovery`" for more details about package
   files.


.. _SCM: https://en.wikipedia.org/wiki/Software_configuration_management
.. _VCS: https://en.wikipedia.org/wiki/Version_control
.. _7-zip: https://www.7-zip.org
alt-python312-setuptools/docs/development/releases.rst000064400000002615150410147340017122 0ustar00===============
Release Process
===============

In order to allow for rapid, predictable releases, Setuptools uses a
mechanical technique for releases, enacted on tagged commits by
continuous integration.

To finalize a release, run ``tox -e finalize``, review, then push
the changes.

If tests pass, the release will be uploaded to PyPI.

Release Frequency
-----------------

Some have asked why Setuptools is released so frequently. Because Setuptools
uses a mechanical release process, it's very easy to make releases whenever the
code is stable (tests are passing). As a result, the philosophy is to release
early and often.

While some find the frequent releases somewhat surprising, they only empower
the user. Although releases are made frequently, users can choose the frequency
at which they use those releases. If instead Setuptools contributions were only
released in batches, the user would be constrained to only use Setuptools when
those official releases were made. With frequent releases, the user can govern
exactly how often he wishes to update.

Frequent releases also then obviate the need for dev or beta releases in most
cases. Because releases are made early and often, bugs are discovered and
corrected quickly, in many cases before other users have yet to encounter them.

Release Managers
----------------

Additionally, anyone with push access to the master branch has access to cut
releases.
alt-python312-setuptools/docs/development/developer-guide.rst000064400000010750150410147340020376 0ustar00================================
Developer's Guide for Setuptools
================================

If you want to know more about contributing on Setuptools, this is the place.


-------------------
Recommended Reading
-------------------

Please read `How to write the perfect pull request
<https://blog.jaraco.com/how-to-write-perfect-pull-request/>`_ for some tips
on contributing to open source projects. Although the article is not
authoritative, it was authored by the maintainer of Setuptools, so reflects
his opinions and will improve the likelihood of acceptance and quality of
contribution.

------------------
Project Management
------------------

Setuptools is maintained primarily in GitHub at `this home
<https://github.com/pypa/setuptools>`_. Setuptools is maintained under the
Python Packaging Authority (PyPA) with several core contributors. All bugs
for Setuptools are filed and the canonical source is maintained in GitHub.

User support and discussions are done through
`GitHub Discussions <https://github.com/pypa/setuptools/discussions>`_,
or the issue tracker (for specific issues).

Discussions about development happen on GitHub Discussions or
the ``setuptools`` channel on `PyPA Discord <https://discord.com/invite/pypa>`_.

-----------------
Authoring Tickets
-----------------

Before authoring any source code, it's often prudent to file a ticket
describing the motivation behind making changes. First search to see if a
ticket already exists for your issue. If not, create one. Try to think from
the perspective of the reader. Explain what behavior you expected, what you
got instead, and what factors might have contributed to the unexpected
behavior. In GitHub, surround a block of code or traceback with the triple
backtick "\`\`\`" so that it is formatted nicely.

Filing a ticket provides a forum for justification, discussion, and
clarification. The ticket provides a record of the purpose for the change and
any hard decisions that were made. It provides a single place for others to
reference when trying to understand why the software operates the way it does
or why certain changes were made.

Setuptools makes extensive use of hyperlinks to tickets in the changelog so
that system integrators and other users can get a quick summary, but then
jump to the in-depth discussion about any subject referenced.

---------------------
Making a pull request
---------------------

When making a pull request, please
:ref:`include a short summary of the changes <Adding change notes
with your PRs>` and a reference to any issue tickets that the PR is
intended to solve.
All PRs with code changes should include tests. All changes should
include a changelog entry.

.. include:: ../../newsfragments/README.rst

-------------------
Auto-Merge Requests
-------------------

To support running all code through CI, even lightweight contributions,
the project employs Mergify to auto-merge pull requests tagged as
auto-merge.

Use ``hub pull-request -l auto-merge`` to create such a pull request
from the command line after pushing a new branch.

-------
Testing
-------

The primary tests are run using tox.  Make sure you have tox installed,
and invoke it::

    $ tox

Under continuous integration, additional tests may be run. See the
``.travis.yml`` file for full details on the tests run under Travis-CI.

-------------------
Semantic Versioning
-------------------

Setuptools follows ``semver``.

.. explain value of reflecting meaning in versions.

----------------------
Building Documentation
----------------------

Setuptools relies on the `Sphinx`_ system for building documentation.
The `published documentation`_ is hosted on Read the Docs.

To build the docs locally, use tox::

    $ tox -e docs

.. _Sphinx: https://www.sphinx-doc.org/en/master/
.. _published documentation: https://setuptools.pypa.io/en/latest/

---------------------
Vendored Dependencies
---------------------

Setuptools has some dependencies, but due to `bootstrapping issues
<https://github.com/pypa/setuptools/issues/980>`_, those dependencies
cannot be declared as they won't be resolved soon enough to build
setuptools from source. Eventually, this limitation may be lifted as
PEP 517/518 reach ubiquitous adoption, but for now, Setuptools
cannot declare dependencies other than through
``setuptools/_vendor/vendored.txt`` and
``pkg_resources/_vendor/vendored.txt``.

All the dependencies specified in these files are "vendorized" using a
simple Python script ``tools/vendor.py``.

To refresh the dependencies, run the following command::

    $ tox -e vendor
alt-python312-setuptools/docs/development/index.rst000064400000002657150410147340016434 0ustar00-------------------------
Development on Setuptools
-------------------------

Setuptools is maintained by the Python community under the Python Packaging
Authority (PyPA) and led by Jason R. Coombs.

This document describes the process by which Setuptools is developed.
This document assumes the reader has some passing familiarity with
*using* setuptools, the ``pkg_resources`` module, and pip.  It
does not attempt to explain basic concepts like inter-project
dependencies, nor does it contain detailed lexical syntax for most
file formats.  Neither does it explain concepts like "namespace
packages" or "resources" in any detail, as all of these subjects are
covered at length in the setuptools developer's guide and the
``pkg_resources`` reference manual.

Instead, this is **internal** documentation for how those concepts and
features are *implemented* in concrete terms.  It is intended for people
who are working on the setuptools code base, who want to be able to
troubleshoot setuptools problems, want to write code that reads the file
formats involved, or want to otherwise tinker with setuptools-generated
files and directories.

Note, however, that these are all internal implementation details and
are therefore subject to change; stick to the published API if you don't
want to be responsible for keeping your code from breaking when
setuptools changes.  You have been warned.

.. toctree::
   :maxdepth: 1

   developer-guide
   releases
alt-python312-setuptools/docs/userguide/pyproject_config.rst000064400000034503150410147340020336 0ustar00.. _pyproject.toml config:

-----------------------------------------------------
Configuring setuptools using ``pyproject.toml`` files
-----------------------------------------------------

.. note:: New in 61.0.0

.. important::
   If compatibility with legacy builds or versions of tools that don't support
   certain packaging standards (e.g. :pep:`517` or :pep:`660`), a simple ``setup.py``
   script can be added to your project [#setupcfg-caveats]_
   (while keeping the configuration in ``pyproject.toml``):

   .. code-block:: python

       from setuptools import setup

       setup()

Starting with :pep:`621`, the Python community selected ``pyproject.toml`` as
a standard way of specifying *project metadata*.
``Setuptools`` has adopted this standard and will use the information contained
in this file as an input in the build process.

The example below illustrates how to write a ``pyproject.toml`` file that can
be used with ``setuptools``. It contains two TOML tables (identified by the
``[table-header]`` syntax): ``build-system`` and ``project``.
The ``build-system`` table is used to tell the build frontend (e.g.
:pypi:`build` or :pypi:`pip`) to use ``setuptools`` and any other plugins (e.g.
``setuptools-scm``) to build the package.
The ``project`` table contains metadata fields as described by the
:doc:`PyPUG:guides/writing-pyproject-toml` guide.

.. _example-pyproject-config:

.. code-block:: toml

   [build-system]
   requires = ["setuptools", "setuptools-scm"]
   build-backend = "setuptools.build_meta"

   [project]
   name = "my_package"
   authors = [
       {name = "Josiah Carberry", email = "josiah_carberry@brown.edu"},
   ]
   description = "My package description"
   readme = "README.rst"
   requires-python = ">=3.7"
   keywords = ["one", "two"]
   license = {text = "BSD-3-Clause"}
   classifiers = [
       "Framework :: Django",
       "Programming Language :: Python :: 3",
   ]
   dependencies = [
       "requests",
       'importlib-metadata; python_version<"3.8"',
   ]
   dynamic = ["version"]

   [project.optional-dependencies]
   pdf = ["ReportLab>=1.2", "RXP"]
   rest = ["docutils>=0.3", "pack ==1.1, ==1.3"]

   [project.scripts]
   my-script = "my_package.module:function"

   # ... other project metadata fields as listed in:
   #     https://packaging.python.org/en/latest/guides/writing-pyproject-toml/

.. _setuptools-table:

Setuptools-specific configuration
=================================

While the standard ``project`` table in the ``pyproject.toml`` file covers most
of the metadata used during the packaging process, there are still some
``setuptools``-specific configurations that can be set by users that require
customization.
These configurations are completely optional and probably can be skipped when
creating simple packages.
They are equivalent to the :doc:`/references/keywords` used by the ``setup.py``
file, and can be set via the ``tool.setuptools`` table:

========================= =========================== =========================
Key                       Value Type (TOML)           Notes
========================= =========================== =========================
``py-modules``            array                       See tip below.
``packages``              array or ``find`` directive See tip below.
``package-dir``           table/inline-table          Used when explicitly/manually listing ``packages``.
------------------------- --------------------------- -------------------------
``package-data``          table/inline-table          See :doc:`/userguide/datafiles`.
``include-package-data``  boolean                     ``True`` by default (only when using ``pyproject.toml`` project metadata/config).
                                                      See :doc:`/userguide/datafiles`.
``exclude-package-data``  table/inline-table          Empty by default. See :doc:`/userguide/datafiles`.
------------------------- --------------------------- -------------------------
``license-files``         array of glob patterns      **Provisional** - likely to change with :pep:`639`
                                                      (by default: ``['LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*']``)
``data-files``            table/inline-table          **Discouraged** - check :doc:`/userguide/datafiles`.
                                                      Whenever possible, consider using data files inside the package directories.
``script-files``          array                       **Discouraged** - equivalent to the ``script`` keyword in ``setup.py``.
                                                      Whenever possible, please use ``project.scripts`` instead.
------------------------- --------------------------- -------------------------
``provides``              array                       *ignored by pip when installing packages*
``obsoletes``             array                       *ignored by pip when installing packages*
``platforms``             array                       Sets the ``Platform`` :doc:`core-metadata <PyPUG:specifications/core-metadata>` field
                                                      (*ignored by pip when installing packages*).
------------------------- --------------------------- -------------------------
``zip-safe``              boolean                     **Obsolete** - only relevant for ``pkg_resources``, ``easy_install`` and ``setup.py install``
                                                      in the context of :doc:`eggs </deprecated/python_eggs>` (deprecated).
``eager-resources``       array                       **Obsolete** - only relevant for ``pkg_resources``, ``easy_install`` and ``setup.py install``
                                                      in the context of :doc:`eggs </deprecated/python_eggs>` (deprecated).
``namespace-packages``    array                       **Deprecated** - use implicit namespaces instead (:pep:`420`).
========================= =========================== =========================

.. note::
   The `TOML value types`_ ``array`` and ``table/inline-table`` are roughly
   equivalent to the Python's :obj:`list` and :obj:`dict` data types, respectively.

Please note that some of these configurations are deprecated, obsolete or at least
discouraged, but they are made available to ensure portability.
Deprecated and obsolete configurations may be removed in future versions of ``setuptools``.
New packages should avoid relying on discouraged fields if possible, and
existing packages should consider migrating to alternatives.

.. tip::
   When both ``py-modules`` and ``packages`` are left unspecified,
   ``setuptools`` will attempt to perform :ref:`auto-discovery`, which should
   cover most popular project directory organization techniques, such as the
   :ref:`src-layout` and the :ref:`flat-layout`.

   However if your project does not follow these conventional layouts
   (e.g. you want to use a ``flat-layout`` but at the same time have custom
   directories at the root of your project), you might need to use the ``find``
   directive [#directives]_ as shown below:

   .. code-block:: toml

      [tool.setuptools.packages.find]
      where = ["src"]  # list of folders that contain the packages (["."] by default)
      include = ["my_package*"]  # package names should match these glob patterns (["*"] by default)
      exclude = ["my_package.tests*"]  # exclude packages matching these glob patterns (empty by default)
      namespaces = false  # to disable scanning PEP 420 namespaces (true by default)

   Note that the glob patterns in the example above need to be matched
   by the **entire** package name. This means that if you specify ``exclude = ["tests"]``,
   modules like ``tests.my_package.test1`` will still be included in the distribution
   (to remove them, add a wildcard to the end of the pattern: ``"tests*"``).

   Alternatively, you can explicitly list the packages in modules:

   .. code-block:: toml

      [tool.setuptools]
      packages = ["my_package"]

   If you want to publish a distribution that does not include any Python module
   (e.g. a "meta-distribution" that just aggregate dependencies), please
   consider something like the following:

   .. code-block:: toml

      [tool.setuptools]
      packages = []


.. _dynamic-pyproject-config:

Dynamic Metadata
================

Note that in the first example of this page we use ``dynamic`` to identify
which metadata fields are dynamically computed during the build by either
``setuptools`` itself or the plugins installed via ``build-system.requires``
(e.g. ``setuptools-scm`` is capable of deriving the current project version
directly from the ``git`` :wiki:`version control` system).

Currently the following fields can be listed as dynamic: ``version``,
``classifiers``, ``description``, ``entry-points``, ``scripts``,
``gui-scripts`` and ``readme``.
When these fields are expected to be provided by ``setuptools`` a
corresponding entry is required in the ``tool.setuptools.dynamic`` table
[#entry-points]_. For example:

.. code-block:: toml

   # ...
   [project]
   name = "my_package"
   dynamic = ["version", "readme"]
   # ...
   [tool.setuptools.dynamic]
   version = {attr = "my_package.VERSION"}
   readme = {file = ["README.rst", "USAGE.rst"]}

In the ``dynamic`` table, the ``attr`` directive [#directives]_ will read an
attribute from the given module [#attr]_, while ``file`` will read the contents
of all given files and concatenate them in a single string.

========================== =================== =================================================================================================
Key                        Directive           Notes
========================== =================== =================================================================================================
``version``                ``attr``, ``file``
``readme``                 ``file``            Here you can also set ``"content-type"``:

                                               ``readme = {file = ["README.txt", "USAGE.txt"], content-type = "text/plain"}``

                                               If ``content-type`` is not given, ``"text/x-rst"`` is used by default.
``description``            ``file``            One-line text (no line breaks)
``classifiers``            ``file``            Multi-line text with one classifier per line
``entry-points``           ``file``            INI format following :doc:`PyPUG:specifications/entry-points`
                                               (``console_scripts`` and ``gui_scripts`` can be included)
``dependencies``           ``file``            *subset* of the ``requirements.txt`` format
                                               (``#`` comments and blank lines excluded) **BETA**
``optional-dependencies``  ``file``            *subset* of the ``requirements.txt`` format per group
                                               (``#`` comments and blank lines excluded) **BETA**
========================== =================== =================================================================================================

Supporting ``file`` for dependencies is meant for a convenience for packaging
applications with possibly strictly versioned dependencies.

Library packagers are discouraged from using overly strict (or "locked")
dependency versions in their ``dependencies`` and ``optional-dependencies``.

Currently, when specifying ``optional-dependencies`` dynamically, all of the groups
must be specified dynamically; one can not specify some of them statically and
some of them dynamically.

Also note that the file format for specifying dependencies resembles a ``requirements.txt`` file,
however please keep in mind that all non-comment lines must conform with :pep:`508`
(``pip``-specify syntaxes, e.g. ``-c/-r/-e`` flags, are not supported).


.. note::
   If you are using an old version of ``setuptools``, you might need to ensure
   that all files referenced by the ``file`` directive are included in the ``sdist``
   (you can do that via ``MANIFEST.in`` or using plugins such as ``setuptools-scm``,
   please have a look on :doc:`/userguide/miscellaneous` for more information).

   .. versionchanged:: 66.1.0
      Newer versions of ``setuptools`` will automatically add these files to the ``sdist``.

It is advisable to use literal values together with ``attr`` (e.g. ``str``,
``tuple[str]``, see :func:`ast.literal_eval`). This is recommend
in order to support the common case of a literal value assigned to a variable
in a module containing (directly or indirectly) third-party imports.

``attr`` first tries to read the value from the module by examining the
module's AST. If that fails, ``attr`` falls back to importing the module,
using :func:`importlib.util.spec_from_file_location` recommended recipe
(see :ref:`example on Python docs <python:importlib-examples>`
about "Importing a source file directly").
Note however that importing the module is error prone since your package is
not installed yet. You may also need to manually add the project directory to
``sys.path`` (via ``setup.py``) in order to be able to do that.

----

.. rubric:: Notes

.. [#setupcfg-caveats] ``pip`` may allow editable install only with ``pyproject.toml``
   and ``setup.cfg``. However, this behavior may not be consistent over various ``pip``
   versions and other packaging-related tools
   (``setup.py`` is more reliable on those scenarios).

.. [#entry-points] Dynamic ``scripts`` and ``gui-scripts`` are a special case.
   When resolving these metadata keys, ``setuptools`` will look for
   ``tool.setuptools.dynamic.entry-points``, and use the values of the
   ``console_scripts`` and ``gui_scripts`` :doc:`entry-point groups
   <PyPUG:specifications/entry-points>`.

.. [#directives] In the context of this document, *directives* are special TOML
   values that are interpreted differently by ``setuptools`` (usually triggering an
   associated function). Most of the times they correspond to a special TOML table
   (or inline-table) with a single top-level key.
   For example, you can have the ``{find = {where = ["src"], exclude=["tests*"]}}``
   directive for ``tool.setuptools.packages``, or ``{attr = "mymodule.attr"}``
   directive for ``tool.setuptools.dynamic.version``.

.. [#attr] ``attr`` is meant to be used when the module attribute is statically
   specified (e.g. as a string, list or tuple). As a rule of thumb, the
   attribute should be able to be parsed with :func:`ast.literal_eval`, and
   should not be modified or re-assigned.

.. _TOML value types: https://toml.io/en/v1.0.0
alt-python312-setuptools/docs/userguide/declarative_config.rst000064400000032520150410147340020577 0ustar00.. _declarative config:

------------------------------------------------
Configuring setuptools using ``setup.cfg`` files
------------------------------------------------

.. note:: New in 30.3.0 (8 Dec 2016).

.. important::
    If compatibility with legacy builds (i.e. those not using the :pep:`517`
    build API) is desired, a ``setup.py`` file containing a ``setup()`` function
    call is still required even if your configuration resides in ``setup.cfg``.

``Setuptools`` allows using configuration files (usually :file:`setup.cfg`)
to define a package’s metadata and other options that are normally supplied
to the ``setup()`` function (declarative config).

This approach not only allows automation scenarios but also reduces
boilerplate code in some cases.

.. _example-setup-config:

.. code-block:: ini

    [metadata]
    name = my_package
    version = attr: my_package.VERSION
    author = Josiah Carberry
    author_email = josiah_carberry@brown.edu
    description = My package description
    long_description = file: README.rst, CHANGELOG.rst, LICENSE.rst
    keywords = one, two
    license = BSD-3-Clause
    classifiers =
        Framework :: Django
        Programming Language :: Python :: 3

    [options]
    zip_safe = False
    include_package_data = True
    packages = find:
    python_requires = >=3.7
    install_requires =
        requests
        importlib-metadata; python_version<"3.8"

    [options.package_data]
    * = *.txt, *.rst
    hello = *.msg

    [options.entry_points]
    console_scripts =
        executable-name = my_package.module:function

    [options.extras_require]
    pdf = ReportLab>=1.2; RXP
    rest = docutils>=0.3; pack ==1.1, ==1.3

    [options.packages.find]
    exclude =
        examples*
        tools*
        docs*
        my_package.tests*

Metadata and options are set in the config sections of the same name.

* Keys are the same as the :doc:`keyword arguments </references/keywords>` one
  provides to the ``setup()`` function.

* Complex values can be written comma-separated or placed one per line
  in *dangling* config values. The following are equivalent:

  .. code-block:: ini

      [metadata]
      keywords = one, two

      [metadata]
      keywords =
          one
          two

* In some cases, complex values can be provided in dedicated subsections for
  clarity.

* Some keys allow ``file:``, ``attr:``, ``find:``, and ``find_namespace:`` directives in
  order to cover common usecases.

* Unknown keys are ignored.


Using a ``src/`` layout
=======================

One commonly used configuration has all the Python source code in a
subdirectory (often called the ``src/`` layout), like this::

    ├── src
    │   └── mypackage
    │       ├── __init__.py
    │       └── mod1.py
    ├── setup.py
    └── setup.cfg

You can set up your ``setup.cfg`` to automatically find all your packages in
the subdirectory, using :ref:`package_dir <keyword/package_dir>`, like this:

.. code-block:: ini

    # This example contains just the necessary options for a src-layout, set up
    # the rest of the file as described above.

    [options]
    package_dir=
        =src
    packages=find:

    [options.packages.find]
    where=src

In this example, the value for the :ref:`package_dir <keyword/package_dir>`
configuration (i.e. ``=src``) is parsed as ``{"": "src"}``.
The ``""`` key has a special meaning in this context, and indicates that all the
packages are contained inside the given directory.
Also note that the value for ``[options.packages.find] where`` matches the
value associated with ``""`` in the ``package_dir`` dictionary.

..
   TODO: Add the following tip once the auto-discovery is no longer experimental:

   Starting in version 61, ``setuptools`` can automatically infer the
   configurations for both ``packages`` and ``package_dir`` for projects using
   a ``src/`` layout (as long as no value is specified for ``py_modules``).
   Please see :doc:`package discovery </userguide/package_discovery>` for more
   details.

Specifying values
=================

Some values are treated as simple strings, some allow more logic.

Type names used below:

* ``str`` - simple string
* ``list-comma`` - dangling list or string of comma-separated values
* ``list-semi`` - dangling list or string of semicolon-separated values
* ``bool`` - ``True`` is 1, yes, true
* ``dict`` - list-comma where each entry corresponds to a key/value pair,
  with keys separated from values by ``=``.
  If an entry starts with ``=``, the key is assumed to be an empty string
  (e.g. ``=src`` is parsed as ``{"": "src"}``).
* ``section`` - values are read from a dedicated (sub)section


Special directives:

* ``attr:`` - Value is read from a module attribute.

  It is advisable to use literal values together with ``attr:`` (e.g. ``str``,
  ``tuple[str]``, see :func:`ast.literal_eval`). This is recommend
  in order to support the common case of a literal value assigned to a variable
  in a module containing (directly or indirectly) third-party imports.

  ``attr:`` first tries to read the value from the module by examining the
  module's AST.  If that fails, ``attr:`` falls back to importing the module,
  using :func:`importlib.util.spec_from_file_location` recommended recipe
  (see :ref:`example on Python docs <python:importlib-examples>`
  about "Importing a source file directly").
  Note however that importing the module is error prone since your package is
  not installed yet. You may also need to manually add the project directory to
  ``sys.path`` (via ``setup.py``) in order to be able to do that.

  When the module is imported, ``attr:`` supports
  callables and iterables; unsupported types are cast using ``str()``.


* ``file:`` - Value is read from a list of files and then concatenated

  .. important::
      The ``file:`` directive is sandboxed and won't reach anything outside the
      project directory (i.e. the directory containing ``setup.cfg``/``pyproject.toml``).

  .. note::
      If you are using an old version of ``setuptools``, you might need to ensure
      that all files referenced by the ``file:`` directive are included in the ``sdist``
      (you can do that via ``MANIFEST.in`` or using plugins such as ``setuptools-scm``,
      please have a look on :doc:`/userguide/miscellaneous` for more information).

      .. versionchanged:: 66.1.0
         Newer versions of ``setuptools`` will automatically add these files to the ``sdist``.


Metadata
--------

.. attention::
    The aliases given below are supported for compatibility reasons,
    but their use is not advised.

==============================  =================  =================  =============== ==========
Key                             Aliases            Type               Minimum Version Notes
==============================  =================  =================  =============== ==========
name                                               str
version                                            attr:, file:, str  39.2.0          [#meta-1]_
url                             home-page          str
download_url                    download-url       str
project_urls                                       dict               38.3.0
author                                             str
author_email                    author-email       str
maintainer                                         str
maintainer_email                maintainer-email   str
classifiers                     classifier         file:, list-comma
license                                            str
license_files                   license_file       list-comma         42.0.0
description                     summary            file:, str
long_description                long-description   file:, str
long_description_content_type                      str                38.6.0
keywords                                           list-comma
platforms                       platform           list-comma
provides                                           list-comma
requires                                           list-comma
obsoletes                                          list-comma
==============================  =================  =================  =============== ==========

**Notes**:

.. [#meta-1] The ``version`` file attribute has only been supported since 39.2.0.

   A version loaded using the ``file:`` directive must comply with PEP 440.
   It is easy to accidentally put something other than a valid version
   string in such a file, so validation is stricter in this case.


Options
-------

=======================  ===================================  =============== ====================
Key                      Type                                 Minimum Version Notes
=======================  ===================================  =============== ====================
zip_safe                 bool
setup_requires           list-semi                            36.7.0
install_requires         file:, list-semi                                     **BETA** [#opt-2]_, [#opt-6]_
extras_require           file:, section                                       **BETA** [#opt-2]_, [#opt-6]_
python_requires          str                                  34.4.0
entry_points             file:, section                       51.0.0
scripts                  list-comma
eager_resources          list-comma
dependency_links         list-comma
tests_require            list-semi
include_package_data     bool
packages                 find:, find_namespace:, list-comma                   [#opt-3]_
package_dir              dict
package_data             section                                              [#opt-1]_
exclude_package_data     section
namespace_packages       list-comma                                           [#opt-5]_
py_modules               list-comma                           34.4.0
data_files               section                              40.6.0          [#opt-4]_
=======================  ===================================  =============== ====================

**Notes**:

.. [#opt-1] In the ``package_data`` section, a key named with a single asterisk
   (``*``) refers to all packages, in lieu of the empty string used in ``setup.py``.

.. [#opt-2] In ``install_requires`` and ``extras_require``, values are parsed as ``list-semi``.
   This implies that in order to include markers, each requirement **must** be *dangling*
   in a new line:

   .. code-block:: ini

      [options]
      install_requires =
          importlib-metadata; python_version<"3.8"

      [options.extras_require]
      all =
          importlib-metadata; python_version < "3.8"

.. [#opt-3] The ``find:`` and ``find_namespace:`` directive can be further configured
   in a dedicated subsection ``options.packages.find``. This subsection accepts the
   same keys as the ``setuptools.find_packages`` and the
   ``setuptools.find_namespace_packages`` function:
   ``where``, ``include``, and ``exclude``.

   The ``find_namespace:`` directive is supported since Python >=3.3.

.. [#opt-4] ``data_files`` is deprecated and should be avoided.
   Please check :doc:`/userguide/datafiles` for more information.

.. [#opt-5] ``namespace_packages`` is deprecated in favour of native/implicit
   namespaces (:pep:`420`). Check :doc:`the Python Packaging User Guide
   <PyPUG:guides/packaging-namespace-packages>` for more information.

.. [#opt-6] ``file:`` directives for reading requirements are supported since version 62.6.
   The format for the file resembles a ``requirements.txt`` file,
   however please keep in mind that all non-comment lines must conform with :pep:`508`
   (``pip``-specify syntaxes, e.g. ``-c/-r/-e`` flags, are not supported).
   Library developers should avoid tightly pinning their dependencies to a specific
   version (e.g. via a "locked" requirements file).


Compatibility with other tools
==============================

Historically, several tools explored declarative package configuration
in parallel. And several of them chose to place the packaging
configuration within the project's :file:`setup.cfg` file.
One of the first was ``distutils2``, which development has stopped in
2013. Other include ``pbr`` which is still under active development or
``d2to1``, which was a plug-in that backports declarative configuration
to ``distutils``, but has had no release since Oct. 2015.
As a way to harmonize packaging tools, ``setuptools``, having held the
position of *de facto* standard, has gradually integrated those
features as part of its core features.

Still this has lead to some confusion and feature incompatibilities:

- some tools support features others don't;
- some have similar features but the declarative syntax differs;

The table below tries to summarize the differences. But, please, refer
to each tool documentation for up-to-date information.

=========================== ========== ========== ===== ===
feature                     setuptools distutils2 d2to1 pbr
=========================== ========== ========== ===== ===
[metadata] description-file S          Y          Y     Y
[files]                     S          Y          Y     Y
entry_points                Y          Y          Y     S
[backwards_compat]          N          Y          Y     Y
=========================== ========== ========== ===== ===

Y: supported, N: unsupported, S: syntax differs (see
:ref:`above example<example-setup-config>`).

Also note that some features were only recently added to ``setuptools``.
Please refer to the previous sections to find out when.
alt-python312-setuptools/docs/userguide/development_mode.rst000064400000027764150410147340020333 0ustar00Development Mode (a.k.a. "Editable Installs")
=============================================

When creating a Python project, developers usually want to implement and test
changes iteratively, before cutting a release and preparing a distribution archive.

In normal circumstances this can be quite cumbersome and require the developers
to manipulate the ``PYTHONPATH`` environment variable or to continuously re-build
and re-install the project.

To facilitate iterative exploration and experimentation, setuptools allows
users to instruct the Python interpreter and its import machinery to load the
code under development directly from the project folder without having to
copy the files to a different location in the disk.
This means that changes in the Python source code can immediately take place
without requiring a new installation.

You can enter this "development mode" by performing an :doc:`editable installation
<pip:topics/local-project-installs>` inside of a :term:`virtual environment`,
using :doc:`pip's <pip:cli/pip_install>` ``-e/--editable`` flag, as shown below:

.. code-block:: bash

   $ cd your-python-project
   $ python -m venv .venv
   # Activate your environment with:
   #      `source .venv/bin/activate` on Unix/macOS
   # or   `.venv\Scripts\activate` on Windows

   $ pip install --editable .

   # Now you have access to your package
   # as if it was installed in .venv
   $ python -c "import your_python_project"


An "editable installation" works very similarly to a regular install with
``pip install .``, except that it only installs your package dependencies,
metadata and wrappers for :ref:`console and GUI scripts <console-scripts>`.
Under the hood, setuptools will try to create a special :mod:`.pth file <site>`
in the target directory (usually ``site-packages``) that extends the
``PYTHONPATH`` or install a custom :doc:`import hook <python:reference/import>`.

When you're done with a given development task, you can simply uninstall your
package (as you would normally do with ``pip uninstall <package name>``).

Please note that, by default an editable install will expose at least all the
files that would be available in a regular installation. However, depending on
the file and directory organization in your project, it might also expose
as a side effect files that would not be normally available.
This is allowed so you can iteratively create new Python modules.
Please have a look on the following section if you are looking for a different behaviour.

.. admonition:: Virtual Environments

   You can think about virtual environments as "isolated Python runtime deployments"
   that allow users to install different sets of libraries and tools without
   messing with the global behaviour of the system.

   They are a safe way of testing new projects and can be created easily
   with the :mod:`venv` module from the standard library.

   Please note however that depending on your operating system or distribution,
   ``venv`` might not come installed by default with Python. For those cases,
   you might need to use the OS package manager to install it.
   For example, in Debian/Ubuntu-based systems you can obtain it via:

   .. code-block:: bash

       sudo apt install python3-venv

   Alternatively, you can also try installing :pypi:`virtualenv`.
   More information is available on the Python Packaging User Guide on
   :doc:`PyPUG:guides/installing-using-pip-and-virtual-environments`.

.. note::
    .. versionchanged:: v64.0.0
       Editable installation hooks implemented according to :pep:`660`.
       Support for :pep:`namespace packages <420>` is still **EXPERIMENTAL**.


"Strict" editable installs
--------------------------

When thinking about editable installations, users might have the following
expectations:

1. It should allow developers to add new files (or split/rename existing ones)
   and have them automatically exposed.
2. It should behave as close as possible to a regular installation and help
   users to detect problems (e.g. new files not being included in the distribution).

Unfortunately these expectations are in conflict with each other.
To solve this problem ``setuptools`` allows developers to choose a more
*"strict"* mode for the editable installation. This can be done by passing
a special *configuration setting* via :pypi:`pip`, as indicated below:

.. code-block:: bash

    pip install -e . --config-settings editable_mode=strict

In this mode, new files **won't** be exposed and the editable installs will
try to mimic as much as possible the behavior of a regular install.
Under the hood, ``setuptools`` will create a tree of file links in an auxiliary
directory (``$your_project_dir/build``) and add it to ``PYTHONPATH`` via a
:mod:`.pth file <site>`. (Please be careful to not delete this repository
by mistake otherwise your files may stop being accessible).

.. warning::
   Strict editable installs require auxiliary files to be placed in a
   ``build/__editable__.*`` directory (relative to your project root).

   Please be careful to not remove this directory while testing your project,
   otherwise your editable installation may be compromised.

   You can remove the ``build/__editable__.*`` directory after uninstalling.


.. note::
    .. versionadded:: v64.0.0
       Added new *strict* mode for editable installations.
       The exact details of how this mode is implemented may vary.


Limitations
-----------

- The *editable* term is used to refer only to Python modules
  inside the package directories. Non-Python files, external (data) files,
  executable script files, binary extensions, headers and metadata may be
  exposed as a *snapshot* of the version they were at the moment of the
  installation.
- Adding new dependencies, entry-points or changing your project's metadata
  require a fresh "editable" re-installation.
- Console scripts and GUI scripts **MUST** be specified via :doc:`entry-points
  </userguide/entry_point>` to work properly.
- *Strict* editable installs require the file system to support
  either :wiki:`symbolic <symbolic link>` or :wiki:`hard links <hard link>`.
  This installation mode might also generate auxiliary files under the project directory.
- There is *no guarantee* that the editable installation will be performed
  using a specific technique. Depending on each project, ``setuptools`` may
  select a different approach to ensure the package is importable at runtime.
- There is *no guarantee* that files outside the top-level package directory
  will be accessible after an editable install.
- There is *no guarantee* that attributes like ``__path__`` or ``__file__``
  will correspond to the exact location of the original files (e.g.,
  ``setuptools`` might employ file links to perform the editable installation).
  Users are encouraged to use tools like :mod:`importlib.resources` or
  :mod:`importlib.metadata` when trying to access package files directly.
- Editable installations may not work with
  :doc:`namespaces created with pkgutil or pkg_resources
  <PyPUG:guides/packaging-namespace-packages>`.
  Please use :pep:`420`-style implicit namespaces [#namespaces]_.
- Support for :pep:`420`-style implicit namespace packages for
  projects structured using :ref:`flat-layout` is still **experimental**.
  If you experience problems, you can try converting your package structure
  to the :ref:`src-layout`.
- File system entries in the current working directory
  whose names coincidentally match installed packages
  may take precedence in :doc:`Python's import system <python:reference/import>`.
  Users are encouraged to avoid such scenarios [#cwd]_.
- Setuptools will try to give the right precedence to modules in an editable install.
  However this is not always an easy task. If you have a particular order in
  ``sys.path`` or some specific import precedence that needs to be respected,
  the editable installation as supported by Setuptools might not be able to
  fulfil this requirement, and therefore it might not be the right tool for your use case.

.. attention::
   Editable installs are **not a perfect replacement for regular installs**
   in a test environment. When in doubt, please test your projects as
   installed via a regular wheel. There are tools in the Python ecosystem,
   like :pypi:`tox` or :pypi:`nox`, that can help you with that
   (when used with appropriate configuration).


Legacy Behavior
---------------

If your project is not compatible with the new "editable installs" or you wish
to replicate the legacy behavior, for the time being you can also perform the
installation in the ``compat`` mode:

.. code-block:: bash

    pip install -e . --config-settings editable_mode=compat

This installation mode will try to emulate how ``python setup.py develop``
works (still within the context of :pep:`660`).

.. warning::
   The ``compat`` mode is *transitional* and will be removed in
   future versions of ``setuptools``, it exists only to help during the
   migration period.
   Also note that support for this mode is limited:
   it is safe to assume that the ``compat`` mode is offered "as is", and
   improvements are unlikely to be implemented.
   Users are encouraged to try out the new editable installation techniques
   and make the necessary adaptations.

.. note::
   Newer versions of ``pip`` no longer run the fallback command
   ``python setup.py develop`` when the ``pyproject.toml`` file is present.
   This means that setting the environment variable
   ``SETUPTOOLS_ENABLE_FEATURES="legacy-editable"``
   will have no effect when installing a package with ``pip``.


How editable installations work
-------------------------------

*Advanced topic*

There are many techniques that can be used to expose packages under development
in such a way that they are available as if they were installed.
Depending on the project file structure and the selected mode, ``setuptools``
will choose one of these approaches for the editable installation [#criteria]_.

A non-exhaustive list of implementation mechanisms is presented below.
More information is available on the text of :pep:`PEP 660 <660#what-to-put-in-the-wheel>`.

- A static ``.pth`` file [#static_pth]_ can be added to one of the directories
  listed in :func:`site.getsitepackages` or :func:`site.getusersitepackages` to
  extend :obj:`sys.path`.
- A directory containing a *farm of file links* that mimic the
  project structure and point to the original files can be employed.
  This directory can then be added to :obj:`sys.path` using a static ``.pth`` file.
- A dynamic ``.pth`` file [#dynamic_pth]_ can also be used to install an
  "import :term:`finder`" (:obj:`~importlib.abc.MetaPathFinder` or
  :obj:`~importlib.abc.PathEntryFinder`) that will hook into Python's
  :doc:`import system <python:reference/import>` machinery.

.. attention::
   ``Setuptools`` offers **no guarantee** of which technique will be used to
   perform an editable installation. This will vary from project to project
   and may change depending on the specific version of ``setuptools`` being
   used.


----

.. rubric:: Notes

.. [#namespaces]
   You *may* be able to use *strict* editable installations with namespace
   packages created with ``pkgutil`` or ``pkg_namespaces``, however this is not
   officially supported.

.. [#cwd]
   Techniques like the :ref:`src-layout` or tooling-specific options like
   `tox's changedir <https://tox.wiki/en/stable/config.html#conf-changedir>`_
   can be used to prevent such kinds of situations (checkout `this blog post
   <https://blog.ganssle.io/articles/2019/08/test-as-installed.html>`_ for more
   insights).

.. [#criteria]
   ``setuptools`` strives to find a balance between allowing the user to see
   the effects of project files being edited while still trying to keep the
   editable installation as similar as possible to a regular installation.

.. [#static_pth]
   i.e., a ``.pth`` file where each line correspond to a path that should be
   added to :obj:`sys.path`. See :mod:`Site-specific configuration hook <site>`.

.. [#dynamic_pth]
   i.e., a ``.pth`` file that starts where each line starts with an ``import``
   statement and executes arbitrary Python code. See :mod:`Site-specific
   configuration hook <site>`.
alt-python312-setuptools/docs/userguide/entry_point.rst000064400000043673150410147340017354 0ustar00.. _`entry_points`:

============
Entry Points
============

Entry points are a type of metadata that can be exposed by packages on installation.
They are a very useful feature of the Python ecosystem,
and come specially handy in two scenarios:

1. The package would like to provide commands to be run at the terminal.
This functionality is known as *console* scripts. The command may also
open up a GUI, in which case it is known as a *GUI* script. An example
of a console script is the one provided by the :pypi:`pip` package, which
allows you to run commands like ``pip install`` in the terminal.

2. A package would like to enable customization of its functionalities
via *plugins*. For example, the test framework :pypi:`pytest` allows
customization via the ``pytest11`` entry point, and the syntax
highlighting tool :pypi:`pygments` allows specifying additional styles
using the entry point ``pygments.styles``.


.. _console-scripts:

Console Scripts
===============

Let us start with console scripts.
First consider an example without entry points. Imagine a package
defined thus::

    project_root_directory
    ├── pyproject.toml        # and/or setup.cfg, setup.py
    └── src
        └── timmins
            ├── __init__.py
            └── ...

with ``__init__.py`` as:

.. code-block:: python

    def hello_world():
        print("Hello world")

Now, suppose that we would like to provide some way of executing the
function ``hello_world()`` from the command-line. One way to do this
is to create a file ``src/timmins/__main__.py`` providing a hook as
follows:

.. code-block:: python

    from . import hello_world

    if __name__ == '__main__':
        hello_world()

Then, after installing the package ``timmins``, we may invoke the ``hello_world()``
function as follows, through the `runpy <https://docs.python.org/3/library/runpy.html>`_
module:

.. code-block:: bash

    $ python -m timmins
    Hello world

Instead of this approach using ``__main__.py``, you can also create a
user-friendly CLI executable that can be called directly without ``python -m``.
In the above example, to create a command ``hello-world`` that invokes
``timmins.hello_world``, add a console script entry point to your
configuration:

.. tab:: pyproject.toml

   .. code-block:: toml

        [project.scripts]
        hello-world = "timmins:hello_world"

.. tab:: setup.cfg

    .. code-block:: ini

        [options.entry_points]
        console_scripts =
            hello-world = timmins:hello_world

.. tab:: setup.py

    .. code-block:: python

        from setuptools import setup

        setup(
            # ...,
            entry_points={
                'console_scripts': [
                    'hello-world = timmins:hello_world',
                ]
            }
        )


After installing the package, a user may invoke that function by simply calling
``hello-world`` on the command line:

.. code-block:: bash

   $ hello-world
   Hello world

Note that any function used as a console script, i.e. ``hello_world()`` in
this example, should not accept any arguments. If your function requires any input
from the user, you can use regular command-line argument parsing utilities like
:mod:`argparse` within the body of
the function to parse user input given via :obj:`sys.argv`.

You may have noticed that we have used a special syntax to specify the function
that must be invoked by the console script, i.e. we have written ``timmins:hello_world``
with a colon ``:`` separating the package name and the function name. The full
specification of this syntax is discussed in the `last section <#entry-points-syntax>`_
of this document, and this can be used to specify a function located anywhere in
your package, not just in ``__init__.py``.

GUI Scripts
===========

In addition to ``console_scripts``, Setuptools supports ``gui_scripts``, which
will launch a GUI application without running in a terminal window.

For example, if we have a project with the same directory structure as before,
with an ``__init__.py`` file containing the following:

.. code-block:: python

    import PySimpleGUI as sg

    def hello_world():
        sg.Window(title="Hello world", layout=[[]], margins=(100, 50)).read()

Then, we can add a GUI script entry point:

.. tab:: pyproject.toml

   .. code-block:: toml

        [project.gui-scripts]
        hello-world = "timmins:hello_world"

.. tab:: setup.cfg

    .. code-block:: ini

        [options.entry_points]
        gui_scripts =
            hello-world = timmins:hello_world

.. tab:: setup.py

    .. code-block:: python

        from setuptools import setup

        setup(
            # ...,
            entry_points={
                'gui_scripts': [
                    'hello-world = timmins:hello_world',
                ]
            }
        )

.. note::
   To be able to import ``PySimpleGUI``, you need to add ``pysimplegui`` to your package dependencies.
   See :doc:`/userguide/dependency_management` for more information.

Now, running:

.. code-block:: bash

   $ hello-world

will open a small application window with the title 'Hello world'.

Note that just as with console scripts, any function used as a GUI script
should not accept any arguments, and any user input can be parsed within the
body of the function. GUI scripts also use the same syntax (discussed in the
`last section <#entry-points-syntax>`_) for specifying the function to be invoked.

.. note::

    The difference between ``console_scripts`` and ``gui_scripts`` only affects
    Windows systems. [#use_for_scripts]_ ``console_scripts`` are wrapped in a console
    executable, so they are attached to a console and can use ``sys.stdin``,
    ``sys.stdout`` and ``sys.stderr`` for input and output. ``gui_scripts`` are
    wrapped in a GUI executable, so they can be started without a console, but
    cannot use standard streams unless application code redirects them. Other
    platforms do not have the same distinction.

.. note::

    Console and GUI scripts work because behind the scenes, installers like :pypi:`pip`
    create wrapper scripts around the function(s) being invoked. For example,
    the ``hello-world`` entry point in the above two examples would create a
    command ``hello-world`` launching a script like this: [#use_for_scripts]_

    .. code-block:: python

        import sys
        from timmins import hello_world
        sys.exit(hello_world())

.. _dynamic discovery of services and plugins:

Advertising Behavior
====================

Console/GUI scripts are one use of the more general concept of entry points. Entry
points more generally allow a packager to advertise behavior for discovery by
other libraries and applications. This feature enables "plug-in"-like
functionality, where one library solicits entry points and any number of other
libraries provide those entry points.

A good example of this plug-in behavior can be seen in
`pytest plugins <https://docs.pytest.org/en/latest/writing_plugins.html>`_,
where pytest is a test framework that allows other libraries to extend
or modify its functionality through the ``pytest11`` entry point.

The console/GUI scripts work similarly, where libraries advertise their commands
and tools like ``pip`` create wrapper scripts that invoke those commands.

Entry Points for Plugins
========================

Let us consider a simple example to understand how we can implement entry points
corresponding to plugins. Say we have a package ``timmins`` with the following
directory structure::

    timmins
    ├── pyproject.toml        # and/or setup.cfg, setup.py
    └── src
        └── timmins
            └── __init__.py

and in ``src/timmins/__init__.py`` we have the following code:

.. code-block:: python

   def hello_world():
       print('Hello world')

Basically, we have defined a ``hello_world()`` function which will print the text
'Hello world'. Now, let us say we want to print the text 'Hello world' in different
ways. The current function just prints the text as it is - let us say we want another
style in which the text is enclosed within exclamation marks::

    !!! Hello world !!!

Let us see how this can be done using plugins. First, let us separate the style of
printing the text from the text itself. In other words, we can change the code in
``src/timmins/__init__.py`` to something like this:

.. code-block:: python

   def display(text):
       print(text)

   def hello_world():
       display('Hello world')

Here, the ``display()`` function controls the style of printing the text, and the
``hello_world()`` function calls the ``display()`` function to print the text 'Hello
world`.

Right now the ``display()`` function just prints the text as it is. In order to be able
to customize it, we can do the following. Let us introduce a new *group* of entry points
named ``timmins.display``, and expect plugin packages implementing this entry point
to supply a ``display()``-like function. Next, to be able to automatically discover plugin
packages that implement this entry point, we can use the
:mod:`importlib.metadata` module,
as follows:

.. code-block:: python

   from importlib.metadata import entry_points
   display_eps = entry_points(group='timmins.display')

.. note::
   Each ``importlib.metadata.EntryPoint`` object is an object containing a ``name``, a
   ``group``, and a ``value``. For example, after setting up the plugin package as
   described below, ``display_eps`` in the above code will look like this: [#package_metadata]_

   .. code-block:: python

       (
           EntryPoint(name='excl', value='timmins_plugin_fancy:excl_display', group='timmins.display'),
           ...,
       )

``display_eps`` will now be a list of ``EntryPoint`` objects, each referring to ``display()``-like
functions defined by one or more installed plugin packages. Then, to import a specific
``display()``-like function - let us choose the one corresponding to the first discovered
entry point - we can use the ``load()`` method as follows:

.. code-block:: python

   display = display_eps[0].load()

Finally, a sensible behaviour would be that if we cannot find any plugin packages customizing
the ``display()`` function, we should fall back to our default implementation which prints
the text as it is. With this behaviour included, the code in ``src/timmins/__init__.py``
finally becomes:

.. code-block:: python

   from importlib.metadata import entry_points
   display_eps = entry_points(group='timmins.display')
   try:
       display = display_eps[0].load()
   except IndexError:
       def display(text):
           print(text)

   def hello_world():
       display('Hello world')

That finishes the setup on ``timmins``'s side. Next, we need to implement a plugin
which implements the entry point ``timmins.display``. Let us name this plugin
``timmins-plugin-fancy``, and set it up with the following directory structure::

    timmins-plugin-fancy
    ├── pyproject.toml        # and/or setup.cfg, setup.py
    └── src
        └── timmins_plugin_fancy
            └── __init__.py

And then, inside ``src/timmins_plugin_fancy/__init__.py``, we can put a function
named ``excl_display()`` that prints the given text surrounded by exclamation marks:

.. code-block:: python

   def excl_display(text):
       print('!!!', text, '!!!')

This is the ``display()``-like function that we are looking to supply to the
``timmins`` package. We can do that by adding the following in the configuration
of ``timmins-plugin-fancy``:

.. tab:: pyproject.toml

   .. code-block:: toml

        # Note the quotes around timmins.display in order to escape the dot .
        [project.entry-points."timmins.display"]
        excl = "timmins_plugin_fancy:excl_display"

.. tab:: setup.cfg

   .. code-block:: ini

        [options.entry_points]
        timmins.display =
            excl = timmins_plugin_fancy:excl_display

.. tab:: setup.py

   .. code-block:: python

        from setuptools import setup

        setup(
            # ...,
            entry_points = {
                'timmins.display': [
                    'excl = timmins_plugin_fancy:excl_display'
                ]
            }
        )

Basically, this configuration states that we are a supplying an entry point
under the group ``timmins.display``. The entry point is named ``excl`` and it
refers to the function ``excl_display`` defined by the package ``timmins-plugin-fancy``.

Now, if we install both ``timmins`` and ``timmins-plugin-fancy``, we should get
the following:

.. code-block:: pycon

   >>> from timmins import hello_world
   >>> hello_world()
   !!! Hello world !!!

whereas if we only install ``timmins`` and not ``timmins-plugin-fancy``, we should
get the following:

.. code-block:: pycon

   >>> from timmins import hello_world
   >>> hello_world()
   Hello world

Therefore, our plugin works.

Our plugin could have also defined multiple entry points under the group ``timmins.display``.
For example, in ``src/timmins_plugin_fancy/__init__.py`` we could have two ``display()``-like
functions, as follows:

.. code-block:: python

   def excl_display(text):
       print('!!!', text, '!!!')

   def lined_display(text):
       print(''.join(['-' for _ in text]))
       print(text)
       print(''.join(['-' for _ in text]))

The configuration of ``timmins-plugin-fancy`` would then change to:

.. tab:: pyproject.toml

   .. code-block:: toml

        [project.entry-points."timmins.display"]
        excl = "timmins_plugin_fancy:excl_display"
        lined = "timmins_plugin_fancy:lined_display"

.. tab:: setup.cfg

   .. code-block:: ini

        [options.entry_points]
        timmins.display =
            excl = timmins_plugin_fancy:excl_display
            lined = timmins_plugin_fancy:lined_display

.. tab:: setup.py

   .. code-block:: python

        from setuptools import setup

        setup(
            # ...,
            entry_points = {
                'timmins.display': [
                    'excl = timmins_plugin_fancy:excl_display',
                    'lined = timmins_plugin_fancy:lined_display',
                ]
            }
        )

On the ``timmins`` side, we can also use a different strategy of loading entry
points. For example, we can search for a specific display style:

.. code-block:: python

   display_eps = entry_points(group='timmins.display')
   try:
       display = display_eps['lined'].load()
   except KeyError:
       # if the 'lined' display is not available, use something else
       ...

Or we can also load all plugins under the given group. Though this might not
be of much use in our current example, there are several scenarios in which this
is useful:

.. code-block:: python

   display_eps = entry_points(group='timmins.display')
   for ep in display_eps:
       display = ep.load()
       # do something with display
       ...

Another point is that in this particular example, we have used plugins to
customize the behaviour of a function (``display()``). In general, we can use entry
points to enable plugins to not only customize the behaviour of functions, but also
of entire classes and modules. This is unlike the case of console/GUI scripts,
where entry points can only refer to functions. The syntax used for specifying the
entry points remains the same as for console/GUI scripts, and is discussed in the
`last section <#entry-points-syntax>`_.

.. tip::
    The recommended approach for loading and importing entry points is the
    :mod:`importlib.metadata` module,
    which is a part of the standard library since Python 3.8. For older versions of
    Python, its backport :pypi:`importlib_metadata` should be used. While using the
    backport, the only change that has to be made is to replace ``importlib.metadata``
    with ``importlib_metadata``, i.e.

    .. code-block:: python

       from importlib_metadata import entry_points
       ...

In summary, entry points allow a package to open its functionalities for
customization via plugins.
The package soliciting the entry points need not have any dependency
or prior knowledge about the plugins implementing the entry points, and
downstream users are able to compose functionality by pulling together
plugins implementing the entry points.

Entry Points Syntax
===================

The syntax for entry points is specified as follows::

    <name> = <package_or_module>[:<object>[.<attr>[.<nested-attr>]*]]

Here, the square brackets ``[]`` denote optionality and the asterisk ``*``
denotes repetition.
``name`` is the name of the script/entry point you want to create, the left hand
side of ``:`` is the package or module that contains the object you want to invoke
(think about it as something you would write in an import statement), and the right
hand side is the object you want to invoke (e.g. a function).

To make this syntax more clear, consider the following examples:

Package or module
    If you supply::

       <name> = <package_or_module>

    as the entry point, where ``<package_or_module>`` can contain ``.`` in the case
    of sub-modules or sub-packages, then, tools in the Python ecosystem will roughly
    interpret this value as:

    .. code-block:: python

        import <package_or_module>
        parsed_value = <package_or_module>

Module-level object
   If you supply::

        <name> = <package_or_module>:<object>

   where ``<object>`` does not contain any ``.``, this will be roughly interpreted
   as:

   .. code-block:: python

       from <package_or_module> import <object>
       parsed_value = <object>

Nested object
   If you supply::

        <name> = <package_or_module>:<object>.<attr>.<nested_attr>

   this will be roughly interpreted as:

   .. code-block:: python

       from <package_or_module> import <object>
       parsed_value = <object>.<attr>.<nested_attr>

In the case of console/GUI scripts, this syntax can be used to specify a function, while
in the general case of entry points as used for plugins, it can be used to specify a function,
class or module.

----

.. [#use_for_scripts]
   Reference: https://packaging.python.org/en/latest/specifications/entry-points/#use-for-scripts

.. [#package_metadata]
   Reference: https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/#using-package-metadata
alt-python312-setuptools/docs/userguide/extension.rst000064400000031762150410147340017012 0ustar00.. _Creating ``distutils`` Extensions:

Extending or Customizing Setuptools
===================================

Setuptools design is based on the distutils_ package originally distributed
as part of Python's standard library, effectively serving as its successor
(as established in :pep:`632`).

This means that ``setuptools`` strives to honor the extension mechanisms
provided by ``distutils``, and allows developers to create third party packages
that modify or augment the build process behavior.

A simple way of doing that is to hook in new or existing
commands and ``setup()`` arguments just by defining "entry points".  These
are mappings from command or argument names to a specification of where to
import a handler from.  (See the section on :ref:`Dynamic Discovery of
Services and Plugins` for some more background on entry points).

The following sections describe the most common procedures for extending
the ``distutils`` functionality used by ``setuptools``.

.. important::
   Any entry-point defined in your ``setup.cfg``, ``setup.py`` or
   ``pyproject.toml`` files are not immediately available for use.  Your
   package needs to be installed first, then ``setuptools`` will be able to
   access these entry points.  For example consider a ``Project-A`` that
   defines entry points. When building ``Project-A``, these will not be
   available.  If ``Project-B`` declares a :doc:`build system requirement
   </userguide/dependency_management>` on ``Project-A``, then ``setuptools``
   will be able to use ``Project-A``' customizations.

Customizing Commands
--------------------

Both ``setuptools`` and ``distutils`` are structured around the *command design
pattern*. This means that each main action executed when building a
distribution package (such as creating a :term:`sdist <Source Distribution (or "sdist")>`
or :term:`wheel`) correspond to the implementation of a Python class.

Originally in ``distutils``, these commands would correspond to actual CLI
arguments that could be passed to the ``setup.py`` script to trigger a
different aspect of the build. In ``setuptools``, however, these command
objects are just a design abstraction that encapsulate logic and help to
organise the code.

You can overwrite existing commands (or add new ones) by defining entry
points in the ``distutils.commands`` group.  For example, if you wanted to add
a ``foo`` command, you might add something like this to your project:

.. code-block:: ini

    # setup.cfg
    ...
    [options.entry_points]
    distutils.commands =
         foo = mypackage.some_module:foo

Assuming, of course, that the ``foo`` class in ``mypackage.some_module`` is
a ``setuptools.Command`` subclass (documented below).

Once a project containing such entry points has been activated on ``sys.path``,
(e.g. by running ``pip install``) the command(s) will be available to any
``setuptools``-based project. In fact, this is
how setuptools' own commands are installed: the setuptools project's setup
script defines entry points for them!

The commands ``sdist``, ``build_py`` and ``build_ext`` are especially useful
to customize ``setuptools`` builds. Note however that when overwriting existing
commands, you should be very careful to maintain API compatibility.
Custom commands should try to replicate the same overall behavior as the
original classes, and when possible, even inherit from them.

You should also consider handling exceptions such as ``CompileError``,
``LinkError``, ``LibError``, among others. These exceptions are available in
the ``setuptools.errors`` module.

.. autoclass:: setuptools.Command
   :members:


Supporting sdists and editable installs in ``build`` sub-commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``build`` sub-commands (like ``build_py`` and ``build_ext``)
are encouraged to implement the following protocol:

.. autoclass:: setuptools.command.build.SubCommand
   :members:


Adding Arguments
----------------

.. warning:: Adding arguments to setup is discouraged as such arguments
   are only supported through imperative execution and not supported through
   declarative config.

Sometimes, your commands may need additional arguments to the ``setup()``
call.  You can enable this by defining entry points in the
``distutils.setup_keywords`` group.  For example, if you wanted a ``setup()``
argument called ``bar_baz``, you might add something like this to your
extension project:

.. code-block:: ini

    # setup.cfg
    ...
    [options.entry_points]
    distutils.commands =
         foo = mypackage.some_module:foo
    distutils.setup_keywords =
        bar_baz = mypackage.some_module:validate_bar_baz

The idea here is that the entry point defines a function that will be called
to validate the ``setup()`` argument, if it's supplied.  The ``Distribution``
object will have the initial value of the attribute set to ``None``, and the
validation function will only be called if the ``setup()`` call sets it to
a non-``None`` value.  Here's an example validation function::

    def assert_bool(dist, attr, value):
        """Verify that value is True, False, 0, or 1"""
        if bool(value) != value:
            raise SetupError(
                "%r must be a boolean value (got %r)" % (attr,value)
            )

Your function should accept three arguments: the ``Distribution`` object,
the attribute name, and the attribute value.  It should raise a
``SetupError`` (from the ``setuptools.errors`` module) if the argument
is invalid.  Remember, your function will only be called with non-``None`` values,
and the default value of arguments defined this way is always ``None``.  So, your
commands should always be prepared for the possibility that the attribute will
be ``None`` when they access it later.

If more than one active distribution defines an entry point for the same
``setup()`` argument, *all* of them will be called.  This allows multiple
extensions to define a common argument, as long as they agree on
what values of that argument are valid.


Customizing Distribution Options
--------------------------------

Plugins may wish to extend or alter the options on a ``Distribution`` object to
suit the purposes of that project. For example, a tool that infers the
``Distribution.version`` from SCM-metadata may need to hook into the
option finalization. To enable this feature, Setuptools offers an entry
point ``setuptools.finalize_distribution_options``. That entry point must
be a callable taking one argument (the ``Distribution`` instance).

If the callable has an ``.order`` property, that value will be used to
determine the order in which the hook is called. Lower numbers are called
first and the default is zero (0).

Plugins may read, alter, and set properties on the distribution, but each
plugin is encouraged to load the configuration/settings for their behavior
independently.


Defining Additional Metadata
----------------------------

Some extensible applications and frameworks may need to define their own kinds
of metadata, which they can then access using the :mod:`importlib.metadata` APIs.
Ordinarily, this is done by having plugin
developers include additional files in their ``ProjectName.egg-info``
directory.  However, since it can be tedious to create such files by hand, you
may want to create an extension that will create the necessary files
from arguments to ``setup()``, in much the same way that ``setuptools`` does
for many of the ``setup()`` arguments it adds.  See the section below for more
details.


.. _Adding new EGG-INFO Files:

Adding new EGG-INFO Files
~~~~~~~~~~~~~~~~~~~~~~~~~

Some extensible applications or frameworks may want to allow third parties to
develop plugins with application or framework-specific metadata included in
the plugins' EGG-INFO directory, for easy access via the ``pkg_resources``
metadata API.  The easiest way to allow this is to create an extension
to be used from the plugin projects' setup scripts (via ``setup_requires``)
that defines a new setup keyword, and then uses that data to write an EGG-INFO
file when the ``egg_info`` command is run.

The ``egg_info`` command looks for extension points in an ``egg_info.writers``
group, and calls them to write the files.  Here's a simple example of an
extension defining a setup argument ``foo_bar``, which is a list of
lines that will be written to ``foo_bar.txt`` in the EGG-INFO directory of any
project that uses the argument:

.. code-block:: ini

    # setup.cfg
    ...
    [options.entry_points]
    distutils.setup_keywords =
        foo_bar = setuptools.dist:assert_string_list
    egg_info.writers =
        foo_bar.txt = setuptools.command.egg_info:write_arg

This simple example makes use of two utility functions defined by setuptools
for its own use: a routine to validate that a setup keyword is a sequence of
strings, and another one that looks up a setup argument and writes it to
a file.  Here's what the writer utility looks like::

    def write_arg(cmd, basename, filename):
        argname = os.path.splitext(basename)[0]
        value = getattr(cmd.distribution, argname, None)
        if value is not None:
            value = "\n".join(value) + "\n"
        cmd.write_or_delete_file(argname, filename, value)

As you can see, ``egg_info.writers`` entry points must be a function taking
three arguments: a ``egg_info`` command instance, the basename of the file to
write (e.g. ``foo_bar.txt``), and the actual full filename that should be
written to.

In general, writer functions should honor the command object's ``dry_run``
setting when writing files, and use ``logging`` to do any console output.
The easiest way to conform to this requirement is to use
the ``cmd`` object's ``write_file()``, ``delete_file()``, and
``write_or_delete_file()`` methods exclusively for your file operations.
See those methods' docstrings for more details.


.. _Adding Support for Revision Control Systems:

Adding Support for Revision Control Systems
-------------------------------------------------

If the files you want to include in the source distribution are tracked using
Git, Mercurial or SVN, you can use the following packages to achieve that:

- Git and Mercurial: :pypi:`setuptools_scm`
- SVN: :pypi:`setuptools_svn`

If you would like to create a plugin for ``setuptools`` to find files tracked
by another revision control system, you can do so by adding an entry point to
the ``setuptools.file_finders`` group.  The entry point should be a function
accepting a single directory name, and should yield all the filenames within
that directory (and any subdirectories thereof) that are under revision
control.

For example, if you were going to create a plugin for a revision control system
called "foobar", you would write a function something like this:

.. code-block:: python

    def find_files_for_foobar(dirname):
        ...  # loop to yield paths that start with `dirname`

And you would register it in a setup script using something like this:

.. code-block:: ini

    # setup.cfg
    ...

    [options.entry_points]
    setuptools.file_finders =
        foobar = my_foobar_module:find_files_for_foobar

Then, anyone who wants to use your plugin can simply install it, and their
local setuptools installation will be able to find the necessary files.

It is not necessary to distribute source control plugins with projects that
simply use the other source control system, or to specify the plugins in
``setup_requires``.  When you create a source distribution with the ``sdist``
command, setuptools automatically records what files were found in the
``SOURCES.txt`` file.  That way, recipients of source distributions don't need
to have revision control at all.  However, if someone is working on a package
by checking out with that system, they will need the same plugin(s) that the
original author is using.

A few important points for writing revision control file finders:

* Your finder function MUST return relative paths, created by appending to the
  passed-in directory name.  Absolute paths are NOT allowed, nor are relative
  paths that reference a parent directory of the passed-in directory.

* Your finder function MUST accept an empty string as the directory name,
  meaning the current directory.  You MUST NOT convert this to a dot; just
  yield relative paths.  So, yielding a subdirectory named ``some/dir`` under
  the current directory should NOT be rendered as ``./some/dir`` or
  ``/somewhere/some/dir``, but *always* as simply ``some/dir``

* Your finder function SHOULD NOT raise any errors, and SHOULD deal gracefully
  with the absence of needed programs (i.e., ones belonging to the revision
  control system itself.  It *may*, however, use ``logging.warning()`` to
  inform the user of the missing program(s).


.. _distutils: https://docs.python.org/3.9/library/distutils.html


Final Remarks
-------------

* To use a ``setuptools`` plugin, your users will need to add your package as a
  build requirement to their build-system configuration. Please check out our
  guides on :doc:`/userguide/dependency_management` for more information.

* Directly calling ``python setup.py ...`` is considered a **deprecated** practice.
  You should not add new commands to ``setuptools`` expecting them to be run
  via this interface.
alt-python312-setuptools/docs/userguide/package_discovery.rst000064400000043563150410147340020462 0ustar00.. _`package_discovery`:

========================================
Package Discovery and Namespace Packages
========================================

.. note::
    a full specification for the keywords supplied to ``setup.cfg`` or
    ``setup.py`` can be found at :doc:`keywords reference </references/keywords>`

.. important::
    The examples provided here are only to demonstrate the functionality
    introduced. More metadata and options arguments need to be supplied
    if you want to replicate them on your system. If you are completely
    new to setuptools, the :doc:`quickstart` section is a good place to start.

``Setuptools`` provides powerful tools to handle package discovery, including
support for namespace packages.

Normally, you would specify the packages to be included manually in the following manner:

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        #...
        packages =
            mypkg
            mypkg.subpkg1
            mypkg.subpkg2

.. tab:: setup.py

    .. code-block:: python

        setup(
            # ...
            packages=['mypkg', 'mypkg.subpkg1', 'mypkg.subpkg2']
        )

.. tab:: pyproject.toml

    .. code-block:: toml

        # ...
        [tool.setuptools]
        packages = ["mypkg", "mypkg.subpkg1", "mypkg.subpkg2"]
        # ...


If your packages are not in the root of the repository or do not correspond
exactly to the directory structure, you also need to configure ``package_dir``:

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        # ...
        package_dir =
            = src
            # directory containing all the packages (e.g.  src/mypkg, src/mypkg/subpkg1, ...)
        # OR
        package_dir =
            mypkg = lib
            # mypkg.module corresponds to lib/module.py
            mypkg.subpkg1 = lib1
            # mypkg.subpkg1.module1 corresponds to lib1/module1.py
            mypkg.subpkg2 = lib2
            # mypkg.subpkg2.module2 corresponds to lib2/module2.py
        # ...

.. tab:: setup.py

    .. code-block:: python

        setup(
            # ...
            package_dir = {"": "src"}
            # directory containing all the packages (e.g.  src/mypkg, src/mypkg/subpkg1, ...)
        )

        # OR

        setup(
            # ...
            package_dir = {
                "mypkg": "lib",  # mypkg.module corresponds to lib/module.py
                "mypkg.subpkg1": "lib1",  # mypkg.subpkg1.module1 corresponds to lib1/module1.py
                "mypkg.subpkg2": "lib2"   # mypkg.subpkg2.module2 corresponds to lib2/module2.py
                # ...
        )

.. tab:: pyproject.toml

    .. code-block:: toml

        [tool.setuptools]
        # ...
        package-dir = {"" = "src"}
            # directory containing all the packages (e.g.  src/mypkg1, src/mypkg2)

        # OR

        [tool.setuptools.package-dir]
        mypkg = "lib"
        # mypkg.module corresponds to lib/module.py
        "mypkg.subpkg1" = "lib1"
        # mypkg.subpkg1.module1 corresponds to lib1/module1.py
        "mypkg.subpkg2" = "lib2"
        # mypkg.subpkg2.module2 corresponds to lib2/module2.py
        # ...

This can get tiresome really quickly. To speed things up, you can rely on
setuptools automatic discovery, or use the provided tools, as explained in
the following sections.

.. important::
   Although ``setuptools`` allows developers to create a very complex mapping
   between directory names and package names, it is better to *keep it simple*
   and reflect the desired package hierarchy in the directory structure,
   preserving the same names.

.. _auto-discovery:

Automatic discovery
===================

By default ``setuptools`` will consider 2 popular project layouts, each one with
its own set of advantages and disadvantages [#layout1]_ [#layout2]_ as
discussed in the following sections.

Setuptools will automatically scan your project directory looking for these
layouts and try to guess the correct values for the :ref:`packages <declarative
config>` and :doc:`py_modules </references/keywords>` configuration.

.. important::
   Automatic discovery will **only** be enabled if you **don't** provide any
   configuration for ``packages`` and ``py_modules``.
   If at least one of them is explicitly set, automatic discovery will not take place.

   **Note**: specifying ``ext_modules`` might also prevent auto-discover from
   taking place, unless your opt into :doc:`pyproject_config` (which will
   disable the backward compatible behaviour).

.. _src-layout:

src-layout
----------
The project should contain a ``src`` directory under the project root and
all modules and packages meant for distribution are placed inside this
directory::

    project_root_directory
    ├── pyproject.toml  # AND/OR setup.cfg, setup.py
    ├── ...
    └── src/
        └── mypkg/
            ├── __init__.py
            ├── ...
            ├── module.py
            ├── subpkg1/
            │   ├── __init__.py
            │   ├── ...
            │   └── module1.py
            └── subpkg2/
                ├── __init__.py
                ├── ...
                └── module2.py

This layout is very handy when you wish to use automatic discovery,
since you don't have to worry about other Python files or folders in your
project root being distributed by mistake. In some circumstances it can be
also less error-prone for testing or when using :pep:`420`-style packages.
On the other hand you cannot rely on the implicit ``PYTHONPATH=.`` to fire
up the Python REPL and play with your package (you will need an
`editable install`_ to be able to do that).

.. _flat-layout:

flat-layout
-----------
*(also known as "adhoc")*

The package folder(s) are placed directly under the project root::

    project_root_directory
    ├── pyproject.toml  # AND/OR setup.cfg, setup.py
    ├── ...
    └── mypkg/
        ├── __init__.py
        ├── ...
        ├── module.py
        ├── subpkg1/
        │   ├── __init__.py
        │   ├── ...
        │   └── module1.py
        └── subpkg2/
            ├── __init__.py
            ├── ...
            └── module2.py

This layout is very practical for using the REPL, but in some situations
it can be more error-prone (e.g. during tests or if you have a bunch
of folders or Python files hanging around your project root).

To avoid confusion, file and folder names that are used by popular tools (or
that correspond to well-known conventions, such as distributing documentation
alongside the project code) are automatically filtered out in the case of
*flat-layout*:

.. autoattribute:: setuptools.discovery.FlatLayoutPackageFinder.DEFAULT_EXCLUDE

.. autoattribute:: setuptools.discovery.FlatLayoutModuleFinder.DEFAULT_EXCLUDE

.. warning::
   If you are using auto-discovery with *flat-layout*, ``setuptools`` will
   refuse to create :term:`distribution archives <Distribution Package>` with
   multiple top-level packages or modules.

   This is done to prevent common errors such as accidentally publishing code
   not meant for distribution (e.g. maintenance-related scripts).

   Users that purposefully want to create multi-package distributions are
   advised to use :ref:`custom-discovery` or the ``src-layout``.

There is also a handy variation of the *flat-layout* for utilities/libraries
that can be implemented with a single Python file:

single-module distribution
^^^^^^^^^^^^^^^^^^^^^^^^^^

A standalone module is placed directly under the project root, instead of
inside a package folder::

    project_root_directory
    ├── pyproject.toml  # AND/OR setup.cfg, setup.py
    ├── ...
    └── single_file_lib.py


.. _custom-discovery:

Custom discovery
================

If the automatic discovery does not work for you
(e.g., you want to *include* in the distribution top-level packages with
reserved names such as ``tasks``, ``example`` or ``docs``, or you want to
*exclude* nested packages that would be otherwise included), you can use
the provided tools for package discovery:

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        packages = find:
        #or
        packages = find_namespace:

.. tab:: setup.py

    .. code-block:: python

        from setuptools import find_packages
        # or
        from setuptools import find_namespace_packages

.. tab:: pyproject.toml

    .. code-block:: toml

        # ...
        [tool.setuptools.packages]
        find = {}  # Scanning implicit namespaces is active by default
        # OR
        find = {namespaces = false}  # Disable implicit namespaces


Finding simple packages
-----------------------
Let's start with the first tool. ``find:`` (``find_packages()``) takes a source
directory and two lists of package name patterns to exclude and include, and
then returns a list of ``str`` representing the packages it could find. To use
it, consider the following directory::

    mypkg
    ├── pyproject.toml  # AND/OR setup.cfg, setup.py
    └── src
        ├── pkg1
        │   └── __init__.py
        ├── pkg2
        │   └── __init__.py
        ├── additional
        │   └── __init__.py
        └── pkg
            └── namespace
                └── __init__.py

To have setuptools to automatically include packages found
in ``src`` that start with the name ``pkg`` and not ``additional``:

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        packages = find:
        package_dir =
            =src

        [options.packages.find]
        where = src
        include = pkg*
        # alternatively: `exclude = additional*`

    .. note::
        ``pkg`` does not contain an ``__init__.py`` file, therefore
        ``pkg.namespace`` is ignored by ``find:`` (see ``find_namespace:`` below).

.. tab:: setup.py

    .. code-block:: python

        setup(
            # ...
            packages=find_packages(
                where='src',
                include=['pkg*'],  # alternatively: `exclude=['additional*']`
            ),
            package_dir={"": "src"}
            # ...
        )


    .. note::
        ``pkg`` does not contain an ``__init__.py`` file, therefore
        ``pkg.namespace`` is ignored by ``find_packages()``
        (see ``find_namespace_packages()`` below).

.. tab:: pyproject.toml

    .. code-block:: toml

        [tool.setuptools.packages.find]
        where = ["src"]
        include = ["pkg*"]  # alternatively: `exclude = ["additional*"]`
        namespaces = false

    .. note::
        When using ``tool.setuptools.packages.find`` in ``pyproject.toml``,
        setuptools will consider :pep:`implicit namespaces <420>` by default when
        scanning your project directory.
        To avoid ``pkg.namespace`` from being added to your package list
        you can set ``namespaces = false``. This will prevent any folder
        without an ``__init__.py`` file from being scanned.

.. important::
   ``include`` and ``exclude`` accept strings representing :mod:`glob` patterns.
   These patterns should match the **full** name of the Python module (as if it
   was written in an ``import`` statement).

   For example if you have ``util`` pattern, it will match
   ``util/__init__.py`` but not ``util/files/__init__.py``.

   The fact that the parent package is matched by the pattern will not dictate
   if the submodule will be included or excluded from the distribution.
   You will need to explicitly add a wildcard (e.g. ``util*``)
   if you want the pattern to also match submodules.

.. _Namespace Packages:

Finding namespace packages
--------------------------
``setuptools``  provides ``find_namespace:`` (``find_namespace_packages()``)
which behaves similarly to ``find:`` but works with namespace packages.

Before diving in, it is important to have a good understanding of what
:pep:`namespace packages <420>` are. Here is a quick recap.

When you have two packages organized as follows:

.. code-block:: bash

    /Users/Desktop/timmins/foo/__init__.py
    /Library/timmins/bar/__init__.py

If both ``Desktop`` and ``Library`` are on your ``PYTHONPATH``, then a
namespace package called ``timmins`` will be created automatically for you when
you invoke the import mechanism, allowing you to accomplish the following:

.. code-block:: pycon

    >>> import timmins.foo
    >>> import timmins.bar

as if there is only one ``timmins`` on your system. The two packages can then
be distributed separately and installed individually without affecting the
other one.

Now, suppose you decide to package the ``foo`` part for distribution and start
by creating a project directory organized as follows::

   foo
   ├── pyproject.toml  # AND/OR setup.cfg, setup.py
   └── src
       └── timmins
           └── foo
               └── __init__.py

If you want the ``timmins.foo`` to be automatically included in the
distribution, then you will need to specify:

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        package_dir =
            =src
        packages = find_namespace:

        [options.packages.find]
        where = src

    ``find:`` won't work because ``timmins`` doesn't contain ``__init__.py``
    directly, instead, you have to use ``find_namespace:``.

    You can think of ``find_namespace:`` as identical to ``find:`` except it
    would count a directory as a package even if it doesn't contain ``__init__.py``
    file directly.

.. tab:: setup.py

    .. code-block:: python

        setup(
            # ...
            packages=find_namespace_packages(where='src'),
            package_dir={"": "src"}
            # ...
        )

    When you use ``find_packages()``, all directories without an
    ``__init__.py`` file will be ignored.
    On the other hand, ``find_namespace_packages()`` will scan all
    directories.

.. tab:: pyproject.toml

    .. code-block:: toml

        [tool.setuptools.packages.find]
        where = ["src"]

    When using ``tool.setuptools.packages.find`` in ``pyproject.toml``,
    setuptools will consider :pep:`implicit namespaces <420>` by default when
    scanning your project directory.

After installing the package distribution, ``timmins.foo`` would become
available to your interpreter.

.. warning::
   Please have in mind that ``find_namespace:`` (setup.cfg),
   ``find_namespace_packages()`` (setup.py) and ``find`` (pyproject.toml) will
   scan **all** folders that you have in your project directory if you use a
   :ref:`flat-layout`.

   If used naïvely, this might result in unwanted files being added to your
   final wheel. For example, with a project directory organized as follows::

       foo
       ├── docs
       │   └── conf.py
       ├── timmins
       │   └── foo
       │       └── __init__.py
       └── tests
           └── tests_foo
               └── __init__.py

   final users will end up installing not only ``timmins.foo``, but also
   ``docs`` and ``tests.tests_foo``.

   A simple way to fix this is to adopt the aforementioned :ref:`src-layout`,
   or make sure to properly configure the ``include`` and/or ``exclude``
   accordingly.

.. tip::
   After :ref:`building your package <building>`, you can have a look if all
   the files are correct (nothing missing or extra), by running the following
   commands:

   .. code-block:: bash

      tar tf dist/*.tar.gz
      unzip -l dist/*.whl

   This requires the ``tar`` and ``unzip`` to be installed in your OS.
   On Windows you can also use a GUI program such as 7zip_.


Legacy Namespace Packages
=========================
The fact you can create namespace packages so effortlessly above is credited
to :pep:`420`. It used to be more
cumbersome to accomplish the same result. Historically, there were two methods
to create namespace packages. One is the ``pkg_resources`` style supported by
``setuptools`` and the other one being ``pkgutils`` style offered by
``pkgutils`` module in Python. Both are now considered *deprecated* despite the
fact they still linger in many existing packages. These two differ in many
subtle yet significant aspects and you can find out more on `Python packaging
user guide <https://packaging.python.org/guides/packaging-namespace-packages/>`_.


``pkg_resource`` style namespace package
----------------------------------------
This is the method ``setuptools`` directly supports. Starting with the same
layout, there are two pieces you need to add to it. First, an ``__init__.py``
file directly under your namespace package directory that contains the
following:

.. code-block:: python

    __import__("pkg_resources").declare_namespace(__name__)

And the ``namespace_packages`` keyword in your ``setup.cfg`` or ``setup.py``:

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        namespace_packages = timmins

.. tab:: setup.py

    .. code-block:: python

        setup(
            # ...
            namespace_packages=['timmins']
        )

And your directory should look like this

.. code-block:: bash

   foo
   ├── pyproject.toml  # AND/OR setup.cfg, setup.py
   └── src
       └── timmins
           ├── __init__.py
           └── foo
               └── __init__.py

Repeat the same for other packages and you can achieve the same result as
the previous section.

``pkgutil`` style namespace package
-----------------------------------
This method is almost identical to the ``pkg_resource`` except that the
``namespace_packages`` declaration is omitted and the ``__init__.py``
file contains the following:

.. code-block:: python

    __path__ = __import__('pkgutil').extend_path(__path__, __name__)

The project layout remains the same and ``pyproject.toml/setup.cfg`` remains the same.


----


.. [#layout1] https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-structure
.. [#layout2] https://blog.ionelmc.ro/2017/09/25/rehashing-the-src-layout/

.. _editable install: https://pip.pypa.io/en/stable/cli/pip_install/#editable-installs
.. _7zip: https://www.7-zip.org
alt-python312-setuptools/docs/userguide/quickstart.rst000064400000037560150410147340017172 0ustar00==========
Quickstart
==========

Installation
============

You can install the latest version of ``setuptools`` using :pypi:`pip`::

    pip install --upgrade setuptools

Most of the times, however, you don't have to...

Instead, when creating new Python packages, it is recommended to use
a command line tool called :pypi:`build`. This tool will automatically download
``setuptools`` and any other build-time dependencies that your project might
have. You just need to specify them in a ``pyproject.toml`` file at the root of
your package, as indicated in the :ref:`following section <basic-use>`.

.. _install-build:

You can also :doc:`install build <build:installation>` using :pypi:`pip`::

    pip install --upgrade build

This will allow you to run the command: ``python -m build``.

.. important::
   Please note that some operating systems might be equipped with
   the ``python3`` and ``pip3`` commands instead of ``python`` and ``pip``
   (but they should be equivalent).
   If you don't have ``pip`` or ``pip3`` available in your system, please
   check out :doc:`pip installation docs <pip:installation>`.


Every python package must provide a ``pyproject.toml`` and specify
the backend (build system) it wants to use. The distribution can then
be generated with whatever tool that provides a ``build sdist``-like
functionality.


.. _basic-use:

Basic Use
=========

When creating a Python package, you must provide a ``pyproject.toml`` file
containing a ``build-system`` section similar to the example below:

.. code-block:: toml

    [build-system]
    requires = ["setuptools"]
    build-backend = "setuptools.build_meta"

This section declares what are your build system dependencies, and which
library will be used to actually do the packaging.

.. note::

   Historically this documentation has unnecessarily listed ``wheel``
   in the ``requires`` list, and many projects still do that. This is
   not recommended. The backend automatically adds ``wheel`` dependency
   when it is required, and listing it explicitly causes it to be
   unnecessarily required for source distribution builds.
   You should only include ``wheel`` in ``requires`` if you need to explicitly
   access it during build time (e.g. if your project needs a ``setup.py``
   script that imports ``wheel``).

In addition to specifying a build system, you also will need to add
some package information such as metadata, contents, dependencies, etc.
This can be done in the same ``pyproject.toml`` file,
or in a separated one: ``setup.cfg`` or ``setup.py`` [#setup.py]_.

The following example demonstrates a minimum configuration
(which assumes the project depends on :pypi:`requests` and
:pypi:`importlib-metadata` to be able to run):

.. tab:: pyproject.toml

    .. code-block:: toml

       [project]
       name = "mypackage"
       version = "0.0.1"
       dependencies = [
           "requests",
           'importlib-metadata; python_version<"3.8"',
       ]

    See :doc:`/userguide/pyproject_config` for more information.

.. tab:: setup.cfg

    .. code-block:: ini

        [metadata]
        name = mypackage
        version = 0.0.1

        [options]
        install_requires =
            requests
            importlib-metadata; python_version < "3.8"

    See :doc:`/userguide/declarative_config` for more information.

.. tab:: setup.py [#setup.py]_

    .. code-block:: python

        from setuptools import setup

        setup(
            name='mypackage',
            version='0.0.1',
            install_requires=[
                'requests',
                'importlib-metadata; python_version == "3.8"',
            ],
        )

    See :doc:`/references/keywords` for more information.

Finally, you will need to organize your Python code to make it ready for
distributing into something that looks like the following
(optional files marked with ``#``)::

    mypackage
    ├── pyproject.toml  # and/or setup.cfg/setup.py (depending on the configuration method)
    |   # README.rst or README.md (a nice description of your package)
    |   # LICENCE (properly chosen license information, e.g. MIT, BSD-3, GPL-3, MPL-2, etc...)
    └── mypackage
        ├── __init__.py
        └── ... (other Python files)

With :ref:`build installed in your system <install-build>`, you can then run::

    python -m build

You now have your distribution ready (e.g. a ``tar.gz`` file and a ``.whl`` file
in the ``dist`` directory), which you can :doc:`upload <twine:index>` to PyPI_!

Of course, before you release your project to PyPI_, you'll want to add a bit
more information to help people find or learn about your project.
And maybe your project will have grown by then to include a few
dependencies, and perhaps some data files and scripts. In the next few sections,
we will walk through the additional but essential information you need
to specify to properly package your project.


..
   TODO: A previous generation of this document included a section called
   "Python packaging at a glance". This is a nice title, but the content
   removed because it assumed the reader had familiarity with the history of
   setuptools and PEP 517. We should take advantage of this nice title and add
   this section back, but use it to explain important concepts of the
   ecosystem, such as "sdist", "wheel", "index". It would also be nice if we
   could have a diagram for that (explaining for example that "wheels" are
   built from "sdists" not the source tree).

.. _setuppy_discouraged:
.. admonition:: Info: Using ``setup.py``
  :class: seealso

  Setuptools offers first class support for ``setup.py`` files as a configuration
  mechanism.

  It is important to remember, however, that running this file as a
  script (e.g. ``python setup.py sdist``) is strongly **discouraged**, and
  that the majority of the command line interfaces are (or will be) **deprecated**
  (e.g. ``python setup.py install``, ``python setup.py bdist_wininst``, ...).

  We also recommend users to expose as much as possible configuration in a
  more *declarative* way via the :doc:`pyproject.toml <pyproject_config>` or
  :doc:`setup.cfg <declarative_config>`, and keep the ``setup.py`` minimal
  with only the dynamic parts (or even omit it completely if applicable).

  See `Why you shouldn't invoke setup.py directly`_ for more background.

.. _Why you shouldn't invoke setup.py directly: https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html


Overview
========

Package discovery
-----------------
For projects that follow a simple directory structure, ``setuptools`` should be
able to automatically detect all :term:`packages <package>` and
:term:`namespaces <namespace>`. However, complex projects might include
additional folders and supporting files that not necessarily should be
distributed (or that can confuse ``setuptools`` auto discovery algorithm).

Therefore, ``setuptools`` provides a convenient way to customize
which packages should be distributed and in which directory they should be
found, as shown in the example below:

.. tab:: pyproject.toml

    .. code-block:: toml

        # ...
        [tool.setuptools.packages]
        find = {}  # Scan the project directory with the default parameters

        # OR
        [tool.setuptools.packages.find]
        # All the following settings are optional:
        where = ["src"]  # ["."] by default
        include = ["mypackage*"]  # ["*"] by default
        exclude = ["mypackage.tests*"]  # empty by default
        namespaces = false  # true by default

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        packages = find: # OR `find_namespace:` if you want to use namespaces

        [options.packages.find]  # (always `find` even if `find_namespace:` was used before)
        # This section is optional as well as each of the following options:
        where=src  # . by default
        include=mypackage*  # * by default
        exclude=mypackage.tests*  # empty by default

.. tab:: setup.py [#setup.py]_

    .. code-block:: python

        from setuptools import setup, find_packages  # or find_namespace_packages

        setup(
            # ...
            packages=find_packages(
                # All keyword arguments below are optional:
                where='src',  # '.' by default
                include=['mypackage*'],  # ['*'] by default
                exclude=['mypackage.tests'],  # empty by default
            ),
            # ...
        )

When you pass the above information, alongside other necessary information,
``setuptools`` walks through the directory specified in ``where`` (defaults to ``.``) and filters the packages
it can find following the ``include`` patterns (defaults to ``*``), then it removes
those that match the ``exclude`` patterns (defaults to empty) and returns a list of Python packages.

For more details and advanced use, go to :ref:`package_discovery`.

.. tip::
   Starting with version 61.0.0, setuptools' automatic discovery capabilities
   have been improved to detect popular project layouts (such as the
   :ref:`flat-layout` and :ref:`src-layout`) without requiring any
   special configuration. Check out our :ref:`reference docs <package_discovery>`
   for more information.


Entry points and automatic script creation
-------------------------------------------
Setuptools supports automatic creation of scripts upon installation, that run
code within your package if you specify them as :doc:`entry points
<PyPUG:specifications/entry-points>`.
An example of how this feature can be used in ``pip``:
it allows you to run commands like ``pip install`` instead of having
to type ``python -m pip install``.

The following configuration examples show how to accomplish this:


.. tab:: pyproject.toml

    .. code-block:: toml

       [project.scripts]
       cli-name = "mypkg.mymodule:some_func"

.. tab:: setup.cfg

    .. code-block:: ini

        [options.entry_points]
        console_scripts =
            cli-name = mypkg.mymodule:some_func

.. tab:: setup.py [#setup.py]_

    .. code-block:: python

        setup(
            # ...
            entry_points={
                'console_scripts': [
                    'cli-name = mypkg.mymodule:some_func',
                ]
            }
        )

When this project is installed, a ``cli-name`` executable will be created.
``cli-name`` will invoke the function ``some_func`` in the
``mypkg/mymodule.py`` file when called by the user.
Note that you can also use the ``entry-points`` mechanism to advertise
components between installed packages and implement plugin systems.
For detailed usage, go to :doc:`entry_point`.


Dependency management
---------------------
Packages built with ``setuptools`` can specify dependencies to be automatically
installed when the package itself is installed.
The example below shows how to configure this kind of dependencies:

.. tab:: pyproject.toml

    .. code-block:: toml

        [project]
        # ...
        dependencies = [
            "docutils",
            "requests <= 0.4",
        ]
        # ...

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        install_requires =
            docutils
            requests <= 0.4

.. tab:: setup.py [#setup.py]_

    .. code-block:: python

        setup(
            # ...
            install_requires=["docutils", "requests <= 0.4"],
            # ...
        )

Each dependency is represented by a string that can optionally contain version requirements
(e.g. one of the operators <, >, <=, >=, == or !=, followed by a version identifier),
and/or conditional environment markers, e.g. ``sys_platform == "win32"``
(see :doc:`PyPUG:specifications/version-specifiers` for more information).

When your project is installed, all of the dependencies not already installed
will be located (via PyPI), downloaded, built (if necessary), and installed.
This, of course, is a simplified scenario. You can also specify groups of
extra dependencies that are not strictly required by your package to work, but
that will provide additional functionalities.
For more advanced use, see :doc:`dependency_management`.


.. _Including Data Files:

Including Data Files
--------------------
Setuptools offers three ways to specify data files to be included in your packages.
For the simplest use, you can simply use the ``include_package_data`` keyword:

.. tab:: pyproject.toml

    .. code-block:: toml

        [tool.setuptools]
        include-package-data = true
        # This is already the default behaviour if you are using
        # pyproject.toml to configure your build.
        # You can deactivate that with `include-package-data = false`

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        include_package_data = True

.. tab:: setup.py [#setup.py]_

    .. code-block:: python

        setup(
            # ...
            include_package_data=True,
            # ...
        )

This tells setuptools to install any data files it finds in your packages.
The data files must be specified via the :ref:`MANIFEST.in <Using MANIFEST.in>`
file or automatically added by a :ref:`Revision Control System plugin
<Adding Support for Revision Control Systems>`.
For more details, see :doc:`datafiles`.


Development mode
----------------

``setuptools`` allows you to install a package without copying any files
to your interpreter directory (e.g. the ``site-packages`` directory).
This allows you to modify your source code and have the changes take
effect without you having to rebuild and reinstall.
Here's how to do it::

    pip install --editable .

See :doc:`development_mode` for more information.

.. tip::

    Prior to :ref:`pip v21.1 <pip:v21-1>`, a ``setup.py`` script was
    required to be compatible with development mode. With late
    versions of pip, projects without ``setup.py`` may be installed in this mode.

    If you have a version of ``pip`` older than v21.1 or is using a different
    packaging-related tool that does not support :pep:`660`, you might need to keep a
    ``setup.py`` file in file in your repository if you want to use editable
    installs.

    A simple script will suffice, for example:

    .. code-block:: python

        from setuptools import setup

        setup()

    You can still keep all the configuration in
    :doc:`pyproject.toml </userguide/pyproject_config>` and/or
    :doc:`setup.cfg </userguide/declarative_config>`


Uploading your package to PyPI
------------------------------
After generating the distribution files, the next step would be to upload your
distribution so others can use it. This functionality is provided by
:pypi:`twine` and is documented in the :doc:`Python packaging tutorial
<PyPUG:tutorials/packaging-projects>`.


Transitioning from ``setup.py`` to ``setup.cfg``
------------------------------------------------
To avoid executing arbitrary scripts and boilerplate code, we are transitioning
into a full-fledged ``setup.cfg`` to declare your package information instead
of running ``setup()``. This inevitably brings challenges due to a different
syntax. :doc:`Here </userguide/declarative_config>` we provide a quick guide to
understanding how ``setup.cfg`` is parsed by ``setuptools`` to ease the pain of
transition.

.. _packaging-resources:

Resources on Python packaging
=============================
Packaging in Python can be hard and is constantly evolving.
`Python Packaging User Guide <https://packaging.python.org>`_ has tutorials and
up-to-date references that can help you when it is time to distribute your work.



----

.. rubric:: Notes

.. [#setup.py]
   New projects are advised to avoid ``setup.py`` configurations (beyond the minimal stub)
   when custom scripting during the build is not necessary.
   Examples are kept in this document to help people interested in maintaining or
   contributing to existing packages that use ``setup.py``.
   Note that you can still keep most of configuration declarative in
   :doc:`setup.cfg <declarative_config>` or :doc:`pyproject.toml
   <pyproject_config>` and use ``setup.py`` only for the parts not
   supported in those files (e.g. C extensions).
   See :ref:`note <setuppy_discouraged>`.

.. _PyPI: https://pypi.org
alt-python312-setuptools/docs/userguide/distribution.rst000064400000024112150410147340017504 0ustar00.. _Specifying Your Project's Version:

Specifying Your Project's Version
=================================

Setuptools can work well with most versioning schemes. Over the years,
setuptools has tried to closely follow the :pep:`440` scheme, but it
also supports legacy versions. There are, however, a
few special things to watch out for, in order to ensure that setuptools and
other tools can always tell what version of your package is newer than another
version.  Knowing these things will also help you correctly specify what
versions of other projects your project depends on.

A version consists of an alternating series of release numbers and
`pre-release <https://peps.python.org/pep-0440/#pre-releases>`_
or `post-release <https://peps.python.org/pep-0440/#post-releases>`_ tags.  A
release number is a series of digits punctuated by
dots, such as ``2.4`` or ``0.5``.  Each series of digits is treated
numerically, so releases ``2.1`` and ``2.1.0`` are different ways to spell the
same release number, denoting the first subrelease of release 2.  But  ``2.10``
is the *tenth* subrelease of release 2, and so is a different and newer release
from ``2.1`` or ``2.1.0``.  Leading zeros within a series of digits are also
ignored, so ``2.01`` is the same as ``2.1``, and different from ``2.0.1``.

Following a release number, you can have either a pre-release or post-release
tag.  Pre-release tags make a version be considered *older* than the version
they are appended to.  So, revision ``2.4`` is *newer* than release candidate
``2.4rc1``, which in turn is newer than beta release ``2.4b1`` or
alpha release ``2.4a1``.  Postrelease tags make
a version be considered *newer* than the version they are appended to.  So,
revisions like ``2.4.post1`` are newer than ``2.4``, but *older*
than ``2.4.1`` (which has a higher release number).

In the case of legacy versions (for example, ``2.4pl1``), they are considered
older than non-legacy versions. Taking that in count, a revision ``2.4pl1``
is *older* than ``2.4``. Note that ``2.4pl1`` is not :pep:`440`-compliant.

A pre-release tag is a series of letters that are alphabetically before
"final".  Some examples of prerelease tags would include ``alpha``, ``beta``,
``a``, ``c``, ``dev``, and so on.  You do not have to place a dot or dash
before the prerelease tag if it's immediately after a number, but it's okay to
do so if you prefer.  Thus, ``2.4c1`` and ``2.4.c1`` and ``2.4-c1`` all
represent release candidate 1 of version ``2.4``, and are treated as identical
by setuptools. Note that only ``a``, ``b``, and ``rc`` are :pep:`440`-compliant
pre-release tags.

In addition, there are three special prerelease tags that are treated as if
they were ``rc``: ``c``, ``pre``, and ``preview``.  So, version
``2.4c1``, ``2.4pre1`` and ``2.4preview1`` are all the exact same version as
``2.4rc1``, and are treated as identical by setuptools.

A post-release tag is the string ``.post``, followed by a non-negative integer
value. Post-release tags are generally used to separate patch numbers, port
numbers, build numbers, revision numbers, or date stamps from the release
number.  For example, the version ``2.4.post1263`` might denote Subversion
revision 1263 of a post-release patch of version ``2.4``. Or you might use
``2.4.post20051127`` to denote a date-stamped post-release. Legacy post-release
tags could be either a series of letters that are alphabetically greater than or
equal to "final", or a dash (``-``) - for example ``2.4-r1263`` or
``2.4-20051127``.

Notice that after each legacy pre or post-release tag, you are free to place
another release number, followed again by more pre- or post-release tags.  For
example, ``0.6a9.dev41475`` could denote Subversion revision 41475 of the
in-development version of the ninth alpha of release 0.6.  Notice that ``dev``
is a pre-release tag, so this version is a *lower* version number than
``0.6a9``, which would be the actual ninth alpha of release 0.6.  But the
``41475`` is a post-release tag, so this version is *newer* than ``0.6a9.dev``.

For the most part, setuptools' interpretation of version numbers is intuitive,
but here are a few tips that will keep you out of trouble in the corner cases:

* Don't stick adjoining pre-release tags together without a dot or number
  between them.  Version ``1.9adev`` is the ``adev`` prerelease of ``1.9``,
  *not* a development pre-release of ``1.9a``.  Use ``.dev`` instead, as in
  ``1.9a.dev``, or separate the prerelease tags with a number, as in
  ``1.9a0dev``.  ``1.9a.dev``, ``1.9a0dev``, and even ``1.9a0.dev0`` are
  identical versions from setuptools' point of view, so you can use whatever
  scheme you prefer. Of these examples, only ``1.9a0.dev0`` is
  :pep:`440`-compliant.

* If you want to be certain that your chosen numbering scheme works the way
  you think it will, you can use the ``pkg_resources.parse_version()`` function
  to compare different version numbers::

    >>> from pkg_resources import parse_version
    >>> parse_version("1.9.a.dev") == parse_version("1.9a0dev")
    True
    >>> parse_version("2.1-rc2") < parse_version("2.1")
    True
    >>> parse_version("0.6a9dev-r41475") < parse_version("0.6a9")
    True

Once you've decided on a version numbering scheme for your project, you can
have setuptools automatically tag your in-development releases with various
pre- or post-release tags. See the following section for more details.


Tagging and "Daily Build" or "Snapshot" Releases
------------------------------------------------

.. warning::
   Please note that running ``python setup.py ...`` directly is no longer
   considered a good practice and that in the future the commands ``egg_info``
   and ``rotate`` will be deprecated.

   As a result, the instructions and information presented in this section
   should be considered **transitional** while setuptools don't provide a
   mechanism for tagging releases.

   Meanwhile, if you can also consider using :pypi:`setuptools-scm` to achieve
   similar objectives.


When a set of related projects are under development, it may be important to
track finer-grained version increments than you would normally use for e.g.
"stable" releases.  While stable releases might be measured in dotted numbers
with alpha/beta/etc. status codes, development versions of a project often
need to be tracked by revision or build number or even build date.  This is
especially true when projects in development need to refer to one another, and
therefore may literally need an up-to-the-minute version of something!

To support these scenarios, ``setuptools`` allows you to "tag" your source and
egg distributions by adding one or more of the following to the project's
"official" version identifier:

* A manually-specified pre-release tag, such as "build" or "dev", or a
  manually-specified post-release tag, such as a build or revision number
  (``--tag-build=STRING, -bSTRING``)

* An 8-character representation of the build date (``--tag-date, -d``), as
  a postrelease tag

You can add these tags by adding ``egg_info`` and the desired options to
the command line ahead of the ``sdist`` or ``bdist`` commands that you want
to generate a daily build or snapshot for.  See the section below on the
:ref:`egg_info <egg_info>` command for more details.

(Also, before you release your project, be sure to see the section on
:ref:`Specifying Your Project's Version` for more information about how pre- and
post-release tags affect how version numbers are interpreted.  This is
important in order to make sure that dependency processing tools will know
which versions of your project are newer than others).

Finally, if you are creating builds frequently, and either building them in a
downloadable location or are copying them to a distribution server, you should
probably also check out the :ref:`rotate <rotate>` command, which lets you automatically
delete all but the N most-recently-modified distributions matching a glob
pattern.  So, you can use a command line like::

    setup.py egg_info -rbDEV bdist_egg rotate -m.egg -k3

to build an egg whose version info includes "DEV-rNNNN" (where NNNN is the
most recent Subversion revision that affected the source tree), and then
delete any egg files from the distribution directory except for the three
that were built most recently.

If you have to manage automated builds for multiple packages, each with
different tagging and rotation policies, you may also want to check out the
:ref:`alias <alias>` command, which would let each package define an alias like ``daily``
that would perform the necessary tag, build, and rotate commands.  Then, a
simpler script or cron job could just run ``setup.py daily`` in each project
directory.  (And, you could also define sitewide or per-user default versions
of the ``daily`` alias, so that projects that didn't define their own would
use the appropriate defaults.)

Making "Official" (Non-Snapshot) Releases
-----------------------------------------

When you make an official release, creating source or binary distributions,
you will need to override the tag settings from ``setup.cfg``, so that you
don't end up registering versions like ``foobar-0.7a1.dev-r34832``.  This is
easy to do if you are developing on the trunk and using tags or branches for
your releases - just make the change to ``setup.cfg`` after branching or
tagging the release, so the trunk will still produce development snapshots.

Alternately, if you are not branching for releases, you can override the
default version options on the command line, using something like::

    setup.py egg_info -Db "" sdist bdist_egg

The first part of this command (``egg_info -Db ""``) will override the
configured tag information, before creating source and binary eggs. Thus, these
commands will use the plain version from your ``setup.py``, without adding the
build designation string.

Of course, if you will be doing this a lot, you may wish to create a personal
alias for this operation, e.g.::

    setup.py alias -u release egg_info -Db ""

You can then use it like this::

    setup.py release sdist bdist_egg

Or of course you can create more elaborate aliases that do all of the above.
See the sections below on the :ref:`egg_info <egg_info>` and
:ref:`alias <alias>` commands for more ideas.
alt-python312-setuptools/docs/userguide/datafiles.rst000064400000046712150410147340016733 0ustar00====================
Data Files Support
====================

Old packaging installation methods in the Python ecosystem
have traditionally allowed installation of "data files", which
are placed in a platform-specific location.  However, the most common use case
for data files distributed with a package is for use *by* the package, usually
by including the data files **inside the package directory**.

Setuptools focuses on this most common type of data files and offers three ways
of specifying which files should be included in your packages, as described in
the following sections.

include_package_data
====================

First, you can simply use the ``include_package_data`` keyword.
For example, if the package tree looks like this::

    project_root_directory
    ├── setup.py        # and/or setup.cfg, pyproject.toml
    └── src
        └── mypkg
            ├── __init__.py
            ├── data1.rst
            ├── data2.rst
            ├── data1.txt
            └── data2.txt

and you supply this configuration:

.. tab:: pyproject.toml

   .. code-block:: toml

        [tool.setuptools]
        # ...
        # By default, include-package-data is true in pyproject.toml, so you do
        # NOT have to specify this line.
        include-package-data = true

        [tool.setuptools.packages.find]
        where = ["src"]

.. tab:: setup.cfg

   .. code-block:: ini

        [options]
        # ...
        packages = find:
        package_dir =
            = src
        include_package_data = True

        [options.packages.find]
        where = src

.. tab:: setup.py

   .. code-block:: python

    from setuptools import setup, find_packages
    setup(
        # ...,
        packages=find_packages(where="src"),
        package_dir={"": "src"},
        include_package_data=True
    )

then all the ``.txt`` and ``.rst`` files will be automatically installed with
your package, provided:

1. These files are included via the :ref:`MANIFEST.in <Using MANIFEST.in>` file,
   like so::

        include src/mypkg/*.txt
        include src/mypkg/*.rst

2. OR, they are being tracked by a revision control system such as Git, Mercurial
   or SVN, and you have configured an appropriate plugin such as
   :pypi:`setuptools-scm` or :pypi:`setuptools-svn`.
   (See the section below on :ref:`Adding Support for Revision
   Control Systems` for information on how to write such plugins.)

.. note::
   .. versionadded:: v61.0.0
      The default value for ``tool.setuptools.include-package-data`` is ``True``
      when projects are configured via ``pyproject.toml``.
      This behaviour differs from ``setup.cfg`` and ``setup.py``
      (where ``include_package_data=False`` by default), which was not changed
      to ensure backwards compatibility with existing projects.

package_data
============

By default, ``include_package_data`` considers **all** non ``.py`` files found inside
the package directory (``src/mypkg`` in this case) as data files, and includes those that
satisfy (at least) one of the above two conditions into the source distribution, and
consequently in the installation of your package.
If you want finer-grained control over what files are included, then you can also use
the ``package_data`` keyword.
For example, if the package tree looks like this::

    project_root_directory
    ├── setup.py        # and/or setup.cfg, pyproject.toml
    └── src
        └── mypkg
            ├── __init__.py
            ├── data1.rst
            ├── data2.rst
            ├── data1.txt
            └── data2.txt

then you can use the following configuration to capture the ``.txt`` and ``.rst`` files as
data files:

.. tab:: pyproject.toml

   .. code-block:: toml

        [tool.setuptools.packages.find]
        where = ["src"]

        [tool.setuptools.package-data]
        mypkg = ["*.txt", "*.rst"]

.. tab:: setup.cfg

   .. code-block:: ini

        [options]
        # ...
        packages = find:
        package_dir =
            = src

        [options.packages.find]
        where = src

        [options.package_data]
        mypkg =
            *.txt
            *.rst

.. tab:: setup.py

    .. code-block:: python

        from setuptools import setup, find_packages
        setup(
            # ...,
            packages=find_packages(where="src"),
            package_dir={"": "src"},
            package_data={"mypkg": ["*.txt", "*.rst"]}
        )

The ``package_data`` argument is a dictionary that maps from package names to
lists of glob patterns. Note that the data files specified using the ``package_data``
option neither require to be included within a :ref:`MANIFEST.in <Using MANIFEST.in>`
file, nor require to be added by a revision control system plugin.

.. note::
        If your glob patterns use paths, you *must* use a forward slash (``/``) as
        the path separator, even if you are on Windows.  Setuptools automatically
        converts slashes to appropriate platform-specific separators at build time.

.. important::
        Glob patterns do not automatically match dotfiles, i.e., directory or file names
        starting with a dot (``.``). To include such files, you must explicitly start
        the pattern with a dot, e.g. ``.*`` to match ``.gitignore``.

If you have multiple top-level packages and a common pattern of data files for all these
packages, for example::

    project_root_directory
    ├── setup.py        # and/or setup.cfg, pyproject.toml
    └── src
        ├── mypkg1
        │   ├── data1.rst
        │   ├── data1.txt
        │   └── __init__.py
        └── mypkg2
            ├── data2.txt
            └── __init__.py

Here, both packages ``mypkg1`` and ``mypkg2`` share a common pattern of having ``.txt``
data files. However, only ``mypkg1`` has ``.rst`` data files. In such a case, if you want to
use the ``package_data`` option, the following configuration will work:

.. tab:: pyproject.toml

   .. code-block:: toml

        [tool.setuptools.packages.find]
        where = ["src"]

        [tool.setuptools.package-data]
        "*" = ["*.txt"]
        mypkg1 = ["data1.rst"]

.. tab:: setup.cfg

   .. code-block:: ini

        [options]
        packages = find:
        package_dir =
            = src

        [options.packages.find]
        where = src

        [options.package_data]
        * =
          *.txt
        mypkg1 =
          data1.rst

.. tab:: setup.py

   .. code-block:: python

        from setuptools import setup, find_packages
        setup(
            # ...,
            packages=find_packages(where="src"),
            package_dir={"": "src"},
            package_data={"": ["*.txt"], "mypkg1": ["data1.rst"]},
        )

Notice that if you list patterns in ``package_data`` under the empty string ``""`` in
``setup.py``, and the asterisk ``*`` in ``setup.cfg`` and ``pyproject.toml``, these
patterns are used to find files in every package. For example, we use ``""`` or ``*``
to indicate that the ``.txt`` files from all packages should be captured as data files.
These placeholders are treated as a special case, ``setuptools`` **do not**
support glob patterns on package names for this configuration
(patterns are only supported on the file paths).
Also note how we can continue to specify patterns for individual packages, i.e.
we specify that ``data1.rst`` from ``mypkg1`` alone should be captured as well.

.. note::
    When building an ``sdist``, the data files are also drawn from the
    ``package_name.egg-info/SOURCES.txt`` file which works as a form of cache.
    So make sure that this file is removed if ``package_data`` is updated,
    before re-building the package.

.. attention::
   In Python any directory is considered a package
   (even if it does not contain ``__init__.py``,
   see *native namespaces packages* on :doc:`PyPUG:guides/packaging-namespace-packages`).
   Therefore, if you are not relying on :doc:`automatic discovery </userguide/package_discovery>`,
   you *SHOULD* ensure that **all** packages (including the ones that don't
   contain any Python files) are included in the ``packages`` configuration
   (see :doc:`/userguide/package_discovery` for more information).

   Moreover, it is advisable to use full packages name using the dot
   notation instead of a nested path, to avoid error prone configurations.
   Please check :ref:`section subdirectories <subdir-data-files>` below.


exclude_package_data
====================

Sometimes, the ``include_package_data`` or ``package_data`` options alone
aren't sufficient to precisely define what files you want included. For example,
consider a scenario where you have ``include_package_data=True``, and you are using
a revision control system with an appropriate plugin.
Sometimes developers add directory-specific marker files (such as ``.gitignore``,
``.gitkeep``, ``.gitattributes``, or ``.hgignore``), these files are probably being
tracked by the revision control system, and therefore by default they will be
included when the package is installed.

Supposing you want to prevent these files from being included in the
installation (they are not relevant to Python or the package), then you could
use the ``exclude_package_data`` option:

.. tab:: pyproject.toml

   .. code-block:: toml

        [tool.setuptools.packages.find]
        where = ["src"]

        [tool.setuptools.exclude-package-data]
        mypkg = [".gitattributes"]

.. tab:: setup.cfg

   .. code-block:: ini

        [options]
        # ...
        packages = find:
        package_dir =
            = src
        include_package_data = True

        [options.packages.find]
        where = src

        [options.exclude_package_data]
        mypkg =
            .gitattributes

.. tab:: setup.py

    .. code-block:: python

        from setuptools import setup, find_packages
        setup(
            # ...,
            packages=find_packages(where="src"),
            package_dir={"": "src"},
            include_package_data=True,
            exclude_package_data={"mypkg": [".gitattributes"]},
        )

The ``exclude_package_data`` option is a dictionary mapping package names to
lists of wildcard patterns, just like the ``package_data`` option.  And, just
as with that option, you can use the empty string key ``""`` in ``setup.py`` and the
asterisk ``*`` in ``setup.cfg`` and ``pyproject.toml`` to match all top-level packages.

Any files that match these patterns will be *excluded* from installation,
even if they were listed in ``package_data`` or were included as a result of using
``include_package_data``.


.. _subdir-data-files:

Subdirectory for Data Files
===========================

A common pattern is where some (or all) of the data files are placed under
a separate subdirectory. For example::

    project_root_directory
    ├── setup.py        # and/or setup.cfg, pyproject.toml
    └── src
        └── mypkg
            ├── data
            │   ├── data1.rst
            │   └── data2.rst
            ├── __init__.py
            ├── data1.txt
            └── data2.txt

Here, the ``.rst`` files are placed under a ``data`` subdirectory inside ``mypkg``,
while the ``.txt`` files are directly under ``mypkg``.

In this case, the recommended approach is to treat ``data`` as a namespace package
(refer :pep:`420`). With ``package_data``,
the configuration might look like this:

.. tab:: pyproject.toml

   .. code-block:: toml

        # Scanning for namespace packages in the ``src`` directory is true by
        # default in pyproject.toml, so you do NOT need to include the
        # `tool.setuptools.packages.find` if it looks like the following:
        # [tool.setuptools.packages.find]
        # namespaces = true
        # where = ["src"]

        [tool.setuptools.package-data]
        mypkg = ["*.txt"]
        "mypkg.data" = ["*.rst"]

.. tab:: setup.cfg

   .. code-block:: ini

        [options]
        # ...
        packages = find_namespace:
        package_dir =
            = src

        [options.packages.find]
        where = src

        [options.package_data]
        mypkg =
            *.txt
        mypkg.data =
            *.rst

.. tab:: setup.py

   .. code-block:: python

        from setuptools import setup, find_namespace_packages
        setup(
            # ...,
            packages=find_namespace_packages(where="src"),
            package_dir={"": "src"},
            package_data={
                "mypkg": ["*.txt"],
                "mypkg.data": ["*.rst"],
            }
        )

In other words, we allow Setuptools to scan for namespace packages in the ``src`` directory,
which enables the ``data`` directory to be identified, and then, we separately specify data
files for the root package ``mypkg``, and the namespace package ``data`` under the package
``mypkg``.

With ``include_package_data`` the configuration is simpler: you simply need to enable
scanning of namespace packages in the ``src`` directory and the rest is handled by Setuptools.

.. tab:: pyproject.toml

   .. code-block:: toml

        [tool.setuptools]
        # ...
        # By default, include-package-data is true in pyproject.toml, so you do
        # NOT have to specify this line.
        include-package-data = true

        [tool.setuptools.packages.find]
        # scanning for namespace packages is true by default in pyproject.toml, so
        # you need NOT include the following line.
        namespaces = true
        where = ["src"]

.. tab:: setup.cfg

   .. code-block:: ini

        [options]
        packages = find_namespace:
        package_dir =
            = src
        include_package_data = True

        [options.packages.find]
        where = src

.. tab:: setup.py

   .. code-block:: python

        from setuptools import setup, find_namespace_packages
        setup(
            # ... ,
            packages=find_namespace_packages(where="src"),
            package_dir={"": "src"},
            include_package_data=True,
        )

Summary
=======

In summary, the three options allow you to:

``include_package_data``
    Accept all data files and directories matched by
    :ref:`MANIFEST.in <Using MANIFEST.in>` or added by
    a :ref:`plugin <Adding Support for Revision Control Systems>`.

``package_data``
    Specify additional patterns to match files that may or may
    not be matched by :ref:`MANIFEST.in <Using MANIFEST.in>`
    or added by a :ref:`plugin <Adding Support for Revision Control Systems>`.

``exclude_package_data``
    Specify patterns for data files and directories that should *not* be
    included when a package is installed, even if they would otherwise have
    been included due to the use of the preceding options.

.. note::
    Due to the way the build process works, a data file that you
    include in your project and then stop including may be "orphaned" in your
    project's build directories, requiring you to manually deleting them.
    This may also be important for your users and contributors
    if they track intermediate revisions of your project using Subversion; be sure
    to let them know when you make changes that remove files from inclusion so they
    can also manually delete them.


.. _Accessing Data Files at Runtime:

Accessing Data Files at Runtime
===============================

Typically, existing programs manipulate a package's ``__file__`` attribute in
order to find the location of data files. For example, if you have a structure
like this::

    project_root_directory
    ├── setup.py        # and/or setup.cfg, pyproject.toml
    └── src
        └── mypkg
            ├── data
            │   └── data1.txt
            ├── __init__.py
            └── foo.py

Then, in ``mypkg/foo.py``, you may try something like this in order to access
``mypkg/data/data1.txt``:

.. code-block:: python

   import os
   data_path = os.path.join(os.path.dirname(__file__), 'data', 'data1.txt')
   with open(data_path, 'r') as data_file:
        ...

However, this manipulation isn't compatible with :pep:`302`-based import hooks,
including importing from zip files and Python Eggs.  It is strongly recommended that,
if you are using data files, you should use :mod:`importlib.resources` to access them.
In this case, you would do something like this:

.. code-block:: python

   from importlib.resources import files
   data_text = files('mypkg.data').joinpath('data1.txt').read_text()

:mod:`importlib.resources` was added to Python 3.7. However, the API illustrated in
this code (using ``files()``) was added only in Python 3.9, [#files_api]_ and support
for accessing data files via namespace packages was added only in Python 3.10 [#namespace_support]_
(the ``data`` subdirectory is a namespace package under the root package ``mypkg``).
Therefore, you may find this code to work only in Python 3.10 (and above). For other
versions of Python, you are recommended to use the :pypi:`importlib-resources` backport
which provides the latest version of this library. In this case, the only change that
has to be made to the above code is to replace ``importlib.resources`` with ``importlib_resources``, i.e.

.. code-block:: python

   from importlib_resources import files
   ...

See :doc:`importlib-resources:using` for detailed instructions.

.. tip:: Files inside the package directory should be *read-only* to avoid a
   series of common problems (e.g. when multiple users share a common Python
   installation, when the package is loaded from a zip file, or when multiple
   instances of a Python application run in parallel).

   If your Python package needs to write to a file for shared data or configuration,
   you can use standard platform/OS-specific system directories, such as
   ``~/.local/config/$appname`` or ``/usr/share/$appname/$version`` (Linux specific) [#system-dirs]_.
   A common approach is to add a read-only template file to the package
   directory that is then copied to the correct system directory if no
   pre-existing file is found.


Data Files from Plugins and Extensions
======================================

You can resort to a :doc:`native/implicit namespace package
<PyPUG:guides/packaging-namespace-packages>` (as a container for files)
if you want plugins and extensions to your package to contribute with package data files.
This way, all files will be listed during runtime
when :doc:`using importlib.resources <importlib-resources:using>`.
Note that, although not strictly guaranteed, mainstream Python package managers,
like :pypi:`pip` and derived tools, will install files belong to multiple distributions
that share a same namespace into the same directory in the file system.
This means that the overhead for :mod:`importlib.resources` will be minimum.


Non-Package Data Files
======================

Historically, ``setuptools`` by way of ``easy_install`` would encapsulate data
files from the distribution into the egg (see `the old docs
<https://github.com/pypa/setuptools/blob/52aacd5b276fedd6849c3a648a0014f5da563e93/docs/setuptools.txt#L970-L1001>`_). As eggs are deprecated and pip-based installs
fall back to the platform-specific location for installing data files, there is
no supported facility to reliably retrieve these resources.

Instead, the PyPA recommends that any data files you wish to be accessible at
run time be included **inside the package**.


----

.. [#system-dirs] These locations can be discovered with the help of
   third-party libraries such as :pypi:`platformdirs`.

.. [#files_api] Reference: https://importlib-resources.readthedocs.io/en/latest/using.html#migrating-from-legacy

.. [#namespace_support] Reference: https://github.com/python/importlib_resources/pull/196#issuecomment-734520374
alt-python312-setuptools/docs/userguide/ext_modules.rst000064400000016106150410147340017321 0ustar00==========================
Building Extension Modules
==========================

Setuptools can build C/C++ extension modules.  The keyword argument
``ext_modules`` of ``setup()`` should be a list of instances of the
:class:`setuptools.Extension` class.


For example, let's consider a simple project with only one extension module::

    <project_folder>
    ├── pyproject.toml
    └── foo.c

and all project metadata configuration in the ``pyproject.toml`` file:

.. code-block:: toml

   # pyproject.toml
   [build-system]
   requires = ["setuptools"]
   build-backend = "setuptools.build_meta"

   [project]
   name = "mylib-foo"  # as it would appear on PyPI
   version = "0.42"

To instruct setuptools to compile the ``foo.c`` file into the extension module
``mylib.foo``, we need to add a ``setup.py`` file similar to the following:

.. code-block:: python

   from setuptools import Extension, setup

   setup(
       ext_modules=[
           Extension(
               name="mylib.foo",  # as it would be imported
                                  # may include packages/namespaces separated by `.`

               sources=["foo.c"], # all sources are compiled into a single binary file
           ),
       ]
   )

.. seealso::
   You can find more information on the `Python docs about C/C++ extensions`_.
   Alternatively, you might also be interested in learning about `Cython`_.

   If you plan to distribute a package that uses extensions across multiple
   platforms, :pypi:`cibuildwheel` can also be helpful.

.. important::
   All files used to compile your extension need to be available on the system
   when building the package, so please make sure to include some documentation
   on how developers interested in building your package from source
   can obtain operating system level dependencies
   (e.g. compilers and external binary libraries/artifacts).

   You will also need to make sure that all auxiliary files that are contained
   inside your :term:`project` (e.g. C headers authored by you or your team)
   are configured to be included in your :term:`sdist <Source Distribution (or "sdist")>`.
   Please have a look on our section on :ref:`Controlling files in the distribution`.


Compiler and linker options
===========================

The command ``build_ext`` builds C/C++ extension modules.  It creates
a command line for running the compiler and linker by combining
compiler and linker options from various sources:

.. Reference: `test_customize_compiler` in distutils/tests/test_sysconfig.py

* the ``sysconfig`` variables ``CC``, ``CXX``, ``CCSHARED``,
  ``LDSHARED``, and ``CFLAGS``,
* the environment variables ``CC``, ``CPP``,
  ``CXX``, ``LDSHARED`` and ``CFLAGS``,
  ``CPPFLAGS``, ``LDFLAGS``,
* the ``Extension`` attributes ``include_dirs``,
  ``library_dirs``, ``extra_compile_args``, ``extra_link_args``,
  ``runtime_library_dirs``.

.. Ignoring AR, ARFLAGS, RANLIB here because they are used by the (obsolete?) build_clib, not build_ext.

Specifically, if the environment variables ``CC``, ``CPP``, ``CXX``, and ``LDSHARED``
are set, they will be used instead of the ``sysconfig`` variables of the same names.

The compiler options appear in the command line in the following order:

.. Reference: "compiler_so" and distutils.ccompiler.gen_preprocess_options, CCompiler.compile, UnixCCompiler._compile

* first, the options provided by the ``sysconfig`` variable ``CFLAGS``,
* then, the options provided by the environment variables ``CFLAGS`` and ``CPPFLAGS``,
* then, the options provided by the ``sysconfig`` variable ``CCSHARED``,
* then, a ``-I`` option for each element of ``Extension.include_dirs``,
* finally, the options provided by ``Extension.extra_compile_args``.

The linker options appear in the command line in the following order:

.. Reference: "linker_so" and CCompiler.link

* first, the options provided by environment variables and ``sysconfig`` variables,
* then, a ``-L`` option for each element of ``Extension.library_dirs``,
* then, a linker-specific option like ``-Wl,-rpath`` for each element of ``Extension.runtime_library_dirs``,
* finally, the options provided by ``Extension.extra_link_args``.

The resulting command line is then processed by the compiler and linker.
According to the GCC manual sections on `directory options`_ and
`environment variables`_, the C/C++ compiler searches for files named in
``#include <file>`` directives in the following order:

* first, in directories given by ``-I`` options (in left-to-right order),
* then, in directories given by the environment variable ``CPATH`` (in left-to-right order),
* then, in directories given by ``-isystem`` options (in left-to-right order),
* then, in directories given by the environment variable ``C_INCLUDE_PATH`` (for C) and ``CPLUS_INCLUDE_PATH`` (for C++),
* then, in standard system directories,
* finally, in directories given by ``-idirafter`` options (in left-to-right order).

The linker searches for libraries in the following order:

* first, in directories given by ``-L`` options (in left-to-right order),
* then, in directories given by the environment variable ``LIBRARY_PATH`` (in left-to-right order).


Distributing Extensions compiled with Cython
============================================

When your :pypi:`Cython` extension modules *are declared using the*
:class:`setuptools.Extension` *class*, ``setuptools`` will detect at build time
whether Cython is installed or not.

If Cython is present, then ``setuptools`` will use it to build the ``.pyx`` files.
Otherwise, ``setuptools`` will try to find and compile the equivalent ``.c`` files
(instead of ``.pyx``). These files can be generated using the
`cython command line tool`_.

You can ensure that Cython is always automatically installed into the build
environment by including it as a :ref:`build dependency <build-requires>` in
your ``pyproject.toml``:

.. code-block:: toml

    [build-system]
    requires = [
        # ...,
        "cython",
    ]

Alternatively, you can include the ``.c`` code that is pre-compiled by Cython
into your source distribution, alongside the original ``.pyx`` files (this
might save a few seconds when building from an ``sdist``).
To improve version compatibility, you probably also want to include current
``.c`` files in your :wiki:`revision control system`, and rebuild them whenever
you check changes in for the ``.pyx`` source files.
This will ensure that people tracking your project will be able to build it
without installing Cython, and that there will be no variation due to small
differences in the generate C files.
Please checkout our docs on :ref:`controlling files in the distribution` for
more information.

----

Extension API Reference
=======================

.. autoclass:: setuptools.Extension


.. _Python docs about C/C++ extensions: https://docs.python.org/3/extending/extending.html
.. _Cython: https://cython.readthedocs.io/en/stable/index.html
.. _directory options: https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html
.. _environment variables: https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
.. _cython command line tool: https://cython.readthedocs.io/en/stable/src/userguide/source_files_and_compilation.html
alt-python312-setuptools/docs/userguide/index.rst000064400000003145150410147340016077 0ustar00==================================================
Building and Distributing Packages with Setuptools
==================================================

The first step towards sharing a Python library or program is to build a
distribution package [#package-overload]_. This includes adding a set of
additional files containing metadata and configuration to not only instruct
``setuptools`` on how the distribution should be built but also
to help installer (such as :pypi:`pip`) during the installation process.

This document contains information to help Python developers through this
process. Please check the :doc:`/userguide/quickstart` for an overview of
the workflow.

Also note that ``setuptools`` is what is known in the community as :pep:`build
backend <517#terminology-and-goals>`, user facing interfaces are provided by tools
such as :pypi:`pip` and :pypi:`build`. To use ``setuptools``, one must
explicitly create a ``pyproject.toml`` file as described :doc:`/build_meta`.


Contents
========

.. toctree::
    :maxdepth: 1

    quickstart
    package_discovery
    dependency_management
    development_mode
    entry_point
    datafiles
    ext_modules
    distribution
    miscellaneous
    extension
    declarative_config
    pyproject_config

---

.. rubric:: Notes

.. [#package-overload]
   A :term:`Distribution Package` is also referred in the Python community simply as "package"
   Unfortunately, this jargon might be a bit confusing for new users because the term package
   can also to refer any :term:`directory <package>` (or sub directory) used to organize
   :term:`modules <module>` and auxiliary files.
alt-python312-setuptools/docs/userguide/miscellaneous.rst000064400000022541150410147340017634 0ustar00.. _Controlling files in the distribution:

Controlling files in the distribution
=====================================

For the most common use cases, ``setuptools`` will automatically find out which
files are necessary for distributing the package. More precisely, the following
files are included in a source distribution by default:

- :term:`pure Python module <Pure Module>` files implied by the ``py-modules`` and ``packages``
  configuration parameters in ``pyproject.toml`` and/or equivalent
  in ``setup.cfg``/``setup.py``;
- C source files mentioned in the ``ext_modules`` or ``libraries``
  ``setup()`` arguments;
- Files that match the following glob patterns: ``tests/test*.py``,
  ``test/test*.py``;
- Scripts specified by the ``scripts-files`` configuration parameter
  in ``pyproject.toml`` or ``scripts`` in ``setup.py``/``setup.cfg``;
- All files specified by the ``package-data`` and ``data-files``
  configuration parameters in ``pyproject.toml`` and/or equivalent
  in ``setup.cfg``/``setup.py``;
- The file specified by the ``license_file`` option in ``setup.cfg``;
- All files specified by the ``license-files`` configuration parameter
  in ``pyproject.toml`` and/or equivalent in ``setup.cfg``/``setup.py``;
  note that if you don't explicitly set this parameter, ``setuptools``
  will include any files that match the following glob patterns:
  ``LICENSE*``, ``LICENCE*``, ``COPYING*``, ``NOTICE*``, ``AUTHORS**``;
- ``pyproject.toml``;
- ``setup.cfg``;
- ``setup.py``;
- ``README``, ``README.txt``, ``README.rst`` or ``README.md``;
- ``MANIFEST.in``

Please note that the list above is guaranteed to work with the last stable version
of ``setuptools``. The behavior of older versions might differ.

.. note::
   .. versionadded:: v68.3.0
      ``setuptools`` will attempt to include type information files
      by default in the distribution
      (``.pyi`` and ``py.typed``, as specified in :pep:`561`).

    *Please note however that this feature is* **EXPERIMENTAL** *and may change in
    the future.*

    If you have ``.pyi`` and ``py.typed`` files in your project, but do not
    wish to distribute them, you can opt out by setting
    :doc:`exclude-package-data </userguide/datafiles>` to remove them.

However, when building more complex packages (e.g. packages that include
non-Python files, or that need to use custom C headers), you might find that
not all files present in your project folder are included in package
:term:`distribution archive <Distribution Package>`.

If you are using a :wiki:`Revision Control System`, such as git_ or mercurial_,
and your source distributions only need to include files that you're
tracking in revision control, you can use a ``setuptools`` :ref:`plugin <Adding
Support for Revision Control Systems>`, such as :pypi:`setuptools-scm` or
:pypi:`setuptools-svn` to automatically include all tracked files into the ``sdist``.

.. _Using MANIFEST.in:

Alternatively, if you need finer control over the files (e.g. you don't want to
distribute :wiki:`CI/CD`-related files) or you need automatically generated files,
you can add a ``MANIFEST.in`` file at the root of your project,
to specify any files that the default file location algorithm doesn't catch.

This file contains instructions that tell ``setuptools`` which files exactly
should be part of the ``sdist`` (or not).

.. attention::
   Please note that ``setuptools`` supports the ``MANIFEST.in``,
   and not ``MANIFEST`` (no extension). Any documentation, tutorial or example
   that recommends using ``MANIFEST`` (no extension) is likely outdated.

.. tip::
   The ``MANIFEST.in`` file contains commands that allow you to discover and
   manipulate lists of files. There are many commands that can be used with
   different objectives, but you should try to not make your ``MANIFEST.in``
   file too fine grained.

   A good idea is to start with a ``graft`` command (to add all
   files inside a set of directories) and then fine tune the file selection
   by removing the excess or adding isolated files.


A :file:`MANIFEST.in` file consists of commands, one per line, instructing
setuptools to add or remove some set of files from the sdist.  The commands
are:

=========================================================  ==================================================================================================
Command                                                    Description
=========================================================  ==================================================================================================
:samp:`include {pat1} {pat2} ...`                          Add all files matching any of the listed patterns
                                                           (Files must be given as paths relative to the root of the project)
:samp:`exclude {pat1} {pat2} ...`                          Remove all files matching any of the listed patterns
                                                           (Files must be given as paths relative to the root of the project)
:samp:`recursive-include {dir-pattern} {pat1} {pat2} ...`  Add all files under directories matching ``dir-pattern`` that match any of the listed patterns
:samp:`recursive-exclude {dir-pattern} {pat1} {pat2} ...`  Remove all files under directories matching ``dir-pattern`` that match any of the listed patterns
:samp:`global-include {pat1} {pat2} ...`                   Add all files anywhere in the source tree matching any of the listed patterns
:samp:`global-exclude {pat1} {pat2} ...`                   Remove all files anywhere in the source tree matching any of the listed patterns
:samp:`graft {dir-pattern}`                                Add all files under directories matching ``dir-pattern``
:samp:`prune {dir-pattern}`                                Remove all files under directories matching ``dir-pattern``
=========================================================  ==================================================================================================

The patterns here are glob-style patterns: ``*`` matches zero or more regular
filename characters (on Unix, everything except forward slash; on Windows,
everything except backslash and colon); ``?`` matches a single regular filename
character, and ``[chars]`` matches any one of the characters between the square
brackets (which may contain character ranges, e.g., ``[a-z]`` or
``[a-fA-F0-9]``).  Setuptools also has support for ``**`` matching
zero or more characters including forward slash, backslash, and colon.

Directory patterns are relative to the root of the project directory; e.g.,
``graft example*`` will include a directory named :file:`examples` in the
project root but will not include :file:`docs/examples/`.

File & directory names in :file:`MANIFEST.in` should be ``/``-separated;
setuptools will automatically convert the slashes to the local platform's
appropriate directory separator.

Commands are processed in the order they appear in the :file:`MANIFEST.in`
file.  For example, given the commands:

.. code-block:: bash

    graft tests
    global-exclude *.py[cod]

the contents of the directory tree :file:`tests` will first be added to the
sdist, and then after that all files in the sdist with a ``.pyc``, ``.pyo``, or
``.pyd`` extension will be removed from the sdist.  If the commands were in the
opposite order, then ``*.pyc`` files etc. would be only be removed from what
was already in the sdist before adding :file:`tests`, and if :file:`tests`
happened to contain any ``*.pyc`` files, they would end up included in the
sdist because the exclusion happened before they were included.

An example of ``MANIFEST.in`` for a simple project that organized according to a
:ref:`src-layout` is:

.. code-block:: bash

   # MANIFEST.in -- just for illustration
   graft src
   graft tests
   graft docs
   # `-> adds all files inside a directory

   include tox.ini
   # `-> matches file paths relative to the root of the project

   global-exclude *~ *.py[cod] *.so
   # `-> matches file names (regardless of directory)

Once the correct files are present in the ``sdist``, they can then be used by
binary extensions during the build process, or included in the final
:term:`wheel <Wheel>` [#build-process]_ if you configure ``setuptools`` with
``include_package_data=True``.

.. important::
   Please note that, when using ``include_package_data=True``, only files **inside
   the package directory** are included in the final ``wheel``, by default.

   So for example, if you create a :term:`Python project <Project>` that uses
   :pypi:`setuptools-scm` and have a ``tests`` directory outside of the package
   folder, the ``tests`` directory will be present in the ``sdist`` but not in the
   ``wheel`` [#wheel-vs-sdist]_.

   See :doc:`/userguide/datafiles` for more information.

----

.. [#build-process]
   You can think about the build process as two stages: first the ``sdist``
   will be created and then the ``wheel`` will be produced from that ``sdist``.

.. [#wheel-vs-sdist]
   This happens because the ``sdist`` can contain files that are useful during
   development or the build process itself, but not in runtime (e.g. tests,
   docs, examples, etc...).
   The ``wheel``, on the other hand, is a file format that has been optimized
   and is ready to be unpacked into a running installation of Python or
   :term:`Virtual Environment`.
   Therefore it only contains items that are required during runtime.

.. _git: https://git-scm.com
.. _mercurial: https://www.mercurial-scm.org
alt-python312-setuptools/docs/userguide/dependency_management.rst000064400000026511150410147340021304 0ustar00=====================================
Dependencies Management in Setuptools
=====================================

There are three types of dependency styles offered by setuptools:
1) build system requirement, 2) required dependency and 3) optional
dependency.

Each dependency, regardless of type, needs to be specified according to :pep:`508`
and :pep:`440`.
This allows adding version :pep:`range restrictions <440#version-specifiers>`
and :ref:`environment markers <environment-markers>`.


.. _build-requires:

Build system requirement
========================

After organizing all the scripts and files and getting ready for packaging,
there needs to be a way to specify what programs and libraries are actually needed
do the packaging (in our case, ``setuptools`` of course).
This needs to be specified in your ``pyproject.toml`` file
(if you have forgot what this is, go to :doc:`/userguide/quickstart` or :doc:`/build_meta`):

.. code-block:: toml

    [build-system]
    requires = ["setuptools"]
    #...

Please note that you should also include here any other ``setuptools`` plugin
(e.g., :pypi:`setuptools-scm`, :pypi:`setuptools-golang`, :pypi:`setuptools-rust`)
or build-time dependency (e.g., :pypi:`Cython`, :pypi:`cppy`, :pypi:`pybind11`).

.. note::
    In previous versions of ``setuptools``,
    this used to be accomplished with the ``setup_requires`` keyword but is
    now considered deprecated in favor of the :pep:`517` style described above.
    To peek into how this legacy keyword is used, consult our :doc:`guide on
    deprecated practice (WIP) </deprecated/index>`.


.. _Declaring Dependencies:

Declaring required dependency
=============================
This is where a package declares its core dependencies, without which it won't
be able to run. ``setuptools`` supports automatically downloading and installing
these dependencies when the package is installed. Although there is more
finesse to it, let's start with a simple example.

.. tab:: pyproject.toml

    .. code-block:: toml

        [project]
        # ...
        dependencies = [
            "docutils",
            "BazSpam == 1.1",
        ]
        # ...

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        #...
        install_requires =
            docutils
            BazSpam ==1.1

.. tab:: setup.py

    .. code-block:: python

        setup(
            ...,
            install_requires=[
                'docutils',
                'BazSpam ==1.1',
            ],
        )


When your project is installed (e.g., using :pypi:`pip`), all of the dependencies not
already installed will be located (via `PyPI`_), downloaded, built (if necessary),
and installed and 2) Any scripts in your project will be installed with wrappers
that verify the availability of the specified dependencies at runtime.


.. _environment-markers:

Platform specific dependencies
------------------------------
Setuptools offers the capability to evaluate certain conditions before blindly
installing everything listed in ``install_requires``. This is great for platform
specific dependencies. For example, the ``enum`` package was added in Python
3.4, therefore, package that depends on it can elect to install it only when
the Python version is older than 3.4. To accomplish this

.. tab:: pyproject.toml

    .. code-block:: toml

        [project]
        # ...
        dependencies = [
            "enum34; python_version<'3.4'",
        ]
        # ...

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        #...
        install_requires =
            enum34;python_version<'3.4'

.. tab:: setup.py

    .. code-block:: python

        setup(
            ...,
            install_requires=[
                "enum34;python_version<'3.4'",
            ],
        )

Similarly, if you also wish to declare ``pywin32`` with a minimal version of 1.0
and only install it if the user is using a Windows operating system:

.. tab:: pyproject.toml

    .. code-block:: toml

        [project]
        # ...
        dependencies = [
            "enum34; python_version<'3.4'",
            "pywin32 >= 1.0; platform_system=='Windows'",
        ]
        # ...

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        #...
        install_requires =
            enum34;python_version<'3.4'
            pywin32 >= 1.0;platform_system=='Windows'

.. tab:: setup.py

    .. code-block:: python

        setup(
            ...,
            install_requires=[
                "enum34;python_version<'3.4'",
                "pywin32 >= 1.0;platform_system=='Windows'",
            ],
        )

The environmental markers that may be used for testing platform types are
detailed in :pep:`508`.

.. seealso::
   Alternatively, a :ref:`backend wrapper <backend-wrapper>` can be used for
   specific use cases where environment markers aren't sufficient.


Direct URL dependencies
-----------------------

.. attention::
   `PyPI`_ and other standards-conformant package indices **do not** accept
   packages that declare dependencies using direct URLs. ``pip`` will accept them
   when installing packages from the local filesystem or from another URL,
   however.

Dependencies that are not available on a package index but can be downloaded
elsewhere in the form of a source repository or archive may be specified
using a variant of :pep:`PEP 440's direct references <440#direct-references>`:

.. tab:: pyproject.toml

    .. code-block:: toml

        [project]
        # ...
        dependencies = [
            "Package-A @ git+https://example.net/package-a.git@main",
            "Package-B @ https://example.net/archives/package-b.whl",
        ]

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        #...
        install_requires =
            Package-A @ git+https://example.net/package-a.git@main
            Package-B @ https://example.net/archives/package-b.whl

.. tab:: setup.py

    .. code-block:: python

        setup(
            install_requires=[
               "Package-A @ git+https://example.net/package-a.git@main",
               "Package-B @ https://example.net/archives/package-b.whl",
            ],
            ...,
        )

For source repository URLs, a list of supported protocols and VCS-specific
features such as selecting certain branches or tags can be found in pip's
documentation on `VCS support <https://pip.pypa.io/en/latest/topics/vcs-support/>`_.
Supported formats for archive URLs are sdists and wheels.


Optional dependencies
=====================
Setuptools allows you to declare dependencies that are not installed by default.
This effectively means that you can create a "variant" of your package with a
set of extra functionalities.

For example, let's consider a ``Package-A`` that offers
optional PDF support and requires two other dependencies for it to work:

.. tab:: pyproject.toml

    .. code-block:: toml

        [project]
        name = "Package-A"
        # ...
        [project.optional-dependencies]
        PDF = ["ReportLab>=1.2", "RXP"]

.. tab:: setup.cfg

    .. code-block:: ini

        [metadata]
        name = Package-A

        [options.extras_require]
        PDF =
            ReportLab>=1.2
            RXP


.. tab:: setup.py

    .. code-block:: python

        setup(
            name="Package-A",
            ...,
            extras_require={
                "PDF": ["ReportLab>=1.2", "RXP"],
            },
        )

.. sidebar::

   .. tip::
      It is also convenient to declare optional requirements for
      ancillary tasks such as running tests and or building docs.

The name ``PDF`` is an arbitrary :pep:`identifier <685>` of such a list of dependencies, to
which other components can refer and have them installed.

A use case for this approach is that other package can use this "extra" for their
own dependencies. For example, if ``Package-B`` needs ``Package-A`` with PDF support
installed, it might declare the dependency like this:

.. tab:: pyproject.toml

    .. code-block:: toml

        [project]
        name = "Package-B"
        # ...
        dependencies = [
            "Package-A[PDF]"
        ]

.. tab:: setup.cfg

    .. code-block:: ini

        [metadata]
        name = Package-B
        #...

        [options]
        #...
        install_requires =
            Package-A[PDF]

.. tab:: setup.py

    .. code-block:: python

        setup(
            name="Package-B",
            install_requires=["Package-A[PDF]"],
            ...,
        )

This will cause ``ReportLab`` to be installed along with ``Package-A``, if ``Package-B`` is
installed -- even if ``Package-A`` was already installed.  In this way, a project
can encapsulate groups of optional "downstream dependencies" under a feature
name, so that packages that depend on it don't have to know what the downstream
dependencies are.  If a later version of ``Package-A`` builds in PDF support and
no longer needs ``ReportLab``, or if it ends up needing other dependencies besides
``ReportLab`` in order to provide PDF support, ``Package-B``'s setup information does
not need to change, but the right packages will still be installed if needed.

.. tip::
    Best practice: if a project ends up no longer needing any other packages to
    support a feature, it should keep an empty requirements list for that feature
    in its ``extras_require`` argument, so that packages depending on that feature
    don't break (due to an invalid feature name).

.. warning::
    Historically ``setuptools`` also used to support extra dependencies in console
    scripts, for example:

    .. tab:: setup.cfg

        .. code-block:: ini

            [metadata]
            name = Package-A
            #...

            [options]
            #...
            entry_points=
                [console_scripts]
                rst2pdf = project_a.tools.pdfgen [PDF]
                rst2html = project_a.tools.htmlgen

    .. tab:: setup.py

        .. code-block:: python

            setup(
                name="Package-A",
                ...,
                entry_points={
                    "console_scripts": [
                        "rst2pdf = project_a.tools.pdfgen [PDF]",
                        "rst2html = project_a.tools.htmlgen",
                    ],
                },
            )

    This syntax indicates that the entry point (in this case a console script)
    is only valid when the PDF extra is installed. It is up to the installer
    to determine how to handle the situation where PDF was not indicated
    (e.g., omit the console script, provide a warning when attempting to load
    the entry point, assume the extras are present and let the implementation
    fail later).

    **However**, ``pip`` and other tools might not support this use case for extra
    dependencies, therefore this practice is considered **deprecated**.
    See :doc:`PyPUG:specifications/entry-points`.


Python requirement
==================
In some cases, you might need to specify the minimum required python version.
This can be configured as shown in the example below.

.. tab:: pyproject.toml

    .. code-block:: toml

        [project]
        name = "Package-B"
        requires-python = ">=3.6"
        # ...

.. tab:: setup.cfg

    .. code-block:: ini

        [metadata]
        name = Package-B
        #...

        [options]
        #...
        python_requires = >=3.6

.. tab:: setup.py

    .. code-block:: python

        setup(
            name="Package-B",
            python_requires=">=3.6",
            ...,
        )


.. _PyPI: https://pypi.org
alt-python312-setuptools/docs/roadmap.rst000064400000000241150410147350014412 0ustar00=======
Roadmap
=======

Setuptools maintains a series of `milestones
<https://github.com/pypa/setuptools/milestones>`_ to track
a roadmap of large-scale goals.
alt-python312-setuptools/docs/pkg_resources.rst000064400000270140150410147350015651 0ustar00=============================================================
Package Discovery and Resource Access using ``pkg_resources``
=============================================================

The ``pkg_resources`` module distributed with ``setuptools`` provides an API
for Python libraries to access their resource files, and for extensible
applications and frameworks to automatically discover plugins.  It also
provides runtime support for using C extensions that are inside zipfile-format
eggs, support for merging packages that have separately-distributed modules or
subpackages, and APIs for managing Python's current "working set" of active
packages.

.. attention::
   Use of ``pkg_resources`` is deprecated in favor of
   :mod:`importlib.resources`, :mod:`importlib.metadata`
   and their backports (:pypi:`importlib_resources`, :pypi:`importlib_metadata`).
   Some useful APIs are also provided by :pypi:`packaging` (e.g. requirements
   and version parsing).
   Users should refrain from new usage of ``pkg_resources`` and
   should work to port to importlib-based solutions.


--------
Overview
--------

The ``pkg_resources`` module provides runtime facilities for finding,
introspecting, activating and using installed Python distributions. Some
of the more advanced features (notably the support for parallel installation
of multiple versions) rely specifically on the "egg" format (either as a
zip archive or subdirectory), while others (such as plugin discovery) will
work correctly so long as "egg-info" metadata directories are available for
relevant distributions.

Eggs are a distribution format for Python modules, similar in concept to
Java's "jars" or Ruby's "gems", or the "wheel" format defined in PEP 427.
However, unlike a pure distribution format, eggs can also be installed and
added directly to ``sys.path`` as an import location. When installed in
this way, eggs are *discoverable*, meaning that they carry metadata that
unambiguously identifies their contents and dependencies. This means that
an installed egg can be *automatically* found and added to ``sys.path`` in
response to simple requests of the form, "get me everything I need to use
docutils' PDF support". This feature allows mutually conflicting versions of
a distribution to co-exist in the same Python installation, with individual
applications activating the desired version at runtime by manipulating the
contents of ``sys.path`` (this differs from the virtual environment
approach, which involves creating isolated environments for each
application).

The following terms are needed in order to explain the capabilities offered
by this module:

project
    A library, framework, script, plugin, application, or collection of data
    or other resources, or some combination thereof.  Projects are assumed to
    have "relatively unique" names, e.g. names registered with PyPI.

release
    A snapshot of a project at a particular point in time, denoted by a version
    identifier.

distribution
    A file or files that represent a particular release.

importable distribution
    A file or directory that, if placed on ``sys.path``, allows Python to
    import any modules contained within it.

pluggable distribution
    An importable distribution whose filename unambiguously identifies its
    release (i.e. project and version), and whose contents unambiguously
    specify what releases of other projects will satisfy its runtime
    requirements.

extra
    An "extra" is an optional feature of a release, that may impose additional
    runtime requirements.  For example, if docutils PDF support required a
    PDF support library to be present, docutils could define its PDF support as
    an "extra", and list what other project releases need to be available in
    order to provide it.

environment
    A collection of distributions potentially available for importing, but not
    necessarily active.  More than one distribution (i.e. release version) for
    a given project may be present in an environment.

working set
    A collection of distributions actually available for importing, as on
    ``sys.path``.  At most one distribution (release version) of a given
    project may be present in a working set, as otherwise there would be
    ambiguity as to what to import.

eggs
    Eggs are pluggable distributions in one of the three formats currently
    supported by ``pkg_resources``.  There are built eggs, development eggs,
    and egg links.  Built eggs are directories or zipfiles whose name ends
    with ``.egg`` and follows the egg naming conventions, and contain an
    ``EGG-INFO`` subdirectory (zipped or otherwise).  Development eggs are
    normal directories of Python code with one or more ``ProjectName.egg-info``
    subdirectories. The development egg format is also used to provide a
    default version of a distribution that is available to software that
    doesn't use ``pkg_resources`` to request specific versions. Egg links
    are ``*.egg-link`` files that contain the name of a built or
    development egg, to support symbolic linking on platforms that do not
    have native symbolic links (or where the symbolic link support is
    limited).

(For more information about these terms and concepts, see also this
`architectural overview`_ of ``pkg_resources`` and Python Eggs in general.)

.. _architectural overview: https://mail.python.org/pipermail/distutils-sig/2005-June/004652.html


.. -----------------
.. Developer's Guide
.. -----------------

.. This section isn't written yet.  Currently planned topics include
    Accessing Resources
    Finding and Activating Package Distributions
        get_provider()
        require()
        WorkingSet
        iter_distributions
    Running Scripts
    Configuration
    Namespace Packages
    Extensible Applications and Frameworks
        Locating entry points
        Activation listeners
        Metadata access
        Extended Discovery and Installation
    Supporting Custom PEP 302 Implementations
.. For now, please check out the extensive `API Reference`_ below.


-------------
API Reference
-------------

Namespace Package Support
=========================

A namespace package is a package that only contains other packages and modules,
with no direct contents of its own.  Such packages can be split across
multiple, separately-packaged distributions.  They are normally used to split
up large packages produced by a single organization, such as in the ``zope``
namespace package for Zope Corporation packages, and the ``peak`` namespace
package for the Python Enterprise Application Kit.

To create a namespace package, you list it in the ``namespace_packages``
argument to ``setup()``, in your project's ``setup.py``.  (See the
:ref:`setuptools documentation on namespace packages <Namespace Packages>` for
more information on this.)  Also, you must add a ``declare_namespace()`` call
in the package's ``__init__.py`` file(s):

``declare_namespace(name)``
    Declare that the dotted package name ``name`` is a "namespace package" whose
    contained packages and modules may be spread across multiple distributions.
    The named package's ``__path__`` will be extended to include the
    corresponding package in all distributions on ``sys.path`` that contain a
    package of that name.  (More precisely, if an importer's
    ``find_module(name)`` returns a loader, then it will also be searched for
    the package's contents.)  Whenever a Distribution's ``activate()`` method
    is invoked, it checks for the presence of namespace packages and updates
    their ``__path__`` contents accordingly.

Applications that manipulate namespace packages or directly alter ``sys.path``
at runtime may also need to use this API function:

``fixup_namespace_packages(path_item)``
    Declare that ``path_item`` is a newly added item on ``sys.path`` that may
    need to be used to update existing namespace packages.  Ordinarily, this is
    called for you when an egg is automatically added to ``sys.path``, but if
    your application modifies ``sys.path`` to include locations that may
    contain portions of a namespace package, you will need to call this
    function to ensure they are added to the existing namespace packages.

Although by default ``pkg_resources`` only supports namespace packages for
filesystem and zip importers, you can extend its support to other "importers"
compatible with PEP 302 using the ``register_namespace_handler()`` function.
See the section below on `Supporting Custom Importers`_ for details.


``WorkingSet`` Objects
======================

The ``WorkingSet`` class provides access to a collection of "active"
distributions.  In general, there is only one meaningful ``WorkingSet``
instance: the one that represents the distributions that are currently active
on ``sys.path``.  This global instance is available under the name
``working_set`` in the ``pkg_resources`` module.  However, specialized
tools may wish to manipulate working sets that don't correspond to
``sys.path``, and therefore may wish to create other ``WorkingSet`` instances.

It's important to note that the global ``working_set`` object is initialized
from ``sys.path`` when ``pkg_resources`` is first imported, but is only updated
if you do all future ``sys.path`` manipulation via ``pkg_resources`` APIs.  If
you manually modify ``sys.path``, you must invoke the appropriate methods on
the ``working_set`` instance to keep it in sync.  Unfortunately, Python does
not provide any way to detect arbitrary changes to a list object like
``sys.path``, so ``pkg_resources`` cannot automatically update the
``working_set`` based on changes to ``sys.path``.

``WorkingSet(entries=None)``
    Create a ``WorkingSet`` from an iterable of path entries.  If ``entries``
    is not supplied, it defaults to the value of ``sys.path`` at the time
    the constructor is called.

    Note that you will not normally construct ``WorkingSet`` instances
    yourself, but instead you will implicitly or explicitly use the global
    ``working_set`` instance.  For the most part, the ``pkg_resources`` API
    is designed so that the ``working_set`` is used by default, such that you
    don't have to explicitly refer to it most of the time.

All distributions available directly on ``sys.path`` will be activated
automatically when ``pkg_resources`` is imported. This behaviour can cause
version conflicts for applications which require non-default versions of
those distributions. To handle this situation, ``pkg_resources`` checks for a
``__requires__`` attribute in the ``__main__`` module when initializing the
default working set, and uses this to ensure a suitable version of each
affected distribution is activated. For example::

    __requires__ = ["CherryPy < 3"] # Must be set before pkg_resources import
    import pkg_resources


Basic ``WorkingSet`` Methods
----------------------------

The following methods of ``WorkingSet`` objects are also available as
module-level functions in ``pkg_resources`` that apply to the default
``working_set`` instance.  Thus, you can use e.g. ``pkg_resources.require()``
as an abbreviation for ``pkg_resources.working_set.require()``:


``require(*requirements)``
    Ensure that distributions matching ``requirements`` are activated

    ``requirements`` must be a string or a (possibly-nested) sequence
    thereof, specifying the distributions and versions required.  The
    return value is a sequence of the distributions that needed to be
    activated to fulfill the requirements; all relevant distributions are
    included, even if they were already activated in this working set.

    For the syntax of requirement specifiers, see the section below on
    `Requirements Parsing`_.

    In general, it should not be necessary for you to call this method
    directly.  It's intended more for use in quick-and-dirty scripting and
    interactive interpreter hacking than for production use. If you're creating
    an actual library or application, it's strongly recommended that you create
    a "setup.py" script using ``setuptools``, and declare all your requirements
    there.  That way, tools like pip can automatically detect what requirements
    your package has, and deal with them accordingly.

    Note that calling ``require('SomePackage')`` will not install
    ``SomePackage`` if it isn't already present.  If you need to do this, you
    should use the ``resolve()`` method instead, which allows you to pass an
    ``installer`` callback that will be invoked when a needed distribution
    can't be found on the local machine.  You can then have this callback
    display a dialog, automatically download the needed distribution, or
    whatever else is appropriate for your application. See the documentation
    below on the ``resolve()`` method for more information, and also on the
    ``obtain()`` method of ``Environment`` objects.

``run_script(requires, script_name)``
    Locate distribution specified by ``requires`` and run its ``script_name``
    script.  ``requires`` must be a string containing a requirement specifier.
    (See `Requirements Parsing`_ below for the syntax.)

    The script, if found, will be executed in *the caller's globals*.  That's
    because this method is intended to be called from wrapper scripts that
    act as a proxy for the "real" scripts in a distribution.  A wrapper script
    usually doesn't need to do anything but invoke this function with the
    correct arguments.

    If you need more control over the script execution environment, you
    probably want to use the ``run_script()`` method of a ``Distribution``
    object's `Metadata API`_ instead.

``iter_entry_points(group, name=None)``
    Yield entry point objects from ``group`` matching ``name``

    If ``name`` is None, yields all entry points in ``group`` from all
    distributions in the working set, otherwise only ones matching both
    ``group`` and ``name`` are yielded.  Entry points are yielded from the active
    distributions in the order that the distributions appear in the working
    set.  (For the global ``working_set``, this should be the same as the order
    that they are listed in ``sys.path``.)  Note that within the entry points
    advertised by an individual distribution, there is no particular ordering.

    Please see the section below on `Entry Points`_ for more information.


``WorkingSet`` Methods and Attributes
-------------------------------------

These methods are used to query or manipulate the contents of a specific
working set, so they must be explicitly invoked on a particular ``WorkingSet``
instance:

``add_entry(entry)``
    Add a path item to the ``entries``, finding any distributions on it.  You
    should use this when you add additional items to ``sys.path`` and you want
    the global ``working_set`` to reflect the change.  This method is also
    called by the ``WorkingSet()`` constructor during initialization.

    This method uses ``find_distributions(entry,True)`` to find distributions
    corresponding to the path entry, and then ``add()`` them.  ``entry`` is
    always appended to the ``entries`` attribute, even if it is already
    present, however. (This is because ``sys.path`` can contain the same value
    more than once, and the ``entries`` attribute should be able to reflect
    this.)

``__contains__(dist)``
    True if ``dist`` is active in this ``WorkingSet``.  Note that only one
    distribution for a given project can be active in a given ``WorkingSet``.

``__iter__()``
    Yield distributions for non-duplicate projects in the working set.
    The yield order is the order in which the items' path entries were
    added to the working set.

``find(req)``
    Find a distribution matching ``req`` (a ``Requirement`` instance).
    If there is an active distribution for the requested project, this
    returns it, as long as it meets the version requirement specified by
    ``req``.  But, if there is an active distribution for the project and it
    does *not* meet the ``req`` requirement, ``VersionConflict`` is raised.
    If there is no active distribution for the requested project, ``None``
    is returned.

``resolve(requirements, env=None, installer=None)``
    List all distributions needed to (recursively) meet ``requirements``

    ``requirements`` must be a sequence of ``Requirement`` objects.  ``env``,
    if supplied, should be an ``Environment`` instance.  If
    not supplied, an ``Environment`` is created from the working set's
    ``entries``.  ``installer``, if supplied, will be invoked with each
    requirement that cannot be met by an already-installed distribution; it
    should return a ``Distribution`` or ``None``.  (See the ``obtain()`` method
    of `Environment Objects`_, below, for more information on the ``installer``
    argument.)

``add(dist, entry=None)``
    Add ``dist`` to working set, associated with ``entry``

    If ``entry`` is unspecified, it defaults to ``dist.location``.  On exit from
    this routine, ``entry`` is added to the end of the working set's ``.entries``
    (if it wasn't already present).

    ``dist`` is only added to the working set if it's for a project that
    doesn't already have a distribution active in the set.  If it's
    successfully added, any  callbacks registered with the ``subscribe()``
    method will be called.  (See `Receiving Change Notifications`_, below.)

    Note: ``add()`` is automatically called for you by the ``require()``
    method, so you don't normally need to use this method directly.

``entries``
    This attribute represents a "shadow" ``sys.path``, primarily useful for
    debugging.  If you are experiencing import problems, you should check
    the global ``working_set`` object's ``entries`` against ``sys.path``, to
    ensure that they match.  If they do not, then some part of your program
    is manipulating ``sys.path`` without updating the ``working_set``
    accordingly.  IMPORTANT NOTE: do not directly manipulate this attribute!
    Setting it equal to ``sys.path`` will not fix your problem, any more than
    putting black tape over an "engine warning" light will fix your car!  If
    this attribute is out of sync with ``sys.path``, it's merely an *indicator*
    of the problem, not the cause of it.


Receiving Change Notifications
------------------------------

Extensible applications and frameworks may need to receive notification when
a new distribution (such as a plug-in component) has been added to a working
set.  This is what the ``subscribe()`` method and ``add_activation_listener()``
function are for.

``subscribe(callback)``
    Invoke ``callback(distribution)`` once for each active distribution that is
    in the set now, or gets added later.  Because the callback is invoked for
    already-active distributions, you do not need to loop over the working set
    yourself to deal with the existing items; just register the callback and
    be prepared for the fact that it will be called immediately by this method.

    Note that callbacks *must not* allow exceptions to propagate, or they will
    interfere with the operation of other callbacks and possibly result in an
    inconsistent working set state.  Callbacks should use a try/except block
    to ignore, log, or otherwise process any errors, especially since the code
    that caused the callback to be invoked is unlikely to be able to handle
    the errors any better than the callback itself.

``pkg_resources.add_activation_listener()`` is an alternate spelling of
``pkg_resources.working_set.subscribe()``.


Locating Plugins
----------------

Extensible applications will sometimes have a "plugin directory" or a set of
plugin directories, from which they want to load entry points or other
metadata.  The ``find_plugins()`` method allows you to do this, by scanning an
environment for the newest version of each project that can be safely loaded
without conflicts or missing requirements.

``find_plugins(plugin_env, full_env=None, fallback=True)``
   Scan ``plugin_env`` and identify which distributions could be added to this
   working set without version conflicts or missing requirements.

   Example usage::

       distributions, errors = working_set.find_plugins(
           Environment(plugin_dirlist)
       )
       map(working_set.add, distributions)  # add plugins+libs to sys.path
       print "Couldn't load", errors        # display errors

   The ``plugin_env`` should be an ``Environment`` instance that contains only
   distributions that are in the project's "plugin directory" or directories.
   The ``full_env``, if supplied, should be an ``Environment`` instance that
   contains all currently-available distributions.

   If ``full_env`` is not supplied, one is created automatically from the
   ``WorkingSet`` this method is called on, which will typically mean that
   every directory on ``sys.path`` will be scanned for distributions.

   This method returns a 2-tuple: (``distributions``, ``error_info``), where
   ``distributions`` is a list of the distributions found in ``plugin_env`` that
   were loadable, along with any other distributions that are needed to resolve
   their dependencies.  ``error_info`` is a dictionary mapping unloadable plugin
   distributions to an exception instance describing the error that occurred.
   Usually this will be a ``DistributionNotFound`` or ``VersionConflict``
   instance.

   Most applications will use this method mainly on the master ``working_set``
   instance in ``pkg_resources``, and then immediately add the returned
   distributions to the working set so that they are available on sys.path.
   This will make it possible to find any entry points, and allow any other
   metadata tracking and hooks to be activated.

   The resolution algorithm used by ``find_plugins()`` is as follows.  First,
   the project names of the distributions present in ``plugin_env`` are sorted.
   Then, each project's eggs are tried in descending version order (i.e.,
   newest version first).

   An attempt is made to resolve each egg's dependencies. If the attempt is
   successful, the egg and its dependencies are added to the output list and to
   a temporary copy of the working set.  The resolution process continues with
   the next project name, and no older eggs for that project are tried.

   If the resolution attempt fails, however, the error is added to the error
   dictionary.  If the ``fallback`` flag is true, the next older version of the
   plugin is tried, until a working version is found.  If false, the resolution
   process continues with the next plugin project name.

   Some applications may have stricter fallback requirements than others. For
   example, an application that has a database schema or persistent objects
   may not be able to safely downgrade a version of a package. Others may want
   to ensure that a new plugin configuration is either 100% good or else
   revert to a known-good configuration.  (That is, they may wish to revert to
   a known configuration if the ``error_info`` return value is non-empty.)

   Note that this algorithm gives precedence to satisfying the dependencies of
   alphabetically prior project names in case of version conflicts. If two
   projects named "AaronsPlugin" and "ZekesPlugin" both need different versions
   of "TomsLibrary", then "AaronsPlugin" will win and "ZekesPlugin" will be
   disabled due to version conflict.


``Environment`` Objects
=======================

An "environment" is a collection of ``Distribution`` objects, usually ones
that are present and potentially importable on the current platform.
``Environment`` objects are used by ``pkg_resources`` to index available
distributions during dependency resolution.

``Environment(search_path=None, platform=get_supported_platform(), python=PY_MAJOR)``
    Create an environment snapshot by scanning ``search_path`` for distributions
    compatible with ``platform`` and ``python``.  ``search_path`` should be a
    sequence of strings such as might be used on ``sys.path``.  If a
    ``search_path`` isn't supplied, ``sys.path`` is used.

    ``platform`` is an optional string specifying the name of the platform
    that platform-specific distributions must be compatible with.  If
    unspecified, it defaults to the current platform.  ``python`` is an
    optional string naming the desired version of Python (e.g. ``'2.4'``);
    it defaults to the currently-running version.

    You may explicitly set ``platform`` (and/or ``python``) to ``None`` if you
    wish to include *all* distributions, not just those compatible with the
    running platform or Python version.

    Note that ``search_path`` is scanned immediately for distributions, and the
    resulting ``Environment`` is a snapshot of the found distributions.  It
    is not automatically updated if the system's state changes due to e.g.
    installation or removal of distributions.

``__getitem__(project_name)``
    Returns a list of distributions for the given project name, ordered
    from newest to oldest version.  (And highest to lowest format precedence
    for distributions that contain the same version of the project.)  If there
    are no distributions for the project, returns an empty list.

``__iter__()``
    Yield the unique project names of the distributions in this environment.
    The yielded names are always in lower case.

``add(dist)``
    Add ``dist`` to the environment if it matches the platform and python version
    specified at creation time, and only if the distribution hasn't already
    been added. (i.e., adding the same distribution more than once is a no-op.)

``remove(dist)``
    Remove ``dist`` from the environment.

``can_add(dist)``
    Is distribution ``dist`` acceptable for this environment?  If it's not
    compatible with the ``platform`` and ``python`` version values specified
    when the environment was created, a false value is returned.

``__add__(dist_or_env)``  (``+`` operator)
    Add a distribution or environment to an ``Environment`` instance, returning
    a *new* environment object that contains all the distributions previously
    contained by both.  The new environment will have a ``platform`` and
    ``python`` of ``None``, meaning that it will not reject any distributions
    from being added to it; it will simply accept whatever is added.  If you
    want the added items to be filtered for platform and Python version, or
    you want to add them to the *same* environment instance, you should use
    in-place addition (``+=``) instead.

``__iadd__(dist_or_env)``  (``+=`` operator)
    Add a distribution or environment to an ``Environment`` instance
    *in-place*, updating the existing instance and returning it.  The
    ``platform`` and ``python`` filter attributes take effect, so distributions
    in the source that do not have a suitable platform string or Python version
    are silently ignored.

``best_match(req, working_set, installer=None)``
    Find distribution best matching ``req`` and usable on ``working_set``

    This calls the ``find(req)`` method of the ``working_set`` to see if a
    suitable distribution is already active.  (This may raise
    ``VersionConflict`` if an unsuitable version of the project is already
    active in the specified ``working_set``.)  If a suitable distribution isn't
    active, this method returns the newest distribution in the environment
    that meets the ``Requirement`` in ``req``.  If no suitable distribution is
    found, and ``installer`` is supplied, then the result of calling
    the environment's ``obtain(req, installer)`` method will be returned.

``obtain(requirement, installer=None)``
    Obtain a distro that matches requirement (e.g. via download).  In the
    base ``Environment`` class, this routine just returns
    ``installer(requirement)``, unless ``installer`` is None, in which case
    None is returned instead.  This method is a hook that allows subclasses
    to attempt other ways of obtaining a distribution before falling back
    to the ``installer`` argument.

``scan(search_path=None)``
    Scan ``search_path`` for distributions usable on ``platform``

    Any distributions found are added to the environment.  ``search_path`` should
    be a sequence of strings such as might be used on ``sys.path``.  If not
    supplied, ``sys.path`` is used.  Only distributions conforming to
    the platform/python version defined at initialization are added.  This
    method is a shortcut for using the ``find_distributions()`` function to
    find the distributions from each item in ``search_path``, and then calling
    ``add()`` to add each one to the environment.


``Requirement`` Objects
=======================

``Requirement`` objects express what versions of a project are suitable for
some purpose.  These objects (or their string form) are used by various
``pkg_resources`` APIs in order to find distributions that a script or
distribution needs.


Requirements Parsing
--------------------

``parse_requirements(s)``
    Yield ``Requirement`` objects for a string or iterable of lines.  Each
    requirement must start on a new line.  See below for syntax.

``Requirement.parse(s)``
    Create a ``Requirement`` object from a string or iterable of lines.  A
    ``ValueError`` is raised if the string or lines do not contain a valid
    requirement specifier, or if they contain more than one specifier.  (To
    parse multiple specifiers from a string or iterable of strings, use
    ``parse_requirements()`` instead.)

    The syntax of a requirement specifier is defined in full in PEP 508.

    Some examples of valid requirement specifiers::

        FooProject >= 1.2
        Fizzy [foo, bar]
        PickyThing>1.6,<=1.9,!=1.8.6
        SomethingWhoseVersionIDontCareAbout
        SomethingWithMarker[foo]>1.0;python_version<"2.7"

    The project name is the only required portion of a requirement string, and
    if it's the only thing supplied, the requirement will accept any version
    of that project.

    The "extras" in a requirement are used to request optional features of a
    project, that may require additional project distributions in order to
    function.  For example, if the hypothetical "Report-O-Rama" project offered
    optional PDF support, it might require an additional library in order to
    provide that support.  Thus, a project needing Report-O-Rama's PDF features
    could use a requirement of ``Report-O-Rama[PDF]`` to request installation
    or activation of both Report-O-Rama and any libraries it needs in order to
    provide PDF support.  For example, you could use::

        pip install Report-O-Rama[PDF]

    To install the necessary packages using pip, or call
    ``pkg_resources.require('Report-O-Rama[PDF]')`` to add the necessary
    distributions to sys.path at runtime.

    The "markers" in a requirement are used to specify when a requirement
    should be installed -- the requirement will be installed if the marker
    evaluates as true in the current environment. For example, specifying
    ``argparse;python_version<"3.0"`` will not install in an Python 3
    environment, but will in a Python 2 environment.

``Requirement`` Methods and Attributes
--------------------------------------

``__contains__(dist_or_version)``
    Return true if ``dist_or_version`` fits the criteria for this requirement.
    If ``dist_or_version`` is a ``Distribution`` object, its project name must
    match the requirement's project name, and its version must meet the
    requirement's version criteria.  If ``dist_or_version`` is a string, it is
    parsed using the ``parse_version()`` utility function.  Otherwise, it is
    assumed to be an already-parsed version.

    The ``Requirement`` object's version specifiers (``.specs``) are internally
    sorted into ascending version order, and used to establish what ranges of
    versions are acceptable.  Adjacent redundant conditions are effectively
    consolidated (e.g. ``">1, >2"`` produces the same results as ``">2"``, and
    ``"<2,<3"`` produces the same results as ``"<2"``). ``"!="`` versions are
    excised from the ranges they fall within.  The version being tested for
    acceptability is then checked for membership in the resulting ranges.

``__eq__(other_requirement)``
    A requirement compares equal to another requirement if they have
    case-insensitively equal project names, version specifiers, and "extras".
    (The order that extras and version specifiers are in is also ignored.)
    Equal requirements also have equal hashes, so that requirements can be
    used in sets or as dictionary keys.

``__str__()``
    The string form of a ``Requirement`` is a string that, if passed to
    ``Requirement.parse()``, would return an equal ``Requirement`` object.

``project_name``
    The name of the required project

``key``
    An all-lowercase version of the ``project_name``, useful for comparison
    or indexing.

``extras``
    A tuple of names of "extras" that this requirement calls for.  (These will
    be all-lowercase and normalized using the ``safe_extra()`` parsing utility
    function, so they may not exactly equal the extras the requirement was
    created with.)

``specs``
    A list of ``(op,version)`` tuples, sorted in ascending parsed-version
    order.  The ``op`` in each tuple is a comparison operator, represented as
    a string.  The ``version`` is the (unparsed) version number.

``marker``
    An instance of ``packaging.markers.Marker`` that allows evaluation
    against the current environment. May be None if no marker specified.

``url``
    The location to download the requirement from if specified.

Entry Points
============

Entry points are a simple way for distributions to "advertise" Python objects
(such as functions or classes) for use by other distributions.  Extensible
applications and frameworks can search for entry points with a particular name
or group, either from a specific distribution or from all active distributions
on sys.path, and then inspect or load the advertised objects at will.

Entry points belong to "groups" which are named with a dotted name similar to
a Python package or module name.  For example, the ``setuptools`` package uses
an entry point named ``distutils.commands`` in order to find commands defined
by distutils extensions.  ``setuptools`` treats the names of entry points
defined in that group as the acceptable commands for a setup script.

In a similar way, other packages can define their own entry point groups,
either using dynamic names within the group (like ``distutils.commands``), or
possibly using predefined names within the group.  For example, a blogging
framework that offers various pre- or post-publishing hooks might define an
entry point group and look for entry points named "pre_process" and
"post_process" within that group.

To advertise an entry point, a project needs to use ``setuptools`` and provide
an ``entry_points`` argument to ``setup()`` in its setup script, so that the
entry points will be included in the distribution's metadata.  For more
details, see :ref:`Advertising Behavior<dynamic discovery of services and plugins>`.

Each project distribution can advertise at most one entry point of a given
name within the same entry point group.  For example, a distutils extension
could advertise two different ``distutils.commands`` entry points, as long as
they had different names.  However, there is nothing that prevents *different*
projects from advertising entry points of the same name in the same group.  In
some cases, this is a desirable thing, since the application or framework that
uses the entry points may be calling them as hooks, or in some other way
combining them.  It is up to the application or framework to decide what to do
if multiple distributions advertise an entry point; some possibilities include
using both entry points, displaying an error message, using the first one found
in sys.path order, etc.


Convenience API
---------------

In the following functions, the ``dist`` argument can be a ``Distribution``
instance, a ``Requirement`` instance, or a string specifying a requirement
(i.e. project name, version, etc.).  If the argument is a string or
``Requirement``, the specified distribution is located (and added to sys.path
if not already present).  An error will be raised if a matching distribution is
not available.

The ``group`` argument should be a string containing a dotted identifier,
identifying an entry point group.  If you are defining an entry point group,
you should include some portion of your package's name in the group name so as
to avoid collision with other packages' entry point groups.

``load_entry_point(dist, group, name)``
    Load the named entry point from the specified distribution, or raise
    ``ImportError``.

``get_entry_info(dist, group, name)``
    Return an ``EntryPoint`` object for the given ``group`` and ``name`` from
    the specified distribution.  Returns ``None`` if the distribution has not
    advertised a matching entry point.

``get_entry_map(dist, group=None)``
    Return the distribution's entry point map for ``group``, or the full entry
    map for the distribution.  This function always returns a dictionary,
    even if the distribution advertises no entry points.  If ``group`` is given,
    the dictionary maps entry point names to the corresponding ``EntryPoint``
    object.  If ``group`` is None, the dictionary maps group names to
    dictionaries that then map entry point names to the corresponding
    ``EntryPoint`` instance in that group.

``iter_entry_points(group, name=None)``
    Yield entry point objects from ``group`` matching ``name``.

    If ``name`` is None, yields all entry points in ``group`` from all
    distributions in the working set on sys.path, otherwise only ones matching
    both ``group`` and ``name`` are yielded.  Entry points are yielded from
    the active distributions in the order that the distributions appear on
    sys.path.  (Within entry points for a particular distribution, however,
    there is no particular ordering.)

    (This API is actually a method of the global ``working_set`` object; see
    the section above on `Basic WorkingSet Methods`_ for more information.)


Creating and Parsing
--------------------

``EntryPoint(name, module_name, attrs=(), extras=(), dist=None)``
    Create an ``EntryPoint`` instance.  ``name`` is the entry point name.  The
    ``module_name`` is the (dotted) name of the module containing the advertised
    object.  ``attrs`` is an optional tuple of names to look up from the
    module to obtain the advertised object.  For example, an ``attrs`` of
    ``("foo","bar")`` and a ``module_name`` of ``"baz"`` would mean that the
    advertised object could be obtained by the following code::

        import baz
        advertised_object = baz.foo.bar

    The ``extras`` are an optional tuple of "extra feature" names that the
    distribution needs in order to provide this entry point.  When the
    entry point is loaded, these extra features are looked up in the ``dist``
    argument to find out what other distributions may need to be activated
    on sys.path; see the ``load()`` method for more details.  The ``extras``
    argument is only meaningful if ``dist`` is specified.  ``dist`` must be
    a ``Distribution`` instance.

``EntryPoint.parse(src, dist=None)`` (classmethod)
    Parse a single entry point from string ``src``

    Entry point syntax follows the form::

        name = some.module:some.attr [extra1,extra2]

    The entry name and module name are required, but the ``:attrs`` and
    ``[extras]`` parts are optional, as is the whitespace shown between
    some of the items.  The ``dist`` argument is passed through to the
    ``EntryPoint()`` constructor, along with the other values parsed from
    ``src``.

``EntryPoint.parse_group(group, lines, dist=None)`` (classmethod)
    Parse ``lines`` (a string or sequence of lines) to create a dictionary
    mapping entry point names to ``EntryPoint`` objects.  ``ValueError`` is
    raised if entry point names are duplicated, if ``group`` is not a valid
    entry point group name, or if there are any syntax errors.  (Note: the
    ``group`` parameter is used only for validation and to create more
    informative error messages.)  If ``dist`` is provided, it will be used to
    set the ``dist`` attribute of the created ``EntryPoint`` objects.

``EntryPoint.parse_map(data, dist=None)`` (classmethod)
    Parse ``data`` into a dictionary mapping group names to dictionaries mapping
    entry point names to ``EntryPoint`` objects.  If ``data`` is a dictionary,
    then the keys are used as group names and the values are passed to
    ``parse_group()`` as the ``lines`` argument.  If ``data`` is a string or
    sequence of lines, it is first split into .ini-style sections (using
    the ``split_sections()`` utility function) and the section names are used
    as group names.  In either case, the ``dist`` argument is passed through to
    ``parse_group()`` so that the entry points will be linked to the specified
    distribution.


``EntryPoint`` Objects
----------------------

For simple introspection, ``EntryPoint`` objects have attributes that
correspond exactly to the constructor argument names: ``name``,
``module_name``, ``attrs``, ``extras``, and ``dist`` are all available.  In
addition, the following methods are provided:

``load()``
    Load the entry point, returning the advertised Python object.  Effectively
    calls ``self.require()`` then returns ``self.resolve()``.

``require(env=None, installer=None)``
    Ensure that any "extras" needed by the entry point are available on
    sys.path.  ``UnknownExtra`` is raised if the ``EntryPoint`` has ``extras``,
    but no ``dist``, or if the named extras are not defined by the
    distribution.  If ``env`` is supplied, it must be an ``Environment``, and it
    will be used to search for needed distributions if they are not already
    present on sys.path.  If ``installer`` is supplied, it must be a callable
    taking a ``Requirement`` instance and returning a matching importable
    ``Distribution`` instance or None.

``resolve()``
    Resolve the entry point from its module and attrs, returning the advertised
    Python object. Raises ``ImportError`` if it cannot be obtained.

``__str__()``
    The string form of an ``EntryPoint`` is a string that could be passed to
    ``EntryPoint.parse()`` to produce an equivalent ``EntryPoint``.


``Distribution`` Objects
========================

``Distribution`` objects represent collections of Python code that may or may
not be importable, and may or may not have metadata and resources associated
with them.  Their metadata may include information such as what other projects
the distribution depends on, what entry points the distribution advertises, and
so on.


Getting or Creating Distributions
---------------------------------

Most commonly, you'll obtain ``Distribution`` objects from a ``WorkingSet`` or
an ``Environment``.  (See the sections above on `WorkingSet Objects`_ and
`Environment Objects`_, which are containers for active distributions and
available distributions, respectively.)  You can also obtain ``Distribution``
objects from one of these high-level APIs:

``find_distributions(path_item, only=False)``
    Yield distributions accessible via ``path_item``.  If ``only`` is true, yield
    only distributions whose ``location`` is equal to ``path_item``.  In other
    words, if ``only`` is true, this yields any distributions that would be
    importable if ``path_item`` were on ``sys.path``.  If ``only`` is false, this
    also yields distributions that are "in" or "under" ``path_item``, but would
    not be importable unless their locations were also added to ``sys.path``.

``get_distribution(dist_spec)``
    Return a ``Distribution`` object for a given ``Requirement`` or string.
    If ``dist_spec`` is already a ``Distribution`` instance, it is returned.
    If it is a ``Requirement`` object or a string that can be parsed into one,
    it is used to locate and activate a matching distribution, which is then
    returned.

However, if you're creating specialized tools for working with distributions,
or creating a new distribution format, you may also need to create
``Distribution`` objects directly, using one of the three constructors below.

These constructors all take an optional ``metadata`` argument, which is used to
access any resources or metadata associated with the distribution.  ``metadata``
must be an object that implements the ``IResourceProvider`` interface, or None.
If it is None, an ``EmptyProvider`` is used instead.  ``Distribution`` objects
implement both the `IResourceProvider`_ and `IMetadataProvider Methods`_ by
delegating them to the ``metadata`` object.

``Distribution.from_location(location, basename, metadata=None, **kw)`` (classmethod)
    Create a distribution for ``location``, which must be a string such as a
    URL, filename, or other string that might be used on ``sys.path``.
    ``basename`` is a string naming the distribution, like ``Foo-1.2-py2.4.egg``.
    If ``basename`` ends with ``.egg``, then the project's name, version, python
    version and platform are extracted from the filename and used to set those
    properties of the created distribution.  Any additional keyword arguments
    are forwarded to the ``Distribution()`` constructor.

``Distribution.from_filename(filename, metadata=None**kw)`` (classmethod)
    Create a distribution by parsing a local filename.  This is a shorter way
    of saying  ``Distribution.from_location(normalize_path(filename),
    os.path.basename(filename), metadata)``.  In other words, it creates a
    distribution whose location is the normalize form of the filename, parsing
    name and version information from the base portion of the filename.  Any
    additional keyword arguments are forwarded to the ``Distribution()``
    constructor.

``Distribution(location,metadata,project_name,version,py_version,platform,precedence)``
    Create a distribution by setting its properties.  All arguments are
    optional and default to None, except for ``py_version`` (which defaults to
    the current Python version) and ``precedence`` (which defaults to
    ``EGG_DIST``; for more details see ``precedence`` under `Distribution
    Attributes`_ below).  Note that it's usually easier to use the
    ``from_filename()`` or ``from_location()`` constructors than to specify
    all these arguments individually.


``Distribution`` Attributes
---------------------------

location
    A string indicating the distribution's location.  For an importable
    distribution, this is the string that would be added to ``sys.path`` to
    make it actively importable.  For non-importable distributions, this is
    simply a filename, URL, or other way of locating the distribution.

project_name
    A string, naming the project that this distribution is for.  Project names
    are defined by a project's setup script, and they are used to identify
    projects on PyPI.  When a ``Distribution`` is constructed, the
    ``project_name`` argument is passed through the ``safe_name()`` utility
    function to filter out any unacceptable characters.

key
    ``dist.key`` is short for ``dist.project_name.lower()``.  It's used for
    case-insensitive comparison and indexing of distributions by project name.

extras
    A list of strings, giving the names of extra features defined by the
    project's dependency list (the ``extras_require`` argument specified in
    the project's setup script).

version
    A string denoting what release of the project this distribution contains.
    When a ``Distribution`` is constructed, the ``version`` argument is passed
    through the ``safe_version()`` utility function to filter out any
    unacceptable characters.  If no ``version`` is specified at construction
    time, then attempting to access this attribute later will cause the
    ``Distribution`` to try to discover its version by reading its ``PKG-INFO``
    metadata file.  If ``PKG-INFO`` is unavailable or can't be parsed,
    ``ValueError`` is raised.

parsed_version
    The ``parsed_version`` is an object representing a "parsed" form of the
    distribution's ``version``.  ``dist.parsed_version`` is a shortcut for
    calling ``parse_version(dist.version)``.  It is used to compare or sort
    distributions by version.  (See the `Parsing Utilities`_ section below for
    more information on the ``parse_version()`` function.)  Note that accessing
    ``parsed_version`` may result in a ``ValueError`` if the ``Distribution``
    was constructed without a ``version`` and without ``metadata`` capable of
    supplying the missing version info.

py_version
    The major/minor Python version the distribution supports, as a string.
    For example, "2.7" or "3.4".  The default is the current version of Python.

platform
    A string representing the platform the distribution is intended for, or
    ``None`` if the distribution is "pure Python" and therefore cross-platform.
    See `Platform Utilities`_ below for more information on platform strings.

precedence
    A distribution's ``precedence`` is used to determine the relative order of
    two distributions that have the same ``project_name`` and
    ``parsed_version``.  The default precedence is ``pkg_resources.EGG_DIST``,
    which is the highest (i.e. most preferred) precedence.  The full list
    of predefined precedences, from most preferred to least preferred, is:
    ``EGG_DIST``, ``BINARY_DIST``, ``SOURCE_DIST``, ``CHECKOUT_DIST``, and
    ``DEVELOP_DIST``.  Normally, precedences other than ``EGG_DIST`` are used
    only by the ``setuptools.package_index`` module, when sorting distributions
    found in a package index to determine their suitability for installation.
    "System" and "Development" eggs (i.e., ones that use the ``.egg-info``
    format), however, are automatically given a precedence of ``DEVELOP_DIST``.



``Distribution`` Methods
------------------------

``activate(path=None)``
    Ensure distribution is importable on ``path``.  If ``path`` is None,
    ``sys.path`` is used instead.  This ensures that the distribution's
    ``location`` is in the ``path`` list, and it also performs any necessary
    namespace package fixups or declarations.  (That is, if the distribution
    contains namespace packages, this method ensures that they are declared,
    and that the distribution's contents for those namespace packages are
    merged with the contents provided by any other active distributions.  See
    the section above on `Namespace Package Support`_ for more information.)

    ``pkg_resources`` adds a notification callback to the global ``working_set``
    that ensures this method is called whenever a distribution is added to it.
    Therefore, you should not normally need to explicitly call this method.
    (Note that this means that namespace packages on ``sys.path`` are always
    imported as soon as ``pkg_resources`` is, which is another reason why
    namespace packages should not contain any code or import statements.)

``as_requirement()``
    Return a ``Requirement`` instance that matches this distribution's project
    name and version.

``requires(extras=())``
    List the ``Requirement`` objects that specify this distribution's
    dependencies.  If ``extras`` is specified, it should be a sequence of names
    of "extras" defined by the distribution, and the list returned will then
    include any dependencies needed to support the named "extras".

``clone(**kw)``
    Create a copy of the distribution.  Any supplied keyword arguments override
    the corresponding argument to the ``Distribution()`` constructor, allowing
    you to change some of the copied distribution's attributes.

``egg_name()``
    Return what this distribution's standard filename should be, not including
    the ".egg" extension.  For example, a distribution for project "Foo"
    version 1.2 that runs on Python 2.3 for Windows would have an ``egg_name()``
    of ``Foo-1.2-py2.3-win32``.  Any dashes in the name or version are
    converted to underscores.  (``Distribution.from_location()`` will convert
    them back when parsing a ".egg" file name.)

``__cmp__(other)``, ``__hash__()``
    Distribution objects are hashed and compared on the basis of their parsed
    version and precedence, followed by their key (lowercase project name),
    location, Python version, and platform.

The following methods are used to access ``EntryPoint`` objects advertised
by the distribution.  See the section above on `Entry Points`_ for more
detailed information about these operations:

``get_entry_info(group, name)``
    Return the ``EntryPoint`` object for ``group`` and ``name``, or None if no
    such point is advertised by this distribution.

``get_entry_map(group=None)``
    Return the entry point map for ``group``.  If ``group`` is None, return
    a dictionary mapping group names to entry point maps for all groups.
    (An entry point map is a dictionary of entry point names to ``EntryPoint``
    objects.)

``load_entry_point(group, name)``
    Short for ``get_entry_info(group, name).load()``.  Returns the object
    advertised by the named entry point, or raises ``ImportError`` if
    the entry point isn't advertised by this distribution, or there is some
    other import problem.

In addition to the above methods, ``Distribution`` objects also implement all
of the `IResourceProvider`_ and `IMetadataProvider Methods`_ (which are
documented in later sections):

* ``has_metadata(name)``
* ``metadata_isdir(name)``
* ``metadata_listdir(name)``
* ``get_metadata(name)``
* ``get_metadata_lines(name)``
* ``run_script(script_name, namespace)``
* ``get_resource_filename(manager, resource_name)``
* ``get_resource_stream(manager, resource_name)``
* ``get_resource_string(manager, resource_name)``
* ``has_resource(resource_name)``
* ``resource_isdir(resource_name)``
* ``resource_listdir(resource_name)``

If the distribution was created with a ``metadata`` argument, these resource and
metadata access methods are all delegated to that ``metadata`` provider.
Otherwise, they are delegated to an ``EmptyProvider``, so that the distribution
will appear to have no resources or metadata.  This delegation approach is used
so that supporting custom importers or new distribution formats can be done
simply by creating an appropriate `IResourceProvider`_ implementation; see the
section below on `Supporting Custom Importers`_ for more details.

.. _ResourceManager API:

``ResourceManager`` API
=======================

The ``ResourceManager`` class provides uniform access to package resources,
whether those resources exist as files and directories or are compressed in
an archive of some kind.

Normally, you do not need to create or explicitly manage ``ResourceManager``
instances, as the ``pkg_resources`` module creates a global instance for you,
and makes most of its methods available as top-level names in the
``pkg_resources`` module namespace.  So, for example, this code actually
calls the ``resource_string()`` method of the global ``ResourceManager``::

    import pkg_resources
    my_data = pkg_resources.resource_string(__name__, "foo.dat")

Thus, you can use the APIs below without needing an explicit
``ResourceManager`` instance; just import and use them as needed.


Basic Resource Access
---------------------

In the following methods, the ``package_or_requirement`` argument may be either
a Python package/module name (e.g. ``foo.bar``) or a ``Requirement`` instance.
If it is a package or module name, the named module or package must be
importable (i.e., be in a distribution or directory on ``sys.path``), and the
``resource_name`` argument is interpreted relative to the named package.  (Note
that if a module name is used, then the resource name is relative to the
package immediately containing the named module.  Also, you should not use use
a namespace package name, because a namespace package can be spread across
multiple distributions, and is therefore ambiguous as to which distribution
should be searched for the resource.)

If it is a ``Requirement``, then the requirement is automatically resolved
(searching the current ``Environment`` if necessary) and a matching
distribution is added to the ``WorkingSet`` and ``sys.path`` if one was not
already present.  (Unless the ``Requirement`` can't be satisfied, in which
case an exception is raised.)  The ``resource_name`` argument is then interpreted
relative to the root of the identified distribution; i.e. its first path
segment will be treated as a peer of the top-level modules or packages in the
distribution.

Note that resource names must be ``/``-separated paths rooted at the package,
cannot contain relative names like ``".."``, and cannot be absolute.  Do *not* use
``os.path`` routines to manipulate resource paths, as they are *not* filesystem
paths.

``resource_exists(package_or_requirement, resource_name)``
    Does the named resource exist?  Return ``True`` or ``False`` accordingly.

``resource_stream(package_or_requirement, resource_name)``
    Return a readable file-like object for the specified resource; it may be
    an actual file, a ``StringIO``, or some similar object.  The stream is
    in "binary mode", in the sense that whatever bytes are in the resource
    will be read as-is.

``resource_string(package_or_requirement, resource_name)``
    Return the specified resource as ``bytes``.  The resource is read in
    binary fashion, such that the returned string contains exactly the bytes
    that are stored in the resource.

``resource_isdir(package_or_requirement, resource_name)``
    Is the named resource a directory?  Return ``True`` or ``False``
    accordingly.

``resource_listdir(package_or_requirement, resource_name)``
    List the contents of the named resource directory, just like ``os.listdir``
    except that it works even if the resource is in a zipfile.

Note that only ``resource_exists()`` and ``resource_isdir()`` are insensitive
as to the resource type.  You cannot use ``resource_listdir()`` on a file
resource, and you can't use ``resource_string()`` or ``resource_stream()`` on
directory resources.  Using an inappropriate method for the resource type may
result in an exception or undefined behavior, depending on the platform and
distribution format involved.


Resource Extraction
-------------------

``resource_filename(package_or_requirement, resource_name)``
    Sometimes, it is not sufficient to access a resource in string or stream
    form, and a true filesystem filename is needed.  In such cases, you can
    use this method (or module-level function) to obtain a filename for a
    resource.  If the resource is in an archive distribution (such as a zipped
    egg), it will be extracted to a cache directory, and the filename within
    the cache will be returned.  If the named resource is a directory, then
    all resources within that directory (including subdirectories) are also
    extracted.  If the named resource is a C extension or "eager resource"
    (see the ``setuptools`` documentation for details), then all C extensions
    and eager resources are extracted at the same time.

    Archived resources are extracted to a cache location that can be managed by
    the following two methods:

``set_extraction_path(path)``
    Set the base path where resources will be extracted to, if needed.

    If you do not call this routine before any extractions take place, the
    path defaults to the return value of ``get_default_cache()``.  (Which is
    based on the ``PYTHON_EGG_CACHE`` environment variable, with various
    platform-specific fallbacks.  See that routine's documentation for more
    details.)

    Resources are extracted to subdirectories of this path based upon
    information given by the resource provider.  You may set this to a
    temporary directory, but then you must call ``cleanup_resources()`` to
    delete the extracted files when done.  There is no guarantee that
    ``cleanup_resources()`` will be able to remove all extracted files.  (On
    Windows, for example, you can't unlink .pyd or .dll files that are still
    in use.)

    Note that you may not change the extraction path for a given resource
    manager once resources have been extracted, unless you first call
    ``cleanup_resources()``.

``cleanup_resources(force=False)``
    Delete all extracted resource files and directories, returning a list
    of the file and directory names that could not be successfully removed.
    This function does not have any concurrency protection, so it should
    generally only be called when the extraction path is a temporary
    directory exclusive to a single process.  This method is not
    automatically called; you must call it explicitly or register it as an
    ``atexit`` function if you wish to ensure cleanup of a temporary
    directory used for extractions.


"Provider" Interface
--------------------

If you are implementing an ``IResourceProvider`` and/or ``IMetadataProvider``
for a new distribution archive format, you may need to use the following
``IResourceManager`` methods to coordinate extraction of resources to the
filesystem.  If you're not implementing an archive format, however, you have
no need to use these methods.  Unlike the other methods listed above, they are
*not* available as top-level functions tied to the global ``ResourceManager``;
you must therefore have an explicit ``ResourceManager`` instance to use them.

``get_cache_path(archive_name, names=())``
    Return absolute location in cache for ``archive_name`` and ``names``

    The parent directory of the resulting path will be created if it does
    not already exist.  ``archive_name`` should be the base filename of the
    enclosing egg (which may not be the name of the enclosing zipfile!),
    including its ".egg" extension.  ``names``, if provided, should be a
    sequence of path name parts "under" the egg's extraction location.

    This method should only be called by resource providers that need to
    obtain an extraction location, and only for names they intend to
    extract, as it tracks the generated names for possible cleanup later.

``extraction_error()``
    Raise an ``ExtractionError`` describing the active exception as interfering
    with the extraction process.  You should call this if you encounter any
    OS errors extracting the file to the cache path; it will format the
    operating system exception for you, and add other information to the
    ``ExtractionError`` instance that may be needed by programs that want to
    wrap or handle extraction errors themselves.

``postprocess(tempname, filename)``
    Perform any platform-specific postprocessing of ``tempname``.
    Resource providers should call this method ONLY after successfully
    extracting a compressed resource.  They must NOT call it on resources
    that are already in the filesystem.

    ``tempname`` is the current (temporary) name of the file, and ``filename``
    is the name it will be renamed to by the caller after this routine
    returns.


Metadata API
============

The metadata API is used to access metadata resources bundled in a pluggable
distribution.  Metadata resources are virtual files or directories containing
information about the distribution, such as might be used by an extensible
application or framework to connect "plugins".  Like other kinds of resources,
metadata resource names are ``/``-separated and should not contain ``..`` or
begin with a ``/``.  You should not use ``os.path`` routines to manipulate
resource paths.

The metadata API is provided by objects implementing the ``IMetadataProvider``
or ``IResourceProvider`` interfaces.  ``Distribution`` objects implement this
interface, as do objects returned by the ``get_provider()`` function:

``get_provider(package_or_requirement)``
    If a package name is supplied, return an ``IResourceProvider`` for the
    package.  If a ``Requirement`` is supplied, resolve it by returning a
    ``Distribution`` from the current working set (searching the current
    ``Environment`` if necessary and adding the newly found ``Distribution``
    to the working set).  If the named package can't be imported, or the
    ``Requirement`` can't be satisfied, an exception is raised.

    NOTE: if you use a package name rather than a ``Requirement``, the object
    you get back may not be a pluggable distribution, depending on the method
    by which the package was installed.  In particular, "development" packages
    and "single-version externally-managed" packages do not have any way to
    map from a package name to the corresponding project's metadata.  Do not
    write code that passes a package name to ``get_provider()`` and then tries
    to retrieve project metadata from the returned object.  It may appear to
    work when the named package is in an ``.egg`` file or directory, but
    it will fail in other installation scenarios.  If you want project
    metadata, you need to ask for a *project*, not a package.


``IMetadataProvider`` Methods
-----------------------------

The methods provided by objects (such as ``Distribution`` instances) that
implement the ``IMetadataProvider`` or ``IResourceProvider`` interfaces are:

``has_metadata(name)``
    Does the named metadata resource exist?

``metadata_isdir(name)``
    Is the named metadata resource a directory?

``metadata_listdir(name)``
    List of metadata names in the directory (like ``os.listdir()``)

``get_metadata(name)``
    Return the named metadata resource as a string.  The data is read in binary
    mode; i.e., the exact bytes of the resource file are returned.

``get_metadata_lines(name)``
    Yield named metadata resource as list of non-blank non-comment lines.  This
    is short for calling ``yield_lines(provider.get_metadata(name))``.  See the
    section on `yield_lines()`_ below for more information on the syntax it
    recognizes.

``run_script(script_name, namespace)``
    Execute the named script in the supplied namespace dictionary.  Raises
    ``ResolutionError`` if there is no script by that name in the ``scripts``
    metadata directory.  ``namespace`` should be a Python dictionary, usually
    a module dictionary if the script is being run as a module.


Exceptions
==========

``pkg_resources`` provides a simple exception hierarchy for problems that may
occur when processing requests to locate and activate packages::

    ResolutionError
        DistributionNotFound
        VersionConflict
        UnknownExtra

    ExtractionError

``ResolutionError``
    This class is used as a base class for the other three exceptions, so that
    you can catch all of them with a single "except" clause.  It is also raised
    directly for miscellaneous requirement-resolution problems like trying to
    run a script that doesn't exist in the distribution it was requested from.

``DistributionNotFound``
    A distribution needed to fulfill a requirement could not be found.

``VersionConflict``
    The requested version of a project conflicts with an already-activated
    version of the same project.

``UnknownExtra``
    One of the "extras" requested was not recognized by the distribution it
    was requested from.

``ExtractionError``
    A problem occurred extracting a resource to the Python Egg cache.  The
    following attributes are available on instances of this exception:

    manager
        The resource manager that raised this exception

    cache_path
        The base directory for resource extraction

    original_error
        The exception instance that caused extraction to fail


Supporting Custom Importers
===========================

By default, ``pkg_resources`` supports normal filesystem imports, and
``zipimport`` importers.  If you wish to use the ``pkg_resources`` features
with other (PEP 302-compatible) importers or module loaders, you may need to
register various handlers and support functions using these APIs:

``register_finder(importer_type, distribution_finder)``
    Register ``distribution_finder`` to find distributions in ``sys.path`` items.
    ``importer_type`` is the type or class of a PEP 302 "Importer" (``sys.path``
    item handler), and ``distribution_finder`` is a callable that, when passed a
    path item, the importer instance, and an ``only`` flag, yields
    ``Distribution`` instances found under that path item.  (The ``only`` flag,
    if true, means the finder should yield only ``Distribution`` objects whose
    ``location`` is equal to the path item provided.)

    See the source of the ``pkg_resources.find_on_path`` function for an
    example finder function.

``register_loader_type(loader_type, provider_factory)``
    Register ``provider_factory`` to make ``IResourceProvider`` objects for
    ``loader_type``.  ``loader_type`` is the type or class of a PEP 302
    ``module.__loader__``, and ``provider_factory`` is a function that, when
    passed a module object, returns an `IResourceProvider`_ for that module,
    allowing it to be used with the `ResourceManager API`_.

``register_namespace_handler(importer_type, namespace_handler)``
    Register ``namespace_handler`` to declare namespace packages for the given
    ``importer_type``.  ``importer_type`` is the type or class of a PEP 302
    "importer" (sys.path item handler), and ``namespace_handler`` is a callable
    with a signature like this::

        def namespace_handler(importer, path_entry, moduleName, module):
            # return a path_entry to use for child packages

    Namespace handlers are only called if the relevant importer object has
    already agreed that it can handle the relevant path item.  The handler
    should only return a subpath if the module ``__path__`` does not already
    contain an equivalent subpath.  Otherwise, it should return None.

    For an example namespace handler, see the source of the
    ``pkg_resources.file_ns_handler`` function, which is used for both zipfile
    importing and regular importing.


IResourceProvider
-----------------

``IResourceProvider`` is an abstract class that documents what methods are
required of objects returned by a ``provider_factory`` registered with
``register_loader_type()``.  ``IResourceProvider`` is a subclass of
``IMetadataProvider``, so objects that implement this interface must also
implement all of the `IMetadataProvider Methods`_ as well as the methods
shown here.  The ``manager`` argument to the methods below must be an object
that supports the full `ResourceManager API`_ documented above.

``get_resource_filename(manager, resource_name)``
    Return a true filesystem path for ``resource_name``, coordinating the
    extraction with ``manager``, if the resource must be unpacked to the
    filesystem.

``get_resource_stream(manager, resource_name)``
    Return a readable file-like object for ``resource_name``.

``get_resource_string(manager, resource_name)``
    Return a string containing the contents of ``resource_name``.

``has_resource(resource_name)``
    Does the package contain the named resource?

``resource_isdir(resource_name)``
    Is the named resource a directory?  Return a false value if the resource
    does not exist or is not a directory.

``resource_listdir(resource_name)``
    Return a list of the contents of the resource directory, ala
    ``os.listdir()``.  Requesting the contents of a non-existent directory may
    raise an exception.

Note, by the way, that your provider classes need not (and should not) subclass
``IResourceProvider`` or ``IMetadataProvider``!  These classes exist solely
for documentation purposes and do not provide any useful implementation code.
You may instead wish to subclass one of the `built-in resource providers`_.


Built-in Resource Providers
---------------------------

``pkg_resources`` includes several provider classes that are automatically used
where appropriate.  Their inheritance tree looks like this::

    NullProvider
        EggProvider
            DefaultProvider
                PathMetadata
            ZipProvider
                EggMetadata
        EmptyProvider
            FileMetadata


``NullProvider``
    This provider class is just an abstract base that provides for common
    provider behaviors (such as running scripts), given a definition for just
    a few abstract methods.

``EggProvider``
    This provider class adds in some egg-specific features that are common
    to zipped and unzipped eggs.

``DefaultProvider``
    This provider class is used for unpacked eggs and "plain old Python"
    filesystem modules.

``ZipProvider``
    This provider class is used for all zipped modules, whether they are eggs
    or not.

``EmptyProvider``
    This provider class always returns answers consistent with a provider that
    has no metadata or resources.  ``Distribution`` objects created without
    a ``metadata`` argument use an instance of this provider class instead.
    Since all ``EmptyProvider`` instances are equivalent, there is no need
    to have more than one instance.  ``pkg_resources`` therefore creates a
    global instance of this class under the name ``empty_provider``, and you
    may use it if you have need of an ``EmptyProvider`` instance.

``PathMetadata(path, egg_info)``
    Create an ``IResourceProvider`` for a filesystem-based distribution, where
    ``path`` is the filesystem location of the importable modules, and ``egg_info``
    is the filesystem location of the distribution's metadata directory.
    ``egg_info`` should usually be the ``EGG-INFO`` subdirectory of ``path`` for an
    "unpacked egg", and a ``ProjectName.egg-info`` subdirectory of ``path`` for
    a "development egg".  However, other uses are possible for custom purposes.

``EggMetadata(zipimporter)``
    Create an ``IResourceProvider`` for a zipfile-based distribution.  The
    ``zipimporter`` should be a ``zipimport.zipimporter`` instance, and may
    represent a "basket" (a zipfile containing multiple ".egg" subdirectories)
    a specific egg *within* a basket, or a zipfile egg (where the zipfile
    itself is a ".egg").  It can also be a combination, such as a zipfile egg
    that also contains other eggs.

``FileMetadata(path_to_pkg_info)``
    Create an ``IResourceProvider`` that provides exactly one metadata
    resource: ``PKG-INFO``.  The supplied path should be a distutils PKG-INFO
    file.  This is basically the same as an ``EmptyProvider``, except that
    requests for ``PKG-INFO`` will be answered using the contents of the
    designated file.  (This provider is used to wrap ``.egg-info`` files
    installed by vendor-supplied system packages.)


Utility Functions
=================

In addition to its high-level APIs, ``pkg_resources`` also includes several
generally-useful utility routines.  These routines are used to implement the
high-level APIs, but can also be quite useful by themselves.


Parsing Utilities
-----------------

``parse_version(version)``
    Parsed a project's version string as defined by PEP 440. The returned
    value will be an object that represents the version. These objects may
    be compared to each other and sorted. The sorting algorithm is as defined
    by PEP 440 with the addition that any version which is not a valid PEP 440
    version will be considered less than any valid PEP 440 version and the
    invalid versions will continue sorting using the original algorithm.

.. _yield_lines():

``yield_lines(strs)``
    Yield non-empty/non-comment lines from a string/unicode or a
    possibly-nested sequence thereof.  If ``strs`` is an instance of
    ``basestring``, it is split into lines, and each non-blank, non-comment
    line is yielded after stripping leading and trailing whitespace.  (Lines
    whose first non-blank character is ``#`` are considered comment lines.)

    If ``strs`` is not an instance of ``basestring``, it is iterated over, and
    each item is passed recursively to ``yield_lines()``, so that an arbitrarily
    nested sequence of strings, or sequences of sequences of strings can be
    flattened out to the lines contained therein.  So for example, passing
    a file object or a list of strings to ``yield_lines`` will both work.
    (Note that between each string in a sequence of strings there is assumed to
    be an implicit line break, so lines cannot bridge two strings in a
    sequence.)

    This routine is used extensively by ``pkg_resources`` to parse metadata
    and file formats of various kinds, and most other ``pkg_resources``
    parsing functions that yield multiple values will use it to break up their
    input.  However, this routine is idempotent, so calling ``yield_lines()``
    on the output of another call to ``yield_lines()`` is completely harmless.

``split_sections(strs)``
    Split a string (or possibly-nested iterable thereof), yielding ``(section,
    content)`` pairs found using an ``.ini``-like syntax.  Each ``section`` is
    a whitespace-stripped version of the section name ("``[section]``")
    and each ``content`` is a list of stripped lines excluding blank lines and
    comment-only lines.  If there are any non-blank, non-comment lines before
    the first section header, they're yielded in a first ``section`` of
    ``None``.

    This routine uses ``yield_lines()`` as its front end, so you can pass in
    anything that ``yield_lines()`` accepts, such as an open text file, string,
    or sequence of strings.  ``ValueError`` is raised if a malformed section
    header is found (i.e. a line starting with ``[`` but not ending with
    ``]``).

    Note that this simplistic parser assumes that any line whose first nonblank
    character is ``[`` is a section heading, so it can't support .ini format
    variations that allow ``[`` as the first nonblank character on other lines.

``safe_name(name)``
    Return a "safe" form of a project's name, suitable for use in a
    ``Requirement`` string, as a distribution name, or a PyPI project name.
    All non-alphanumeric runs are condensed to single "-" characters, such that
    a name like "The $$$ Tree" becomes "The-Tree".  Note that if you are
    generating a filename from this value you should combine it with a call to
    ``to_filename()`` so all dashes ("-") are replaced by underscores ("_").
    See ``to_filename()``.

``safe_version(version)``
    This will return the normalized form of any PEP 440 version. If the version
    string is not PEP 440 compatible, this function behaves similar to
    ``safe_name()`` except that spaces in the input become dots, and dots are
    allowed to exist in the output.  As with ``safe_name()``, if you are
    generating a filename from this you should replace any "-" characters in
    the output with underscores.

``safe_extra(extra)``
    Return a "safe" form of an extra's name, suitable for use in a requirement
    string or a setup script's ``extras_require`` keyword.  This routine is
    similar to ``safe_name()`` except that non-alphanumeric runs are replaced
    by a single underbar (``_``), and the result is lowercased.

``to_filename(name_or_version)``
    Escape a name or version string so it can be used in a dash-separated
    filename (or ``#egg=name-version`` tag) without ambiguity.  You
    should only pass in values that were returned by ``safe_name()`` or
    ``safe_version()``.


Platform Utilities
------------------

``get_build_platform()``
    Return this platform's identifier string.  For Windows, the return value
    is ``"win32"``, and for macOS it is a string of the form
    ``"macosx-10.4-ppc"``.  All other platforms return the same uname-based
    string that the ``distutils.util.get_platform()`` function returns.
    This string is the minimum platform version required by distributions built
    on the local machine.  (Backward compatibility note: setuptools versions
    prior to 0.6b1 called this function ``get_platform()``, and the function is
    still available under that name for backward compatibility reasons.)

``get_supported_platform()`` (New in 0.6b1)
    This is the similar to ``get_build_platform()``, but is the maximum
    platform version that the local machine supports.  You will usually want
    to use this value as the ``provided`` argument to the
    ``compatible_platforms()`` function.

``compatible_platforms(provided, required)``
    Return true if a distribution built on the ``provided`` platform may be used
    on the ``required`` platform.  If either platform value is ``None``, it is
    considered a wildcard, and the platforms are therefore compatible.
    Likewise, if the platform strings are equal, they're also considered
    compatible, and ``True`` is returned.  Currently, the only non-equal
    platform strings that are considered compatible are macOS platform
    strings with the same hardware type (e.g. ``ppc``) and major version
    (e.g. ``10``) with the ``provided`` platform's minor version being less than
    or equal to the ``required`` platform's minor version.

``get_default_cache()``
    Determine the default cache location for extracting resources from zipped
    eggs.  This routine returns the ``PYTHON_EGG_CACHE`` environment variable,
    if set.  Otherwise, on Windows, it returns a "Python-Eggs" subdirectory of
    the user's "Application Data" directory.  On all other systems, it returns
    ``os.path.expanduser("~/.python-eggs")`` if ``PYTHON_EGG_CACHE`` is not
    set.


PEP 302 Utilities
-----------------

``get_importer(path_item)``
    A deprecated alias for ``pkgutil.get_importer()``


File/Path Utilities
-------------------

``ensure_directory(path)``
    Ensure that the parent directory (``os.path.dirname``) of ``path`` actually
    exists, using ``os.makedirs()`` if necessary.

``normalize_path(path)``
    Return a "normalized" version of ``path``, such that two paths represent
    the same filesystem location if they have equal ``normalized_path()``
    values.  Specifically, this is a shortcut for calling ``os.path.realpath``
    and ``os.path.normcase`` on ``path``.  Unfortunately, on certain platforms
    (notably Cygwin and macOS) the ``normcase`` function does not accurately
    reflect the platform's case-sensitivity, so there is always the possibility
    of two apparently-different paths being equal on such platforms.

History
-------

0.6c9
 * Fix ``resource_listdir('')`` always returning an empty list for zipped eggs.

0.6c7
 * Fix package precedence problem where single-version eggs installed in
   ``site-packages`` would take precedence over ``.egg`` files (or directories)
   installed in ``site-packages``.

0.6c6
 * Fix extracted C extensions not having executable permissions under Cygwin.

 * Allow ``.egg-link`` files to contain relative paths.

 * Fix cache dir defaults on Windows when multiple environment vars are needed
   to construct a path.

0.6c4
 * Fix "dev" versions being considered newer than release candidates.

0.6c3
 * Python 2.5 compatibility fixes.

0.6c2
 * Fix a problem with eggs specified directly on ``PYTHONPATH`` on
   case-insensitive filesystems possibly not showing up in the default
   working set, due to differing normalizations of ``sys.path`` entries.

0.6b3
 * Fixed a duplicate path insertion problem on case-insensitive filesystems.

0.6b1
 * Split ``get_platform()`` into ``get_supported_platform()`` and
   ``get_build_platform()`` to work around a Mac versioning problem that caused
   the behavior of ``compatible_platforms()`` to be platform specific.

 * Fix entry point parsing when a standalone module name has whitespace
   between it and the extras.

0.6a11
 * Added ``ExtractionError`` and ``ResourceManager.extraction_error()`` so that
   cache permission problems get a more user-friendly explanation of the
   problem, and so that programs can catch and handle extraction errors if they
   need to.

0.6a10
 * Added the ``extras`` attribute to ``Distribution``, the ``find_plugins()``
   method to ``WorkingSet``, and the ``__add__()`` and ``__iadd__()`` methods
   to ``Environment``.

 * ``safe_name()`` now allows dots in project names.

 * There is a new ``to_filename()`` function that escapes project names and
   versions for safe use in constructing egg filenames from a Distribution
   object's metadata.

 * Added ``Distribution.clone()`` method, and keyword argument support to other
   ``Distribution`` constructors.

 * Added the ``DEVELOP_DIST`` precedence, and automatically assign it to
   eggs using ``.egg-info`` format.

0.6a9
 * Don't raise an error when an invalid (unfinished) distribution is found
   unless absolutely necessary.  Warn about skipping invalid/unfinished eggs
   when building an Environment.

 * Added support for ``.egg-info`` files or directories with version/platform
   information embedded in the filename, so that system packagers have the
   option of including ``PKG-INFO`` files to indicate the presence of a
   system-installed egg, without needing to use ``.egg`` directories, zipfiles,
   or ``.pth`` manipulation.

 * Changed ``parse_version()`` to remove dashes before pre-release tags, so
   that ``0.2-rc1`` is considered an *older* version than ``0.2``, and is equal
   to ``0.2rc1``.  The idea that a dash *always* meant a post-release version
   was highly non-intuitive to setuptools users and Python developers, who
   seem to want to use ``-rc`` version numbers a lot.

0.6a8
 * Fixed a problem with ``WorkingSet.resolve()`` that prevented version
   conflicts from being detected at runtime.

 * Improved runtime conflict warning message to identify a line in the user's
   program, rather than flagging the ``warn()`` call in ``pkg_resources``.

 * Avoid giving runtime conflict warnings for namespace packages, even if they
   were declared by a different package than the one currently being activated.

 * Fix path insertion algorithm for case-insensitive filesystems.

 * Fixed a problem with nested namespace packages (e.g. ``peak.util``) not
   being set as an attribute of their parent package.

0.6a6
 * Activated distributions are now inserted in ``sys.path`` (and the working
   set) just before the directory that contains them, instead of at the end.
   This allows e.g. eggs in ``site-packages`` to override unmanaged modules in
   the same location, and allows eggs found earlier on ``sys.path`` to override
   ones found later.

 * When a distribution is activated, it now checks whether any contained
   non-namespace modules have already been imported and issues a warning if
   a conflicting module has already been imported.

 * Changed dependency processing so that it's breadth-first, allowing a
   depender's preferences to override those of a dependee, to prevent conflicts
   when a lower version is acceptable to the dependee, but not the depender.

 * Fixed a problem extracting zipped files on Windows, when the egg in question
   has had changed contents but still has the same version number.

0.6a4
 * Fix a bug in ``WorkingSet.resolve()`` that was introduced in 0.6a3.

0.6a3
 * Added ``safe_extra()`` parsing utility routine, and use it for Requirement,
   EntryPoint, and Distribution objects' extras handling.

0.6a1
 * Enhanced performance of ``require()`` and related operations when all
   requirements are already in the working set, and enhanced performance of
   directory scanning for distributions.

 * Fixed some problems using ``pkg_resources`` w/PEP 302 loaders other than
   ``zipimport``, and the previously-broken "eager resource" support.

 * Fixed ``pkg_resources.resource_exists()`` not working correctly, along with
   some other resource API bugs.

 * Many API changes and enhancements:

   * Added ``EntryPoint``, ``get_entry_map``, ``load_entry_point``, and
     ``get_entry_info`` APIs for dynamic plugin discovery.

   * ``list_resources`` is now ``resource_listdir`` (and it actually works)

   * Resource API functions like ``resource_string()`` that accepted a package
     name and resource name, will now also accept a ``Requirement`` object in
     place of the package name (to allow access to non-package data files in
     an egg).

   * ``get_provider()`` will now accept a ``Requirement`` instance or a module
     name.  If it is given a ``Requirement``, it will return a corresponding
     ``Distribution`` (by calling ``require()`` if a suitable distribution
     isn't already in the working set), rather than returning a metadata and
     resource provider for a specific module.  (The difference is in how
     resource paths are interpreted; supplying a module name means resources
     path will be module-relative, rather than relative to the distribution's
     root.)

   * ``Distribution`` objects now implement the ``IResourceProvider`` and
     ``IMetadataProvider`` interfaces, so you don't need to reference the (no
     longer available) ``metadata`` attribute to get at these interfaces.

   * ``Distribution`` and ``Requirement`` both have a ``project_name``
     attribute for the project name they refer to.  (Previously these were
     ``name`` and ``distname`` attributes.)

   * The ``path`` attribute of ``Distribution`` objects is now ``location``,
     because it isn't necessarily a filesystem path (and hasn't been for some
     time now).  The ``location`` of ``Distribution`` objects in the filesystem
     should always be normalized using ``pkg_resources.normalize_path()``; all
     of the setuptools' code that generates distributions from the filesystem
     (including ``Distribution.from_filename()``) ensure this invariant, but if
     you use a more generic API like ``Distribution()`` or
     ``Distribution.from_location()`` you should take care that you don't
     create a distribution with an un-normalized filesystem path.

   * ``Distribution`` objects now have an ``as_requirement()`` method that
     returns a ``Requirement`` for the distribution's project name and version.

   * Distribution objects no longer have an ``installed_on()`` method, and the
     ``install_on()`` method is now ``activate()`` (but may go away altogether
     soon).  The ``depends()`` method has also been renamed to ``requires()``,
     and ``InvalidOption`` is now ``UnknownExtra``.

   * ``find_distributions()`` now takes an additional argument called ``only``,
     that tells it to only yield distributions whose location is the passed-in
     path.  (It defaults to False, so that the default behavior is unchanged.)

   * ``AvailableDistributions`` is now called ``Environment``, and the
     ``get()``, ``__len__()``, and ``__contains__()`` methods were removed,
     because they weren't particularly useful.  ``__getitem__()`` no longer
     raises ``KeyError``; it just returns an empty list if there are no
     distributions for the named project.

   * The ``resolve()`` method of ``Environment`` is now a method of
     ``WorkingSet`` instead, and the ``best_match()`` method now uses a working
     set instead of a path list as its second argument.

   * There is a new ``pkg_resources.add_activation_listener()`` API that lets
     you register a callback for notifications about distributions added to
     ``sys.path`` (including the distributions already on it).  This is
     basically a hook for extensible applications and frameworks to be able to
     search for plugin metadata in distributions added at runtime.

0.5a13
 * Fixed a bug in resource extraction from nested packages in a zipped egg.

0.5a12
 * Updated extraction/cache mechanism for zipped resources to avoid
   inter-process and inter-thread races during extraction.  The default cache
   location can now be set via the ``PYTHON_EGGS_CACHE`` environment variable,
   and the default Windows cache is now a ``Python-Eggs`` subdirectory of the
   current user's "Application Data" directory, if the ``PYTHON_EGGS_CACHE``
   variable isn't set.

0.5a10
 * Fix a problem with ``pkg_resources`` being confused by non-existent eggs on
   ``sys.path`` (e.g. if a user deletes an egg without removing it from the
   ``easy-install.pth`` file).

 * Fix a problem with "basket" support in ``pkg_resources``, where egg-finding
   never actually went inside ``.egg`` files.

 * Made ``pkg_resources`` import the module you request resources from, if it's
   not already imported.

0.5a4
 * ``pkg_resources.AvailableDistributions.resolve()`` and related methods now
   accept an ``installer`` argument: a callable taking one argument, a
   ``Requirement`` instance.  The callable must return a ``Distribution``
   object, or ``None`` if no distribution is found.  This feature is used by
   EasyInstall to resolve dependencies by recursively invoking itself.

0.4a4
 * Fix problems with ``resource_listdir()``, ``resource_isdir()`` and resource
   directory extraction for zipped eggs.

0.4a3
 * Fixed scripts not being able to see a ``__file__`` variable in ``__main__``

 * Fixed a problem with ``resource_isdir()`` implementation that was introduced
   in 0.4a2.

0.4a1
 * Fixed a bug in requirements processing for exact versions (i.e. ``==`` and
   ``!=``) when only one condition was included.

 * Added ``safe_name()`` and ``safe_version()`` APIs to clean up handling of
   arbitrary distribution names and versions found on PyPI.

0.3a4
 * ``pkg_resources`` now supports resource directories, not just the resources
   in them.  In particular, there are ``resource_listdir()`` and
   ``resource_isdir()`` APIs.

 * ``pkg_resources`` now supports "egg baskets" -- .egg zipfiles which contain
   multiple distributions in subdirectories whose names end with ``.egg``.
   Having such a "basket" in a directory on ``sys.path`` is equivalent to
   having the individual eggs in that directory, but the contained eggs can
   be individually added (or not) to ``sys.path``.  Currently, however, there
   is no automated way to create baskets.

 * Namespace package manipulation is now protected by the Python import lock.

0.3a1
 * Initial release.
alt-python312-setuptools/docs/conf.py000064400000021547150410147350013550 0ustar00extensions = [
    'sphinx.ext.autodoc',
    'jaraco.packaging.sphinx',
]

master_doc = "index"
html_theme = "furo"

# Link dates and other references in the changelog
extensions += ['rst.linker']
link_files = {
    '../NEWS.rst': dict(
        using=dict(
            BB='https://bitbucket.org',
            GH='https://github.com',
        ),
        replace=[
            dict(
                pattern=r'(Issue #|\B#)(?P<issue>\d+)',
                url='{package_url}/issues/{issue}',
            ),
            dict(
                pattern=r'(?m:^((?P<scm_version>v?\d+(\.\d+){1,2}))\n[-=]+\n)',
                with_scm='{text}\n{rev[timestamp]:%d %b %Y}\n',
            ),
            dict(
                pattern=r'PEP[- ](?P<pep_number>\d+)',
                url='https://peps.python.org/pep-{pep_number:0>4}/',
            ),
            dict(
                pattern=r'(?<!\w)PR #(?P<pull>\d+)',
                url='{package_url}/pull/{pull}',
            ),
            dict(
                pattern=r'BB Pull Request ?#(?P<bb_pull_request>\d+)',
                url='{BB}/pypa/setuptools/pull-request/{bb_pull_request}',
            ),
            dict(
                pattern=r'Distribute #(?P<distribute>\d+)',
                url='{BB}/tarek/distribute/issue/{distribute}',
            ),
            dict(
                pattern=r'Buildout #(?P<buildout>\d+)',
                url='{GH}/buildout/buildout/issues/{buildout}',
            ),
            dict(
                pattern=r'Old Setuptools #(?P<old_setuptools>\d+)',
                url='https://bugs.python.org/setuptools/issue{old_setuptools}',
            ),
            dict(
                pattern=r'Jython #(?P<jython>\d+)',
                url='https://bugs.jython.org/issue{jython}',
            ),
            dict(
                pattern=r'(Python #|bpo-)(?P<python>\d+)',
                url='https://bugs.python.org/issue{python}',
            ),
            dict(
                pattern=r'Interop #(?P<interop>\d+)',
                url='{GH}/pypa/interoperability-peps/issues/{interop}',
            ),
            dict(
                pattern=r'Pip #(?P<pip>\d+)',
                url='{GH}/pypa/pip/issues/{pip}',
            ),
            dict(
                pattern=r'Packaging #(?P<packaging>\d+)',
                url='{GH}/pypa/packaging/issues/{packaging}',
            ),
            dict(
                pattern=r'[Pp]ackaging (?P<packaging_ver>\d+(\.\d+)+)',
                url='{GH}/pypa/packaging/blob/{packaging_ver}/CHANGELOG.rst',
            ),
            dict(
                pattern=r'setuptools_svn #(?P<setuptools_svn>\d+)',
                url='{GH}/jaraco/setuptools_svn/issues/{setuptools_svn}',
            ),
            dict(
                pattern=r'pypa/(?P<issue_repo>[\-\.\w]+)#(?P<issue_number>\d+)',
                url='{GH}/pypa/{issue_repo}/issues/{issue_number}',
            ),
            dict(
                pattern=r'pypa/(?P<commit_repo>[\-\.\w]+)@(?P<commit_number>[\da-f]+)',
                url='{GH}/pypa/{commit_repo}/commit/{commit_number}',
            ),
        ],
    ),
}

# Be strict about any broken references
nitpicky = True

# Include Python intersphinx mapping to prevent failures
# jaraco/skeleton#51
extensions += ['sphinx.ext.intersphinx']
intersphinx_mapping = {
    'python': ('https://docs.python.org/3', None),
}

# Preserve authored syntax for defaults
autodoc_preserve_defaults = True

intersphinx_mapping.update(
    {
        'pip': ('https://pip.pypa.io/en/latest', None),
        'build': ('https://pypa-build.readthedocs.io/en/latest', None),
        'PyPUG': ('https://packaging.python.org/en/latest/', None),
        'packaging': ('https://packaging.pypa.io/en/latest/', None),
        'twine': ('https://twine.readthedocs.io/en/stable/', None),
        'importlib-resources': (
            'https://importlib-resources.readthedocs.io/en/latest',
            None,
        ),
    }
)

# Add support for linking usernames
github_url = 'https://github.com'
github_repo_org = 'pypa'
github_repo_name = 'setuptools'
github_repo_slug = f'{github_repo_org}/{github_repo_name}'
github_repo_url = f'{github_url}/{github_repo_slug}'
github_sponsors_url = f'{github_url}/sponsors'
extlinks = {
    'user': (f'{github_sponsors_url}/%s', '@%s'),  # noqa: WPS323
    'pypi': ('https://pypi.org/project/%s', '%s'),  # noqa: WPS323
    'wiki': ('https://wikipedia.org/wiki/%s', '%s'),  # noqa: WPS323
}
extensions += ['sphinx.ext.extlinks']

# Ref: https://github.com/python-attrs/attrs/pull/571/files\
#      #diff-85987f48f1258d9ee486e3191495582dR82
default_role = 'any'

# HTML theme
html_theme = 'furo'
html_logo = "images/logo.svg"

html_theme_options = {
    "sidebar_hide_name": True,
    "light_css_variables": {
        "color-brand-primary": "#336790",  # "blue"
        "color-brand-content": "#336790",
    },
    "dark_css_variables": {
        "color-brand-primary": "#E5B62F",  # "yellow"
        "color-brand-content": "#E5B62F",
    },
}

# Redirect old docs so links and references in the ecosystem don't break
extensions += ['sphinx_reredirects']
redirects = {
    "userguide/keywords": "/deprecated/changed_keywords.html",
    "userguide/commands": "/deprecated/commands.html",
}

# Add support for inline tabs
extensions += ['sphinx_inline_tabs']

# Support for distutils

# Ref: https://stackoverflow.com/a/30624034/595220
nitpick_ignore = [
    ('c:func', 'SHGetSpecialFolderPath'),  # ref to MS docs
    ('envvar', 'DISTUTILS_DEBUG'),  # undocumented
    ('envvar', 'HOME'),  # undocumented
    ('envvar', 'PLAT'),  # undocumented
    ('envvar', 'DIST_EXTRA_CONFIG'),  # undocumented
    ('py:attr', 'CCompiler.language_map'),  # undocumented
    ('py:attr', 'CCompiler.language_order'),  # undocumented
    ('py:class', 'distutils.dist.Distribution'),  # undocumented
    ('py:class', 'distutils.extension.Extension'),  # undocumented
    ('py:class', 'BorlandCCompiler'),  # undocumented
    ('py:class', 'CCompiler'),  # undocumented
    ('py:class', 'CygwinCCompiler'),  # undocumented
    ('py:class', 'distutils.dist.DistributionMetadata'),  # undocumented
    ('py:class', 'FileList'),  # undocumented
    ('py:class', 'IShellLink'),  # ref to MS docs
    ('py:class', 'MSVCCompiler'),  # undocumented
    ('py:class', 'OptionDummy'),  # undocumented
    ('py:class', 'UnixCCompiler'),  # undocumented
    ('py:exc', 'CompileError'),  # undocumented
    ('py:exc', 'DistutilsExecError'),  # undocumented
    ('py:exc', 'DistutilsFileError'),  # undocumented
    ('py:exc', 'LibError'),  # undocumented
    ('py:exc', 'LinkError'),  # undocumented
    ('py:exc', 'PreprocessError'),  # undocumented
    ('py:exc', 'setuptools.errors.PlatformError'),  # sphinx cannot find it
    ('py:func', 'distutils.CCompiler.new_compiler'),  # undocumented
    # undocumented:
    ('py:func', 'distutils.dist.DistributionMetadata.read_pkg_file'),
    ('py:func', 'distutils.file_util._copy_file_contents'),  # undocumented
    ('py:func', 'distutils.log.debug'),  # undocumented
    ('py:func', 'distutils.spawn.find_executable'),  # undocumented
    ('py:func', 'distutils.spawn.spawn'),  # undocumented
    # TODO: check https://docutils.rtfd.io in the future
    ('py:mod', 'docutils'),  # there's no Sphinx site documenting this
]

# Allow linking objects on other Sphinx sites seamlessly:
intersphinx_mapping.update(
    # python=('https://docs.python.org/3', None),
    python=('https://docs.python.org/3.11/', None),
    # ^-- Python 3.11 is required because it still contains `distutils`.
    #     Just leaving it as `3` would imply 3.12+, but that causes an
    #     error with the cross references to distutils functions.
    #     Inventory cache may cause errors, deleting it solves the problem.
)

# Add support for the unreleased "next-version" change notes
extensions += ['sphinxcontrib.towncrier']
# Extension needs a path from here to the towncrier config.
towncrier_draft_working_directory = '..'
# Avoid an empty section for unpublished changes.
towncrier_draft_include_empty = False
# sphinx-contrib/sphinxcontrib-towncrier#81
towncrier_draft_config_path = 'towncrier.toml'

extensions += ['jaraco.tidelift']

# Add icons (aka "favicons") to documentation
extensions += ['sphinx_favicon']
html_static_path = ['images']  # should contain the folder with icons

# Add support for nice Not Found 404 pages
extensions += ['notfound.extension']

# List of dicts with <link> HTML attributes
# static-file points to files in the html_static_path (href is computed)
favicons = [
    {  # "Catch-all" goes first, otherwise some browsers will overwrite
        "rel": "icon",
        "type": "image/svg+xml",
        "static-file": "logo-symbol-only.svg",
        "sizes": "any",
    },
    {  # Version with thicker strokes for better visibility at smaller sizes
        "rel": "icon",
        "type": "image/svg+xml",
        "static-file": "favicon.svg",
        "sizes": "16x16 24x24 32x32 48x48",
    },
    # rel="apple-touch-icon" does not support SVG yet
]
alt-python312-setuptools/docs/references/keywords.rst000064400000046401150410147350016767 0ustar00========
Keywords
========

The following are keywords ``setuptools.setup()`` accepts.
They allow configuring the build process for a Python distribution or adding
metadata via a ``setup.py`` script placed at the root of your project.
All of them are optional; you do not have to supply them unless you need the
associated ``setuptools`` feature.

Metadata and configuration supplied via ``setup()`` is complementary to (and
may be overwritten by) the information present in ``setup.cfg`` and ``pyproject.toml``.
Some important metadata, such as ``name`` and ``version``, may assume
a default *degenerate* value if not specified.

Users are strongly encouraged to use a declarative config either via
:doc:`setup.cfg </userguide/declarative_config>` or :doc:`pyproject.toml
</userguide/pyproject_config>` and only rely on ``setup.py`` if they need to
tap into special behaviour that requires scripting (such as building C
extensions).

.. note::
   When using declarative configs via ``pyproject.toml``
   with ``setuptools<64.0.0``, users can still keep a very simple ``setup.py``
   just to ensure editable installs are supported, for example::

       from setuptools import setup

       setup()

   Versions of ``setuptools`` ``>=64.0.0`` do not require this extra minimal
   ``setup.py`` file.

.. _keyword/name:

``name``
    A string specifying the name of the package.

.. _keyword/version:

``version``
    A string specifying the version number of the package.

.. _keyword/description:

``description``
    A string describing the package in a single line.

.. _keyword/long_description:

``long_description``
    A string providing a longer description of the package.

.. _keyword/long_description_content_type:

``long_description_content_type``
    A string specifying the content type is used for the ``long_description``
    (e.g. ``text/markdown``)

.. _keyword/author:

``author``
    A string specifying the author of the package.

.. _keyword/author_email:

``author_email``
    A string specifying the email address of the package author.

.. _keyword/maintainer:

``maintainer``
    A string specifying the name of the current maintainer, if different from
    the author. Note that if the maintainer is provided, setuptools will use it
    as the author in ``PKG-INFO``.

.. _keyword/maintainer_email:

``maintainer_email``
    A string specifying the email address of the current maintainer, if
    different from the author.

.. _keyword/url:

``url``
    A string specifying the URL for the package homepage.

.. _keyword/download_url:

``download_url``
    A string specifying the URL to download the package.

.. _keyword/packages:

``packages``
    A list of strings specifying the packages that setuptools will manipulate.

.. _keyword/py_modules:

``py_modules``
    A list of strings specifying the modules that setuptools will manipulate.

.. _keyword/scripts:

``scripts``
    A list of strings specifying the standalone script files to be built and
    installed.

.. _keyword/ext_package:

``ext_package``
    A string specifying the base package name for the extensions provided by
    this package.

.. _keyword/ext_modules:

``ext_modules``
    A list of instances of ``setuptools.Extension`` providing the list of
    Python extensions to be built.

.. _keyword/classifiers:

``classifiers``
    A list of strings describing the categories for the package.

.. _keyword/distclass:

``distclass``
    A subclass of ``Distribution`` to use.

.. _keyword/script_name:

``script_name``
    A string specifying the name of the setup.py script -- defaults to
    ``sys.argv[0]``

.. _keyword/script_args:

``script_args``
    A list of strings defining the arguments to supply to the setup script.

.. _keyword/options:

``options``
    A dictionary providing the default options for the setup script.

.. _keyword/license:

``license``
    A string specifying the license of the package.

.. _keyword/license_file:

``license_file``
    .. warning::
        ``license_file`` is deprecated. Use ``license_files`` instead.

.. _keyword/license_files:

``license_files``
    A list of glob patterns for license related files that should be included.
    If neither ``license_file`` nor ``license_files`` is specified, this option
    defaults to ``LICEN[CS]E*``, ``COPYING*``, ``NOTICE*``, and ``AUTHORS*``.

.. _keyword/keywords:

``keywords``
    A list of strings or a comma-separated string providing descriptive
    meta-data. See: :ref:`Core Metadata Specifications<core-metadata-keywords>`.

.. _keyword/platforms:

``platforms``
    A list of strings or comma-separated string.

.. _keyword/cmdclass:

``cmdclass``
    A dictionary providing a mapping of command names to ``Command``
    subclasses.

.. _keyword/data_files:

``data_files``
    .. warning::
        ``data_files`` is deprecated. It does not work with wheels, so it
        should be avoided.

    A list of strings specifying the data files to install.

.. _keyword/package_dir:

``package_dir``
    A dictionary that maps package names (as they will be
    imported by the end-users) into directory paths (that actually exist in the
    project's source tree). This configuration has two main purposes:

    1. To effectively "rename" paths when building your package.
       For example, ``package_dir={"mypkg": "dir1/dir2/code_for_mypkg"}``
       will instruct setuptools to copy the ``dir1/dir2/code_for_mypkg/...`` files
       as ``mypkg/...`` when building the final :term:`wheel distribution <Wheel>`.

       .. attention::
          While it is *possible* to specify arbitrary mappings, developers are
          **STRONGLY ADVISED AGAINST** that. They should try as much as possible
          to keep the directory names and hierarchy identical to the way they will
          appear in the final wheel, only deviating when absolutely necessary.

    2. To indicate that the relevant code is entirely contained inside
       a specific directory (instead of directly placed under the project's root).
       In this case, a special key is required (the empty string, ``""``),
       for example: ``package_dir={"": "<name of the container directory>"}``.
       All the directories inside the container directory will be copied
       directly into the final :term:`wheel distribution <Wheel>`, but the
       container directory itself will not.

       This practice is very common in the community to help separate the
       package implementation from auxiliary files (e.g. CI configuration files),
       and is referred to as :ref:`src-layout`, because the container
       directory is commonly named ``src``.

    All paths in ``package_dir`` must be relative to the project root directory
    and use a forward slash (``/``) as path separator regardless of the
    operating system.

    .. tip::
       When using :doc:`package discovery </userguide/package_discovery>`
       together with :doc:`setup.cfg </userguide/declarative_config>` or
       :doc:`pyproject.toml </userguide/pyproject_config>`, it is very likely
       that you don't need to specify a value for ``package_dir``.  Please have
       a look at the definitions of :ref:`src-layout` and :ref:`flat-layout` to
       learn common practices on how to design a project's directory structure
       and minimise the amount of configuration that is needed.

.. _keyword/requires:

``requires``
   .. warning::
      ``requires`` is superseded by ``install_requires`` and should not be used
      anymore.

.. _keyword/obsoletes:

``obsoletes``
   .. warning::
      ``obsoletes`` is currently ignored by ``pip``.

   List of strings describing packages which this package renders obsolete,
   meaning that the two projects should not be installed at the same time.

   Version declarations can be supplied. Version numbers must be in the format
   specified in Version specifiers (e.g. ``foo (<3.0)``).

   This field may be followed by an environment marker after a semicolon (e.g.
   ``foo; os_name == "posix"``)

   The most common use of this field will be in case a project name changes,
   e.g. Gorgon 2.3 gets subsumed into Torqued Python 1.0. When you install
   Torqued Python, the Gorgon distribution should be removed.

.. _keyword/provides:

``provides``
   .. warning::
      ``provides`` is currently ignored by ``pip``.

   List of strings describing package- and virtual package names contained
   within this package.

   A package may provide additional names, e.g. to indicate that multiple
   projects have been bundled together. For instance, source distributions of
   the ZODB project have historically included the transaction project, which
   is now available as a separate distribution. Installing such a source
   distribution satisfies requirements for both ZODB and transaction.

   A package may also provide a “virtual” project name, which does not
   correspond to any separately-distributed project: such a name might be used
   to indicate an abstract capability which could be supplied by one of
   multiple projects. E.g., multiple projects might supply RDBMS bindings for
   use by a given ORM: each project might declare that it provides
   ORM-bindings, allowing other projects to depend only on having at most one
   of them installed.

   A version declaration may be supplied and must follow the rules described in
   Version specifiers. The distribution’s version number will be implied if
   none is specified (e.g. ``foo (<3.0)``).

   Each package may be followed by an environment marker after a semicolon
   (e.g. ``foo; os_name == "posix"``).

.. _keyword/include_package_data:

``include_package_data``
    If set to ``True``, this tells ``setuptools`` to automatically include any
    data files it finds inside your package directories that are specified by
    your ``MANIFEST.in`` file.  For more information, see the section on
    :ref:`Including Data Files`.

.. _keyword/exclude_package_data:

``exclude_package_data``
    A dictionary mapping package names to lists of glob patterns that should
    be *excluded* from your package directories.  You can use this to trim back
    any excess files included by ``include_package_data``.  For a complete
    description and examples, see the section on :ref:`Including Data Files`.

.. _keyword/package_data:

``package_data``
    A dictionary mapping package names to lists of glob patterns.  For a
    complete description and examples, see the section on :ref:`Including Data
    Files`.  You do not need to use this option if you are using
    ``include_package_data``, unless you need to add e.g. files that are
    generated by your setup script and build process.  (And are therefore not
    in source control or are files that you don't want to include in your
    source distribution.)

.. _keyword/zip_safe:

``zip_safe``
    A boolean (True or False) flag specifying whether the project can be
    safely installed and run from a zip file.  If this argument is not
    supplied, the ``bdist_egg`` command will have to analyze all of your
    project's contents for possible problems each time it builds an egg.

.. _keyword/install_requires:

``install_requires``
    A string or list of strings specifying what other distributions need to
    be installed when this one is.  See the section on :ref:`Declaring
    Dependencies` for details and examples of the format of this argument.

.. _keyword/entry_points:

``entry_points``
    A dictionary mapping entry point group names to strings or lists of strings
    defining the entry points.  Entry points are used to support dynamic
    discovery of services or plugins provided by a project.  See :ref:`Dynamic
    Discovery of Services and Plugins` for details and examples of the format
    of this argument.  In addition, this keyword is used to support
    :ref:`Automatic Script Creation <entry_points>`.

.. _keyword/extras_require:

``extras_require``
    A dictionary mapping names of "extras" (optional features of your project)
    to strings or lists of strings specifying what other distributions must be
    installed to support those features.  See the section on :ref:`Declaring
    Dependencies` for details and examples of the format of this argument.

.. _keyword/python_requires:

``python_requires``
    A string corresponding to a version specifier (as defined in PEP 440) for
    the Python version, used to specify the Requires-Python defined in PEP 345.

.. _keyword/setup_requires:

``setup_requires``
    .. warning::
        Using ``setup_requires`` is discouraged in favor of :pep:`518`.

    A string or list of strings specifying what other distributions need to
    be present in order for the *setup script* to run.  ``setuptools`` will
    attempt to obtain these before processing the
    rest of the setup script or commands.  This argument is needed if you
    are using distutils extensions as part of your build process; for
    example, extensions that process setup() arguments and turn them into
    EGG-INFO metadata files.

    (Note: projects listed in ``setup_requires`` will NOT be automatically
    installed on the system where the setup script is being run.  They are
    simply downloaded to the ./.eggs directory if they're not locally available
    already.  If you want them to be installed, as well as being available
    when the setup script is run, you should add them to ``install_requires``
    **and** ``setup_requires``.)

.. _keyword/dependency_links:

``dependency_links``
    .. warning::
        ``dependency_links`` is deprecated. It is not supported anymore by pip.

    A list of strings naming URLs to be searched when satisfying dependencies.
    These links will be used if needed to install packages specified by
    ``setup_requires`` or ``tests_require``.  They will also be written into
    the egg's metadata for use during install by tools that support them.

.. _keyword/namespace_packages:

``namespace_packages``
    .. warning::
        The ``namespace_packages`` implementation relies on ``pkg_resources``.
        However, ``pkg_resources`` has some undesirable behaviours, and
        Setuptools intends to obviate its usage in the future. Therefore,
        ``namespace_packages`` was deprecated in favor of native/implicit
        namespaces (:pep:`420`). Check :doc:`the Python Packaging User Guide
        <PyPUG:guides/packaging-namespace-packages>` for more information.

    A list of strings naming the project's "namespace packages".  A namespace
    package is a package that may be split across multiple project
    distributions.  For example, Zope 3's ``zope`` package is a namespace
    package, because subpackages like ``zope.interface`` and ``zope.publisher``
    may be distributed separately.  The egg runtime system can automatically
    merge such subpackages into a single parent package at runtime, as long
    as you declare them in each project that contains any subpackages of the
    namespace package, and as long as the namespace package's ``__init__.py``
    does not contain any code other than a namespace declaration.  See the
    section on :ref:`Namespace Packages` for more information.

.. _keyword/test_suite:

``test_suite``
    A string naming a ``unittest.TestCase`` subclass (or a package or module
    containing one or more of them, or a method of such a subclass), or naming
    a function that can be called with no arguments and returns a
    ``unittest.TestSuite``.  If the named suite is a module, and the module
    has an ``additional_tests()`` function, it is called and the results are
    added to the tests to be run.  If the named suite is a package, any
    submodules and subpackages are recursively added to the overall test suite.

    Specifying this argument enables use of the :ref:`test <test>` command to run the
    specified test suite, e.g. via ``setup.py test``.  See the section on the
    :ref:`test <test>` command below for more details.

    .. warning::
       .. deprecated:: 41.5.0
          The test command will be removed in a future version of ``setuptools``,
          alongside any test configuration parameter.

.. _keyword/tests_require:

``tests_require``
    If your project's tests need one or more additional packages besides those
    needed to install it, you can use this option to specify them.  It should
    be a string or list of strings specifying what other distributions need to
    be present for the package's tests to run.  When you run the ``test``
    command, ``setuptools`` will  attempt to obtain these.
    Note that these required projects will *not* be installed on
    the system where the tests are run, but only downloaded to the project's setup
    directory if they're not already installed locally.

    .. warning::
       .. deprecated:: 41.5.0
          The test command will be removed in a future version of ``setuptools``,
          alongside any test configuration parameter.

.. _test_loader:

.. _keyword/test_loader:

``test_loader``
    If you would like to use a different way of finding tests to run than what
    setuptools normally uses, you can specify a module name and class name in
    this argument.  The named class must be instantiable with no arguments, and
    its instances must support the ``loadTestsFromNames()`` method as defined
    in the Python ``unittest`` module's ``TestLoader`` class.  Setuptools will
    pass only one test "name" in the ``names`` argument: the value supplied for
    the ``test_suite`` argument.  The loader you specify may interpret this
    string in any way it likes, as there are no restrictions on what may be
    contained in a ``test_suite`` string.

    The module name and class name must be separated by a ``:``.  The default
    value of this argument is ``"setuptools.command.test:ScanningLoader"``.  If
    you want to use the default ``unittest`` behavior, you can specify
    ``"unittest:TestLoader"`` as your ``test_loader`` argument instead.  This
    will prevent automatic scanning of submodules and subpackages.

    The module and class you specify here may be contained in another package,
    as long as you use the ``tests_require`` option to ensure that the package
    containing the loader class is available when the ``test`` command is run.

    .. warning::
       .. deprecated:: 41.5.0
          The test command will be removed in a future version of ``setuptools``,
          alongside any test configuration parameter.

.. _keyword/eager_resources:

``eager_resources``
    A list of strings naming resources that should be extracted together, if
    any of them is needed, or if any C extensions included in the project are
    imported.  This argument is only useful if the project will be installed as
    a zipfile, and there is a need to have all of the listed resources be
    extracted to the filesystem *as a unit*.  Resources listed here
    should be '/'-separated paths, relative to the source root, so to list a
    resource ``foo.png`` in package ``bar.baz``, you would include the string
    ``bar/baz/foo.png`` in this argument.

    If you only need to obtain resources one at a time, or you don't have any C
    extensions that access other files in the project (such as data files or
    shared libraries), you probably do NOT need this argument and shouldn't
    mess with it.  For more details on how this argument works, see the section
    below on :ref:`Automatic Resource Extraction`.

.. _keyword/project_urls:

``project_urls``
    An arbitrary map of URL names to hyperlinks, allowing more extensible
    documentation of where various resources can be found than the simple
    ``url`` and ``download_url`` options provide.
alt-python312-setuptools/docs/setuptools.rst000064400000015066150410147350015223 0ustar00==================================================
Building and Distributing Packages with Setuptools
==================================================

``Setuptools`` is a collection of enhancements to the Python ``distutils``
that allow developers to more easily build and
distribute Python packages, especially ones that have dependencies on other
packages.

Packages built and distributed using ``setuptools`` look to the user like
ordinary Python packages based on the ``distutils``.

Feature Highlights:

* Create `Python Eggs <http://peak.telecommunity.com/DevCenter/PythonEggs>`_ -
  a single-file importable distribution format

* Enhanced support for accessing data files hosted in zipped packages.

* Automatically include all packages in your source tree, without listing them
  individually in setup.py

* Automatically include all relevant files in your source distributions,
  without needing to create a :ref:`MANIFEST.in <Using MANIFEST.in>` file,
  and without having to force regeneration of the ``MANIFEST`` file when your
  source tree changes [#manifest]_.

* Automatically generate wrapper scripts or Windows (console and GUI) .exe
  files for any number of "main" functions in your project.  (Note: this is not
  a py2exe replacement; the .exe files rely on the local Python installation.)

* Transparent Cython support, so that your setup.py can list ``.pyx`` files and
  still work even when the end-user doesn't have Cython installed (as long as
  you include the Cython-generated C in your source distribution)

* Command aliases - create project-specific, per-user, or site-wide shortcut
  names for commonly used commands and options

* Deploy your project in "development mode", such that it's available on
  ``sys.path``, yet can still be edited directly from its source checkout.

* Easily extend the distutils with new commands or ``setup()`` arguments, and
  distribute/reuse your extensions for multiple projects, without copying code.

* Create extensible applications and frameworks that automatically discover
  extensions, using simple "entry points" declared in a project's setup script.

* Full support for PEP 420 via ``find_namespace_packages()``, which is also backwards
  compatible to the existing ``find_packages()`` for Python >= 3.3.

-----------------
Developer's Guide
-----------------

The developer's guide has been updated. See the :doc:`most recent version <userguide/index>`.































TRANSITIONAL NOTE
~~~~~~~~~~~~~~~~~

Setuptools automatically calls ``declare_namespace()`` for you at runtime,
but future versions may *not*.  This is because the automatic declaration
feature has some negative side effects, such as needing to import all namespace
packages during the initialization of the ``pkg_resources`` runtime, and also
the need for ``pkg_resources`` to be explicitly imported before any namespace
packages work at all.  In some future releases, you'll be responsible
for including your own declaration lines, and the automatic declaration feature
will be dropped to get rid of the negative side effects.

During the remainder of the current development cycle, therefore, setuptools
will warn you about missing ``declare_namespace()`` calls in your
``__init__.py`` files, and you should correct these as soon as possible
before the compatibility support is removed.
Namespace packages without declaration lines will not work
correctly once a user has upgraded to a later version, so it's important that
you make this change now in order to avoid having your code break in the field.
Our apologies for the inconvenience, and thank you for your patience.

















setup.cfg-only projects
=======================

.. versionadded:: 40.9.0

If ``setup.py`` is missing from the project directory when a :pep:`517`
build is invoked, ``setuptools`` emulates a dummy ``setup.py`` file containing
only a ``setuptools.setup()`` call.

.. note::

    :pep:`517` doesn't support editable installs so this is currently
    incompatible with ``pip install -e .``.

This means that you can have a Python project with all build configuration
specified in ``setup.cfg``, without a ``setup.py`` file, if you **can rely
on** your project always being built by a :pep:`517`/:pep:`518` compatible
frontend.

To use this feature:

* Specify build requirements and :pep:`517` build backend in
  ``pyproject.toml``.
  For example:

  .. code-block:: toml

      [build-system]
      requires = [
        "setuptools >= 40.9.0",
      ]
      build-backend = "setuptools.build_meta"

* Use a :pep:`517` compatible build frontend, such as ``pip >= 19`` or ``build``.

  .. warning::

      As :pep:`517` is new, support is not universal, and frontends that
      do support it may still have bugs. For compatibility, you may want to
      put a ``setup.py`` file containing only a ``setuptools.setup()``
      invocation.


Configuration API
=================

Some automation tools may wish to access data from a configuration file.

``Setuptools`` exposes a ``read_configuration()`` function for
parsing ``metadata`` and ``options`` sections into a dictionary.


.. code-block:: python

    from setuptools.config import read_configuration

    conf_dict = read_configuration("/home/user/dev/package/setup.cfg")


By default, ``read_configuration()`` will read only the file provided
in the first argument. To include values from other configuration files
which could be in various places, set the ``find_others`` keyword argument
to ``True``.

If you have only a configuration file but not the whole package, you can still
try to get data out of it with the help of the ``ignore_option_errors`` keyword
argument. When it is set to ``True``, all options with errors possibly produced
by directives, such as ``attr:`` and others, will be silently ignored.
As a consequence, the resulting dictionary will include no such options.











Forum and Bug Tracker
=====================

Please use `GitHub Discussions`_ for questions and discussion about
setuptools, and the `setuptools bug tracker`_ ONLY for issues you have
confirmed via the forum are actual bugs, and which you have reduced to a minimal
set of steps to reproduce.

.. _GitHub Discussions: https://github.com/pypa/setuptools/discussions
.. _setuptools bug tracker: https://github.com/pypa/setuptools/


----


.. [#manifest] The default behaviour for ``setuptools`` will work well for pure
   Python packages, or packages with simple C extensions (that don't require
   any special C header). See :ref:`Controlling files in the distribution` and
   :doc:`userguide/datafiles` for more information about complex scenarios, if
   you want to include other types of files.
alt-python312-setuptools/docs/history.rst000064400000003555150410147350014503 0ustar00:tocdepth: 2

.. _changes:

History
*******

.. towncrier-draft-entries:: DRAFT, unreleased as on |today|

.. include:: ../NEWS (links).rst

Credits
*******

* The original design for the ``.egg`` format and the ``pkg_resources`` API was
  co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first
  version of ``pkg_resources``, and supplied the macOS operating system version
  compatibility algorithm.

* Ian Bicking implemented many early "creature comfort" features of
  easy_install, including support for downloading via Sourceforge and
  Subversion repositories. Ian's comments on the Web-SIG about WSGI
  application deployment also inspired the concept of "entry points" in eggs,
  and he has given talks at PyCon and elsewhere to inform and educate the
  community about eggs and setuptools.

* Jim Fulton contributed time and effort to build automated tests of various
  aspects of ``easy_install``, and supplied the doctests for the command-line
  ``.exe`` wrappers on Windows.

* Phillip J. Eby is the seminal author of setuptools, and
  first proposed the idea of an importable binary distribution format for
  Python application plug-ins.

* Significant parts of the implementation of setuptools were funded by the Open
  Source Applications Foundation, to provide a plug-in infrastructure for the
  Chandler PIM application. In addition, many OSAF staffers (such as Mike
  "Code Bear" Taylor) contributed their time and stress as guinea pigs for the
  use of eggs and setuptools, even before eggs were "cool".  (Thanks, guys!)

* Tarek Ziadé is the principal author of the Distribute fork, which
  re-invigorated the community on the project, encouraged renewed innovation,
  and addressed many defects.

* Jason R. Coombs performed the merge with Distribute, maintaining the
  project for several years in coordination with the Python Packaging
  Authority (PyPA).
alt-python312-setuptools/docs/index.rst000064400000001531150410147350014101 0ustar00.. image:: images/banner-640x320.svg
   :align: center

Documentation
=============

Setuptools is a fully-featured, actively-maintained, and stable library
designed to facilitate packaging Python projects.

It helps developers to easily share reusable code (in the form of a library)
and programs (e.g., CLI/GUI tools implemented in Python), that can be installed
with :pypi:`pip` and uploaded to `PyPI <https://pypi.org>`_.

.. sidebar-links::
   :home:
   :pypi:

.. toctree::
   :maxdepth: 1
   :hidden:

   User guide <userguide/index>
   build_meta
   pkg_resources
   references/keywords
   setuptools

.. toctree::
   :caption: Project
   :maxdepth: 1
   :hidden:

   roadmap
   Development guide <development/index>
   Backward compatibility & deprecated practice <deprecated/index>
   Changelog <history>
   artwork

.. tidelift-referral-banner::
alt-python312-setuptools/docs/deprecated/commands.rst000064400000071752150410147350016707 0ustar00===============================
Running ``setuptools`` commands
===============================

Historically, ``setuptools`` allowed running commands via a ``setup.py`` script
at the root of a Python project, as indicated in the examples below::

    python setup.py --help
    python setup.py --help-commands
    python setup.py --version
    python setup.py sdist
    python setup.py bdist_wheel

You could also run commands in other circumstances:

* ``setuptools`` projects without ``setup.py`` (e.g., ``setup.cfg``-only)::

   python -c "from setuptools import setup; setup()" --help

* ``distutils`` projects (with a ``setup.py`` importing ``distutils``)::

   python -c "import setuptools; with open('setup.py') as f: exec(compile(f.read(), 'setup.py', 'exec'))" develop

That is, you can simply list the normal setup commands and options following the quoted part.

.. warning::
   While it is perfectly fine that users write ``setup.py`` files to configure
   a package build (e.g. to specify binary extensions or customize commands),
   on recent versions of ``setuptools``, running ``python setup.py`` directly
   as a script is considered **deprecated**. This also means that users should
   avoid running commands directly via ``python setup.py <command>``.

   If you want to create :term:`sdist <Source Distribution (or "sdist")>` or :term:`wheel`
   distributions the recommendation is to use the command line tool provided by :pypi:`build`::

       pip install build  # needs to be installed first

       python -m build  # builds both sdist and wheel
       python -m build --sdist
       python -m build --wheel

   Build will automatically download ``setuptools`` and build the package in an
   isolated environment. You can also specify specific versions of
   ``setuptools``, by setting the :doc:`build requirements in pyproject.toml
   </build_meta>`.

   If you want to install a package, you can use :pypi:`pip` or :pypi:`installer`::

      pip install /path/to/wheel/file.whl
      pip install /path/to/sdist/file.tar.gz
      pip install .  # replacement for python setup.py install
      pip install --editable .  # replacement for python setup.py develop

      pip install installer  # needs to be installed first
      python -m installer /path/to/wheel/file.whl

-----------------
Command Reference
-----------------

.. _alias:

``alias`` - Define shortcuts for commonly used commands
=======================================================

Sometimes, you need to use the same commands over and over, but you can't
necessarily set them as defaults.  For example, if you produce both development
snapshot releases and "stable" releases of a project, you may want to put
the distributions in different places, or use different ``egg_info`` tagging
options, etc.  In these cases, it doesn't make sense to set the options in
a distutils configuration file, because the values of the options changed based
on what you're trying to do.

Setuptools therefore allows you to define "aliases" - shortcut names for
an arbitrary string of commands and options, using ``setup.py alias aliasname
expansion``, where aliasname is the name of the new alias, and the remainder of
the command line supplies its expansion.  For example, this command defines
a sitewide alias called "daily", that sets various ``egg_info`` tagging
options::

    setup.py alias --global-config daily egg_info --tag-build=development

Once the alias is defined, it can then be used with other setup commands,
e.g.::

    setup.py daily bdist_egg        # generate a daily-build .egg file
    setup.py daily sdist            # generate a daily-build source distro
    setup.py daily sdist bdist_egg  # generate both

The above commands are interpreted as if the word ``daily`` were replaced with
``egg_info --tag-build=development``.

Note that setuptools will expand each alias *at most once* in a given command
line.  This serves two purposes.  First, if you accidentally create an alias
loop, it will have no effect; you'll instead get an error message about an
unknown command.  Second, it allows you to define an alias for a command, that
uses that command.  For example, this (project-local) alias::

    setup.py alias bdist_egg bdist_egg rotate -k1 -m.egg

redefines the ``bdist_egg`` command so that it always runs the ``rotate``
command afterwards to delete all but the newest egg file.  It doesn't loop
indefinitely on ``bdist_egg`` because the alias is only expanded once when
used.

You can remove a defined alias with the ``--remove`` (or ``-r``) option, e.g.::

    setup.py alias --global-config --remove daily

would delete the "daily" alias we defined above.

Aliases can be defined on a project-specific, per-user, or sitewide basis.  The
default is to define or remove a project-specific alias, but you can use any of
the `configuration file options`_ (listed under the `saveopts`_ command, below)
to determine which distutils configuration file an aliases will be added to
(or removed from).

Note that if you omit the "expansion" argument to the ``alias`` command,
you'll get output showing that alias' current definition (and what
configuration file it's defined in).  If you omit the alias name as well,
you'll get a listing of all current aliases along with their configuration
file locations.


``bdist_egg`` - Create a Python Egg for the project
===================================================

.. warning::
    **eggs** are deprecated in favor of wheels, and not supported by pip.

This command generates a Python Egg (``.egg`` file) for the project.  Python
Eggs are the preferred binary distribution format for EasyInstall, because they
are cross-platform (for "pure" packages), directly importable, and contain
project metadata including scripts and information about the project's
dependencies.  They can be simply downloaded and added to ``sys.path``
directly, or they can be placed in a directory on ``sys.path`` and then
automatically discovered by the egg runtime system.

This command runs the `egg_info`_ command (if it hasn't already run) to update
the project's metadata (``.egg-info``) directory.  If you have added any extra
metadata files to the ``.egg-info`` directory, those files will be included in
the new egg file's metadata directory, for use by the egg runtime system or by
any applications or frameworks that use that metadata.

You won't usually need to specify any special options for this command; just
use ``bdist_egg`` and you're done.  But there are a few options that may
be occasionally useful:

``--dist-dir=DIR, -d DIR``
    Set the directory where the ``.egg`` file will be placed.  If you don't
    supply this, then the ``--dist-dir`` setting of the ``bdist`` command
    will be used, which is usually a directory named ``dist`` in the project
    directory.

``--plat-name=PLATFORM, -p PLATFORM``
    Set the platform name string that will be embedded in the egg's filename
    (assuming the egg contains C extensions).  This can be used to override
    the distutils default platform name with something more meaningful.  Keep
    in mind, however, that the egg runtime system expects to see eggs with
    distutils platform names, so it may ignore or reject eggs with non-standard
    platform names.  Similarly, the EasyInstall program may ignore them when
    searching web pages for download links.  However, if you are
    cross-compiling or doing some other unusual things, you might find a use
    for this option.

``--exclude-source-files``
    Don't include any modules' ``.py`` files in the egg, just compiled Python,
    C, and data files.  (Note that this doesn't affect any ``.py`` files in the
    EGG-INFO directory or its subdirectories, since for example there may be
    scripts with a ``.py`` extension which must still be retained.)  We don't
    recommend that you use this option except for packages that are being
    bundled for proprietary end-user applications, or for "embedded" scenarios
    where space is at an absolute premium.  On the other hand, if your package
    is going to be installed and used in compressed form, you might as well
    exclude the source because Python's ``traceback`` module doesn't currently
    understand how to display zipped source code anyway, or how to deal with
    files that are in a different place from where their code was compiled.

There are also some options you will probably never need, but which are there
because they were copied from similar ``bdist`` commands used as an example for
creating this one.  They may be useful for testing and debugging, however,
which is why we kept them:

``--keep-temp, -k``
    Keep the contents of the ``--bdist-dir`` tree around after creating the
    ``.egg`` file.

``--bdist-dir=DIR, -b DIR``
    Set the temporary directory for creating the distribution.  The entire
    contents of this directory are zipped to create the ``.egg`` file, after
    running various installation commands to copy the package's modules, data,
    and extensions here.

``--skip-build``
    Skip doing any "build" commands; just go straight to the
    install-and-compress phases.


.. _develop:

``develop`` - Deploy the project source in "Development Mode"
=============================================================

This command allows you to deploy your project's source for use in one or more
"staging areas" where it will be available for importing.  This deployment is
done in such a way that changes to the project source are immediately available
in the staging area(s), without needing to run a build or install step after
each change.

The ``develop`` command works by creating an ``.egg-link`` file (named for the
project) in the given staging area.  If the staging area is Python's
``site-packages`` directory, it also updates an ``easy-install.pth`` file so
that the project is on ``sys.path`` by default for all programs run using that
Python installation.

The ``develop`` command also installs wrapper scripts in the staging area (or
a separate directory, as specified) that will ensure the project's dependencies
are available on ``sys.path`` before running the project's source scripts.
And, it ensures that any missing project dependencies are available in the
staging area, by downloading and installing them if necessary.

Last, but not least, the ``develop`` command invokes the ``build_ext -i``
command to ensure any C extensions in the project have been built and are
up-to-date, and the ``egg_info`` command to ensure the project's metadata is
updated (so that the runtime and wrappers know what the project's dependencies
are).  If you make any changes to the project's setup script or C extensions,
you should rerun the ``develop`` command against all relevant staging areas to
keep the project's scripts, metadata and extensions up-to-date.  Most other
kinds of changes to your project should not require any build operations or
rerunning ``develop``, but keep in mind that even minor changes to the setup
script (e.g. changing an entry point definition) require you to re-run the
``develop`` or ``test`` commands to keep the distribution updated.

Here are some of the options that the ``develop`` command accepts.  Note that
they affect the project's dependencies as well as the project itself, so if you
have dependencies that need to be installed and you use ``--exclude-scripts``
(for example), the dependencies' scripts will not be installed either!  For
this reason, you may want to use pip to install the project's dependencies
before using the ``develop`` command, if you need finer control over the
installation options for dependencies.

``--uninstall, -u``
    Un-deploy the current project.  You may use the ``--install-dir`` or ``-d``
    option to designate the staging area.  The created ``.egg-link`` file will
    be removed, if present and it is still pointing to the project directory.
    The project directory will be removed from ``easy-install.pth`` if the
    staging area is Python's ``site-packages`` directory.

    Note that this option currently does *not* uninstall script wrappers!  You
    must uninstall them yourself, or overwrite them by using pip to install a
    different version of the package.  You can also avoid installing script
    wrappers in the first place, if you use the ``--exclude-scripts`` (aka
    ``-x``) option when you run ``develop`` to deploy the project.

``--multi-version, -m``
    "Multi-version" mode. Specifying this option prevents ``develop`` from
    adding an ``easy-install.pth`` entry for the project(s) being deployed, and
    if an entry for any version of a project already exists, the entry will be
    removed upon successful deployment.  In multi-version mode, no specific
    version of the package is available for importing, unless you use
    ``pkg_resources.require()`` to put it on ``sys.path``, or you are running
    a wrapper script generated by ``setuptools``.  (In which case the wrapper
    script calls ``require()`` for you.)

    Note that if you install to a directory other than ``site-packages``,
    this option is automatically in effect, because ``.pth`` files can only be
    used in ``site-packages`` (at least in Python 2.3 and 2.4). So, if you use
    the ``--install-dir`` or ``-d`` option (or they are set via configuration
    file(s)) your project and its dependencies will be deployed in
    multi-version mode.

``--install-dir=DIR, -d DIR``
    Set the installation directory (staging area).  If this option is not
    directly specified on the command line or in a distutils configuration
    file, the distutils default installation location is used.  Normally, this
    will be the ``site-packages`` directory, but if you are using distutils
    configuration files, setting things like ``prefix`` or ``install_lib``,
    then those settings are taken into account when computing the default
    staging area.

``--script-dir=DIR, -s DIR``
    Set the script installation directory.  If you don't supply this option
    (via the command line or a configuration file), but you *have* supplied
    an ``--install-dir`` (via command line or config file), then this option
    defaults to the same directory, so that the scripts will be able to find
    their associated package installation.  Otherwise, this setting defaults
    to the location where the distutils would normally install scripts, taking
    any distutils configuration file settings into account.

``--exclude-scripts, -x``
    Don't deploy script wrappers.  This is useful if you don't want to disturb
    existing versions of the scripts in the staging area.

``--always-copy, -a``
    Copy all needed distributions to the staging area, even if they
    are already present in another directory on ``sys.path``.  By default, if
    a requirement can be met using a distribution that is already available in
    a directory on ``sys.path``, it will not be copied to the staging area.

``--egg-path=DIR``
    Force the generated ``.egg-link`` file to use a specified relative path
    to the source directory.  This can be useful in circumstances where your
    installation directory is being shared by code running under multiple
    platforms (e.g. Mac and Windows) which have different absolute locations
    for the code under development, but the same *relative* locations with
    respect to the installation directory.  If you use this option when
    installing, you must supply the same relative path when uninstalling.

In addition to the above options, the ``develop`` command also accepts all of
the same options accepted by ``easy_install``.  If you've configured any
``easy_install`` settings in your ``setup.cfg`` (or other distutils config
files), the ``develop`` command will use them as defaults, unless you override
them in a ``[develop]`` section or on the command line.


.. _egg_info:

``egg_info`` - Create egg metadata and set build tags
=====================================================

This command performs two operations: it updates a project's ``.egg-info``
metadata directory (used by the ``bdist_egg``, ``develop``, and ``test``
commands), and it allows you to temporarily change a project's version string,
to support "daily builds" or "snapshot" releases.  It is run automatically by
the ``sdist``, ``bdist_egg``, ``develop``, and ``test`` commands in order to
update the project's metadata, but you can also specify it explicitly in order
to temporarily change the project's version string while executing other
commands.  (It also generates the ``.egg-info/SOURCES.txt`` manifest file, which
is used when you are building source distributions.)

In addition to writing the core egg metadata defined by ``setuptools`` and
required by ``pkg_resources``, this command can be extended to write other
metadata files as well, by defining entry points in the ``egg_info.writers``
group.  See the section on :ref:`Adding new EGG-INFO Files` below for more details.
Note that using additional metadata writers may require you to include a
``setup_requires`` argument to ``setup()`` in order to ensure that the desired
writers are available on ``sys.path``.


Release Tagging Options
-----------------------

The following options can be used to modify the project's version string for
all remaining commands on the setup command line.  The options are processed
in the order shown, so if you use more than one, the requested tags will be
added in the following order:

``--tag-build=NAME, -b NAME``
    Append NAME to the project's version string.  Due to the way setuptools
    processes "pre-release" version suffixes beginning with the letters "a"
    through "e" (like "alpha", "beta", and "candidate"), you will usually want
    to use a tag like ".build" or ".dev", as this will cause the version number
    to be considered *lower* than the project's default version.  (If you
    want to make the version number *higher* than the default version, you can
    always leave off --tag-build and then use one or both of the following
    options.)

    If you have a default build tag set in your ``setup.cfg``, you can suppress
    it on the command line using ``-b ""`` or ``--tag-build=""`` as an argument
    to the ``egg_info`` command.

``--tag-date, -d``
    Add a date stamp of the form "-YYYYMMDD" (e.g. "-20050528") to the
    project's version number.

``--no-date, -D``
    Don't include a date stamp in the version number.  This option is included
    so you can override a default setting in ``setup.cfg``.


(Note: Because these options modify the version number used for source and
binary distributions of your project, you should first make sure that you know
how the resulting version numbers will be interpreted by automated tools
like pip.  See the section above on :ref:`Specifying Your Project's Version` for an
explanation of pre- and post-release tags, as well as tips on how to choose and
verify a versioning scheme for your project.)

For advanced uses, there is one other option that can be set, to change the
location of the project's ``.egg-info`` directory.  Commands that need to find
the project's source directory or metadata should get it from this setting:


Other ``egg_info`` Options
--------------------------

``--egg-base=SOURCEDIR, -e SOURCEDIR``
    Specify the directory that should contain the .egg-info directory.  This
    should normally be the root of your project's source tree (which is not
    necessarily the same as your project directory; some projects use a ``src``
    or ``lib`` subdirectory as the source root).  You should not normally need
    to specify this directory, as it is normally determined from the
    ``package_dir`` argument to the ``setup()`` function, if any.  If there is
    no ``package_dir`` set, this option defaults to the current directory.


``egg_info`` Examples
---------------------

Creating a dated "nightly build" snapshot egg::

    setup.py egg_info --tag-date --tag-build=DEV bdist_egg

Creating a release with no version tags, even if some default tags are
specified in ``setup.cfg``::

    setup.py egg_info -RDb "" sdist bdist_egg

(Notice that ``egg_info`` must always appear on the command line *before* any
commands that you want the version changes to apply to.)

.. _rotate:

``rotate`` - Delete outdated distribution files
===============================================

As you develop new versions of your project, your distribution (``dist``)
directory will gradually fill up with older source and/or binary distribution
files.  The ``rotate`` command lets you automatically clean these up, keeping
only the N most-recently modified files matching a given pattern.

``--match=PATTERNLIST, -m PATTERNLIST``
    Comma-separated list of glob patterns to match.  This option is *required*.
    The project name and ``-*`` is prepended to the supplied patterns, in order
    to match only distributions belonging to the current project (in case you
    have a shared distribution directory for multiple projects).  Typically,
    you will use a glob pattern like ``.zip`` or ``.egg`` to match files of
    the specified type.  Note that each supplied pattern is treated as a
    distinct group of files for purposes of selecting files to delete.

``--keep=COUNT, -k COUNT``
    Number of matching distributions to keep.  For each group of files
    identified by a pattern specified with the ``--match`` option, delete all
    but the COUNT most-recently-modified files in that group.  This option is
    *required*.

``--dist-dir=DIR, -d DIR``
    Directory where the distributions are.  This defaults to the value of the
    ``bdist`` command's ``--dist-dir`` option, which will usually be the
    project's ``dist`` subdirectory.

**Example 1**: Delete all .tar.gz files from the distribution directory, except
for the 3 most recently modified ones::

    setup.py rotate --match=.tar.gz --keep=3

**Example 2**: Delete all Python 2.3 or Python 2.4 eggs from the distribution
directory, except the most recently modified one for each Python version::

    setup.py rotate --match=-py2.3*.egg,-py2.4*.egg --keep=1


.. _saveopts:

``saveopts`` - Save used options to a configuration file
========================================================

Finding and editing ``distutils`` configuration files can be a pain, especially
since you also have to translate the configuration options from command-line
form to the proper configuration file format.  You can avoid these hassles by
using the ``saveopts`` command.  Just add it to the command line to save the
options you used.  For example, this command builds the project using
the ``mingw32`` C compiler, then saves the --compiler setting as the default
for future builds (even those run implicitly by the ``install`` command)::

    setup.py build --compiler=mingw32 saveopts

The ``saveopts`` command saves all options for every command specified on the
command line to the project's local ``setup.cfg`` file, unless you use one of
the `configuration file options`_ to change where the options are saved.  For
example, this command does the same as above, but saves the compiler setting
to the site-wide (global) distutils configuration::

    setup.py build --compiler=mingw32 saveopts -g

Note that it doesn't matter where you place the ``saveopts`` command on the
command line; it will still save all the options specified for all commands.
For example, this is another valid way to spell the last example::

    setup.py saveopts -g build --compiler=mingw32

Note, however, that all of the commands specified are always run, regardless of
where ``saveopts`` is placed on the command line.


Configuration File Options
--------------------------

Normally, settings such as options and aliases are saved to the project's
local ``setup.cfg`` file.  But you can override this and save them to the
global or per-user configuration files, or to a manually-specified filename.

``--global-config, -g``
    Save settings to the global ``distutils.cfg`` file inside the ``distutils``
    package directory.  You must have write access to that directory to use
    this option.  You also can't combine this option with ``-u`` or ``-f``.

``--user-config, -u``
    Save settings to the current user's ``~/.pydistutils.cfg`` (POSIX) or
    ``$HOME/pydistutils.cfg`` (Windows) file.  You can't combine this option
    with ``-g`` or ``-f``.

``--filename=FILENAME, -f FILENAME``
    Save settings to the specified configuration file to use.  You can't
    combine this option with ``-g`` or ``-u``.  Note that if you specify a
    non-standard filename, the ``distutils`` and ``setuptools`` will not
    use the file's contents.  This option is mainly included for use in
    testing.

These options are used by other ``setuptools`` commands that modify
configuration files, such as the `alias`_ and `setopt`_ commands.


.. _setopt:

``setopt`` - Set a distutils or setuptools option in a config file
==================================================================

This command is mainly for use by scripts, but it can also be used as a quick
and dirty way to change a distutils configuration option without having to
remember what file the options are in and then open an editor.

**Example 1**.  Set the default C compiler to ``mingw32`` (using long option
names)::

    setup.py setopt --command=build --option=compiler --set-value=mingw32

**Example 2**.  Remove any setting for the distutils default package
installation directory (short option names)::

    setup.py setopt -c install -o install_lib -r


Options for the ``setopt`` command:

``--command=COMMAND, -c COMMAND``
    Command to set the option for.  This option is required.

``--option=OPTION, -o OPTION``
    The name of the option to set.  This option is required.

``--set-value=VALUE, -s VALUE``
    The value to set the option to.  Not needed if ``-r`` or ``--remove`` is
    set.

``--remove, -r``
    Remove (unset) the option, instead of setting it.

In addition to the above options, you may use any of the `configuration file
options`_ (listed under the `saveopts`_ command, above) to determine which
distutils configuration file the option will be added to (or removed from).


.. _test:

``test`` - Build package and run a unittest suite
=================================================

.. warning::
    ``test`` is deprecated and will be removed in a future version. Users
    looking for a generic test entry point independent of test runner are
    encouraged to use `tox <https://tox.readthedocs.io>`_.

When doing test-driven development, or running automated builds that need
testing before they are deployed for downloading or use, it's often useful
to be able to run a project's unit tests without actually deploying the project
anywhere, even using the ``develop`` command.  The ``test`` command runs a
project's unit tests without actually deploying it, by temporarily putting the
project's source on ``sys.path``, after first running ``build_ext -i`` and
``egg_info`` to ensure that any C extensions and project metadata are
up-to-date.

To use this command, your project's tests must be wrapped in a ``unittest``
test suite by either a function, a ``TestCase`` class or method, or a module
or package containing ``TestCase`` classes.  If the named suite is a module,
and the module has an ``additional_tests()`` function, it is called and the
result (which must be a ``unittest.TestSuite``) is added to the tests to be
run.  If the named suite is a package, any submodules and subpackages are
recursively added to the overall test suite.  (Note: if your project specifies
a ``test_loader``, the rules for processing the chosen ``test_suite`` may
differ; see the :ref:`test_loader <test_loader>` documentation for more details.)

Note that many test systems including ``doctest`` support wrapping their
non-``unittest`` tests in ``TestSuite`` objects.  So, if you are using a test
package that does not support this, we suggest you encourage its developers to
implement test suite support, as this is a convenient and standard way to
aggregate a collection of tests to be run under a common test harness.

By default, tests will be run in the "verbose" mode of the ``unittest``
package's text test runner, but you can get the "quiet" mode (just dots) if
you supply the ``-q`` or ``--quiet`` option, either as a global option to
the setup script (e.g. ``setup.py -q test``) or as an option for the ``test``
command itself (e.g. ``setup.py test -q``).  There is one other option
available:

``--test-suite=NAME, -s NAME``
    Specify the test suite (or module, class, or method) to be run
    (e.g. ``some_module.test_suite``).  The default for this option can be
    set by giving a ``test_suite`` argument to the ``setup()`` function, e.g.::

        setup(
            # ...
            test_suite="my_package.tests.test_all"
        )

    If you did not set a ``test_suite`` in your ``setup()`` call, and do not
    provide a ``--test-suite`` option, an error will occur.

New in 41.5.0: Deprecated the test command.


.. _upload:

``upload`` - Upload source and/or egg distributions to PyPI
===========================================================

The ``upload`` command was deprecated in version 40.0 and removed in version
42.0. Use `twine <https://pypi.org/p/twine>`_ instead.

For  more information on the current best practices in uploading your packages
to PyPI, see the Python Packaging User Guide's "Packaging Python Projects"
tutorial specifically the section on `uploading the distribution archives
<https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives>`_.
alt-python312-setuptools/docs/deprecated/resource_extraction.rst000064400000005747150410147350021176 0ustar00.. _Automatic Resource Extraction:

Automatic Resource Extraction
=============================

In a modern setup, Python packages are usually installed as directories,
and all the files can be found on deterministic locations on the disk.
This means that most of the tools expect package resources to be "real" files.

There are a few occasions however that packages are loaded in a different way
(e.g., from a zip file), which is incompatible with the assumptions mentioned above.
Moreover, a package developer may also include non-extension native libraries or other files that
C extensions may expect to be able to access.

In these scenarios, the use of :mod:`importlib.resources` is recommended.

Old implementations (prior to the advent of :mod:`importlib.resources`) and
long-living projects, however, may still rely on the library ``pkg_resources``
to access these files.

If you have to support such systems, or want to provide backward compatibility
for ``pkg_resources``, you may need to add an special configuration
to ``setuptools`` when packaging a project.
This can be done by listing as ``eager_resources`` (argument to ``setup()``
in ``setup.py`` or field in ``setup.cfg``) all the files that need to be
extracted together, whenever a C extension in the project is imported.

This is especially important if your project includes shared libraries *other*
than ``distutils``/``setuptools``-built C extensions, and those shared libraries use file
extensions other than ``.dll``, ``.so``, or ``.dylib``, which are the
extensions that setuptools 0.6a8 and higher automatically detects as shared
libraries and adds to the ``native_libs.txt`` file for you.  Any shared
libraries whose names do not end with one of those extensions should be listed
as ``eager_resources``, because they need to be present in the filesystem when
he C extensions that link to them are used.

The ``pkg_resources`` runtime for compressed packages will automatically
extract *all* C extensions and ``eager_resources`` at the same time, whenever
*any* C extension or eager resource is requested via the ``resource_filename()``
API.  (C extensions are imported using ``resource_filename()`` internally.)
This ensures that C extensions will see all of the "real" files that they
expect to see.

Note also that you can list directory resource names in ``eager_resources`` as
well, in which case the directory's contents (including subdirectories) will be
extracted whenever any C extension or eager resource is requested.

Please note that if you're not sure whether you need to use this argument, you
don't!  It's really intended to support projects with lots of non-Python
dependencies and as a last resort for crufty projects that can't otherwise
handle being compressed.  If your package is pure Python, Python plus data
files, or Python plus C, you really don't need this.  You've got to be using
either C or an external program that needs "real" files in your project before
there's any possibility of ``eager_resources`` being relevant to your project.
alt-python312-setuptools/docs/deprecated/zip_safe.rst000064400000007101150410147350016671 0ustar00Understanding the ``zip_safe`` flag
===================================

The ``zip_safe`` flag is a ``setuptools`` configuration mainly associated
with the ``egg`` distribution format
(which got replaced in the ecosystem by the newer ``wheel`` format) and the
``easy_install`` command (deprecated in ``setuptools`` v58.3.0).

It is very unlikely that the values of ``zip_safe`` will affect modern
deployments that use :pypi:`pip` for installing packages.
Moreover, new users of ``setuptools`` should not attempt to create egg files
using the deprecated ``build_egg`` command.
Therefore, this flag is considered **obsolete**.

This document, however, describes what was the historical motivation behind
this flag, and how it was used.

Historical Motivation
---------------------

For some use cases (such as bundling as part of a larger application), Python
packages may be run directly from a zip file.
Not all packages, however, are capable of running in compressed form, because
they may expect to be able to access either source code or data files as
normal operating system files.

In the past, ``setuptools`` would install a project distributed
as a zipfile or a directory (via the ``easy_install`` command or
``python setup.py install``),
the default choice being determined by the project's ``zip_safe`` flag.

How the ``zip_safe`` flag was used?
-----------------------------------

To set this flag, a developer would pass a boolean value for the ``zip_safe`` argument to the
``setup()`` function, or omit it.  When omitted, the ``bdist_egg``
command would analyze the project's contents to see if it could detect any
conditions preventing the project from working in a zipfile.

This was extremely conservative: ``bdist_egg`` would consider the
project unsafe if it contained any C extensions or datafiles whatsoever.  This
does *not* mean that the project couldn't or wouldn't work as a zipfile!  It just
means that the ``bdist_egg`` authors were not yet comfortable asserting that
the project *would* work.  If the project did not contain any C or data files, and did not
attempt to perform ``__file__`` or ``__path__`` introspection or source code manipulation, then
there was an extremely solid chance the project will work when installed as a
zipfile.  (And if the project used ``pkg_resources`` for all its data file
access, then C extensions and other data files shouldn't be a problem at all.
See the :ref:`Accessing Data Files at Runtime` section for more information.)

The developer could manually set ``zip_safe`` to ``True`` to perform tests,
or to override the default behaviour (after checking all the warnings and
understanding the implications), this would allow ``setuptools`` to install the
project as a zip file. Alternatively, by setting ``zip_safe`` to ``False``,
developers could force ``setuptools`` to always install the project as a
directory.

Modern ways of loading packages from zip files
----------------------------------------------

Currently, popular Python package installers (such as :pypi:`pip`) and package
indexes (such as PyPI_) consider that distribution packages are always
installed as a directory.
It is however still possible to load packages from zip files added to
:obj:`sys.path`, thanks to the :mod:`zipimport` module
and the :mod:`importlib` machinery provided by Python standard library.

When working with modules loaded from a zip file, it is important to keep in
mind that values of ``__file__`` and ``__path__`` might not work as expected.
Please check the documentation for :mod:`importlib.resources`, if file
locations are important for your use case.


.. _PyPI: https://pypi.org
alt-python312-setuptools/docs/deprecated/changed_keywords.rst000064400000004201150410147350020407 0ustar00New and Changed ``setup()`` Keywords
====================================

This document tracks historical differences between ``setuptools`` and
``distutils``.

Since ``distutils`` was scheduled for removal from the standard library in
Python 3.12, and ``setuptools`` started its adoption, these differences became less
relevant.
Please check :doc:`/references/keywords` for a complete list of keyword
arguments that can be passed to the ``setuptools.setup()`` function and
a their full description.

.. tab:: Supported by both ``distutils`` and ``setuptoools``

    ``name`` string

    ``version`` string

    ``description`` string

    ``long_description`` string

    ``long_description_content_type`` string

    ``author`` string

    ``author_email`` string

    ``maintainer`` string

    ``maintainer_email`` string

    ``url`` string

    ``download_url`` string

    ``packages`` list

    ``py_modules`` list

    ``scripts`` list

    ``ext_package`` string

    ``ext_modules`` list

    ``classifiers`` list

    ``distclass`` Distribution subclass

    ``script_name`` string

    ``script_args`` list

    ``options`` dictionary

    ``license`` string

    ``license_file`` string **deprecated**

    ``license_files`` list

    ``keywords`` string or list

    ``platforms`` list

    ``cmdclass`` dictionary

    ``data_files`` list **deprecated**

    ``package_dir`` dictionary

    ``requires`` string or list **deprecated**

    ``obsoletes`` list **deprecated**

    ``provides`` list

.. tab:: Added or changed by ``setuptoools``

    ``include_package_data`` bool

    ``exclude_package_data`` dictionary

    ``package_data`` dictionary

    ``zip_safe`` bool

    ``install_requires`` string or list

    ``entry_points`` dictionary

    ``extras_require`` dictionary

    ``python_requires`` string

    ``setup_requires`` string or list **deprecated**

    ``dependency_links`` list **deprecated**

    ``namespace_packages`` list

    ``test_suite`` string or function **deprecated**

    ``tests_require`` string or list **deprecated**

    ``test_loader`` class **deprecated**

    ``eager_resources`` list

    ``project_urls`` dictionary
alt-python312-setuptools/docs/deprecated/distutils/apiref.rst000064400000273044150410147350020376 0ustar00.. _api-reference:

*************
API Reference
*************

.. seealso::

   `New and changed setup.py arguments in setuptools`_
      The ``setuptools`` project adds new capabilities to the ``setup`` function
      and other APIs, makes the API consistent across different Python versions,
      and is hence recommended over using ``distutils`` directly.

.. _New and changed setup.py arguments in setuptools: https://setuptools.pypa.io/en/latest/setuptools.html#new-and-changed-setup-keywords

.. include:: ./_setuptools_disclaimer.rst

:mod:`distutils.core` --- Core Distutils functionality
======================================================

.. module:: distutils.core
   :synopsis: The core Distutils functionality


The :mod:`distutils.core` module is the only module that needs to be installed
to use the Distutils. It provides the :func:`setup` (which is called from the
setup script). Indirectly provides the  :class:`distutils.dist.Distribution` and
:class:`distutils.cmd.Command` class.


.. function:: setup(arguments)

   The basic do-everything function that does most everything you could ever ask
   for from a Distutils method.

   The setup function takes a large number of arguments. These are laid out in the
   following table.

   .. tabularcolumns:: |l|L|L|

   +--------------------+--------------------------------+-------------------------------------------------------------+
   | argument name      | value                          | type                                                        |
   +====================+================================+=============================================================+
   | *name*             | The name of the package        | a string                                                    |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *version*          | The version number of the      | a string                                                    |
   |                    | package; see                   |                                                             |
   |                    | :mod:`distutils.version`       |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *description*      | A single line describing the   | a string                                                    |
   |                    | package                        |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *long_description* | Longer description of the      | a string                                                    |
   |                    | package                        |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *author*           | The name of the package author | a string                                                    |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *author_email*     | The email address of the       | a string                                                    |
   |                    | package author                 |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *maintainer*       | The name of the current        | a string                                                    |
   |                    | maintainer, if different from  |                                                             |
   |                    | the author. Note that if       |                                                             |
   |                    | the maintainer is provided,    |                                                             |
   |                    | distutils will use it as the   |                                                             |
   |                    | author in :file:`PKG-INFO`     |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *maintainer_email* | The email address of the       | a string                                                    |
   |                    | current maintainer, if         |                                                             |
   |                    | different from the author      |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *url*              | A URL for the package          | a string                                                    |
   |                    | (homepage)                     |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *download_url*     | A URL to download the package  | a string                                                    |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *packages*         | A list of Python packages that | a list of strings                                           |
   |                    | distutils will manipulate      |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *py_modules*       | A list of Python modules that  | a list of strings                                           |
   |                    | distutils will manipulate      |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *scripts*          | A list of standalone script    | a list of strings                                           |
   |                    | files to be built and          |                                                             |
   |                    | installed                      |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *ext_modules*      | A list of Python extensions to | a list of instances of                                      |
   |                    | be built                       | :class:`distutils.core.Extension`                           |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *classifiers*      | A list of categories for the   | a list of strings; valid classifiers are listed on `PyPI    |
   |                    | package                        | <https://pypi.org/classifiers>`_.                           |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *distclass*        | the :class:`Distribution`      | a subclass of                                               |
   |                    | class to use                   | :class:`distutils.core.Distribution`                        |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *script_name*      | The name of the setup.py       | a string                                                    |
   |                    | script - defaults to           |                                                             |
   |                    | ``sys.argv[0]``                |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *script_args*      | Arguments to supply to the     | a list of strings                                           |
   |                    | setup script                   |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *options*          | default options for the setup  | a dictionary                                                |
   |                    | script                         |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *license*          | The license for the package    | a string                                                    |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *keywords*         | Descriptive meta-data, see     | a list of strings or a comma-separated string               |
   |                    | :pep:`314`                     |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *platforms*        |                                | a list of strings or a comma-separated string               |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *cmdclass*         | A mapping of command names to  | a dictionary                                                |
   |                    | :class:`Command` subclasses    |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *data_files*       | A list of data files to        | a list                                                      |
   |                    | install                        |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+
   | *package_dir*      | A mapping of package to        | a dictionary                                                |
   |                    | directory names                |                                                             |
   +--------------------+--------------------------------+-------------------------------------------------------------+



.. function:: run_setup(script_name[, script_args=None, stop_after='run'])

   Run a setup script in a somewhat controlled environment, and return  the
   :class:`distutils.dist.Distribution` instance that drives things.   This is
   useful if you need to find out the distribution meta-data  (passed as keyword
   args from *script* to :func:`setup`), or  the contents of the config files or
   command-line.

   *script_name* is a file that will be read and run with :func:`exec`.  ``sys.argv[0]``
   will be replaced with *script* for the duration of the call.  *script_args* is a
   list of strings; if supplied, ``sys.argv[1:]`` will be replaced by *script_args*
   for the duration  of the call.

   *stop_after* tells :func:`setup` when to stop processing; possible  values:

   .. tabularcolumns:: |l|L|

   +---------------+---------------------------------------------+
   | value         | description                                 |
   +===============+=============================================+
   | *init*        | Stop after the :class:`Distribution`        |
   |               | instance has been created  and populated    |
   |               | with the keyword arguments to :func:`setup` |
   +---------------+---------------------------------------------+
   | *config*      | Stop after config files have been parsed    |
   |               | (and their data stored in the               |
   |               | :class:`Distribution` instance)             |
   +---------------+---------------------------------------------+
   | *commandline* | Stop after the command-line                 |
   |               | (``sys.argv[1:]`` or  *script_args*) have   |
   |               | been parsed (and the data stored in the     |
   |               | :class:`Distribution` instance.)            |
   +---------------+---------------------------------------------+
   | *run*         | Stop after all commands have been run (the  |
   |               | same as  if :func:`setup` had been called   |
   |               | in the usual way). This is the default      |
   |               | value.                                      |
   +---------------+---------------------------------------------+

In addition, the :mod:`distutils.core` module exposed a number of  classes that
live elsewhere.

* :class:`~distutils.extension.Extension` from :mod:`distutils.extension`

* :class:`~distutils.cmd.Command` from :mod:`distutils.cmd`

* :class:`~distutils.dist.Distribution` from :mod:`distutils.dist`

A short description of each of these follows, but see the relevant module for
the full reference.


.. class:: Extension

   The Extension class describes a single C or C++ extension module in a setup
   script. It accepts the following keyword arguments in its constructor:

   .. tabularcolumns:: |l|L|l|

   +------------------------+--------------------------------+---------------------------+
   | argument name          | value                          | type                      |
   +========================+================================+===========================+
   | *name*                 | the full name of the           | a string                  |
   |                        | extension, including any       |                           |
   |                        | packages --- ie. *not* a       |                           |
   |                        | filename or pathname, but      |                           |
   |                        | Python dotted name             |                           |
   +------------------------+--------------------------------+---------------------------+
   | *sources*              | list of source filenames,      | a list of strings         |
   |                        | relative to the distribution   |                           |
   |                        | root (where the setup script   |                           |
   |                        | lives), in Unix form           |                           |
   |                        | (slash-separated) for          |                           |
   |                        | portability.                   |                           |
   |                        | Source files may be C, C++,    |                           |
   |                        | SWIG (.i), platform-specific   |                           |
   |                        | resource files, or whatever    |                           |
   |                        | else is recognized by the      |                           |
   |                        | :command:`build_ext` command   |                           |
   |                        | as source for a Python         |                           |
   |                        | extension.                     |                           |
   +------------------------+--------------------------------+---------------------------+
   | *include_dirs*         | list of directories to search  | a list of strings         |
   |                        | for C/C++ header files (in     |                           |
   |                        | Unix form for portability)     |                           |
   +------------------------+--------------------------------+---------------------------+
   | *define_macros*        | list of macros to define; each | a list of tuples          |
   |                        | macro is defined using a       |                           |
   |                        | 2-tuple ``(name, value)``,     |                           |
   |                        | where *value* is               |                           |
   |                        | either the string to define it |                           |
   |                        | to or ``None`` to define it    |                           |
   |                        | without a particular value     |                           |
   |                        | (equivalent of ``#define FOO`` |                           |
   |                        | in source or :option:`!-DFOO`  |                           |
   |                        | on Unix C compiler command     |                           |
   |                        | line)                          |                           |
   +------------------------+--------------------------------+---------------------------+
   | *undef_macros*         | list of macros to undefine     | a list of strings         |
   |                        | explicitly                     |                           |
   +------------------------+--------------------------------+---------------------------+
   | *library_dirs*         | list of directories to search  | a list of strings         |
   |                        | for C/C++ libraries at link    |                           |
   |                        | time                           |                           |
   +------------------------+--------------------------------+---------------------------+
   | *libraries*            | list of library names (not     | a list of strings         |
   |                        | filenames or paths) to link    |                           |
   |                        | against                        |                           |
   +------------------------+--------------------------------+---------------------------+
   | *runtime_library_dirs* | list of directories to search  | a list of strings         |
   |                        | for C/C++ libraries at run     |                           |
   |                        | time (for shared extensions,   |                           |
   |                        | this is when the extension is  |                           |
   |                        | loaded)                        |                           |
   +------------------------+--------------------------------+---------------------------+
   | *extra_objects*        | list of extra files to link    | a list of strings         |
   |                        | with (eg. object files not     |                           |
   |                        | implied by 'sources', static   |                           |
   |                        | library that must be           |                           |
   |                        | explicitly specified, binary   |                           |
   |                        | resource files, etc.)          |                           |
   +------------------------+--------------------------------+---------------------------+
   | *extra_compile_args*   | any extra platform- and        | a list of strings         |
   |                        | compiler-specific information  |                           |
   |                        | to use when compiling the      |                           |
   |                        | source files in 'sources'. For |                           |
   |                        | platforms and compilers where  |                           |
   |                        | a command line makes sense,    |                           |
   |                        | this is typically a list of    |                           |
   |                        | command-line arguments, but    |                           |
   |                        | for other platforms it could   |                           |
   |                        | be anything.                   |                           |
   +------------------------+--------------------------------+---------------------------+
   | *extra_link_args*      | any extra platform- and        | a list of strings         |
   |                        | compiler-specific information  |                           |
   |                        | to use when linking object     |                           |
   |                        | files together to create the   |                           |
   |                        | extension (or to create a new  |                           |
   |                        | static Python interpreter).    |                           |
   |                        | Similar interpretation as for  |                           |
   |                        | 'extra_compile_args'.          |                           |
   +------------------------+--------------------------------+---------------------------+
   | *export_symbols*       | list of symbols to be exported | a list of strings         |
   |                        | from a shared extension. Not   |                           |
   |                        | used on all platforms, and not |                           |
   |                        | generally necessary for Python |                           |
   |                        | extensions, which typically    |                           |
   |                        | export exactly one symbol:     |                           |
   |                        | ``init`` + extension_name.     |                           |
   +------------------------+--------------------------------+---------------------------+
   | *depends*              | list of files that the         | a list of strings         |
   |                        | extension depends on           |                           |
   +------------------------+--------------------------------+---------------------------+
   | *language*             | extension language (i.e.       | a string                  |
   |                        | ``'c'``, ``'c++'``,            |                           |
   |                        | ``'objc'``). Will be detected  |                           |
   |                        | from the source extensions if  |                           |
   |                        | not provided.                  |                           |
   +------------------------+--------------------------------+---------------------------+
   | *optional*             | specifies that a build failure | a boolean                 |
   |                        | in the extension should not    |                           |
   |                        | abort the build process, but   |                           |
   |                        | simply skip the extension.     |                           |
   +------------------------+--------------------------------+---------------------------+

   .. versionchanged:: 3.8

      On Unix, C extensions are no longer linked to libpython except on
      Android and Cygwin.


.. class:: Distribution

   A :class:`Distribution` describes how to build, install and package up a Python
   software package.

   See the :func:`setup` function for a list of keyword arguments accepted  by the
   Distribution constructor. :func:`setup` creates a Distribution instance.

   .. versionchanged:: 3.7
      :class:`~distutils.core.Distribution` now warns if ``classifiers``,
      ``keywords`` and ``platforms`` fields are not specified as a list or
      a string.

.. class:: Command

   A :class:`Command` class (or rather, an instance of one of its subclasses)
   implement a single distutils command.


:mod:`distutils.ccompiler` --- CCompiler base class
===================================================

.. module:: distutils.ccompiler
   :synopsis: Abstract CCompiler class


This module provides the abstract base class for the :class:`CCompiler`
classes.  A :class:`CCompiler` instance can be used for all the compile  and
link steps needed to build a single project. Methods are provided to  set
options for the compiler --- macro definitions, include directories,  link path,
libraries and the like.

This module provides the following functions.


.. function:: gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries)

   Generate linker options for searching library directories and linking with
   specific libraries.  *libraries* and *library_dirs* are, respectively, lists of
   library names (not filenames!) and search directories.  Returns a list of
   command-line options suitable for use with some compiler (depending on the two
   format strings passed in).


.. function:: gen_preprocess_options(macros, include_dirs)

   Generate C pre-processor options (:option:`!-D`, :option:`!-U`, :option:`!-I`) as
   used by at least two types of compilers: the typical Unix compiler and Visual
   C++. *macros* is the usual thing, a list of 1- or 2-tuples, where ``(name,)``
   means undefine (:option:`!-U`) macro *name*, and ``(name, value)`` means define
   (:option:`!-D`) macro *name* to *value*.  *include_dirs* is just a list of
   directory names to be added to the header file search path (:option:`!-I`).
   Returns a list of command-line options suitable for either Unix compilers or
   Visual C++.


.. function:: get_default_compiler(osname, platform)

   Determine the default compiler to use for the given platform.

   *osname* should be one of the standard Python OS names (i.e. the ones returned
   by ``os.name``) and *platform* the common value returned by ``sys.platform`` for
   the platform in question.

   The default values are ``os.name`` and ``sys.platform`` in case the parameters
   are not given.


.. function:: new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0)

   Factory function to generate an instance of some CCompiler subclass for the
   supplied platform/compiler combination. *plat* defaults to ``os.name`` (eg.
   ``'posix'``, ``'nt'``), and *compiler*  defaults to the default compiler for
   that platform. Currently only ``'posix'`` and ``'nt'`` are supported, and the
   default compilers are "traditional Unix interface" (:class:`UnixCCompiler`
   class) and Visual C++ (:class:`MSVCCompiler` class).  Note that it's perfectly
   possible to ask for a Unix compiler object under Windows, and a Microsoft
   compiler object under Unix---if you supply a value for *compiler*, *plat* is
   ignored.

   .. % Is the posix/nt only thing still true? Mac OS X seems to work, and
   .. % returns a UnixCCompiler instance. How to document this... hmm.


.. function:: show_compilers()

   Print list of available compilers (used by the :option:`!--help-compiler` options
   to :command:`build`, :command:`build_ext`, :command:`build_clib`).


.. class:: CCompiler([verbose=0, dry_run=0, force=0])

   The abstract base class :class:`CCompiler` defines the interface that  must be
   implemented by real compiler classes.  The class also has  some utility methods
   used by several compiler classes.

   The basic idea behind a compiler abstraction class is that each instance can be
   used for all the compile/link steps in building a single project.  Thus,
   attributes common to all of those compile and link steps --- include
   directories, macros to define, libraries to link against, etc. --- are
   attributes of the compiler instance.  To allow for variability in how individual
   files are treated, most of those attributes may be varied on a per-compilation
   or per-link basis.

   The constructor for each subclass creates an instance of the Compiler object.
   Flags are *verbose* (show verbose output), *dry_run* (don't actually execute the
   steps) and *force* (rebuild everything, regardless of dependencies). All of
   these flags default to ``0`` (off). Note that you probably don't want to
   instantiate :class:`CCompiler` or one of its subclasses directly - use the
   :func:`distutils.CCompiler.new_compiler` factory function instead.

   The following methods allow you to manually alter compiler options for  the
   instance of the Compiler class.


   .. method:: CCompiler.add_include_dir(dir)

      Add *dir* to the list of directories that will be searched for header files.
      The compiler is instructed to search directories in the order in which they are
      supplied by successive calls to :meth:`add_include_dir`.


   .. method:: CCompiler.set_include_dirs(dirs)

      Set the list of directories that will be searched to *dirs* (a list of strings).
      Overrides any preceding calls to :meth:`add_include_dir`; subsequent calls to
      :meth:`add_include_dir` add to the list passed to :meth:`set_include_dirs`.
      This does not affect any list of standard include directories that the compiler
      may search by default.


   .. method:: CCompiler.add_library(libname)

      Add *libname* to the list of libraries that will be included in all links driven
      by this compiler object.  Note that *libname* should \*not\* be the name of a
      file containing a library, but the name of the library itself: the actual
      filename will be inferred by the linker, the compiler, or the compiler class
      (depending on the platform).

      The linker will be instructed to link against libraries in the order they were
      supplied to :meth:`add_library` and/or :meth:`set_libraries`.  It is perfectly
      valid to duplicate library names; the linker will be instructed to link against
      libraries as many times as they are mentioned.


   .. method:: CCompiler.set_libraries(libnames)

      Set the list of libraries to be included in all links driven by this compiler
      object to *libnames* (a list of strings).  This does not affect any standard
      system libraries that the linker may include by default.


   .. method:: CCompiler.add_library_dir(dir)

      Add *dir* to the list of directories that will be searched for libraries
      specified to :meth:`add_library` and :meth:`set_libraries`.  The linker will be
      instructed to search for libraries in the order they are supplied to
      :meth:`add_library_dir` and/or :meth:`set_library_dirs`.


   .. method:: CCompiler.set_library_dirs(dirs)

      Set the list of library search directories to *dirs* (a list of strings).  This
      does not affect any standard library search path that the linker may search by
      default.


   .. method:: CCompiler.add_runtime_library_dir(dir)

      Add *dir* to the list of directories that will be searched for shared libraries
      at runtime.


   .. method:: CCompiler.set_runtime_library_dirs(dirs)

      Set the list of directories to search for shared libraries at runtime to *dirs*
      (a list of strings).  This does not affect any standard search path that the
      runtime linker may search by default.


   .. method:: CCompiler.define_macro(name[, value=None])

      Define a preprocessor macro for all compilations driven by this compiler object.
      The optional parameter *value* should be a string; if it is not supplied, then
      the macro will be defined without an explicit value and the exact outcome
      depends on the compiler used.

      .. XXX true? does ANSI say anything about this?


   .. method:: CCompiler.undefine_macro(name)

      Undefine a preprocessor macro for all compilations driven by this compiler
      object.  If the same macro is defined by :meth:`define_macro` and
      undefined by :meth:`undefine_macro` the last call takes precedence
      (including multiple redefinitions or undefinitions).  If the macro is
      redefined/undefined on a per-compilation basis (ie. in the call to
      :meth:`compile`), then that takes precedence.


   .. method:: CCompiler.add_link_object(object)

      Add *object* to the list of object files (or analogues, such as explicitly named
      library files or the output of "resource compilers") to be included in every
      link driven by this compiler object.


   .. method:: CCompiler.set_link_objects(objects)

      Set the list of object files (or analogues) to be included in every link to
      *objects*.  This does not affect any standard object files that the linker may
      include by default (such as system libraries).

   The following methods implement methods for autodetection of compiler  options,
   providing some functionality similar to GNU :program:`autoconf`.


   .. method:: CCompiler.detect_language(sources)

      Detect the language of a given file, or list of files. Uses the  instance
      attributes :attr:`~CCompiler.language_map` (a dictionary), and  :attr:`~CCompiler.language_order` (a
      list) to do the job.


   .. method:: CCompiler.find_library_file(dirs, lib[, debug=0])

      Search the specified list of directories for a static or shared library file
      *lib* and return the full path to that file.  If *debug* is true, look for a
      debugging version (if that makes sense on the current platform).  Return
      ``None`` if *lib* wasn't found in any of the specified directories.


   .. method:: CCompiler.has_function(funcname [, includes=None, include_dirs=None, libraries=None, library_dirs=None])

      Return a boolean indicating whether *funcname* is supported on the current
      platform.  The optional arguments can be used to augment the compilation
      environment by providing additional include files and paths and libraries and
      paths.


   .. method:: CCompiler.library_dir_option(dir)

      Return the compiler option to add *dir* to the list of directories searched for
      libraries.


   .. method:: CCompiler.library_option(lib)

      Return the compiler option to add *lib* to the list of libraries linked into the
      shared library or executable.


   .. method:: CCompiler.runtime_library_dir_option(dir)

      Return the compiler option to add *dir* to the list of directories searched for
      runtime libraries.


   .. method:: CCompiler.set_executables(**args)

      Define the executables (and options for them) that will be run to perform the
      various stages of compilation.  The exact set of executables that may be
      specified here depends on the compiler class (via the 'executables' class
      attribute), but most will have:

      +--------------+------------------------------------------+
      | attribute    | description                              |
      +==============+==========================================+
      | *compiler*   | the C/C++ compiler                       |
      +--------------+------------------------------------------+
      | *linker_so*  | linker used to create shared objects and |
      |              | libraries                                |
      +--------------+------------------------------------------+
      | *linker_exe* | linker used to create binary executables |
      +--------------+------------------------------------------+
      | *archiver*   | static library creator                   |
      +--------------+------------------------------------------+

      On platforms with a command-line (Unix, DOS/Windows), each of these is a string
      that will be split into executable name and (optional) list of arguments.
      (Splitting the string is done similarly to how Unix shells operate: words are
      delimited by spaces, but quotes and backslashes can override this.  See
      :func:`distutils.util.split_quoted`.)

   The following methods invoke stages in the build process.


   .. method:: CCompiler.compile(sources[, output_dir=None, macros=None, include_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, depends=None])

      Compile one or more source files. Generates object files (e.g.  transforms a
      :file:`.c` file to a :file:`.o` file.)

      *sources* must be a list of filenames, most likely C/C++ files, but in reality
      anything that can be handled by a particular compiler and compiler class (eg.
      :class:`MSVCCompiler` can handle resource files in *sources*).  Return a list of
      object filenames, one per source filename in *sources*.  Depending on the
      implementation, not all source files will necessarily be compiled, but all
      corresponding object filenames will be returned.

      If *output_dir* is given, object files will be put under it, while retaining
      their original path component.  That is, :file:`foo/bar.c` normally compiles to
      :file:`foo/bar.o` (for a Unix implementation); if *output_dir* is *build*, then
      it would compile to :file:`build/foo/bar.o`.

      *macros*, if given, must be a list of macro definitions.  A macro definition is
      either a ``(name, value)`` 2-tuple or a ``(name,)`` 1-tuple. The former defines
      a macro; if the value is ``None``, the macro is defined without an explicit
      value.  The 1-tuple case undefines a macro.  Later
      definitions/redefinitions/undefinitions take precedence.

      *include_dirs*, if given, must be a list of strings, the directories to add to
      the default include file search path for this compilation only.

      *debug* is a boolean; if true, the compiler will be instructed to output debug
      symbols in (or alongside) the object file(s).

      *extra_preargs* and *extra_postargs* are implementation-dependent. On platforms
      that have the notion of a command-line (e.g. Unix, DOS/Windows), they are most
      likely lists of strings: extra command-line arguments to prepend/append to the
      compiler command line.  On other platforms, consult the implementation class
      documentation.  In any event, they are intended as an escape hatch for those
      occasions when the abstract compiler framework doesn't cut the mustard.

      *depends*, if given, is a list of filenames that all targets depend on.  If a
      source file is older than any file in depends, then the source file will be
      recompiled.  This supports dependency tracking, but only at a coarse
      granularity.

      Raises :exc:`CompileError` on failure.


   .. method:: CCompiler.create_static_lib(objects, output_libname[, output_dir=None, debug=0, target_lang=None])

      Link a bunch of stuff together to create a static library file. The "bunch of
      stuff" consists of the list of object files supplied as *objects*, the extra
      object files supplied to :meth:`add_link_object` and/or
      :meth:`set_link_objects`, the libraries supplied to :meth:`add_library` and/or
      :meth:`set_libraries`, and the libraries supplied as *libraries* (if any).

      *output_libname* should be a library name, not a filename; the filename will be
      inferred from the library name.  *output_dir* is the directory where the library
      file will be put.

      .. XXX defaults to what?

      *debug* is a boolean; if true, debugging information will be included in the
      library (note that on most platforms, it is the compile step where this matters:
      the *debug* flag is included here just for consistency).

      *target_lang* is the target language for which the given objects are being
      compiled. This allows specific linkage time treatment of certain languages.

      Raises :exc:`LibError` on failure.


   .. method:: CCompiler.link(target_desc, objects, output_filename[, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None, debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, target_lang=None])

      Link a bunch of stuff together to create an executable or shared library file.

      The "bunch of stuff" consists of the list of object files supplied as *objects*.
      *output_filename* should be a filename.  If *output_dir* is supplied,
      *output_filename* is relative to it (i.e. *output_filename* can provide
      directory components if needed).

      *libraries* is a list of libraries to link against.  These are library names,
      not filenames, since they're translated into filenames in a platform-specific
      way (eg. *foo* becomes :file:`libfoo.a` on Unix and :file:`foo.lib` on
      DOS/Windows).  However, they can include a directory component, which means the
      linker will look in that specific directory rather than searching all the normal
      locations.

      *library_dirs*, if supplied, should be a list of directories to search for
      libraries that were specified as bare library names (ie. no directory
      component).  These are on top of the system default and those supplied to
      :meth:`add_library_dir` and/or :meth:`set_library_dirs`.  *runtime_library_dirs*
      is a list of directories that will be embedded into the shared library and used
      to search for other shared libraries that \*it\* depends on at run-time.  (This
      may only be relevant on Unix.)

      *export_symbols* is a list of symbols that the shared library will export.
      (This appears to be relevant only on Windows.)

      *debug* is as for :meth:`compile` and :meth:`create_static_lib`,  with the
      slight distinction that it actually matters on most platforms (as opposed to
      :meth:`create_static_lib`, which includes a *debug* flag mostly for form's
      sake).

      *extra_preargs* and *extra_postargs* are as for :meth:`compile`  (except of
      course that they supply command-line arguments for the particular linker being
      used).

      *target_lang* is the target language for which the given objects are being
      compiled. This allows specific linkage time treatment of certain languages.

      Raises :exc:`LinkError` on failure.


   .. method:: CCompiler.link_executable(objects, output_progname[, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, target_lang=None])

      Link an executable.  *output_progname* is the name of the file executable, while
      *objects* are a list of object filenames to link in. Other arguments  are as for
      the :meth:`link` method.


   .. method:: CCompiler.link_shared_lib(objects, output_libname[, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None, debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, target_lang=None])

      Link a shared library. *output_libname* is the name of the output  library,
      while *objects* is a list of object filenames to link in.  Other arguments are
      as for the :meth:`link` method.


   .. method:: CCompiler.link_shared_object(objects, output_filename[, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None, debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, target_lang=None])

      Link a shared object. *output_filename* is the name of the shared object that
      will be created, while *objects* is a list of object filenames  to link in.
      Other arguments are as for the :meth:`link` method.


   .. method:: CCompiler.preprocess(source[, output_file=None, macros=None, include_dirs=None, extra_preargs=None, extra_postargs=None])

      Preprocess a single C/C++ source file, named in *source*. Output will be written
      to file named *output_file*, or *stdout* if *output_file* not supplied.
      *macros* is a list of macro definitions as for :meth:`compile`, which will
      augment the macros set with :meth:`define_macro` and :meth:`undefine_macro`.
      *include_dirs* is a list of directory names that will be added to the  default
      list, in the same way as :meth:`add_include_dir`.

      Raises :exc:`PreprocessError` on failure.

   The following utility methods are defined by the :class:`CCompiler` class, for
   use by the various concrete subclasses.


   .. method:: CCompiler.executable_filename(basename[, strip_dir=0, output_dir=''])

      Returns the filename of the executable for the given *basename*.  Typically for
      non-Windows platforms this is the same as the basename,  while Windows will get
      a :file:`.exe` added.


   .. method:: CCompiler.library_filename(libname[, lib_type='static', strip_dir=0, output_dir=''])

      Returns the filename for the given library name on the current platform. On Unix
      a library with *lib_type* of ``'static'`` will typically  be of the form
      :file:`liblibname.a`, while a *lib_type* of ``'dynamic'``  will be of the form
      :file:`liblibname.so`.


   .. method:: CCompiler.object_filenames(source_filenames[, strip_dir=0, output_dir=''])

      Returns the name of the object files for the given source files.
      *source_filenames* should be a list of filenames.


   .. method:: CCompiler.shared_object_filename(basename[, strip_dir=0, output_dir=''])

      Returns the name of a shared object file for the given file name *basename*.


   .. method:: CCompiler.execute(func, args[, msg=None, level=1])

      Invokes :func:`distutils.util.execute`. This method invokes a  Python function
      *func* with the given arguments *args*, after  logging and taking into account
      the *dry_run* flag.


   .. method:: CCompiler.spawn(cmd)

      Invokes :func:`distutils.spawn.spawn`. This invokes an external  process to run
      the given command.


   .. method:: CCompiler.mkpath(name[, mode=511])

      Invokes :func:`distutils.dir_util.mkpath`. This creates a directory  and any
      missing ancestor directories.


   .. method:: CCompiler.move_file(src, dst)

      Invokes :meth:`distutils.file_util.move_file`. Renames *src* to  *dst*.


   .. method:: CCompiler.announce(msg[, level=1])

      Write a message using :func:`distutils.log.debug`.


   .. method:: CCompiler.warn(msg)

      Write a warning message *msg* to standard error.


   .. method:: CCompiler.debug_print(msg)

      If the *debug* flag is set on this :class:`CCompiler` instance, print  *msg* to
      standard output, otherwise do nothing.

.. % \subsection{Compiler-specific modules}
.. %
.. % The following modules implement concrete subclasses of the abstract
.. % \class{CCompiler} class. They should not be instantiated directly, but should
.. % be created using \function{distutils.ccompiler.new_compiler()} factory
.. % function.


:mod:`distutils.unixccompiler` --- Unix C Compiler
==================================================

.. module:: distutils.unixccompiler
   :synopsis: UNIX C Compiler


This module provides the :class:`UnixCCompiler` class, a subclass of
:class:`CCompiler` that handles the typical Unix-style command-line  C compiler:

* macros defined with :option:`!-Dname[=value]`

* macros undefined with :option:`!-Uname`

* include search directories specified with :option:`!-Idir`

* libraries specified with :option:`!-llib`

* library search directories specified with :option:`!-Ldir`

* compile handled by :program:`cc` (or similar) executable with :option:`!-c`
  option: compiles :file:`.c` to :file:`.o`

* link static library handled by :program:`ar` command (possibly with
  :program:`ranlib`)

* link shared library handled by :program:`cc` :option:`!-shared`


:mod:`distutils.msvccompiler` --- Microsoft Compiler
====================================================

.. module:: distutils.msvccompiler
   :synopsis: Microsoft Compiler

.. XXX: This is *waaaaay* out of date!

This module provides :class:`MSVCCompiler`, an implementation of the abstract
:class:`CCompiler` class for Microsoft Visual Studio. Typically, extension
modules need to be compiled with the same compiler that was used to compile
Python. For Python 2.3 and earlier, the compiler was Visual Studio 6. For Python
2.4 and 2.5, the compiler is Visual Studio .NET 2003.

:class:`MSVCCompiler` will normally choose the right compiler, linker etc. on
its own. To override this choice, the environment variables *DISTUTILS_USE_SDK*
and *MSSdk* must be both set. *MSSdk* indicates that the current environment has
been setup by the SDK's ``SetEnv.Cmd`` script, or that the environment variables
had been registered when the SDK was installed; *DISTUTILS_USE_SDK* indicates
that the distutils user has made an explicit choice to override the compiler
selection by :class:`MSVCCompiler`.


:mod:`distutils.bcppcompiler` --- Borland Compiler
==================================================

.. module:: distutils.bcppcompiler


This module provides :class:`BorlandCCompiler`, a subclass of the abstract
:class:`CCompiler` class for the Borland C++ compiler.


:mod:`distutils.cygwinccompiler` --- Cygwin Compiler
====================================================

.. module:: distutils.cygwinccompiler


This module provides the :class:`CygwinCCompiler` class, a subclass of
:class:`UnixCCompiler` that handles the Cygwin port of the GNU C compiler to
Windows.  It also contains the Mingw32CCompiler class which handles the mingw32
port of GCC (same as cygwin in no-cygwin mode).


:mod:`distutils.archive_util` ---  Archiving utilities
======================================================

.. module:: distutils.archive_util
   :synopsis: Utility functions for creating archive files (tarballs, zip files, ...)


This module provides a few functions for creating archive files, such as
tarballs or zipfiles.


.. function:: make_archive(base_name, format[, root_dir=None, base_dir=None, verbose=0, dry_run=0])

   Create an archive file (eg. ``zip`` or ``tar``).  *base_name*  is the name of
   the file to create, minus any format-specific extension;  *format* is the
   archive format: one of ``zip``, ``tar``, ``gztar``, ``bztar``, ``xztar``, or
   ``ztar``. *root_dir* is a directory that will be the root directory of the
   archive; ie. we typically ``chdir`` into *root_dir* before  creating the
   archive.  *base_dir* is the directory where we start  archiving from; ie.
   *base_dir* will be the common prefix of all files and directories in the
   archive.  *root_dir* and *base_dir* both default to the current directory.
   Returns the name of the archive file.

   .. versionchanged:: 3.5
      Added support for the ``xztar`` format.


.. function:: make_tarball(base_name, base_dir[, compress='gzip', verbose=0, dry_run=0])

   'Create an (optional compressed) archive as a tar file from all files in and
   under *base_dir*. *compress* must be ``'gzip'`` (the default),
   ``'bzip2'``, ``'xz'``, ``'compress'``, or ``None``.  For the ``'compress'``
   method the compression utility named by :program:`compress` must be on the
   default program search path, so this is probably Unix-specific.  The output
   tar file will be named :file:`base_dir.tar`, possibly plus the appropriate
   compression extension (``.gz``, ``.bz2``, ``.xz`` or ``.Z``).  Return the
   output filename.

   .. versionchanged:: 3.5
      Added support for the ``xz`` compression.


.. function:: make_zipfile(base_name, base_dir[, verbose=0, dry_run=0])

   Create a zip file from all files in and under *base_dir*.  The output zip file
   will be named *base_name* + :file:`.zip`.  Uses either the  :mod:`zipfile` Python
   module (if available) or the InfoZIP :file:`zip`  utility (if installed and
   found on the default search path).  If neither  tool is available, raises
   :exc:`DistutilsExecError`.   Returns the name of the output zip file.


:mod:`distutils.dep_util` --- Dependency checking
=================================================

.. module:: distutils.dep_util
   :synopsis: Utility functions for simple dependency checking


This module provides functions for performing simple, timestamp-based
dependency of files and groups of files; also, functions based entirely  on such
timestamp dependency analysis.


.. function:: newer(source, target)

   Return true if *source* exists and is more recently modified than *target*, or
   if *source* exists and *target* doesn't. Return false if both exist and *target*
   is the same age or newer  than *source*. Raise :exc:`DistutilsFileError` if
   *source* does not exist.


.. function:: newer_pairwise(sources, targets)

   Walk two filename lists in parallel, testing if each source is newer than its
   corresponding target.  Return a pair of lists (*sources*, *targets*) where
   source is newer than target, according to the semantics of :func:`newer`.

   .. % % equivalent to a listcomp...


.. function:: newer_group(sources, target[, missing='error'])

   Return true if *target* is out-of-date with respect to any file listed in
   *sources*.  In other words, if *target* exists and is newer than every file in
   *sources*, return false; otherwise return true. *missing* controls what we do
   when a source file is missing; the default (``'error'``) is to blow up with an
   :exc:`OSError` from  inside :func:`os.stat`; if it is ``'ignore'``, we silently
   drop any missing source files; if it is ``'newer'``, any missing source files
   make us assume that *target* is out-of-date (this is handy in "dry-run" mode:
   it'll make you pretend to carry out commands that wouldn't work because inputs
   are missing, but that doesn't matter because you're not actually going to run
   the commands).


:mod:`distutils.dir_util` --- Directory tree operations
=======================================================

.. module:: distutils.dir_util
   :synopsis: Utility functions for operating on directories and directory trees


This module provides functions for operating on directories and trees of
directories.


.. function:: mkpath(name[, mode=0o777, verbose=0, dry_run=0])

   Create a directory and any missing ancestor directories.  If the directory
   already exists (or if *name* is the empty string, which means the current
   directory, which of course exists), then do nothing.  Raise
   :exc:`DistutilsFileError` if unable to create some directory along the way (eg.
   some sub-path exists, but is a file rather than a directory).  If *verbose* is
   true, print a one-line summary of each mkdir to stdout.  Return the list of
   directories actually created.


.. function:: create_tree(base_dir, files[, mode=0o777, verbose=0, dry_run=0])

   Create all the empty directories under *base_dir* needed to put *files* there.
   *base_dir* is just the name of a directory which doesn't necessarily exist
   yet; *files* is a list of filenames to be interpreted relative to *base_dir*.
   *base_dir* + the directory portion of every file in *files* will be created if
   it doesn't already exist.  *mode*, *verbose* and *dry_run* flags  are as for
   :func:`mkpath`.


.. function:: copy_tree(src, dst[, preserve_mode=1, preserve_times=1, preserve_symlinks=0, update=0, verbose=0, dry_run=0])

   Copy an entire directory tree *src* to a new location *dst*.  Both *src* and
   *dst* must be directory names.  If *src* is not a directory, raise
   :exc:`DistutilsFileError`.  If *dst* does  not exist, it is created with
   :func:`mkpath`.  The end result of the  copy is that every file in *src* is
   copied to *dst*, and  directories under *src* are recursively copied to *dst*.
   Return the list of files that were copied or might have been copied, using their
   output name. The return value is unaffected by *update* or *dry_run*: it is
   simply the list of all files under *src*, with the names changed to be under
   *dst*.

   *preserve_mode* and *preserve_times* are the same as for
   :func:`distutils.file_util.copy_file`; note that they only apply to
   regular files, not to
   directories.  If *preserve_symlinks* is true, symlinks will be copied as
   symlinks (on platforms that support them!); otherwise (the default), the
   destination of the symlink will be copied.  *update* and *verbose* are the same
   as for :func:`~distutils.file_util.copy_file`.

   Files in *src* that begin with :file:`.nfs` are skipped (more information on
   these files is available in answer D2 of the `NFS FAQ page
   <http://nfs.sourceforge.net/#section_d>`_).

   .. versionchanged:: 3.3.1
      NFS files are ignored.

.. function:: remove_tree(directory[, verbose=0, dry_run=0])

   Recursively remove *directory* and all files and directories underneath it. Any
   errors are ignored (apart from being reported to ``sys.stdout`` if *verbose* is
   true).


:mod:`distutils.file_util` --- Single file operations
=====================================================

.. module:: distutils.file_util
   :synopsis: Utility functions for operating on single files


This module contains some utility functions for operating on individual files.


.. function:: copy_file(src, dst[, preserve_mode=1, preserve_times=1, update=0, link=None, verbose=0, dry_run=0])

   Copy file *src* to *dst*. If *dst* is a directory, then *src* is copied there
   with the same name; otherwise, it must be a filename. (If the file exists, it
   will be ruthlessly clobbered.) If *preserve_mode* is true (the default), the
   file's mode (type and permission bits, or whatever is analogous on the
   current platform) is copied. If *preserve_times* is true (the default), the
   last-modified and last-access times are copied as well. If *update* is true,
   *src* will only be copied if *dst* does not exist, or if *dst* does exist but
   is older than *src*.

   *link* allows you to make hard links (using :func:`os.link`) or symbolic links
   (using :func:`os.symlink`) instead of copying: set it to ``'hard'`` or
   ``'sym'``; if it is ``None`` (the default), files are copied. Don't set *link*
   on systems that don't support it: :func:`copy_file` doesn't check if hard or
   symbolic linking is available.  It uses :func:`~distutils.file_util._copy_file_contents` to copy file
   contents.

   Return a tuple ``(dest_name, copied)``: *dest_name* is the actual  name of the
   output file, and *copied* is true if the file was copied  (or would have been
   copied, if *dry_run* true).

   .. % XXX if the destination file already exists, we clobber it if
   .. % copying, but blow up if linking.  Hmmm.  And I don't know what
   .. % macostools.copyfile() does.  Should definitely be consistent, and
   .. % should probably blow up if destination exists and we would be
   .. % changing it (ie. it's not already a hard/soft link to src OR
   .. % (not update) and (src newer than dst)).


.. function:: move_file(src, dst[, verbose, dry_run])

   Move file *src* to *dst*. If *dst* is a directory, the file will be moved into
   it with the same name; otherwise, *src* is just renamed to *dst*.  Returns the
   new full name of the file.

   .. warning::

      Handles cross-device moves on Unix using :func:`copy_file`.  What about
      other systems?


.. function:: write_file(filename, contents)

   Create a file called *filename* and write *contents* (a sequence of strings
   without line terminators) to it.


:mod:`distutils.util` --- Miscellaneous other utility functions
===============================================================

.. module:: distutils.util
   :synopsis: Miscellaneous other utility functions


This module contains other assorted bits and pieces that don't fit into  any
other utility module.


.. function:: get_platform()

   Return a string that identifies the current platform.  This is used mainly to
   distinguish platform-specific build directories and platform-specific built
   distributions.  Typically includes the OS name and version and the
   architecture (as supplied by 'os.uname()'), although the exact information
   included depends on the OS; e.g., on Linux, the kernel version isn't
   particularly important.

   Examples of returned values:

   * ``linux-i586``
   * ``linux-alpha``
   * ``solaris-2.6-sun4u``

   For non-POSIX platforms, currently just returns ``sys.platform``.

   For Mac OS X systems the OS version reflects the minimal version on which
   binaries will run (that is, the value of ``MACOSX_DEPLOYMENT_TARGET``
   during the build of Python), not the OS version of the current system.

   For universal binary builds on Mac OS X the architecture value reflects
   the universal binary status instead of the architecture of the current
   processor. For 32-bit universal binaries the architecture is ``fat``,
   for 64-bit universal binaries the architecture is ``fat64``, and
   for 4-way universal binaries the architecture is ``universal``. Starting
   from Python 2.7 and Python 3.2 the architecture ``fat3`` is used for
   a 3-way universal build (ppc, i386, x86_64) and ``intel`` is used for
   a universal build with the i386 and x86_64 architectures

   Examples of returned values on Mac OS X:

   * ``macosx-10.3-ppc``

   * ``macosx-10.3-fat``

   * ``macosx-10.5-universal``

   * ``macosx-10.6-intel``

   For AIX, Python 3.9 and later return a string starting with "aix", followed
   by additional fields (separated by ``'-'``) that represent the combined
   values of AIX Version, Release and Technology Level (first field), Build Date
   (second field), and bit-size (third field). Python 3.8 and earlier returned
   only a single additional field with the AIX Version and Release.

   Examples of returned values on AIX:

   * ``aix-5307-0747-32`` # 32-bit build on AIX ``oslevel -s``: 5300-07-00-0000

   * ``aix-7105-1731-64`` # 64-bit build on AIX ``oslevel -s``: 7100-05-01-1731

   * ``aix-7.2``          # Legacy form reported in Python 3.8 and earlier

   .. versionchanged:: 3.9
      The AIX platform string format now also includes the technology level,
      build date, and ABI bit-size.


.. function:: convert_path(pathname)

   Return 'pathname' as a name that will work on the native filesystem, i.e. split
   it on '/' and put it back together again using the current directory separator.
   Needed because filenames in the setup script are always supplied in Unix style,
   and have to be converted to the local convention before we can actually use them
   in the filesystem.  Raises :exc:`ValueError` on non-Unix-ish systems if
   *pathname* either  starts or ends with a slash.


.. function:: change_root(new_root, pathname)

   Return *pathname* with *new_root* prepended.  If *pathname* is relative, this is
   equivalent to ``os.path.join(new_root,pathname)`` Otherwise, it requires making
   *pathname* relative and then joining the two, which is tricky on DOS/Windows.


.. function:: check_environ()

   Ensure that 'os.environ' has all the environment variables we guarantee that
   users can use in config files, command-line options, etc.  Currently this
   includes:

   * :envvar:`HOME` - user's home directory (Unix only)
   * :envvar:`PLAT` - description of the current platform, including hardware and
     OS (see :func:`get_platform`)


.. function:: subst_vars(s, local_vars)

   Perform shell/Perl-style variable substitution on *s*.  Every occurrence of
   ``$`` followed by a name is considered a variable, and variable is substituted
   by the value found in the *local_vars* dictionary, or in ``os.environ`` if it's
   not in *local_vars*. *os.environ* is first checked/augmented to guarantee that
   it contains certain values: see :func:`check_environ`.  Raise :exc:`ValueError`
   for any variables not found in either *local_vars* or ``os.environ``.

   Note that this is not a fully-fledged string interpolation function. A valid
   ``$variable`` can consist only of upper and lower case letters, numbers and an
   underscore. No { } or ( ) style quoting is available.


.. function:: split_quoted(s)

   Split a string up according to Unix shell-like rules for quotes and backslashes.
   In short: words are delimited by spaces, as long as those spaces are not escaped
   by a backslash, or inside a quoted string. Single and double quotes are
   equivalent, and the quote characters can be backslash-escaped.  The backslash is
   stripped from any two-character escape sequence, leaving only the escaped
   character.  The quote characters are stripped from any quoted string.  Returns a
   list of words.

   .. % Should probably be moved into the standard library.


.. function:: execute(func, args[, msg=None, verbose=0, dry_run=0])

   Perform some action that affects the outside world (for instance, writing to the
   filesystem).  Such actions are special because they are disabled by the
   *dry_run* flag.  This method takes  care of all that bureaucracy for you; all
   you have to do is supply the function to call and an argument tuple for it (to
   embody the "external action" being performed), and an optional message to print.


.. function:: strtobool(val)

   Convert a string representation of truth to true (1) or false (0).

   True values are ``y``, ``yes``, ``t``, ``true``, ``on``  and ``1``; false values
   are ``n``, ``no``, ``f``, ``false``,  ``off`` and ``0``.  Raises
   :exc:`ValueError` if *val*  is anything else.


.. function:: byte_compile(py_files[, optimize=0, force=0, prefix=None, base_dir=None, verbose=1, dry_run=0, direct=None])

   Byte-compile a collection of Python source files to :file:`.pyc` files in a
   :file:`__pycache__` subdirectory (see :pep:`3147` and :pep:`488`).
   *py_files* is a list of files to compile; any files that don't end in
   :file:`.py` are silently skipped.  *optimize* must be one of the following:

   * ``0`` - don't optimize
   * ``1`` - normal optimization (like ``python -O``)
   * ``2`` - extra optimization (like ``python -OO``)

   If *force* is true, all files are recompiled regardless of timestamps.

   The source filename encoded in each :term:`bytecode` file defaults to the filenames
   listed in *py_files*; you can modify these with *prefix* and *basedir*.
   *prefix* is a string that will be stripped off of each source filename, and
   *base_dir* is a directory name that will be prepended (after *prefix* is
   stripped).  You can supply either or both (or neither) of *prefix* and
   *base_dir*, as you wish.

   If *dry_run* is true, doesn't actually do anything that would affect the
   filesystem.

   Byte-compilation is either done directly in this interpreter process with the
   standard :mod:`py_compile` module, or indirectly by writing a temporary script
   and executing it.  Normally, you should let :func:`byte_compile` figure out to
   use direct compilation or not (see the source for details).  The *direct* flag
   is used by the script generated in indirect mode; unless you know what you're
   doing, leave it set to ``None``.

   .. versionchanged:: 3.2.3
      Create ``.pyc`` files with an :func:`import magic tag
      <imp.get_tag>` in their name, in a :file:`__pycache__` subdirectory
      instead of files without tag in the current directory.

   .. versionchanged:: 3.5
      Create ``.pyc`` files according to :pep:`488`.


.. function:: rfc822_escape(header)

   Return a version of *header* escaped for inclusion in an :rfc:`822` header, by
   ensuring there are 8 spaces space after each newline. Note that it does no other
   modification of the string.

   .. % this _can_ be replaced

.. % \subsection{Distutils objects}


:mod:`distutils.dist` --- The Distribution class
================================================

.. module:: distutils.dist
   :synopsis: Provides the Distribution class, which represents the module distribution being
              built/installed/distributed


This module provides the :class:`~distutils.core.Distribution` class, which
represents the module distribution being built/installed/distributed.


:mod:`distutils.extension` --- The Extension class
==================================================

.. module:: distutils.extension
   :synopsis: Provides the Extension class, used to describe C/C++ extension modules in setup
              scripts


This module provides the :class:`~distutils.extension.Extension` class,
used to describe C/C++ extension modules in setup scripts.

.. % \subsection{Ungrouped modules}
.. % The following haven't been moved into a more appropriate section yet.


:mod:`distutils.debug` --- Distutils debug mode
===============================================

.. module:: distutils.debug
   :synopsis: Provides the debug flag for distutils


This module provides the DEBUG flag.


:mod:`distutils.errors` --- Distutils exceptions
================================================

.. module:: distutils.errors
   :synopsis: Provides standard distutils exceptions


Provides exceptions used by the Distutils modules.  Note that Distutils modules
may raise standard exceptions; in particular, SystemExit is usually raised for
errors that are obviously the end-user's fault (eg. bad command-line arguments).

This module is safe to use in ``from ... import *`` mode; it only exports
symbols whose names start with ``Distutils`` and end with ``Error``.


:mod:`distutils.fancy_getopt` --- Wrapper around the standard getopt module
===========================================================================

.. module:: distutils.fancy_getopt
   :synopsis: Additional getopt functionality


This module provides a wrapper around the standard :mod:`getopt`  module that
provides the following additional features:

* short and long options are tied together

* options have help strings, so :func:`fancy_getopt` could potentially  create a
  complete usage summary

* options set attributes of a passed-in object

* boolean options can have "negative aliases" --- eg. if :option:`!--quiet` is
  the "negative alias" of :option:`!--verbose`, then :option:`!--quiet` on the
  command line sets *verbose* to false.

.. function:: fancy_getopt(options, negative_opt, object, args)

   Wrapper function. *options* is a list of ``(long_option, short_option,
   help_string)`` 3-tuples as described in the constructor for
   :class:`FancyGetopt`. *negative_opt* should be a dictionary mapping option names
   to option names, both the key and value should be in the *options* list.
   *object* is an object which will be used to store values (see the :meth:`~FancyGetopt.getopt`
   method of the :class:`FancyGetopt` class). *args* is the argument list. Will use
   ``sys.argv[1:]`` if you  pass ``None`` as *args*.


.. function:: wrap_text(text, width)

   Wraps *text* to less than *width* wide.


.. class:: FancyGetopt([option_table=None])

   The option_table is a list of 3-tuples: ``(long_option, short_option,
   help_string)``

   If an option takes an argument, its *long_option* should have ``'='`` appended;
   *short_option* should just be a single character, no ``':'`` in any case.
   *short_option* should be ``None`` if a *long_option*  doesn't have a
   corresponding *short_option*. All option tuples must have long options.

The :class:`FancyGetopt` class provides the following methods:


.. method:: FancyGetopt.getopt([args=None, object=None])

   Parse command-line options in args. Store as attributes on *object*.

   If *args* is ``None`` or not supplied, uses ``sys.argv[1:]``.  If *object* is
   ``None`` or not supplied, creates a new :class:`OptionDummy` instance, stores
   option values there, and returns a tuple ``(args, object)``.  If *object* is
   supplied, it is modified in place and :func:`getopt` just returns *args*; in
   both cases, the returned *args* is a modified copy of the passed-in *args* list,
   which is left untouched.

   .. % and args returned are?


.. method:: FancyGetopt.get_option_order()

   Returns the list of ``(option, value)`` tuples processed by the previous run of
   :meth:`getopt`  Raises :exc:`RuntimeError` if :meth:`getopt` hasn't been called
   yet.


.. method:: FancyGetopt.generate_help([header=None])

   Generate help text (a list of strings, one per suggested line of output) from
   the option table for this :class:`FancyGetopt` object.

   If supplied, prints the supplied *header* at the top of the help.


:mod:`distutils.filelist` --- The FileList class
================================================

.. module:: distutils.filelist
   :synopsis: The FileList class, used for poking about the file system and
              building lists of files.


This module provides the :class:`FileList` class, used for poking about the
filesystem and building lists of files.


:mod:`distutils.log` --- Simple :pep:`282`-style logging
========================================================

.. module:: distutils.log
   :synopsis: A simple logging mechanism, :pep:`282`-style


:mod:`distutils.spawn` --- Spawn a sub-process
==============================================

.. module:: distutils.spawn
   :synopsis: Provides the spawn() function


This module provides the :func:`~distutils.spawn.spawn` function, a
front-end to  various platform-specific functions for launching another
program in a  sub-process.
Also provides :func:`~distutils.spawn.find_executable` to search the path for a given executable
name.


:mod:`distutils.sysconfig` --- System configuration information
===============================================================

.. module:: distutils.sysconfig
   :synopsis: Low-level access to configuration information of the Python interpreter.
.. moduleauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
.. moduleauthor:: Greg Ward <gward@python.net>
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>


The :mod:`distutils.sysconfig` module provides access to Python's low-level
configuration information.  The specific configuration variables available
depend heavily on the platform and configuration. The specific variables depend
on the build process for the specific version of Python being run; the variables
are those found in the :file:`Makefile` and configuration header that are
installed with Python on Unix systems.  The configuration header is called
:file:`pyconfig.h` for Python versions starting with 2.2, and :file:`config.h`
for earlier versions of Python.

Some additional functions are provided which perform some useful manipulations
for other parts of the :mod:`distutils` package.


.. data:: PREFIX

   The result of ``os.path.normpath(sys.prefix)``.


.. data:: EXEC_PREFIX

   The result of ``os.path.normpath(sys.exec_prefix)``.


.. function:: get_config_var(name)

   Return the value of a single variable.  This is equivalent to
   ``get_config_vars().get(name)``.


.. function:: get_config_vars(...)

   Return a set of variable definitions.  If there are no arguments, this returns a
   dictionary mapping names of configuration variables to values.  If arguments are
   provided, they should be strings, and the return value will be a sequence giving
   the associated values. If a given name does not have a corresponding value,
   ``None`` will be included for that variable.


.. function:: get_config_h_filename()

   Return the full path name of the configuration header.  For Unix, this will be
   the header generated by the :program:`configure` script; for other platforms the
   header will have been supplied directly by the Python source distribution.  The
   file is a platform-specific text file.


.. function:: get_makefile_filename()

   Return the full path name of the :file:`Makefile` used to build Python.  For
   Unix, this will be a file generated by the :program:`configure` script; the
   meaning for other platforms will vary.  The file is a platform-specific text
   file, if it exists. This function is only useful on POSIX platforms.


.. function:: get_python_inc([plat_specific[, prefix]])

   Return the directory for either the general or platform-dependent C include
   files.  If *plat_specific* is true, the platform-dependent include directory is
   returned; if false or omitted, the platform-independent directory is returned.
   If *prefix* is given, it is used as either the prefix instead of
   :const:`PREFIX`, or as the exec-prefix instead of :const:`EXEC_PREFIX` if
   *plat_specific* is true.


.. function:: get_python_lib([plat_specific[, standard_lib[, prefix]]])

   Return the directory for either the general or platform-dependent library
   installation.  If *plat_specific* is true, the platform-dependent include
   directory is returned; if false or omitted, the platform-independent directory
   is returned.  If *prefix* is given, it is used as either the prefix instead of
   :const:`PREFIX`, or as the exec-prefix instead of :const:`EXEC_PREFIX` if
   *plat_specific* is true.  If *standard_lib* is true, the directory for the
   standard library is returned rather than the directory for the installation of
   third-party extensions.

The following function is only intended for use within the :mod:`distutils`
package.


.. function:: customize_compiler(compiler)

   Do any platform-specific customization of a
   :class:`distutils.ccompiler.CCompiler` instance.

   This function is only needed on Unix at this time, but should be called
   consistently to support forward-compatibility.  It inserts the information that
   varies across Unix flavors and is stored in Python's :file:`Makefile`.  This
   information includes the selected compiler, compiler and linker options, and the
   extension used by the linker for shared objects.

This function is even more special-purpose, and should only be used from
Python's own build procedures.


.. function:: set_python_build()

   Inform the :mod:`distutils.sysconfig` module that it is being used as part of
   the build process for Python.  This changes a lot of relative locations for
   files, allowing them to be located in the build area rather than in an installed
   Python.


:mod:`distutils.text_file` --- The TextFile class
=================================================

.. module:: distutils.text_file
   :synopsis: Provides the TextFile class, a simple interface to text files


This module provides the :class:`TextFile` class, which gives an interface  to
text files that (optionally) takes care of stripping comments, ignoring  blank
lines, and joining lines with backslashes.


.. class:: TextFile([filename=None, file=None, **options])

   This class provides a file-like object that takes care of all  the things you
   commonly want to do when processing a text file  that has some line-by-line
   syntax: strip comments (as long as ``#``  is your comment character), skip blank
   lines, join adjacent lines by escaping the newline (ie. backslash at end of
   line), strip leading and/or trailing whitespace.  All of these are optional and
   independently controllable.

   The class provides a :meth:`warn` method so you can generate  warning messages
   that report physical line number, even if the  logical line in question spans
   multiple physical lines.  Also  provides :meth:`unreadline` for implementing
   line-at-a-time lookahead.

   :class:`TextFile` instances are create with either *filename*, *file*, or both.
   :exc:`RuntimeError` is raised if both are ``None``. *filename* should be a
   string, and *file* a file object (or something that provides :meth:`readline`
   and :meth:`close`  methods).  It is recommended that you supply at least
   *filename*,  so that :class:`TextFile` can include it in warning messages.  If
   *file* is not supplied, :class:`TextFile` creates its own using the
   :func:`open` built-in function.

   The options are all boolean, and affect the values returned by :meth:`readline`

   .. tabularcolumns:: |l|L|l|

   +------------------+--------------------------------+---------+
   | option name      | description                    | default |
   +==================+================================+=========+
   | *strip_comments* | strip from ``'#'`` to          | true    |
   |                  | end-of-line, as well as any    |         |
   |                  | whitespace leading up to the   |         |
   |                  | ``'#'``\ ---unless it is       |         |
   |                  | escaped by a backslash         |         |
   +------------------+--------------------------------+---------+
   | *lstrip_ws*      | strip leading whitespace from  | false   |
   |                  | each line before returning it  |         |
   +------------------+--------------------------------+---------+
   | *rstrip_ws*      | strip trailing whitespace      | true    |
   |                  | (including line terminator!)   |         |
   |                  | from each line before          |         |
   |                  | returning it.                  |         |
   +------------------+--------------------------------+---------+
   | *skip_blanks*    | skip lines that are empty      | true    |
   |                  | \*after\* stripping comments   |         |
   |                  | and whitespace.  (If both      |         |
   |                  | lstrip_ws and rstrip_ws are    |         |
   |                  | false, then some lines may     |         |
   |                  | consist of solely whitespace:  |         |
   |                  | these will \*not\* be skipped, |         |
   |                  | even if *skip_blanks* is       |         |
   |                  | true.)                         |         |
   +------------------+--------------------------------+---------+
   | *join_lines*     | if a backslash is the last     | false   |
   |                  | non-newline character on a     |         |
   |                  | line after stripping comments  |         |
   |                  | and whitespace, join the       |         |
   |                  | following line to it to form   |         |
   |                  | one logical line; if N         |         |
   |                  | consecutive lines end with a   |         |
   |                  | backslash, then N+1 physical   |         |
   |                  | lines will be joined to form   |         |
   |                  | one logical line.              |         |
   +------------------+--------------------------------+---------+
   | *collapse_join*  | strip leading whitespace from  | false   |
   |                  | lines that are joined to their |         |
   |                  | predecessor; only matters if   |         |
   |                  | ``(join_lines and not          |         |
   |                  | lstrip_ws)``                   |         |
   +------------------+--------------------------------+---------+

   Note that since *rstrip_ws* can strip the trailing newline, the semantics of
   :meth:`readline` must differ from those of the built-in file object's
   :meth:`readline` method!  In particular, :meth:`readline`  returns ``None`` for
   end-of-file: an empty string might just be a  blank line (or an all-whitespace
   line), if *rstrip_ws* is true  but *skip_blanks* is not.


   .. method:: TextFile.open(filename)

      Open a new file *filename*.  This overrides any *file* or *filename*
      constructor arguments.


   .. method:: TextFile.close()

      Close the current file and forget everything we know about it (including the
      filename and the current line number).


   .. method:: TextFile.warn(msg[,line=None])

      Print (to stderr) a warning message tied to the current logical line in the
      current file.  If the current logical line in the file spans multiple physical
      lines, the warning refers to the whole range, such as ``"lines 3-5"``.  If
      *line* is supplied,  it overrides the current line number; it may be a list or
      tuple  to indicate a range of physical lines, or an integer for a  single
      physical line.


   .. method:: TextFile.readline()

      Read and return a single logical line from the current file (or from an internal
      buffer if lines have previously been "unread" with :meth:`unreadline`).  If the
      *join_lines* option  is true, this may involve reading multiple physical lines
      concatenated into a single string.  Updates the current line number,  so calling
      :meth:`warn` after :meth:`readline` emits a warning  about the physical line(s)
      just read.  Returns ``None`` on end-of-file,  since the empty string can occur
      if *rstrip_ws* is true but  *strip_blanks* is not.


   .. method:: TextFile.readlines()

      Read and return the list of all logical lines remaining in the current file.
      This updates the current line number to the last line of the file.


   .. method:: TextFile.unreadline(line)

      Push *line* (a string) onto an internal buffer that will be checked by future
      :meth:`readline` calls.  Handy for implementing a parser with line-at-a-time
      lookahead. Note that lines that are "unread" with :meth:`unreadline` are not
      subsequently re-cleansed (whitespace  stripped, or whatever) when read with
      :meth:`readline`. If multiple calls are made to :meth:`unreadline` before a call
      to :meth:`readline`, the lines will be returned most in most recent first order.


:mod:`distutils.version` --- Version number classes
===================================================

.. module:: distutils.version
   :synopsis: Implements classes that represent module version numbers.


.. % todo
.. % \section{Distutils Commands}
.. %
.. % This part of Distutils implements the various Distutils commands, such
.. % as \code{build}, \code{install} \&c. Each command is implemented as a
.. % separate module, with the command name as the name of the module.


:mod:`distutils.cmd` --- Abstract base class for Distutils commands
===================================================================

.. module:: distutils.cmd
   :synopsis: Provides the abstract base class :class:`~distutils.cmd.Command`. This class
              is subclassed by the modules in the distutils.command subpackage.


This module supplies the abstract base class :class:`Command`.


.. class:: Command(dist)

   Abstract base class for defining command classes, the "worker bees" of the
   Distutils.  A useful analogy for command classes is to think of them as
   subroutines with local variables called *options*.  The options are declared
   in :meth:`initialize_options` and defined (given their final values) in
   :meth:`finalize_options`, both of which must be defined by every command
   class.  The distinction between the two is necessary because option values
   might come from the outside world (command line, config file, ...), and any
   options dependent on other options must be computed after these outside
   influences have been processed --- hence :meth:`finalize_options`.  The body
   of the subroutine, where it does all its work based on the values of its
   options, is the :meth:`run` method, which must also be implemented by every
   command class.

   The class constructor takes a single argument *dist*, a
   :class:`~distutils.core.Distribution` instance.


Creating a new Distutils command
================================

This section outlines the steps to create a new Distutils command.

A new command lives in a module in the :mod:`distutils.command` package. There
is a sample template in that directory called :file:`command_template`.  Copy
this file to a new module with the same name as the new command you're
implementing.  This module should implement a class with the same name as the
module (and the command).  So, for instance, to create the command
``peel_banana`` (so that users can run ``setup.py peel_banana``), you'd copy
:file:`command_template` to :file:`distutils/command/peel_banana.py`, then edit
it so that it's implementing the class ``peel_banana``, a subclass of
:class:`distutils.cmd.Command`.

Subclasses of :class:`Command` must define the following methods.

.. method:: Command.initialize_options()

   Set default values for all the options that this command supports.  Note that
   these defaults may be overridden by other commands, by the setup script, by
   config files, or by the command-line.  Thus, this is not the place to code
   dependencies between options; generally, :meth:`initialize_options`
   implementations are just a bunch of ``self.foo = None`` assignments.


.. method:: Command.finalize_options()

   Set final values for all the options that this command supports. This is
   always called as late as possible, ie.  after any option assignments from the
   command-line or from other commands have been done.  Thus, this is the place
   to code option dependencies: if *foo* depends on *bar*, then it is safe to
   set *foo* from *bar* as long as *foo* still has the same value it was
   assigned in :meth:`initialize_options`.


.. method:: Command.run()

   A command's raison d'etre: carry out the action it exists to perform, controlled
   by the options initialized in :meth:`initialize_options`, customized by other
   commands, the setup script, the command-line, and config files, and finalized in
   :meth:`finalize_options`.  All terminal output and filesystem interaction should
   be done by :meth:`run`.


.. attribute:: Command.sub_commands

   *sub_commands* formalizes the notion of a "family" of commands,
   e.g. ``install`` as the parent with sub-commands ``install_lib``,
   ``install_headers``, etc.  The parent of a family of commands defines
   *sub_commands* as a class attribute; it's a list of 2-tuples ``(command_name,
   predicate)``, with *command_name* a string and *predicate* a function, a
   string or ``None``.  *predicate* is a method of the parent command that
   determines whether the corresponding command is applicable in the current
   situation.  (E.g. ``install_headers`` is only applicable if we have any C
   header files to install.)  If *predicate* is ``None``, that command is always
   applicable.

   *sub_commands* is usually defined at the *end* of a class, because
   predicates can be methods of the class, so they must already have been
   defined.  The canonical example is the :command:`install` command.


:mod:`distutils.command` --- Individual Distutils commands
==========================================================

.. module:: distutils.command
   :synopsis: Contains one module for each standard Distutils command.


.. % \subsubsection{Individual Distutils commands}
.. % todo


:mod:`distutils.command.bdist` --- Build a binary installer
===========================================================

.. module:: distutils.command.bdist
   :synopsis: Build a binary installer for a package


.. % todo


:mod:`distutils.command.bdist_packager` --- Abstract base class for packagers
=============================================================================

.. module:: distutils.command.bdist_packager
   :synopsis: Abstract base class for packagers


.. % todo


:mod:`distutils.command.bdist_dumb` --- Build a "dumb" installer
================================================================

.. module:: distutils.command.bdist_dumb
   :synopsis: Build a "dumb" installer - a simple archive of files


:mod:`distutils.command.bdist_rpm` --- Build a binary distribution as a Redhat RPM and SRPM
===========================================================================================

.. module:: distutils.command.bdist_rpm
   :synopsis: Build a binary distribution as a Redhat RPM and SRPM


.. % todo


:mod:`distutils.command.sdist` --- Build a source distribution
==============================================================

.. module:: distutils.command.sdist
   :synopsis: Build a source distribution


.. % todo


:mod:`distutils.command.build` --- Build all files of a package
===============================================================

.. module:: distutils.command.build
   :synopsis: Build all files of a package


.. % todo


:mod:`distutils.command.build_clib` --- Build any C libraries in a package
==========================================================================

.. module:: distutils.command.build_clib
   :synopsis: Build any C libraries in a package


.. % todo


:mod:`distutils.command.build_ext` --- Build any extensions in a package
========================================================================

.. module:: distutils.command.build_ext
   :synopsis: Build any extensions in a package


.. % todo


:mod:`distutils.command.build_py` --- Build the .py/.pyc files of a package
===========================================================================

.. module:: distutils.command.build_py
   :synopsis: Build the .py/.pyc files of a package


.. class:: build_py


:mod:`distutils.command.build_scripts` --- Build the scripts of a package
=========================================================================

.. module:: distutils.command.build_scripts
   :synopsis: Build the scripts of a package


.. % todo


:mod:`distutils.command.clean` --- Clean a package build area
=============================================================

.. module:: distutils.command.clean
   :synopsis: Clean a package build area

This command removes the temporary files created by :command:`build`
and its subcommands, like intermediary compiled object files.  With
the ``--all`` option, the complete build directory will be removed.

Extension modules built :ref:`in place <distutils-build-ext-inplace>`
will not be cleaned, as they are not in the build directory.


:mod:`distutils.command.config` --- Perform package configuration
=================================================================

.. module:: distutils.command.config
   :synopsis: Perform package configuration


.. % todo


:mod:`distutils.command.install` --- Install a package
======================================================

.. module:: distutils.command.install
   :synopsis: Install a package


.. % todo


:mod:`distutils.command.install_data` --- Install data files from a package
===========================================================================

.. module:: distutils.command.install_data
   :synopsis: Install data files from a package


.. % todo


:mod:`distutils.command.install_headers` --- Install C/C++ header files from a package
======================================================================================

.. module:: distutils.command.install_headers
   :synopsis: Install C/C++ header files from a package


.. % todo


:mod:`distutils.command.install_lib` --- Install library files from a package
=============================================================================

.. module:: distutils.command.install_lib
   :synopsis: Install library files from a package


.. % todo


:mod:`distutils.command.install_scripts` --- Install script files from a package
================================================================================

.. module:: distutils.command.install_scripts
   :synopsis: Install script files from a package


.. % todo


:mod:`distutils.command.register` --- Register a module with the Python Package Index
=====================================================================================

.. module:: distutils.command.register
   :synopsis: Register a module with the Python Package Index


The ``register`` command registers the package with the Python Package  Index.
This is described in more detail in :pep:`301`.

.. % todo


:mod:`distutils.command.check` --- Check the meta-data of a package
===================================================================

.. module:: distutils.command.check
   :synopsis: Check the meta-data of a package


The ``check`` command performs some tests on the meta-data of a package.
For example, it verifies that all required meta-data are provided as
the arguments passed to the :func:`~distutils.core.setup` function.

.. % todo
alt-python312-setuptools/docs/deprecated/distutils/examples.rst000064400000024016150410147350020737 0ustar00.. _distutils_examples:

******************
Distutils Examples
******************

.. include:: ./_setuptools_disclaimer.rst

This chapter provides a number of basic examples to help get started with
distutils.  Additional information about using distutils can be found in the
Distutils Cookbook.


.. seealso::

   `Distutils Cookbook <https://wiki.python.org/moin/Distutils/Cookbook>`_
      Collection of recipes showing how to achieve more control over distutils.


.. _pure-mod:

Pure Python distribution (by module)
====================================

If you're just distributing a couple of modules, especially if they don't live
in a particular package, you can specify them individually using the
``py_modules`` option in the setup script.

In the simplest case, you'll have two files to worry about: a setup script and
the single module you're distributing, :file:`foo.py` in this example::

   <root>/
           setup.py
           foo.py

(In all diagrams in this section, *<root>* will refer to the distribution root
directory.)  A minimal setup script to describe this situation would be::

   from distutils.core import setup
   setup(name='foo',
         version='1.0',
         py_modules=['foo'],
         )

Note that the name of the distribution is specified independently with the
``name`` option, and there's no rule that says it has to be the same as
the name of the sole module in the distribution (although that's probably a good
convention to follow).  However, the distribution name is used to generate
filenames, so you should stick to letters, digits, underscores, and hyphens.

Since ``py_modules`` is a list, you can of course specify multiple
modules, eg. if you're distributing modules ``foo`` and ``bar``, your
setup might look like this::

   <root>/
           setup.py
           foo.py
           bar.py

and the setup script might be  ::

   from distutils.core import setup
   setup(name='foobar',
         version='1.0',
         py_modules=['foo', 'bar'],
         )

You can put module source files into another directory, but if you have enough
modules to do that, it's probably easier to specify modules by package rather
than listing them individually.


.. _pure-pkg:

Pure Python distribution (by package)
=====================================

If you have more than a couple of modules to distribute, especially if they are
in multiple packages, it's probably easier to specify whole packages rather than
individual modules.  This works even if your modules are not in a package; you
can just tell the Distutils to process modules from the root package, and that
works the same as any other package (except that you don't have to have an
:file:`__init__.py` file).

The setup script from the last example could also be written as  ::

   from distutils.core import setup
   setup(name='foobar',
         version='1.0',
         packages=[''],
         )

(The empty string stands for the root package.)

If those two files are moved into a subdirectory, but remain in the root
package, e.g.::

   <root>/
           setup.py
           src/      foo.py
                     bar.py

then you would still specify the root package, but you have to tell the
Distutils where source files in the root package live::

   from distutils.core import setup
   setup(name='foobar',
         version='1.0',
         package_dir={'': 'src'},
         packages=[''],
         )

More typically, though, you will want to distribute multiple modules in the same
package (or in sub-packages).  For example, if the ``foo``  and ``bar``
modules belong in package ``foobar``, one way to layout your source tree is
::

   <root>/
           setup.py
           foobar/
                    __init__.py
                    foo.py
                    bar.py

This is in fact the default layout expected by the Distutils, and the one that
requires the least work to describe in your setup script::

   from distutils.core import setup
   setup(name='foobar',
         version='1.0',
         packages=['foobar'],
         )

If you want to put modules in directories not named for their package, then you
need to use the ``package_dir`` option again.  For example, if the
:file:`src` directory holds modules in the ``foobar`` package::

   <root>/
           setup.py
           src/
                    __init__.py
                    foo.py
                    bar.py

an appropriate setup script would be  ::

   from distutils.core import setup
   setup(name='foobar',
         version='1.0',
         package_dir={'foobar': 'src'},
         packages=['foobar'],
         )

Or, you might put modules from your main package right in the distribution
root::

   <root>/
           setup.py
           __init__.py
           foo.py
           bar.py

in which case your setup script would be  ::

   from distutils.core import setup
   setup(name='foobar',
         version='1.0',
         package_dir={'foobar': ''},
         packages=['foobar'],
         )

(The empty string also stands for the current directory.)

If you have sub-packages, they must be explicitly listed in ``packages``,
but any entries in ``package_dir`` automatically extend to sub-packages.
(In other words, the Distutils does *not* scan your source tree, trying to
figure out which directories correspond to Python packages by looking for
:file:`__init__.py` files.)  Thus, if the default layout grows a sub-package::

   <root>/
           setup.py
           foobar/
                    __init__.py
                    foo.py
                    bar.py
                    subfoo/
                              __init__.py
                              blah.py

then the corresponding setup script would be  ::

   from distutils.core import setup
   setup(name='foobar',
         version='1.0',
         packages=['foobar', 'foobar.subfoo'],
         )


.. _single-ext:

Single extension module
=======================

Extension modules are specified using the ``ext_modules`` option.
``package_dir`` has no effect on where extension source files are found;
it only affects the source for pure Python modules.  The simplest  case, a
single extension module in a single C source file, is::

   <root>/
           setup.py
           foo.c

If the ``foo`` extension belongs in the root package, the setup script for
this could be  ::

   from distutils.core import setup
   from distutils.extension import Extension
   setup(name='foobar',
         version='1.0',
         ext_modules=[Extension('foo', ['foo.c'])],
         )

If the extension actually belongs in a package, say ``foopkg``, then

With exactly the same source tree layout, this extension can be put in the
``foopkg`` package simply by changing the name of the extension::

   from distutils.core import setup
   from distutils.extension import Extension
   setup(name='foobar',
         version='1.0',
         ext_modules=[Extension('foopkg.foo', ['foo.c'])],
         )

Checking a package
==================

The ``check`` command allows you to verify if your package meta-data
meet the minimum requirements to build a distribution.

To run it, just call it using your :file:`setup.py` script. If something is
missing, ``check`` will display a warning.

Let's take an example with a simple script::

    from distutils.core import setup

    setup(name='foobar')

Running the ``check`` command will display some warnings:

.. code-block:: shell-session

    $ python setup.py check
    running check
    warning: check: missing required meta-data: version


If you use the reStructuredText syntax in the ``long_description`` field and
`docutils`_  is installed you can check if the syntax is fine with the
``check`` command, using the ``restructuredtext`` option.

For example, if the :file:`setup.py` script is changed like this::

    from distutils.core import setup

    desc = """\
    My description
    ==============

    This is the description of the ``foobar`` package.
    """

    setup(name='foobar', version='1', author='tarek',
        author_email='tarek@ziade.org',
        url='http://example.com', long_description=desc)

Where the long description is broken, ``check`` will be able to detect it
by using the :mod:`docutils` parser:

.. code-block:: shell-session

    $ python setup.py check --restructuredtext
    running check
    warning: check: Title underline too short. (line 2)
    warning: check: Could not finish the parsing.

Reading the metadata
=====================

The :func:`distutils.core.setup` function provides a command-line interface
that allows you to query the metadata fields of a project through the
``setup.py`` script of a given project:

.. code-block:: shell-session

    $ python setup.py --name
    distribute

This call reads the ``name`` metadata by running the
:func:`distutils.core.setup`  function. Although, when a source or binary
distribution is created with Distutils, the metadata fields are written
in a static file called :file:`PKG-INFO`. When a Distutils-based project is
installed in Python, the :file:`PKG-INFO` file is copied alongside the modules
and packages of the distribution under :file:`NAME-VERSION-pyX.X.egg-info`,
where ``NAME`` is the name of the project, ``VERSION`` its version as defined
in the Metadata, and ``pyX.X`` the major and minor version of Python like
``2.7`` or ``3.2``.

You can read back this static file, by using the
:class:`distutils.dist.DistributionMetadata` class and its
:func:`~distutils.dist.DistributionMetadata.read_pkg_file` method::

    >>> from distutils.dist import DistributionMetadata
    >>> metadata = DistributionMetadata()
    >>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info'))
    >>> metadata.name
    'distribute'
    >>> metadata.version
    '0.6.8'
    >>> metadata.description
    'Easily download, build, install, upgrade, and uninstall Python packages'

Notice that the class can also be instantiated with a metadata file path to
loads its values::

    >>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info'
    >>> DistributionMetadata(pkg_info_path).name
    'distribute'


.. % \section{Multiple extension modules}
.. % \label{multiple-ext}

.. % \section{Putting it all together}


.. _docutils: http://docutils.sourceforge.net
alt-python312-setuptools/docs/deprecated/distutils/uploading.rst000064400000000366150410147350021105 0ustar00:orphan:

***************************************
Uploading Packages to the Package Index
***************************************

See the
`Python Packaging User Guide <https://packaging.python.org>`_
for the best guidance on uploading packages.
alt-python312-setuptools/docs/deprecated/distutils/packageindex.rst000064400000000657150410147350021551 0ustar00:orphan:

.. _package-index:

*******************************
The Python Package Index (PyPI)
*******************************

The `Python Package Index (PyPI) <https://pypi.org>`_ stores
metadata describing distributions packaged with distutils and
other publishing tools, as well the distribution archives
themselves.

The best resource for working with PyPI is the
`Python Packaging User Guide <https://packaging.python.org>`_.
alt-python312-setuptools/docs/deprecated/distutils/sourcedist.rst000064400000023015150410147360021304 0ustar00.. _source-dist:

******************************
Creating a Source Distribution
******************************

.. include:: ./_setuptools_disclaimer.rst

As shown in section :ref:`distutils-simple-example`, you use the :command:`sdist` command
to create a source distribution.  In the simplest case, ::

   python setup.py sdist

(assuming you haven't specified any :command:`sdist` options in the setup script
or config file), :command:`sdist` creates the archive of the default format for
the current platform.  The default format is a gzip'ed tar file
(:file:`.tar.gz`) on Unix, and ZIP file on Windows.

You can specify as many formats as you like using the :option:`!--formats`
option, for example::

   python setup.py sdist --formats=gztar,zip

to create a gzipped tarball and a zip file.  The available formats are:

+-----------+-------------------------+---------+
| Format    | Description             | Notes   |
+===========+=========================+=========+
| ``zip``   | zip file (:file:`.zip`) | (1),(3) |
+-----------+-------------------------+---------+
| ``gztar`` | gzip'ed tar file        | \(2)    |
|           | (:file:`.tar.gz`)       |         |
+-----------+-------------------------+---------+
| ``bztar`` | bzip2'ed tar file       |         |
|           | (:file:`.tar.bz2`)      |         |
+-----------+-------------------------+---------+
| ``xztar`` | xz'ed tar file          |         |
|           | (:file:`.tar.xz`)       |         |
+-----------+-------------------------+---------+
| ``ztar``  | compressed tar file     | \(4)    |
|           | (:file:`.tar.Z`)        |         |
+-----------+-------------------------+---------+
| ``tar``   | tar file (:file:`.tar`) |         |
+-----------+-------------------------+---------+

.. versionchanged:: 3.5
   Added support for the ``xztar`` format.

Notes:

(1)
   default on Windows

(2)
   default on Unix

(3)
   requires either external :program:`zip` utility or :mod:`zipfile` module (part
   of the standard Python library since Python 1.6)

(4)
   requires the :program:`compress` program. Notice that this format is now
   pending for deprecation and will be removed in the future versions of Python.

When using any ``tar`` format (``gztar``, ``bztar``, ``xztar``, ``ztar`` or
``tar``), under Unix you can specify the ``owner`` and ``group`` names
that will be set for each member of the archive.

For example, if you want all files of the archive to be owned by root::

    python setup.py sdist --owner=root --group=root


.. _manifest:

Specifying the files to distribute
==================================

If you don't supply an explicit list of files (or instructions on how to
generate one), the :command:`sdist` command puts a minimal default set into the
source distribution:

* all Python source files implied by the ``py_modules`` and
  ``packages`` options

* all C source files mentioned in the ``ext_modules`` or
  ``libraries`` options

  .. XXX getting C library sources currently broken---no
         :meth:`get_source_files` method in :file:`build_clib.py`!

* scripts identified by the ``scripts`` option
  See :ref:`distutils-installing-scripts`.

* anything that looks like a test script: :file:`test/test\*.py` (currently, the
  Distutils don't do anything with test scripts except include them in source
  distributions, but in the future there will be a standard for testing Python
  module distributions)

* Any of the standard README files (:file:`README`, :file:`README.txt`,
  or :file:`README.rst`), :file:`setup.py` (or whatever you called your setup
  script), and :file:`setup.cfg`.

* all files that matches the ``package_data`` metadata.
  See :ref:`distutils-installing-package-data`.

* all files that matches the ``data_files`` metadata.
  See :ref:`distutils-additional-files`.

Sometimes this is enough, but usually you will want to specify additional files
to distribute.  The typical way to do this is to write a *manifest template*,
called :file:`MANIFEST.in` by default.  The manifest template is just a list of
instructions for how to generate your manifest file, :file:`MANIFEST`, which is
the exact list of files to include in your source distribution.  The
:command:`sdist` command processes this template and generates a manifest based
on its instructions and what it finds in the filesystem.

If you prefer to roll your own manifest file, the format is simple: one filename
per line, regular files (or symlinks to them) only.  If you do supply your own
:file:`MANIFEST`, you must specify everything: the default set of files
described above does not apply in this case.

.. versionchanged:: 3.1
   An existing generated :file:`MANIFEST` will be regenerated without
   :command:`sdist` comparing its modification time to the one of
   :file:`MANIFEST.in` or :file:`setup.py`.

.. versionchanged:: 3.1.3
   :file:`MANIFEST` files start with a comment indicating they are generated.
   Files without this comment are not overwritten or removed.

.. versionchanged:: 3.2.2
   :command:`sdist` will read a :file:`MANIFEST` file if no :file:`MANIFEST.in`
   exists, like it used to do.

.. versionchanged:: 3.7
   :file:`README.rst` is now included in the list of distutils standard READMEs.


The manifest template has one command per line, where each command specifies a
set of files to include or exclude from the source distribution.  For an
example, again we turn to the Distutils' own manifest template:

.. code-block:: none

   include *.txt
   recursive-include examples *.txt *.py
   prune examples/sample?/build

The meanings should be fairly clear: include all files in the distribution root
matching :file:`\*.txt`, all files anywhere under the :file:`examples` directory
matching :file:`\*.txt` or :file:`\*.py`, and exclude all directories matching
:file:`examples/sample?/build`.  All of this is done *after* the standard
include set, so you can exclude files from the standard set with explicit
instructions in the manifest template.  (Or, you can use the
:option:`!--no-defaults` option to disable the standard set entirely.)  There are
several other commands available in the manifest template mini-language; see
section :ref:`sdist-cmd`.

The order of commands in the manifest template matters: initially, we have the
list of default files as described above, and each command in the template adds
to or removes from that list of files.  Once we have fully processed the
manifest template, we remove files that should not be included in the source
distribution:

* all files in the Distutils "build" tree (default :file:`build/`)

* all files in directories named :file:`RCS`, :file:`CVS`, :file:`.svn`,
  :file:`.hg`, :file:`.git`, :file:`.bzr` or :file:`_darcs`

Now we have our complete list of files, which is written to the manifest for
future reference, and then used to build the source distribution archive(s).

You can disable the default set of included files with the
:option:`!--no-defaults` option, and you can disable the standard exclude set
with :option:`!--no-prune`.

Following the Distutils' own manifest template, let's trace how the
:command:`sdist` command builds the list of files to include in the Distutils
source distribution:

#. include all Python source files in the :file:`distutils` and
   :file:`distutils/command` subdirectories (because packages corresponding to
   those two directories were mentioned in the ``packages`` option in the
   setup script---see section :ref:`setup-script`)

#. include :file:`README.txt`, :file:`setup.py`, and :file:`setup.cfg` (standard
   files)

#. include :file:`test/test\*.py` (standard files)

#. include :file:`\*.txt` in the distribution root (this will find
   :file:`README.txt` a second time, but such redundancies are weeded out later)

#. include anything matching :file:`\*.txt` or :file:`\*.py` in the sub-tree
   under :file:`examples`,

#. exclude all files in the sub-trees starting at directories matching
   :file:`examples/sample?/build`\ ---this may exclude files included by the
   previous two steps, so it's important that the ``prune`` command in the manifest
   template comes after the ``recursive-include`` command

#. exclude the entire :file:`build` tree, and any :file:`RCS`, :file:`CVS`,
   :file:`.svn`, :file:`.hg`, :file:`.git`, :file:`.bzr` and :file:`_darcs`
   directories

Just like in the setup script, file and directory names in the manifest template
should always be slash-separated; the Distutils will take care of converting
them to the standard representation on your platform. That way, the manifest
template is portable across operating systems.


.. _manifest-options:

Manifest-related options
========================

The normal course of operations for the :command:`sdist` command is as follows:

* if the manifest file (:file:`MANIFEST` by default) exists and the first line
  does not have a comment indicating it is generated from :file:`MANIFEST.in`,
  then it is used as is, unaltered

* if the manifest file doesn't exist or has been previously automatically
  generated, read :file:`MANIFEST.in` and create the manifest

* if neither :file:`MANIFEST` nor :file:`MANIFEST.in` exist, create a manifest
  with just the default file set

* use the list of files now in :file:`MANIFEST` (either just generated or read
  in) to create the source distribution archive(s)

There are a couple of options that modify this behaviour.  First, use the
:option:`!--no-defaults` and :option:`!--no-prune` to disable the standard
"include" and "exclude" sets.

Second, you might just want to (re)generate the manifest, but not create a source
distribution::

   python setup.py sdist --manifest-only

:option:`!-o` is a shortcut for :option:`!--manifest-only`.
alt-python312-setuptools/docs/deprecated/distutils/builtdist.rst000064400000045624150410147360021135 0ustar00.. _built-dist:

****************************
Creating Built Distributions
****************************

.. include:: ./_setuptools_disclaimer.rst

A "built distribution" is what you're probably used to thinking of either as a
"binary package" or an "installer" (depending on your background).  It's not
necessarily binary, though, because it might contain only Python source code
and/or byte-code; and we don't call it a package, because that word is already
spoken for in Python.  (And "installer" is a term specific to the world of
mainstream desktop systems.)

A built distribution is how you make life as easy as possible for installers of
your module distribution: for users of RPM-based Linux systems, it's a binary
RPM; for Windows users, it's an executable installer; for Debian-based Linux
users, it's a Debian package; and so forth.  Obviously, no one person will be
able to create built distributions for every platform under the sun, so the
Distutils are designed to enable module developers to concentrate on their
specialty---writing code and creating source distributions---while an
intermediary species called *packagers* springs up to turn source distributions
into built distributions for as many platforms as there are packagers.

Of course, the module developer could be their own packager; or the packager could
be a volunteer "out there" somewhere who has access to a platform which the
original developer does not; or it could be software periodically grabbing new
source distributions and turning them into built distributions for as many
platforms as the software has access to.  Regardless of who they are, a packager
uses the setup script and the :command:`bdist` command family to generate built
distributions.

As a simple example, if I run the following command in the Distutils source
tree::

   python setup.py bdist

then the Distutils builds my module distribution (the Distutils itself in this
case), does a "fake" installation (also in the :file:`build` directory), and
creates the default type of built distribution for my platform.  The default
format for built distributions is a "dumb" tar file on Unix, and a simple
executable installer on Windows.  (That tar file is considered "dumb" because it
has to be unpacked in a specific location to work.)

Thus, the above command on a Unix system creates
:file:`Distutils-1.0.{plat}.tar.gz`; unpacking this tarball from the right place
installs the Distutils just as though you had downloaded the source distribution
and run ``python setup.py install``.  (The "right place" is either the root of
the filesystem or  Python's :file:`{prefix}` directory, depending on the options
given to the :command:`bdist_dumb` command; the default is to make dumb
distributions relative to :file:`{prefix}`.)

Obviously, for pure Python distributions, this isn't any simpler than just
running ``python setup.py install``\ ---but for non-pure distributions, which
include extensions that would need to be compiled, it can mean the difference
between someone being able to use your extensions or not.  And creating "smart"
built distributions, such as an RPM package or an executable installer for
Windows, is far more convenient for users even if your distribution doesn't
include any extensions.

The :command:`bdist` command has a :option:`!--formats` option, similar to the
:command:`sdist` command, which you can use to select the types of built
distribution to generate: for example, ::

   python setup.py bdist --format=zip

would, when run on a Unix system, create
:file:`Distutils-1.0.{plat}.zip`\ ---again, this archive would be unpacked
from the root directory to install the Distutils.

The available formats for built distributions are:

+-------------+------------------------------+---------+
| Format      | Description                  | Notes   |
+=============+==============================+=========+
| ``gztar``   | gzipped tar file             | \(1)    |
|             | (:file:`.tar.gz`)            |         |
+-------------+------------------------------+---------+
| ``bztar``   | bzipped tar file             |         |
|             | (:file:`.tar.bz2`)           |         |
+-------------+------------------------------+---------+
| ``xztar``   | xzipped tar file             |         |
|             | (:file:`.tar.xz`)            |         |
+-------------+------------------------------+---------+
| ``ztar``    | compressed tar file          | \(3)    |
|             | (:file:`.tar.Z`)             |         |
+-------------+------------------------------+---------+
| ``tar``     | tar file (:file:`.tar`)      |         |
+-------------+------------------------------+---------+
| ``zip``     | zip file (:file:`.zip`)      | (2),(4) |
+-------------+------------------------------+---------+
| ``rpm``     | RPM                          | \(5)    |
+-------------+------------------------------+---------+
| ``pkgtool`` | Solaris :program:`pkgtool`   |         |
+-------------+------------------------------+---------+
| ``sdux``    | HP-UX :program:`swinstall`   |         |
+-------------+------------------------------+---------+

.. versionchanged:: 3.5
   Added support for the ``xztar`` format.


Notes:

(1)
   default on Unix

(2)
   default on Windows

(3)
   requires external :program:`compress` utility.

(4)
   requires either external :program:`zip` utility or :mod:`zipfile` module (part
   of the standard Python library since Python 1.6)

(5)
   requires external :program:`rpm` utility, version 3.0.4 or better (use ``rpm
   --version`` to find out which version you have)

You don't have to use the :command:`bdist` command with the :option:`!--formats`
option; you can also use the command that directly implements the format you're
interested in.  Some of these :command:`bdist` "sub-commands" actually generate
several similar formats; for instance, the :command:`bdist_dumb` command
generates all the "dumb" archive formats (``tar``, ``gztar``, ``bztar``,
``xztar``, ``ztar``, and ``zip``), and :command:`bdist_rpm` generates both
binary and source RPMs.  The :command:`bdist` sub-commands, and the formats
generated by each, are:

+--------------------------+-------------------------------------+
| Command                  | Formats                             |
+==========================+=====================================+
| :command:`bdist_dumb`    | tar, gztar, bztar, xztar, ztar, zip |
+--------------------------+-------------------------------------+
| :command:`bdist_rpm`     | rpm, srpm                           |
+--------------------------+-------------------------------------+

The following sections give details on the individual :command:`bdist_\*`
commands.


.. .. _creating-dumb:

.. Creating dumb built distributions
.. =================================

.. XXX Need to document absolute vs. prefix-relative packages here, but first
   I have to implement it!


.. _creating-rpms:

Creating RPM packages
=====================

The RPM format is used by many popular Linux distributions, including Red Hat,
SuSE, and Mandrake.  If one of these (or any of the other RPM-based Linux
distributions) is your usual environment, creating RPM packages for other users
of that same distribution is trivial. Depending on the complexity of your module
distribution and differences between Linux distributions, you may also be able
to create RPMs that work on different RPM-based distributions.

The usual way to create an RPM of your module distribution is to run the
:command:`bdist_rpm` command::

   python setup.py bdist_rpm

or the :command:`bdist` command with the :option:`!--format` option::

   python setup.py bdist --formats=rpm

The former allows you to specify RPM-specific options; the latter allows  you to
easily specify multiple formats in one run.  If you need to do both, you can
explicitly specify multiple :command:`bdist_\*` commands and their options::

   python setup.py bdist_rpm --packager="John Doe <jdoe@example.org>" \
                   bdist_dumb --dumb-option=foo

Creating RPM packages is driven by a :file:`.spec` file, much as using the
Distutils is driven by the setup script.  To make your life easier, the
:command:`bdist_rpm` command normally creates a :file:`.spec` file based on the
information you supply in the setup script, on the command line, and in any
Distutils configuration files.  Various options and sections in the
:file:`.spec` file are derived from options in the setup script as follows:

+------------------------------------------+----------------------------------------------+
| RPM :file:`.spec` file option or section | Distutils setup script option                |
+==========================================+==============================================+
| Name                                     | ``name``                                     |
+------------------------------------------+----------------------------------------------+
| Summary (in preamble)                    | ``description``                              |
+------------------------------------------+----------------------------------------------+
| Version                                  | ``version``                                  |
+------------------------------------------+----------------------------------------------+
| Vendor                                   | ``author`` and ``author_email``,             |
|                                          | or  --- & ``maintainer`` and                 |
|                                          | ``maintainer_email``                         |
+------------------------------------------+----------------------------------------------+
| Copyright                                | ``license``                                  |
+------------------------------------------+----------------------------------------------+
| Url                                      | ``url``                                      |
+------------------------------------------+----------------------------------------------+
| %description (section)                   | ``long_description``                         |
+------------------------------------------+----------------------------------------------+

Additionally, there are many options in :file:`.spec` files that don't have
corresponding options in the setup script.  Most of these are handled through
options to the :command:`bdist_rpm` command as follows:

+-------------------------------+-----------------------------+-------------------------+
| RPM :file:`.spec` file option | :command:`bdist_rpm` option | default value           |
| or section                    |                             |                         |
+===============================+=============================+=========================+
| Release                       | ``release``                 | "1"                     |
+-------------------------------+-----------------------------+-------------------------+
| Group                         | ``group``                   | "Development/Libraries" |
+-------------------------------+-----------------------------+-------------------------+
| Vendor                        | ``vendor``                  | (see above)             |
+-------------------------------+-----------------------------+-------------------------+
| Packager                      | ``packager``                | (none)                  |
+-------------------------------+-----------------------------+-------------------------+
| Provides                      | ``provides``                | (none)                  |
+-------------------------------+-----------------------------+-------------------------+
| Requires                      | ``requires``                | (none)                  |
+-------------------------------+-----------------------------+-------------------------+
| Conflicts                     | ``conflicts``               | (none)                  |
+-------------------------------+-----------------------------+-------------------------+
| Obsoletes                     | ``obsoletes``               | (none)                  |
+-------------------------------+-----------------------------+-------------------------+
| Distribution                  | ``distribution_name``       | (none)                  |
+-------------------------------+-----------------------------+-------------------------+
| BuildRequires                 | ``build_requires``          | (none)                  |
+-------------------------------+-----------------------------+-------------------------+
| Icon                          | ``icon``                    | (none)                  |
+-------------------------------+-----------------------------+-------------------------+

Obviously, supplying even a few of these options on the command-line would be
tedious and error-prone, so it's usually best to put them in the setup
configuration file, :file:`setup.cfg`\ ---see section :ref:`setup-config`.  If
you distribute or package many Python module distributions, you might want to
put options that apply to all of them in your personal Distutils configuration
file (:file:`~/.pydistutils.cfg`).  If you want to temporarily disable
this file, you can pass the :option:`!--no-user-cfg` option to :file:`setup.py`.

There are three steps to building a binary RPM package, all of which are
handled automatically by the Distutils:

#. create a :file:`.spec` file, which describes the package (analogous  to the
   Distutils setup script; in fact, much of the information in the  setup script
   winds up in the :file:`.spec` file)

#. create the source RPM

#. create the "binary" RPM (which may or may not contain binary code, depending
   on whether your module distribution contains Python extensions)

Normally, RPM bundles the last two steps together; when you use the Distutils,
all three steps are typically bundled together.

If you wish, you can separate these three steps.  You can use the
:option:`!--spec-only` option to make :command:`bdist_rpm` just create the
:file:`.spec` file and exit; in this case, the :file:`.spec` file will be
written to the "distribution directory"---normally :file:`dist/`, but
customizable with the :option:`!--dist-dir` option.  (Normally, the :file:`.spec`
file winds up deep in the "build tree," in a temporary directory created by
:command:`bdist_rpm`.)

.. % \XXX{this isn't implemented yet---is it needed?!}
.. % You can also specify a custom \file{.spec} file with the
.. % \longprogramopt{spec-file} option; used in conjunction with
.. % \longprogramopt{spec-only}, this gives you an opportunity to customize
.. % the \file{.spec} file manually:
.. %
.. % \ begin{verbatim}
.. % > python setup.py bdist_rpm --spec-only
.. % # ...edit dist/FooBar-1.0.spec
.. % > python setup.py bdist_rpm --spec-file=dist/FooBar-1.0.spec
.. % \ end{verbatim}
.. %
.. % (Although a better way to do this is probably to override the standard
.. % \command{bdist\_rpm} command with one that writes whatever else you want
.. % to the \file{.spec} file.)

.. _cross-compile-windows:

Cross-compiling on Windows
==========================

Starting with Python 2.6, distutils is capable of cross-compiling between
Windows platforms.  In practice, this means that with the correct tools
installed, you can use a 32bit version of Windows to create 64bit extensions
and vice-versa.

To build for an alternate platform, specify the :option:`!--plat-name` option
to the build command.  Valid values are currently 'win32', and  'win-amd64'.
For example, on a 32bit version of Windows, you could execute::

   python setup.py build --plat-name=win-amd64

to build a 64bit version of your extension.

To cross-compile, you must download the Python source code and cross-compile
Python itself for the platform you are targeting - it is not possible from a
binary installation of Python (as the .lib etc file for other platforms are
not included.)  In practice, this means the user of a 32 bit operating
system will need to use Visual Studio 2008 to open the
:file:`PCbuild/PCbuild.sln` solution in the Python source tree and build the
"x64" configuration of the 'pythoncore' project before cross-compiling
extensions is possible.

Note that by default, Visual Studio 2008 does not install 64bit compilers or
tools.  You may need to reexecute the Visual Studio setup process and select
these tools (using Control Panel->[Add/Remove] Programs is a convenient way to
check or modify your existing install.)

.. _postinstallation-script:

The Postinstallation script
---------------------------

Starting with Python 2.3, a postinstallation script can be specified with the
:option:`!--install-script` option.  The basename of the script must be
specified, and the script filename must also be listed in the scripts argument
to the setup function.

This script will be run at installation time on the target system after all the
files have been copied, with ``argv[1]`` set to :option:`!-install`, and again at
uninstallation time before the files are removed with ``argv[1]`` set to
:option:`!-remove`.

The installation script runs embedded in the windows installer, every output
(``sys.stdout``, ``sys.stderr``) is redirected into a buffer and will be
displayed in the GUI after the script has finished.

Some functions especially useful in this context are available as additional
built-in functions in the installation script.


.. function:: directory_created(path)
              file_created(path)

   These functions should be called when a directory or file is created by the
   postinstall script at installation time.  It will register *path* with the
   uninstaller, so that it will be removed when the distribution is uninstalled.
   To be safe, directories are only removed if they are empty.


.. function:: get_special_folder_path(csidl_string)

   This function can be used to retrieve special folder locations on Windows like
   the Start Menu or the Desktop.  It returns the full path to the folder.
   *csidl_string* must be one of the following strings::

      "CSIDL_APPDATA"

      "CSIDL_COMMON_STARTMENU"
      "CSIDL_STARTMENU"

      "CSIDL_COMMON_DESKTOPDIRECTORY"
      "CSIDL_DESKTOPDIRECTORY"

      "CSIDL_COMMON_STARTUP"
      "CSIDL_STARTUP"

      "CSIDL_COMMON_PROGRAMS"
      "CSIDL_PROGRAMS"

      "CSIDL_FONTS"

   If the folder cannot be retrieved, :exc:`OSError` is raised.

   Which folders are available depends on the exact Windows version, and probably
   also the configuration.  For details refer to Microsoft's documentation of the
   :c:func:`SHGetSpecialFolderPath` function.


.. function:: create_shortcut(target, description, filename[, arguments[, workdir[, iconpath[, iconindex]]]])

   This function creates a shortcut. *target* is the path to the program to be
   started by the shortcut. *description* is the description of the shortcut.
   *filename* is the title of the shortcut that the user will see. *arguments*
   specifies the command line arguments, if any. *workdir* is the working directory
   for the program. *iconpath* is the file containing the icon for the shortcut,
   and *iconindex* is the index of the icon in the file *iconpath*.  Again, for
   details consult the Microsoft documentation for the :class:`IShellLink`
   interface.
alt-python312-setuptools/docs/deprecated/distutils/configfile.rst000064400000013464150410147360021234 0ustar00.. _setup-config:

************************************
Writing the Setup Configuration File
************************************

.. include:: ./_setuptools_disclaimer.rst

Often, it's not possible to write down everything needed to build a distribution
*a priori*: you may need to get some information from the user, or from the
user's system, in order to proceed.  As long as that information is fairly
simple---a list of directories to search for C header files or libraries, for
example---then providing a configuration file, :file:`setup.cfg`, for users to
edit is a cheap and easy way to solicit it.  Configuration files also let you
provide default values for any command option, which the installer can then
override either on the command-line or by editing the config file.

The setup configuration file is a useful middle-ground between the setup
script---which, ideally, would be opaque to installers [#]_---and the command-line to
the setup script, which is outside of your control and entirely up to the
installer.  In fact, :file:`setup.cfg` (and any other Distutils configuration
files present on the target system) are processed after the contents of the
setup script, but before the command-line.  This has  several useful
consequences:

.. % (If you have more advanced needs, such as determining which extensions
.. % to build based on what capabilities are present on the target system,
.. % then you need the Distutils ``auto-configuration'' facility.  This
.. % started to appear in Distutils 0.9 but, as of this writing, isn't mature
.. % or stable enough yet for real-world use.)

* installers can override some of what you put in :file:`setup.py` by editing
  :file:`setup.cfg`

* you can provide non-standard defaults for options that are not easily set in
  :file:`setup.py`

* installers can override anything in :file:`setup.cfg` using the command-line
  options to :file:`setup.py` or by pointing :envvar:`DIST_EXTRA_CONFIG`
  to another configuration file

The basic syntax of the configuration file is simple:

.. code-block:: ini

   [command]
   option=value
   ...

where *command* is one of the Distutils commands (e.g. :command:`build_py`,
:command:`install`), and *option* is one of the options that command supports.
Any number of options can be supplied for each command, and any number of
command sections can be included in the file.  Blank lines are ignored, as are
comments, which run from a ``'#'`` character until the end of the line.  Long
option values can be split across multiple lines simply by indenting the
continuation lines.

You can find out the list of options supported by a particular command with the
universal :option:`!--help` option, e.g.

.. code-block:: shell-session

   $ python setup.py --help build_ext
   [...]
   Options for 'build_ext' command:
     --build-lib (-b)     directory for compiled extension modules
     --build-temp (-t)    directory for temporary files (build by-products)
     --inplace (-i)       ignore build-lib and put compiled extensions into the
                          source directory alongside your pure Python modules
     --include-dirs (-I)  list of directories to search for header files
     --define (-D)        C preprocessor macros to define
     --undef (-U)         C preprocessor macros to undefine
     --swig-opts          list of SWIG command line options
   [...]

Note that an option spelled :option:`!--foo-bar` on the command-line  is spelled
``foo_bar`` in configuration files.

.. _distutils-build-ext-inplace:

For example, say you want your extensions to be built "in-place"---that is, you
have an extension ``pkg.ext``, and you want the compiled extension file
(:file:`ext.so` on Unix, say) to be put in the same source directory as your
pure Python modules ``pkg.mod1`` and ``pkg.mod2``.  You can always use the
:option:`!--inplace` option on the command-line to ensure this:

.. code-block:: sh

   python setup.py build_ext --inplace

But this requires that you always specify the :command:`build_ext` command
explicitly, and remember to provide :option:`!--inplace`. An easier way is to
"set and forget" this option, by encoding it in :file:`setup.cfg`, the
configuration file for this distribution:

.. code-block:: ini

   [build_ext]
   inplace=1

This will affect all builds of this module distribution, whether or not you
explicitly specify :command:`build_ext`.  If you include :file:`setup.cfg` in
your source distribution, it will also affect end-user builds---which is
probably a bad idea for this option, since always building extensions in-place
would break installation of the module distribution.  In certain peculiar cases,
though, modules are built right in their installation directory, so this is
conceivably a useful ability.  (Distributing extensions that expect to be built
in their installation directory is almost always a bad idea, though.)

Another example: certain commands take a lot of options that don't change from
run to run; for example, :command:`bdist_rpm` needs to know everything required
to generate a "spec" file for creating an RPM distribution.  Some of this
information comes from the setup script, and some is automatically generated by
the Distutils (such as the list of files installed).  But some of it has to be
supplied as options to :command:`bdist_rpm`, which would be very tedious to do
on the command-line for every run.  Hence, here is a snippet from the Distutils'
own :file:`setup.cfg`:

.. code-block:: ini

   [bdist_rpm]
   release = 1
   packager = Greg Ward <gward@python.net>
   doc_files = CHANGES.txt
               README.txt
               USAGE.txt
               doc/
               examples/

Note that the ``doc_files`` option is simply a whitespace-separated string
split across multiple lines for readability.


.. rubric:: Footnotes

.. [#] This ideal probably won't be achieved until auto-configuration is fully
   supported by the Distutils.
alt-python312-setuptools/docs/deprecated/distutils/extending.rst000064400000010756150410147360021115 0ustar00.. _extending-distutils:

*******************
Extending Distutils
*******************

.. include:: ./_setuptools_disclaimer.rst

Distutils can be extended in various ways.  Most extensions take the form of new
commands or replacements for existing commands.  New commands may be written to
support new types of platform-specific packaging, for example, while
replacements for existing commands may be made to modify details of how the
command operates on a package.

Most extensions of the distutils are made within :file:`setup.py` scripts that
want to modify existing commands; many simply add a few file extensions that
should be copied into packages in addition to :file:`.py` files as a
convenience.

Most distutils command implementations are subclasses of the
:class:`distutils.cmd.Command` class.  New commands may directly inherit from
:class:`~distutils.cmd.Command`, while replacements often derive from :class:`~distutils.cmd.Command`
indirectly, directly subclassing the command they are replacing.  Commands are
required to derive from :class:`~distutils.cmd.Command`.

.. % \section{Extending existing commands}
.. % \label{extend-existing}

.. % \section{Writing new commands}
.. % \label{new-commands}
.. % \XXX{Would an uninstall command be a good example here?}


Integrating new commands
========================

There are different ways to integrate new command implementations into
distutils.  The most difficult is to lobby for the inclusion of the new features
in distutils itself, and wait for (and require) a version of Python that
provides that support.  This is really hard for many reasons.

The most common, and possibly the most reasonable for most needs, is to include
the new implementations with your :file:`setup.py` script, and cause the
:func:`distutils.core.setup` function use them::

   from distutils.command.build_py import build_py as _build_py
   from distutils.core import setup

   class build_py(_build_py):
       """Specialized Python source builder."""

       # implement whatever needs to be different...

   setup(cmdclass={'build_py': build_py},
         ...)

This approach is most valuable if the new implementations must be used to use a
particular package, as everyone interested in the package will need to have the
new command implementation.

Beginning with Python 2.4, a third option is available, intended to allow new
commands to be added which can support existing :file:`setup.py` scripts without
requiring modifications to the Python installation.  This is expected to allow
third-party extensions to provide support for additional packaging systems, but
the commands can be used for anything distutils commands can be used for.  A new
configuration option, ``command_packages`` (command-line option
:option:`!--command-packages`), can be used to specify additional packages to be
searched for modules implementing commands.  Like all distutils options, this
can be specified on the command line or in a configuration file.  This option
can only be set in the ``[global]`` section of a configuration file, or before
any commands on the command line.  If set in a configuration file, it can be
overridden from the command line; setting it to an empty string on the command
line causes the default to be used.  This should never be set in a configuration
file provided with a package.

This new option can be used to add any number of packages to the list of
packages searched for command implementations; multiple package names should be
separated by commas.  When not specified, the search is only performed in the
:mod:`distutils.command` package.  When :file:`setup.py` is run with the option
``--command-packages distcmds,buildcmds``, however, the packages
:mod:`distutils.command`, ``distcmds``, and ``buildcmds`` will be searched
in that order.  New commands are expected to be implemented in modules of the
same name as the command by classes sharing the same name.  Given the example
command line option above, the command :command:`bdist_openpkg` could be
implemented by the class ``distcmds.bdist_openpkg.bdist_openpkg`` or
``buildcmds.bdist_openpkg.bdist_openpkg``.


Adding new distribution types
=============================

Commands that create distributions (files in the :file:`dist/` directory) need
to add ``(command, filename)`` pairs to ``self.distribution.dist_files`` so that
:command:`upload` can upload it to PyPI.  The *filename* in the pair contains no
path information, only the name of the file itself.  In dry-run mode, pairs
should still be added to represent what would have been created.
alt-python312-setuptools/docs/deprecated/distutils/commandref.rst000064400000010750150410147360021235 0ustar00.. _reference:

*****************
Command Reference
*****************

.. include:: ./_setuptools_disclaimer.rst

.. % \section{Building modules: the \protect\command{build} command family}
.. % \label{build-cmds}
.. % \subsubsection{\protect\command{build}}
.. % \label{build-cmd}
.. % \subsubsection{\protect\command{build\_py}}
.. % \label{build-py-cmd}
.. % \subsubsection{\protect\command{build\_ext}}
.. % \label{build-ext-cmd}
.. % \subsubsection{\protect\command{build\_clib}}
.. % \label{build-clib-cmd}


.. _install-cmd:

Installing modules: the :command:`install` command family
=========================================================

The install command ensures that the build commands have been run and then runs
the subcommands :command:`install_lib`, :command:`install_data` and
:command:`install_scripts`.

.. % \subsubsection{\protect\command{install\_lib}}
.. % \label{install-lib-cmd}


.. _install-data-cmd:

:command:`install_data`
-----------------------

This command installs all data files provided with the distribution.


.. _install-scripts-cmd:

:command:`install_scripts`
--------------------------

This command installs all (Python) scripts in the distribution.

.. % \subsection{Cleaning up: the \protect\command{clean} command}
.. % \label{clean-cmd}


.. _sdist-cmd:

Creating a source distribution: the :command:`sdist` command
============================================================

.. XXX fragment moved down from above: needs context!

The manifest template commands are:

+-------------------------------------------+-----------------------------------------------+
| Command                                   | Description                                   |
+===========================================+===============================================+
| :command:`include pat1 pat2 ...`          | include all files matching any of the listed  |
|                                           | patterns                                      |
+-------------------------------------------+-----------------------------------------------+
| :command:`exclude pat1 pat2 ...`          | exclude all files matching any of the listed  |
|                                           | patterns                                      |
+-------------------------------------------+-----------------------------------------------+
| :command:`recursive-include dir pat1 pat2 | include all files under *dir* matching any of |
| ...`                                      | the listed patterns                           |
+-------------------------------------------+-----------------------------------------------+
| :command:`recursive-exclude dir pat1 pat2 | exclude all files under *dir* matching any of |
| ...`                                      | the listed patterns                           |
+-------------------------------------------+-----------------------------------------------+
| :command:`global-include pat1 pat2 ...`   | include all files anywhere in the source tree |
|                                           | matching --- & any of the listed patterns     |
+-------------------------------------------+-----------------------------------------------+
| :command:`global-exclude pat1 pat2 ...`   | exclude all files anywhere in the source tree |
|                                           | matching --- & any of the listed patterns     |
+-------------------------------------------+-----------------------------------------------+
| :command:`prune dir`                      | exclude all files under *dir*                 |
+-------------------------------------------+-----------------------------------------------+
| :command:`graft dir`                      | include all files under *dir*                 |
+-------------------------------------------+-----------------------------------------------+

The patterns here are Unix-style "glob" patterns: ``*`` matches any sequence of
regular filename characters, ``?`` matches any single regular filename
character, and ``[range]`` matches any of the characters in *range* (e.g.,
``a-z``, ``a-zA-Z``, ``a-f0-9_.``).  The definition of "regular filename
character" is platform-specific: on Unix it is anything except slash; on Windows
anything except backslash or colon.

.. XXX Windows support not there yet

.. % \section{Creating a built distribution: the
.. % \protect\command{bdist} command family}
.. % \label{bdist-cmds}

.. % \subsection{\protect\command{bdist}}
.. % \subsection{\protect\command{bdist\_dumb}}
.. % \subsection{\protect\command{bdist\_rpm}}
alt-python312-setuptools/docs/deprecated/distutils/introduction.rst000064400000017606150410147360021652 0ustar00.. _distutils-intro:

****************************
An Introduction to Distutils
****************************

.. include:: ./_setuptools_disclaimer.rst

This document covers using the Distutils to distribute your Python modules,
concentrating on the role of developer/distributor: if you're looking for
information on installing Python modules, you should refer to the
:ref:`install-index` chapter.


.. _distutils-concepts:

Concepts & Terminology
======================

Using the Distutils is quite simple, both for module developers and for
users/administrators installing third-party modules.  As a developer, your
responsibilities (apart from writing solid, well-documented and well-tested
code, of course!) are:

* write a setup script (:file:`setup.py` by convention)

* (optional) write a setup configuration file

* create a source distribution

* (optional) create one or more built (binary) distributions

Each of these tasks is covered in this document.

Not all module developers have access to a multitude of platforms, so it's not
always feasible to expect them to create a multitude of built distributions.  It
is hoped that a class of intermediaries, called *packagers*, will arise to
address this need.  Packagers will take source distributions released by module
developers, build them on one or more platforms, and release the resulting built
distributions.  Thus, users on the most popular platforms will be able to
install most popular Python module distributions in the most natural way for
their platform, without having to run a single setup script or compile a line of
code.


.. _distutils-simple-example:

A Simple Example
================

The setup script is usually quite simple, although since it's written in Python,
there are no arbitrary limits to what you can do with it, though you should be
careful about putting arbitrarily expensive operations in your setup script.
Unlike, say, Autoconf-style configure scripts, the setup script may be run
multiple times in the course of building and installing your module
distribution.

If all you want to do is distribute a module called ``foo``, contained in a
file :file:`foo.py`, then your setup script can be as simple as this::

   from distutils.core import setup
   setup(name='foo',
         version='1.0',
         py_modules=['foo'],
         )

Some observations:

* most information that you supply to the Distutils is supplied as keyword
  arguments to the :func:`~distutils.core.setup` function

* those keyword arguments fall into two categories: package metadata (name,
  version number) and information about what's in the package (a list of pure
  Python modules, in this case)

* modules are specified by module name, not filename (the same will hold true
  for packages and extensions)

* it's recommended that you supply a little more metadata, in particular your
  name, email address and a URL for the project (see section :ref:`setup-script`
  for an example)

To create a source distribution for this module, you would create a setup
script, :file:`setup.py`, containing the above code, and run this command from a
terminal::

   python setup.py sdist

For Windows, open a command prompt window (:menuselection:`Start -->
Accessories`) and change the command to::

   setup.py sdist

:command:`sdist` will create an archive file (e.g., tarball on Unix, ZIP file on Windows)
containing your setup script :file:`setup.py`, and your module :file:`foo.py`.
The archive file will be named :file:`foo-1.0.tar.gz` (or :file:`.zip`), and
will unpack into a directory :file:`foo-1.0`.

If an end-user wishes to install your ``foo`` module, all they have to do is
download :file:`foo-1.0.tar.gz` (or :file:`.zip`), unpack it, and---from the
:file:`foo-1.0` directory---run ::

   python setup.py install

which will ultimately copy :file:`foo.py` to the appropriate directory for
third-party modules in their Python installation.

This simple example demonstrates some fundamental concepts of the Distutils.
First, both developers and installers have the same basic user interface, i.e.
the setup script.  The difference is which Distutils *commands* they use: the
:command:`sdist` command is almost exclusively for module developers, while
:command:`install` is more often for installers (although most developers will
want to install their own code occasionally).

Other useful built distribution formats are RPM, implemented by the
:command:`bdist_rpm` command, Solaris :program:`pkgtool`
(:command:`bdist_pkgtool`), and HP-UX :program:`swinstall`
(:command:`bdist_sdux`).  For example, the following command will create an RPM
file called :file:`foo-1.0.noarch.rpm`::

   python setup.py bdist_rpm

(The :command:`bdist_rpm` command uses the :command:`rpm` executable, therefore
this has to be run on an RPM-based system such as Red Hat Linux, SuSE Linux, or
Mandrake Linux.)

You can find out what distribution formats are available at any time by running
::

   python setup.py bdist --help-formats


.. _python-terms:

General Python terminology
==========================

If you're reading this document, you probably have a good idea of what modules,
extensions, and so forth are.  Nevertheless, just to be sure that everyone is
operating from a common starting point, we offer the following glossary of
common Python terms:

module
   the basic unit of code reusability in Python: a block of code imported by some
   other code.  Three types of modules concern us here: pure Python modules,
   extension modules, and packages.

pure Python module
   a module written in Python and contained in a single :file:`.py` file (and
   possibly associated :file:`.pyc` files).  Sometimes referred to as a
   "pure module."

extension module
   a module written in the low-level language of the Python implementation: C/C++
   for Python, Java for Jython. Typically contained in a single dynamically
   loadable pre-compiled file, e.g. a shared object (:file:`.so`) file for Python
   extensions on Unix, a DLL (given the :file:`.pyd` extension) for Python
   extensions on Windows, or a Java class file for Jython extensions.  (Note that
   currently, the Distutils only handles C/C++ extensions for Python.)

package
   a module that contains other modules; typically contained in a directory in the
   filesystem and distinguished from other directories by the presence of a file
   :file:`__init__.py`.

root package
   the root of the hierarchy of packages.  (This isn't really a package, since it
   doesn't have an :file:`__init__.py` file.  But we have to call it something.)
   The vast majority of the standard library is in the root package, as are many
   small, standalone third-party modules that don't belong to a larger module
   collection. Unlike regular packages, modules in the root package can be found in
   many directories: in fact, every directory listed in ``sys.path`` contributes
   modules to the root package.


.. _distutils-term:

Distutils-specific terminology
==============================

The following terms apply more specifically to the domain of distributing Python
modules using the Distutils:

module distribution
   a collection of Python modules distributed together as a single downloadable
   resource and meant to be installed *en masse*.  Examples of some well-known
   module distributions are NumPy, SciPy, Pillow,
   or mxBase.  (This would be called a *package*, except that term is
   already taken in the Python context: a single module distribution may contain
   zero, one, or many Python packages.)

pure module distribution
   a module distribution that contains only pure Python modules and packages.
   Sometimes referred to as a "pure distribution."

non-pure module distribution
   a module distribution that contains at least one extension module.  Sometimes
   referred to as a "non-pure distribution."

distribution root
   the top-level directory of your source tree (or  source distribution); the
   directory where :file:`setup.py` exists.  Generally  :file:`setup.py` will be
   run from this directory.
alt-python312-setuptools/docs/deprecated/distutils/index.rst000064400000002353150410147360020231 0ustar00.. _distutils-index:

##############################################
  Distributing Python Modules (Legacy version)
##############################################

:Authors: Greg Ward, Anthony Baxter
:Email: distutils-sig@python.org

.. seealso::

   :ref:`distributing-index`
      The up to date module distribution documentations

.. include:: ./_setuptools_disclaimer.rst

.. note::

   This guide only covers the basic tools for building and distributing
   extensions that are provided as part of this version of Python. Third party
   tools offer easier to use and more secure alternatives. Refer to the `quick
   recommendations section <https://packaging.python.org/guides/tool-recommendations/>`__
   in the Python Packaging User Guide for more information.

This document describes the Python Distribution Utilities ("Distutils") from
the module developer's point of view, describing the underlying capabilities
that ``setuptools`` builds on to allow Python developers to make Python modules
and extensions readily available to a wider audience.

.. toctree::
   :maxdepth: 2
   :numbered:

   introduction.rst
   setupscript.rst
   configfile.rst
   sourcedist.rst
   builtdist.rst
   examples.rst
   extending.rst
   commandref.rst
   apiref.rst
alt-python312-setuptools/docs/deprecated/distutils/_setuptools_disclaimer.rst000064400000000350150410147360023671 0ustar00.. note::

   This document is being retained solely until the ``setuptools`` documentation
   at https://setuptools.pypa.io/en/latest/setuptools.html
   independently covers all of the relevant information currently included here.
alt-python312-setuptools/docs/deprecated/distutils/setupscript.rst000064400000075146150410147360021521 0ustar00.. _setup-script:

************************
Writing the Setup Script
************************

.. include:: ./_setuptools_disclaimer.rst

The setup script is the centre of all activity in building, distributing, and
installing modules using the Distutils.  The main purpose of the setup script is
to describe your module distribution to the Distutils, so that the various
commands that operate on your modules do the right thing.  As we saw in section
:ref:`distutils-simple-example` above, the setup script consists mainly of a call to :func:`~distutils.core.setup`, and most information
supplied to the Distutils by the module developer is supplied as keyword
arguments to :func:`~distutils.core.setup`.

Here's a slightly more involved example, which we'll follow for the next couple
of sections: the Distutils' own setup script.  (Keep in mind that although the
Distutils are included with Python 1.6 and later, they also have an independent
existence so that Python 1.5.2 users can use them to install other module
distributions.  The Distutils' own setup script, shown here, is used to install
the package into Python 1.5.2.) ::

    #!/usr/bin/env python

    from distutils.core import setup

    setup(name='Distutils',
          version='1.0',
          description='Python Distribution Utilities',
          author='Greg Ward',
          author_email='gward@python.net',
          url='https://www.python.org/sigs/distutils-sig/',
          packages=['distutils', 'distutils.command'],
         )

There are only two differences between this and the trivial one-file
distribution presented in section :ref:`distutils-simple-example`: more metadata, and the
specification of pure Python modules by package, rather than by module.  This is
important since the Distutils consist of a couple of dozen modules split into
(so far) two packages; an explicit list of every module would be tedious to
generate and difficult to maintain.  For more information on the additional
meta-data, see section :ref:`meta-data`.

Note that any pathnames (files or directories) supplied in the setup script
should be written using the Unix convention, i.e. slash-separated.  The
Distutils will take care of converting this platform-neutral representation into
whatever is appropriate on your current platform before actually using the
pathname.  This makes your setup script portable across operating systems, which
of course is one of the major goals of the Distutils.  In this spirit, all
pathnames in this document are slash-separated.

This, of course, only applies to pathnames given to Distutils functions.  If
you, for example, use standard Python functions such as :func:`glob.glob` or
:func:`os.listdir` to specify files, you should be careful to write portable
code instead of hardcoding path separators::

    glob.glob(os.path.join('mydir', 'subdir', '*.html'))
    os.listdir(os.path.join('mydir', 'subdir'))


.. _listing-packages:

Listing whole packages
======================

The ``packages`` option tells the Distutils to process (build, distribute,
install, etc.) all pure Python modules found in each package mentioned in the
``packages`` list.  In order to do this, of course, there has to be a
correspondence between package names and directories in the filesystem.  The
default correspondence is the most obvious one, i.e. package :mod:`distutils` is
found in the directory :file:`distutils` relative to the distribution root.
Thus, when you say ``packages = ['foo']`` in your setup script, you are
promising that the Distutils will find a file :file:`foo/__init__.py` (which
might be spelled differently on your system, but you get the idea) relative to
the directory where your setup script lives.  If you break this promise, the
Distutils will issue a warning but still process the broken package anyway.

If you use a different convention to lay out your source directory, that's no
problem: you just have to supply the ``package_dir`` option to tell the
Distutils about your convention.  For example, say you keep all Python source
under :file:`lib`, so that modules in the "root package" (i.e., not in any
package at all) are in :file:`lib`, modules in the ``foo`` package are in
:file:`lib/foo`, and so forth.  Then you would put ::

    package_dir = {'': 'lib'}

in your setup script.  The keys to this dictionary are package names, and an
empty package name stands for the root package.  The values are directory names
relative to your distribution root.  In this case, when you say ``packages =
['foo']``, you are promising that the file :file:`lib/foo/__init__.py` exists.

Another possible convention is to put the ``foo`` package right in
:file:`lib`, the ``foo.bar`` package in :file:`lib/bar`, etc.  This would be
written in the setup script as ::

    package_dir = {'foo': 'lib'}

A ``package: dir`` entry in the ``package_dir`` dictionary implicitly
applies to all packages below *package*, so the ``foo.bar`` case is
automatically handled here.  In this example, having ``packages = ['foo',
'foo.bar']`` tells the Distutils to look for :file:`lib/__init__.py` and
:file:`lib/bar/__init__.py`.  (Keep in mind that although ``package_dir``
applies recursively, you must explicitly list all packages in
``packages``: the Distutils will *not* recursively scan your source tree
looking for any directory with an :file:`__init__.py` file.)


.. _listing-modules:

Listing individual modules
==========================

For a small module distribution, you might prefer to list all modules rather
than listing packages---especially the case of a single module that goes in the
"root package" (i.e., no package at all).  This simplest case was shown in
section :ref:`distutils-simple-example`; here is a slightly more involved example::

    py_modules = ['mod1', 'pkg.mod2']

This describes two modules, one of them in the "root" package, the other in the
``pkg`` package.  Again, the default package/directory layout implies that
these two modules can be found in :file:`mod1.py` and :file:`pkg/mod2.py`, and
that :file:`pkg/__init__.py` exists as well. And again, you can override the
package/directory correspondence using the ``package_dir`` option.


.. _describing-extensions:

Describing extension modules
============================

Just as writing Python extension modules is a bit more complicated than writing
pure Python modules, describing them to the Distutils is a bit more complicated.
Unlike pure modules, it's not enough just to list modules or packages and expect
the Distutils to go out and find the right files; you have to specify the
extension name, source file(s), and any compile/link requirements (include
directories, libraries to link with, etc.).

.. XXX read over this section

All of this is done through another keyword argument to
:func:`~distutils.core.setup`, the
``ext_modules`` option.  ``ext_modules`` is just a list of
:class:`~distutils.core.Extension` instances, each of which describes a
single extension module.
Suppose your distribution includes a single extension, called ``foo`` and
implemented by :file:`foo.c`.  If no additional instructions to the
compiler/linker are needed, describing this extension is quite simple::

    Extension('foo', ['foo.c'])

The :class:`~distutils.extension.Extension` class can be imported from :mod:`distutils.core` along
with :func:`~distutils.core.setup`.  Thus, the setup script for a module distribution that
contains only this one extension and nothing else might be::

    from distutils.core import setup, Extension
    setup(name='foo',
          version='1.0',
          ext_modules=[Extension('foo', ['foo.c'])],
          )

The :class:`~distutils.extension.Extension` class (actually, the underlying extension-building
machinery implemented by the :command:`build_ext` command) supports a great deal
of flexibility in describing Python extensions, which is explained in the
following sections.


Extension names and packages
----------------------------

The first argument to the :class:`~distutils.core.Extension` constructor is
always the name of the extension, including any package names.  For example, ::

    Extension('foo', ['src/foo1.c', 'src/foo2.c'])

describes an extension that lives in the root package, while ::

    Extension('pkg.foo', ['src/foo1.c', 'src/foo2.c'])

describes the same extension in the ``pkg`` package.  The source files and
resulting object code are identical in both cases; the only difference is where
in the filesystem (and therefore where in Python's namespace hierarchy) the
resulting extension lives.

If you have a number of extensions all in the same package (or all under the
same base package), use the ``ext_package`` keyword argument to
:func:`~distutils.core.setup`.  For example, ::

    setup(...,
          ext_package='pkg',
          ext_modules=[Extension('foo', ['foo.c']),
                       Extension('subpkg.bar', ['bar.c'])],
         )

will compile :file:`foo.c` to the extension ``pkg.foo``, and
:file:`bar.c` to ``pkg.subpkg.bar``.


Extension source files
----------------------

The second argument to the :class:`~distutils.core.Extension` constructor is
a list of source
files.  Since the Distutils currently only support C, C++, and Objective-C
extensions, these are normally C/C++/Objective-C source files.  (Be sure to use
appropriate extensions to distinguish C++ source files: :file:`.cc` and
:file:`.cpp` seem to be recognized by both Unix and Windows compilers.)

However, you can also include SWIG interface (:file:`.i`) files in the list; the
:command:`build_ext` command knows how to deal with SWIG extensions: it will run
SWIG on the interface file and compile the resulting C/C++ file into your
extension.

.. XXX SWIG support is rough around the edges and largely untested!

This warning notwithstanding, options to SWIG can be currently passed like
this::

    setup(...,
          ext_modules=[Extension('_foo', ['foo.i'],
                                 swig_opts=['-modern', '-I../include'])],
          py_modules=['foo'],
         )

Or on the commandline like this::

    > python setup.py build_ext --swig-opts="-modern -I../include"

On some platforms, you can include non-source files that are processed by the
compiler and included in your extension.  Currently, this just means Windows
message text (:file:`.mc`) files and resource definition (:file:`.rc`) files for
Visual C++. These will be compiled to binary resource (:file:`.res`) files and
linked into the executable.


Preprocessor options
--------------------

Three optional arguments to :class:`~distutils.core.Extension` will help if
you need to specify include directories to search or preprocessor macros to
define/undefine: ``include_dirs``, ``define_macros``, and ``undef_macros``.

For example, if your extension requires header files in the :file:`include`
directory under your distribution root, use the ``include_dirs`` option::

    Extension('foo', ['foo.c'], include_dirs=['include'])

You can specify absolute directories there; if you know that your extension will
only be built on Unix systems with X11R6 installed to :file:`/usr`, you can get
away with ::

    Extension('foo', ['foo.c'], include_dirs=['/usr/include/X11'])

You should avoid this sort of non-portable usage if you plan to distribute your
code: it's probably better to write C code like  ::

    #include <X11/Xlib.h>

If you need to include header files from some other Python extension, you can
take advantage of the fact that header files are installed in a consistent way
by the Distutils :command:`install_headers` command.  For example, the Numerical
Python header files are installed (on a standard Unix installation) to
:file:`/usr/local/include/python1.5/Numerical`. (The exact location will differ
according to your platform and Python installation.)  Since the Python include
directory---\ :file:`/usr/local/include/python1.5` in this case---is always
included in the search path when building Python extensions, the best approach
is to write C code like  ::

    #include <Numerical/arrayobject.h>

If you must put the :file:`Numerical` include directory right into your header
search path, though, you can find that directory using the Distutils
:mod:`distutils.sysconfig` module::

    from distutils.sysconfig import get_python_inc
    incdir = os.path.join(get_python_inc(plat_specific=1), 'Numerical')
    setup(...,
          Extension(..., include_dirs=[incdir]),
          )

Even though this is quite portable---it will work on any Python installation,
regardless of platform---it's probably easier to just write your C code in the
sensible way.

You can define and undefine pre-processor macros with the ``define_macros`` and
``undef_macros`` options. ``define_macros`` takes a list of ``(name, value)``
tuples, where ``name`` is the name of the macro to define (a string) and
``value`` is its value: either a string or ``None``.  (Defining a macro ``FOO``
to ``None`` is the equivalent of a bare ``#define FOO`` in your C source: with
most compilers, this sets ``FOO`` to the string ``1``.)  ``undef_macros`` is
just a list of macros to undefine.

For example::

    Extension(...,
              define_macros=[('NDEBUG', '1'),
                             ('HAVE_STRFTIME', None)],
              undef_macros=['HAVE_FOO', 'HAVE_BAR'])

is the equivalent of having this at the top of every C source file::

    #define NDEBUG 1
    #define HAVE_STRFTIME
    #undef HAVE_FOO
    #undef HAVE_BAR


Library options
---------------

You can also specify the libraries to link against when building your extension,
and the directories to search for those libraries.  The ``libraries`` option is
a list of libraries to link against, ``library_dirs`` is a list of directories
to search for libraries at  link-time, and ``runtime_library_dirs`` is a list of
directories to  search for shared (dynamically loaded) libraries at run-time.

For example, if you need to link against libraries known to be in the standard
library search path on target systems ::

    Extension(...,
              libraries=['gdbm', 'readline'])

If you need to link with libraries in a non-standard location, you'll have to
include the location in ``library_dirs``::

    Extension(...,
              library_dirs=['/usr/X11R6/lib'],
              libraries=['X11', 'Xt'])

(Again, this sort of non-portable construct should be avoided if you intend to
distribute your code.)

.. XXX Should mention clib libraries here or somewhere else!


Other options
-------------

There are still some other options which can be used to handle special cases.

The ``optional`` option is a boolean; if it is true,
a build failure in the extension will not abort the build process, but
instead simply not install the failing extension.

The ``extra_objects`` option is a list of object files to be passed to the
linker. These files must not have extensions, as the default extension for the
compiler is used.

``extra_compile_args`` and ``extra_link_args`` can be used to
specify additional command line options for the respective compiler and linker
command lines.

``export_symbols`` is only useful on Windows.  It can contain a list of
symbols (functions or variables) to be exported. This option is not needed when
building compiled extensions: Distutils  will automatically add ``initmodule``
to the list of exported symbols.

The ``depends`` option is a list of files that the extension depends on
(for example header files). The build command will call the compiler on the
sources to rebuild extension if any on this files has been modified since the
previous build.

Relationships between Distributions and Packages
================================================

A distribution may relate to packages in three specific ways:

#. It can require packages or modules.

#. It can provide packages or modules.

#. It can obsolete packages or modules.

These relationships can be specified using keyword arguments to the
:func:`distutils.core.setup` function.

Dependencies on other Python modules and packages can be specified by supplying
the *requires* keyword argument to :func:`~distutils.core.setup`. The
value must be a list of
strings.  Each string specifies a package that is required, and optionally what
versions are sufficient.

To specify that any version of a module or package is required, the string
should consist entirely of the module or package name. Examples include
``'mymodule'`` and ``'xml.parsers.expat'``.

If specific versions are required, a sequence of qualifiers can be supplied in
parentheses.  Each qualifier may consist of a comparison operator and a version
number.  The accepted comparison operators are::

    <    >    ==
    <=   >=   !=

These can be combined by using multiple qualifiers separated by commas (and
optional whitespace).  In this case, all of the qualifiers must be matched; a
logical AND is used to combine the evaluations.

Let's look at a bunch of examples:

+-------------------------+----------------------------------------------+
| Requires Expression     | Explanation                                  |
+=========================+==============================================+
| ``==1.0``               | Only version ``1.0`` is compatible           |
+-------------------------+----------------------------------------------+
| ``>1.0, !=1.5.1, <2.0`` | Any version after ``1.0`` and before ``2.0`` |
|                         | is compatible, except ``1.5.1``              |
+-------------------------+----------------------------------------------+

Now that we can specify dependencies, we also need to be able to specify what we
provide that other distributions can require.  This is done using the *provides*
keyword argument to :func:`~distutils.core.setup`. The value for this keyword is a list of
strings, each of which names a Python module or package, and optionally
identifies the version.  If the version is not specified, it is assumed to match
that of the distribution.

Some examples:

+---------------------+----------------------------------------------+
| Provides Expression | Explanation                                  |
+=====================+==============================================+
| ``mypkg``           | Provide ``mypkg``, using the distribution    |
|                     | version                                      |
+---------------------+----------------------------------------------+
| ``mypkg (1.1)``     | Provide ``mypkg`` version 1.1, regardless of |
|                     | the distribution version                     |
+---------------------+----------------------------------------------+

A package can declare that it obsoletes other packages using the *obsoletes*
keyword argument.  The value for this is similar to that of the *requires*
keyword: a list of strings giving module or package specifiers.  Each specifier
consists of a module or package name optionally followed by one or more version
qualifiers.  Version qualifiers are given in parentheses after the module or
package name.

The versions identified by the qualifiers are those that are obsoleted by the
distribution being described.  If no qualifiers are given, all versions of the
named module or package are understood to be obsoleted.

.. _distutils-installing-scripts:

Installing Scripts
==================

So far we have been dealing with pure and non-pure Python modules, which are
usually not run by themselves but imported by scripts.

Scripts are files containing Python source code, intended to be started from the
command line.  Scripts don't require Distutils to do anything very complicated.
The only clever feature is that if the first line of the script starts with
``#!`` and contains the word "python", the Distutils will adjust the first line
to refer to the current interpreter location. By default, it is replaced with
the current interpreter location.  The :option:`!--executable` (or :option:`!-e`)
option will allow the interpreter path to be explicitly overridden.

The ``scripts`` option simply is a list of files to be handled in this
way.  From the PyXML setup script::

    setup(...,
          scripts=['scripts/xmlproc_parse', 'scripts/xmlproc_val']
          )

.. versionchanged:: 3.1
   All the scripts will also be added to the ``MANIFEST`` file if no template is
   provided.  See :ref:`manifest`.


.. _distutils-installing-package-data:

Installing Package Data
=======================

Often, additional files need to be installed into a package.  These files are
often data that's closely related to the package's implementation, or text files
containing documentation that might be of interest to programmers using the
package.  These files are called :dfn:`package data`.

Package data can be added to packages using the ``package_data`` keyword
argument to the :func:`~distutils.core.setup` function.  The value must be a mapping from
package name to a list of relative path names that should be copied into the
package.  The paths are interpreted as relative to the directory containing the
package (information from the ``package_dir`` mapping is used if appropriate);
that is, the files are expected to be part of the package in the source
directories. They may contain glob patterns as well.

The path names may contain directory portions; any necessary directories will be
created in the installation.

For example, if a package should contain a subdirectory with several data files,
the files can be arranged like this in the source tree::

    setup.py
    src/
        mypkg/
            __init__.py
            module.py
            data/
                tables.dat
                spoons.dat
                forks.dat

The corresponding call to :func:`~distutils.core.setup` might be::

    setup(...,
          packages=['mypkg'],
          package_dir={'mypkg': 'src/mypkg'},
          package_data={'mypkg': ['data/*.dat']},
          )


.. versionchanged:: 3.1
   All the files that match ``package_data`` will be added to the ``MANIFEST``
   file if no template is provided.  See :ref:`manifest`.


.. _distutils-additional-files:

Installing Additional Files
===========================

The ``data_files`` option can be used to specify additional files needed
by the module distribution: configuration files, message catalogs, data files,
anything which doesn't fit in the previous categories.

``data_files`` specifies a sequence of (*directory*, *files*) pairs in the
following way::

    setup(...,
          data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
                      ('config', ['cfg/data.cfg'])],
         )

Each (*directory*, *files*) pair in the sequence specifies the installation
directory and the files to install there.

Each file name in *files* is interpreted relative to the :file:`setup.py`
script at the top of the package source distribution. Note that you can
specify the directory where the data files will be installed, but you cannot
rename the data files themselves.

The *directory* should be a relative path. It is interpreted relative to the
installation prefix (Python's ``sys.prefix`` for system installations;
``site.USER_BASE`` for user installations). Distutils allows *directory* to be
an absolute installation path, but this is discouraged since it is
incompatible with the wheel packaging format. No directory information from
*files* is used to determine the final location of the installed file; only
the name of the file is used.

You can specify the ``data_files`` options as a simple sequence of files
without specifying a target directory, but this is not recommended, and the
:command:`install` command will print a warning in this case. To install data
files directly in the target directory, an empty string should be given as the
directory.

.. versionchanged:: 3.1
   All the files that match ``data_files`` will be added to the ``MANIFEST``
   file if no template is provided.  See :ref:`manifest`.


.. _meta-data:

Additional meta-data
====================

The setup script may include additional meta-data beyond the name and version.
This information includes:

+----------------------+---------------------------+-----------------+--------+
| Meta-Data            | Description               | Value           | Notes  |
+======================+===========================+=================+========+
| ``name``             | name of the package       | short string    | \(1)   |
+----------------------+---------------------------+-----------------+--------+
| ``version``          | version of this release   | short string    | (1)(2) |
+----------------------+---------------------------+-----------------+--------+
| ``author``           | package author's name     | short string    | \(3)   |
+----------------------+---------------------------+-----------------+--------+
| ``author_email``     | email address of the      | email address   | \(3)   |
|                      | package author            |                 |        |
+----------------------+---------------------------+-----------------+--------+
| ``maintainer``       | package maintainer's name | short string    | \(3)   |
+----------------------+---------------------------+-----------------+--------+
| ``maintainer_email`` | email address of the      | email address   | \(3)   |
|                      | package maintainer        |                 |        |
+----------------------+---------------------------+-----------------+--------+
| ``url``              | home page for the package | URL             |        |
+----------------------+---------------------------+-----------------+--------+
| ``description``      | short, summary            | short string    |        |
|                      | description of the        |                 |        |
|                      | package                   |                 |        |
+----------------------+---------------------------+-----------------+--------+
| ``long_description`` | longer description of the | long string     | \(4)   |
|                      | package                   |                 |        |
+----------------------+---------------------------+-----------------+--------+
| ``download_url``     | location where the        | URL             |        |
|                      | package may be downloaded |                 |        |
+----------------------+---------------------------+-----------------+--------+
| ``classifiers``      | a list of classifiers     | list of strings | (6)(7) |
+----------------------+---------------------------+-----------------+--------+
| ``platforms``        | a list of platforms       | list of strings | (6)(8) |
+----------------------+---------------------------+-----------------+--------+
| ``keywords``         | a list of keywords        | list of strings | (6)(8) |
+----------------------+---------------------------+-----------------+--------+
| ``license``          | license for the package   | short string    | \(5)   |
+----------------------+---------------------------+-----------------+--------+

Notes:

(1)
    These fields are required.

(2)
    It is recommended that versions take the form *major.minor[.patch[.sub]]*.

(3)
    If maintainer is provided and author is not, distutils lists maintainer as
    the author in :file:`PKG-INFO`.

(4)
    The ``long_description`` field is used by PyPI when you publish a package,
    to build its project page.

(5)
    The ``license`` field is a text indicating the license covering the
    package where the license is not a selection from the "License" Trove
    classifiers. See the ``Classifier`` field. Notice that
    there's a ``licence`` distribution option which is deprecated but still
    acts as an alias for ``license``.

(6)
    This field must be a list.

(7)
    The valid classifiers are listed on
    `PyPI <https://pypi.org/classifiers>`_.

(8)
    To preserve backward compatibility, this field also accepts a string. If
    you pass a comma-separated string ``'foo, bar'``, it will be converted to
    ``['foo', 'bar']``, Otherwise, it will be converted to a list of one
    string.

'short string'
    A single line of text, not more than 200 characters.

'long string'
    Multiple lines of plain text in reStructuredText format (see
    http://docutils.sourceforge.net/).

'list of strings'
    See below.

Encoding the version information is an art in itself. Python packages generally
adhere to the version format *major.minor[.patch][sub]*. The major number is 0
for initial, experimental releases of software. It is incremented for releases
that represent major milestones in a package. The minor number is incremented
when important new features are added to the package. The patch number
increments when bug-fix releases are made. Additional trailing version
information is sometimes used to indicate sub-releases.  These are
"a1,a2,...,aN" (for alpha releases, where functionality and API may change),
"b1,b2,...,bN" (for beta releases, which only fix bugs) and "pr1,pr2,...,prN"
(for final pre-release release testing). Some examples:

0.1.0
    the first, experimental release of a package

1.0.1a2
    the second alpha release of the first patch version of 1.0

``classifiers`` must be specified in a list::

    setup(...,
          classifiers=[
              'Development Status :: 4 - Beta',
              'Environment :: Console',
              'Environment :: Web Environment',
              'Intended Audience :: End Users/Desktop',
              'Intended Audience :: Developers',
              'Intended Audience :: System Administrators',
              'License :: OSI Approved :: Python Software Foundation License',
              'Operating System :: MacOS :: MacOS X',
              'Operating System :: Microsoft :: Windows',
              'Operating System :: POSIX',
              'Programming Language :: Python',
              'Topic :: Communications :: Email',
              'Topic :: Office/Business',
              'Topic :: Software Development :: Bug Tracking',
              ],
          )

.. versionchanged:: 3.7
   :class:`~distutils.core.setup` now warns when ``classifiers``, ``keywords``
   or ``platforms`` fields are not specified as a list or a string.

.. _debug-setup-script:

Debugging the setup script
==========================

Sometimes things go wrong, and the setup script doesn't do what the developer
wants.

Distutils catches any exceptions when running the setup script, and print a
simple error message before the script is terminated.  The motivation for this
behaviour is to not confuse administrators who don't know much about Python and
are trying to install a package.  If they get a big long traceback from deep
inside the guts of Distutils, they may think the package or the Python
installation is broken because they don't read all the way down to the bottom
and see that it's a permission problem.

On the other hand, this doesn't help the developer to find the cause of the
failure. For this purpose, the :envvar:`DISTUTILS_DEBUG` environment variable can be set
to anything except an empty string, and distutils will now print detailed
information about what it is doing, dump the full traceback when an exception
occurs, and print the whole command line when an external program (like a C
compiler) fails.
alt-python312-setuptools/docs/deprecated/dependency_links.rst000064400000005453150410147360020420 0ustar00Specifying dependencies that aren't in PyPI via ``dependency_links``
====================================================================

.. warning::
    Dependency links support has been dropped by pip starting with version
    19.0 (released 2019-01-22).

If your project depends on packages that don't exist on PyPI, you *may* still be
able to depend on them if they are available for download as:

- an egg, in the standard distutils ``sdist`` format,
- a single ``.py`` file, or
- a VCS repository (Subversion, Mercurial, or Git).

You need to add some URLs to the ``dependency_links`` argument to ``setup()``.

The URLs must be either:

1. direct download URLs,
2. the URLs of web pages that contain direct download links, or
3. the repository's URL

In general, it's better to link to web pages, because it is usually less
complex to update a web page than to release a new version of your project.
You can also use a SourceForge ``showfiles.php`` link in the case where a
package you depend on is distributed via SourceForge.

If you depend on a package that's distributed as a single ``.py`` file, you
must include an ``"#egg=project-version"`` suffix to the URL, to give a project
name and version number.  (Be sure to escape any dashes in the name or version
by replacing them with underscores.)  EasyInstall will recognize this suffix
and automatically create a trivial ``setup.py`` to wrap the single ``.py`` file
as an egg.

In the case of a VCS checkout, you should also append ``#egg=project-version``
in order to identify for what package that checkout should be used. You can
append ``@REV`` to the URL's path (before the fragment) to specify a revision.
Additionally, you can also force the VCS being used by prepending the URL with
a certain prefix. Currently available are:

-  ``svn+URL`` for Subversion,
-  ``git+URL`` for Git, and
-  ``hg+URL`` for Mercurial

A more complete example would be:

    ``vcs+proto://host/path@revision#egg=project-version``

Be careful with the version. It should match the one inside the project files.
If you want to disregard the version, you have to omit it both in the
``requires`` and in the URL's fragment.

This will do a checkout (or a clone, in Git and Mercurial parlance) to a
temporary folder and run ``setup.py bdist_egg``.

The ``dependency_links`` option takes the form of a list of URL strings.  For
example, this will cause a search of the specified page for eggs or source
distributions, if the package's dependencies aren't already installed:

.. tab:: setup.cfg

    .. code-block:: ini

        [options]
        #...
        dependency_links = http://peak.telecommunity.com/snapshots/

.. tab:: setup.py

    .. code-block:: python

        setup(
            ...,
            dependency_links=[
                "http://peak.telecommunity.com/snapshots/",
            ],
        )
alt-python312-setuptools/docs/deprecated/python_eggs.rst000064400000074337150410147370017440 0ustar00=====================================
The Internal Structure of Python Eggs
=====================================

STOP! This is not the first document you should read!



----------------------
Eggs and their Formats
----------------------

A "Python egg" is a logical structure embodying the release of a
specific version of a Python project, comprising its code, resources,
and metadata. There are multiple formats that can be used to physically
encode a Python egg, and others can be developed. However, a key
principle of Python eggs is that they should be discoverable and
importable. That is, it should be possible for a Python application to
easily and efficiently find out what eggs are present on a system, and
to ensure that the desired eggs' contents are importable.

There are two basic formats currently implemented for Python eggs:

1. ``.egg`` format: a directory or zipfile *containing* the project's
   code and resources, along with an ``EGG-INFO`` subdirectory that
   contains the project's metadata

2. ``.egg-info`` format: a file or directory placed *adjacent* to the
   project's code and resources, that directly contains the project's
   metadata.

Both formats can include arbitrary Python code and resources, including
static data files, package and non-package directories, Python
modules, C extension modules, and so on.  But each format is optimized
for different purposes.

The ``.egg`` format is well-suited to distribution and the easy
uninstallation or upgrades of code, since the project is essentially
self-contained within a single directory or file, unmingled with any
other projects' code or resources.  It also makes it possible to have
multiple versions of a project simultaneously installed, such that
individual programs can select the versions they wish to use.

The ``.egg-info`` format, on the other hand, was created to support
backward-compatibility, performance, and ease of installation for system
packaging tools that expect to install all projects' code and resources
to a single directory (e.g. ``site-packages``).  Placing the metadata
in that same directory simplifies the installation process, since it
isn't necessary to create ``.pth`` files or otherwise modify
``sys.path`` to include each installed egg.

Its disadvantage, however, is that it provides no support for clean
uninstallation or upgrades, and of course only a single version of a
project can be installed to a given directory. Thus, support from a
package management tool is required. (This is why setuptools' "install"
command refers to this type of egg installation as "single-version,
externally managed".)  Also, they lack sufficient data to allow them to
be copied from their installation source.  easy_install can "ship" an
application by copying ``.egg`` files or directories to a target
location, but it cannot do this for ``.egg-info`` installs, because
there is no way to tell what code and resources belong to a particular
egg -- there may be several eggs "scrambled" together in a single
installation location, and the ``.egg-info`` format does not currently
include a way to list the files that were installed.  (This may change
in a future version.)


Code and Resources
==================

The layout of the code and resources is dictated by Python's normal
import layout, relative to the egg's "base location".

For the ``.egg`` format, the base location is the ``.egg`` itself. That
is, adding the ``.egg`` filename or directory name to ``sys.path``
makes its contents importable.

For the ``.egg-info`` format, however, the base location is the
directory that *contains* the ``.egg-info``, and thus it is the
directory that must be added to ``sys.path`` to make the egg importable.
(Note that this means that the "normal" installation of a package to a
``sys.path`` directory is sufficient to make it an "egg" if it has an
``.egg-info`` file or directory installed alongside of it.)


Project Metadata
=================

If eggs contained only code and resources, there would of course be
no difference between them and any other directory or zip file on
``sys.path``.  Thus, metadata must also be included, using a metadata
file or directory.

For the ``.egg`` format, the metadata is placed in an ``EGG-INFO``
subdirectory, directly within the ``.egg`` file or directory.  For the
``.egg-info`` format, metadata is stored directly within the
``.egg-info`` directory itself.

The minimum project metadata that all eggs must have is a standard
Python ``PKG-INFO`` file, named ``PKG-INFO`` and placed within the
metadata directory appropriate to the format.  Because it's possible for
this to be the only metadata file included, ``.egg-info`` format eggs
are not required to be a directory; they can just be a ``.egg-info``
file that directly contains the ``PKG-INFO`` metadata.  This eliminates
the need to create a directory just to store one file.  This option is
*not* available for ``.egg`` formats, since setuptools always includes
other metadata.  (In fact, setuptools itself never generates
``.egg-info`` files, either; the support for using files was added so
that the requirement could easily be satisfied by other tools, such
as distutils).

In addition to the ``PKG-INFO`` file, an egg's metadata directory may
also include files and directories representing various forms of
optional standard metadata (see the section on `Standard Metadata`_,
below) or user-defined metadata required by the project.  For example,
some projects may define a metadata format to describe their application
plugins, and metadata in this format would then be included by plugin
creators in their projects' metadata directories.


Filename-Embedded Metadata
==========================

To allow introspection of installed projects and runtime resolution of
inter-project dependencies, a certain amount of information is embedded
in egg filenames.  At a minimum, this includes the project name, and
ideally will also include the project version number.  Optionally, it
can also include the target Python version and required runtime
platform if platform-specific C code is included.  The syntax of an
egg filename is as follows::

    name ["-" version ["-py" pyver ["-" required_platform]]] "." ext

The "name" and "version" should be escaped using the ``to_filename()``
function provided by ``pkg_resources``, after first processing them with
``safe_name()`` and ``safe_version()`` respectively.  These latter two
functions can also be used to later "unescape" these parts of the
filename.  (For a detailed description of these transformations, please
see the "Parsing Utilities" section of the ``pkg_resources`` manual.)

The "pyver" string is the Python major version, as found in the first
3 characters of ``sys.version``.  "required_platform" is essentially
a distutils ``get_platform()`` string, but with enhancements to properly
distinguish Mac OS versions.  (See the ``get_build_platform()``
documentation in the "Platform Utilities" section of the
``pkg_resources`` manual for more details.)

Finally, the "ext" is either ``.egg`` or ``.egg-info``, as appropriate
for the egg's format.

Normally, an egg's filename should include at least the project name and
version, as this allows the runtime system to find desired project
versions without having to read the egg's PKG-INFO to determine its
version number.

Setuptools, however, only includes the version number in the filename
when an ``.egg`` file is built using the ``bdist_egg`` command, or when
an ``.egg-info`` directory is being installed by the
``install_egg_info`` command. When generating metadata for use with the
original source tree, it only includes the project name, so that the
directory will not have to be renamed each time the project's version
changes.

This is especially important when version numbers change frequently, and
the source metadata directory is kept under version control with the
rest of the project.  (As would be the case when the project's source
includes project-defined metadata that is not generated from by
setuptools from data in the setup script.)


Egg Links
=========

In addition to the ``.egg`` and ``.egg-info`` formats, there is a third
egg-related extension that you may encounter on occasion: ``.egg-link``
files.

These files are not eggs, strictly speaking. They simply provide a way
to reference an egg that is not physically installed in the desired
location. They exist primarily as a cross-platform alternative to
symbolic links, to support "installing" code that is being developed in
a different location than the desired installation location. For
example, if a user is developing an application plugin in their home
directory, but the plugin needs to be "installed" in an application
plugin directory, running "setup.py develop -md /path/to/app/plugins"
will install an ``.egg-link`` file in ``/path/to/app/plugins``, that
tells the egg runtime system where to find the actual egg (the user's
project source directory and its ``.egg-info`` subdirectory).

``.egg-link`` files are named following the format for ``.egg`` and
``.egg-info`` names, but only the project name is included; no version,
Python version, or platform information is included.  When the runtime
searches for available eggs, ``.egg-link`` files are opened and the
actual egg file/directory name is read from them.

Each ``.egg-link`` file should contain a single file or directory name,
with no newlines.  This filename should be the base location of one or
more eggs.  That is, the name must either end in ``.egg``, or else it
should be the parent directory of one or more ``.egg-info`` format eggs.

As of setuptools 0.6c6, the path may be specified as a platform-independent
(i.e. ``/``-separated) relative path from the directory containing the
``.egg-link`` file, and a second line may appear in the file, specifying a
platform-independent relative path from the egg's base directory to its
setup script directory.  This allows installation tools such as EasyInstall
to find the project's setup directory and build eggs or perform other setup
commands on it.


-----------------
Standard Metadata
-----------------

In addition to the minimum required ``PKG-INFO`` metadata, projects can
include a variety of standard metadata files or directories, as
described below.  Except as otherwise noted, these files and directories
are automatically generated by setuptools, based on information supplied
in the setup script or through analysis of the project's code and
resources.

Most of these files and directories are generated via "egg-info
writers" during execution of the setuptools ``egg_info`` command, and
are listed in the ``egg_info.writers`` entry point group defined by
setuptools' own ``setup.py`` file.

Project authors can register their own metadata writers as entry points
in this group (as described in the setuptools manual under "Adding new
EGG-INFO Files") to cause setuptools to generate project-specific
metadata files or directories during execution of the ``egg_info``
command.  It is up to project authors to document these new metadata
formats, if they create any.


``.txt`` File Formats
=====================

Files described in this section that have ``.txt`` extensions have a
simple lexical format consisting of a sequence of text lines, each line
terminated by a linefeed character (regardless of platform).  Leading
and trailing whitespace on each line is ignored, as are blank lines and
lines whose first nonblank character is a ``#`` (comment symbol).  (This
is the parsing format defined by the ``yield_lines()`` function of
the ``pkg_resources`` module.)

All ``.txt`` files defined by this section follow this format, but some
are also "sectioned" files, meaning that their contents are divided into
sections, using square-bracketed section headers akin to Windows
``.ini`` format.  Note that this does *not* imply that the lines within
the sections follow an ``.ini`` format, however.  Please see an
individual metadata file's documentation for a description of what the
lines and section names mean in that particular file.

Sectioned files can be parsed using the ``split_sections()`` function;
see the "Parsing Utilities" section of the ``pkg_resources`` manual for
for details.


Dependency Metadata
===================


``requires.txt``
----------------

This is a "sectioned" text file.  Each section is a sequence of
"requirements", as parsed by the ``parse_requirements()`` function;
please see the ``pkg_resources`` manual for the complete requirement
parsing syntax.

The first, unnamed section (i.e., before the first section header) in
this file is the project's core requirements, which must be installed
for the project to function.  (Specified using the ``install_requires``
keyword to ``setup()``).

The remaining (named) sections describe the project's "extra"
requirements, as specified using the ``extras_require`` keyword to
``setup()``.  The section name is the name of the optional feature, and
the section body lists that feature's dependencies.

Note that it is not normally necessary to inspect this file directly;
``pkg_resources.Distribution`` objects have a ``requires()`` method
that can be used to obtain ``Requirement`` objects describing the
project's core and optional dependencies.


``setup_requires.txt``
----------------------

Much like ``requires.txt`` except represents the requirements
specified by the ``setup_requires`` parameter to the Distribution.


``dependency_links.txt``
------------------------

A list of dependency URLs, one per line, as specified using the
``dependency_links`` keyword to ``setup()``.  These may be direct
download URLs, or the URLs of web pages containing direct download
links. Please see the setuptools manual for more information on
specifying this option.


``depends.txt`` -- Obsolete, do not create!
-------------------------------------------

This file follows an identical format to ``requires.txt``, but is
obsolete and should not be used.  The earliest versions of setuptools
required users to manually create and maintain this file, so the runtime
still supports reading it, if it exists.  The new filename was created
so that it could be automatically generated from ``setup()`` information
without overwriting an existing hand-created ``depends.txt``, if one
was already present in the project's source ``.egg-info`` directory.


``namespace_packages.txt`` -- Namespace Package Metadata
========================================================

A list of namespace package names, one per line, as supplied to the
``namespace_packages`` keyword to ``setup()``.  Please see the manuals
for setuptools and ``pkg_resources`` for more information about
namespace packages.


``entry_points.txt`` -- "Entry Point"/Plugin Metadata
=====================================================

This is a "sectioned" text file, whose contents encode the
``entry_points`` keyword supplied to ``setup()``.  All sections are
named, as the section names specify the entry point groups in which the
corresponding section's entry points are registered.

Each section is a sequence of "entry point" lines, each parseable using
the ``EntryPoint.parse`` classmethod; please see the ``pkg_resources``
manual for the complete entry point parsing syntax.

Note that it is not necessary to parse this file directly; the
``pkg_resources`` module provides a variety of APIs to locate and load
entry points automatically.  Please see the setuptools and
``pkg_resources`` manuals for details on the nature and uses of entry
points.


The ``scripts`` Subdirectory
============================

This directory is currently only created for ``.egg`` files built by
the setuptools ``bdist_egg`` command.  It will contain copies of all
of the project's "traditional" scripts (i.e., those specified using the
``scripts`` keyword to ``setup()``).  This is so that they can be
reconstituted when an ``.egg`` file is installed.

The scripts are placed here using the distutils' standard
``install_scripts`` command, so any ``#!`` lines reflect the Python
installation where the egg was built.  But instead of copying the
scripts to the local script installation directory, EasyInstall writes
short wrapper scripts that invoke the original scripts from inside the
egg, after ensuring that sys.path includes the egg and any eggs it
depends on.  For more about `script wrappers`_, see the section below on
`Installation and Path Management Issues`_.


Zip Support Metadata
====================


``native_libs.txt``
-------------------

A list of C extensions and other dynamic link libraries contained in
the egg, one per line.  Paths are ``/``-separated and relative to the
egg's base location.

This file is generated as part of ``bdist_egg`` processing, and as such
only appears in ``.egg`` files (and ``.egg`` directories created by
unpacking them).  It is used to ensure that all libraries are extracted
from a zipped egg at the same time, in case there is any direct linkage
between them.  Please see the `Zip File Issues`_ section below for more
information on library and resource extraction from ``.egg`` files.


``eager_resources.txt``
-----------------------

A list of resource files and/or directories, one per line, as specified
via the ``eager_resources`` keyword to ``setup()``.  Paths are
``/``-separated and relative to the egg's base location.

Resource files or directories listed here will be extracted
simultaneously, if any of the named resources are extracted, or if any
native libraries listed in ``native_libs.txt`` are extracted.  Please
see the setuptools manual for details on what this feature is used for
and how it works, as well as the `Zip File Issues`_ section below.


``zip-safe`` and ``not-zip-safe``
---------------------------------

These are zero-length files, and either one or the other should exist.
If ``zip-safe`` exists, it means that the project will work properly
when installed as an ``.egg`` zipfile, and conversely the existence of
``not-zip-safe`` means the project should not be installed as an
``.egg`` file.  The ``zip_safe`` option to setuptools' ``setup()``
determines which file will be written. If the option isn't provided,
setuptools attempts to make its own assessment of whether the package
can work, based on code and content analysis.

If neither file is present at installation time, EasyInstall defaults
to assuming that the project should be unzipped.  (Command-line options
to EasyInstall, however, take precedence even over an existing
``zip-safe`` or ``not-zip-safe`` file.)

Note that these flag files appear only in ``.egg`` files generated by
``bdist_egg``, and in ``.egg`` directories created by unpacking such an
``.egg`` file.



``top_level.txt`` -- Conflict Management Metadata
=================================================

This file is a list of the top-level module or package names provided
by the project, one Python identifier per line.

Subpackages are not included; a project containing both a ``foo.bar``
and a ``foo.baz`` would include only one line, ``foo``, in its
``top_level.txt``.

This data is used by ``pkg_resources`` at runtime to issue a warning if
an egg is added to ``sys.path`` when its contained packages may have
already been imported.

(It was also once used to detect conflicts with non-egg packages at
installation time, but in more recent versions, setuptools installs eggs
in such a way that they always override non-egg packages, thus
preventing a problem from arising.)


``SOURCES.txt`` -- Source Files Manifest
========================================

This file is roughly equivalent to the distutils' ``MANIFEST`` file.
The differences are as follows:

* The filenames always use ``/`` as a path separator, which must be
  converted back to a platform-specific path whenever they are read.

* The file is automatically generated by setuptools whenever the
  ``egg_info`` or ``sdist`` commands are run, and it is *not*
  user-editable.

Although this metadata is included with distributed eggs, it is not
actually used at runtime for any purpose.  Its function is to ensure
that setuptools-built *source* distributions can correctly discover
what files are part of the project's source, even if the list had been
generated using revision control metadata on the original author's
system.

In other words, ``SOURCES.txt`` has little or no runtime value for being
included in distributed eggs, and it is possible that future versions of
the ``bdist_egg`` and ``install_egg_info`` commands will strip it before
installation or distribution.  Therefore, do not rely on its being
available outside of an original source directory or source
distribution.


------------------------------
Other Technical Considerations
------------------------------


Zip File Issues
===============

Although zip files resemble directories, they are not fully
substitutable for them.  Most platforms do not support loading dynamic
link libraries contained in zipfiles, so it is not possible to directly
import C extensions from ``.egg`` zipfiles.  Similarly, there are many
existing libraries -- whether in Python or C -- that require actual
operating system filenames, and do not work with arbitrary "file-like"
objects or in-memory strings, and thus cannot operate directly on the
contents of zip files.

To address these issues, the ``pkg_resources`` module provides a
"resource API" to support obtaining either the contents of a resource,
or a true operating system filename for the resource.  If the egg
containing the resource is a directory, the resource's real filename
is simply returned.  However, if the egg is a zipfile, then the
resource is first extracted to a cache directory, and the filename
within the cache is returned.

The cache directory is determined by the ``pkg_resources`` API; please
see the ``set_cache_path()`` and ``get_default_cache()`` documentation
for details.


The Extraction Process
----------------------

Resources are extracted to a cache subdirectory whose name is based
on the enclosing ``.egg`` filename and the path to the resource.  If
there is already a file of the correct name, size, and timestamp, its
filename is returned to the requester.  Otherwise, the desired file is
extracted first to a temporary name generated using
``mkstemp(".$extract",target_dir)``, and then its timestamp is set to
match the one in the zip file, before renaming it to its final name.
(Some collision detection and resolution code is used to handle the
fact that Windows doesn't overwrite files when renaming.)

If a resource directory is requested, all of its contents are
recursively extracted in this fashion, to ensure that the directory
name can be used as if it were valid all along.

If the resource requested for extraction is listed in the
``native_libs.txt`` or ``eager_resources.txt`` metadata files, then
*all* resources listed in *either* file will be extracted before the
requested resource's filename is returned, thus ensuring that all
C extensions and data used by them will be simultaneously available.


Extension Import Wrappers
-------------------------

Since Python's built-in zip import feature does not support loading
C extension modules from zipfiles, the setuptools ``bdist_egg`` command
generates special import wrappers to make it work.

The wrappers are ``.py`` files (along with corresponding ``.pyc``
and/or ``.pyo`` files) that have the same module name as the
corresponding C extension.  These wrappers are located in the same
package directory (or top-level directory) within the zipfile, so that
say, ``foomodule.so`` will get a corresponding ``foo.py``, while
``bar/baz.pyd`` will get a corresponding ``bar/baz.py``.

These wrapper files contain a short stanza of Python code that asks
``pkg_resources`` for the filename of the corresponding C extension,
then reloads the module using the obtained filename.  This will cause
``pkg_resources`` to first ensure that all of the egg's C extensions
(and any accompanying "eager resources") are extracted to the cache
before attempting to link to the C library.

Note, by the way, that ``.egg`` directories will also contain these
wrapper files.  However, Python's default import priority is such that
C extensions take precedence over same-named Python modules, so the
import wrappers are ignored unless the egg is a zipfile.


Installation and Path Management Issues
=======================================

Python's initial setup of ``sys.path`` is very dependent on the Python
version and installation platform, as well as how Python was started
(i.e., script vs. ``-c`` vs. ``-m`` vs. interactive interpreter).
In fact, Python also provides only two relatively robust ways to affect
``sys.path`` outside of direct manipulation in code: the ``PYTHONPATH``
environment variable, and ``.pth`` files.

However, with no cross-platform way to safely and persistently change
environment variables, this leaves ``.pth`` files as EasyInstall's only
real option for persistent configuration of ``sys.path``.

But ``.pth`` files are rather strictly limited in what they are allowed
to do normally.  They add directories only to the *end* of ``sys.path``,
after any locally-installed ``site-packages`` directory, and they are
only processed *in* the ``site-packages`` directory to start with.

This is a double whammy for users who lack write access to that
directory, because they can't create a ``.pth`` file that Python will
read, and even if a sympathetic system administrator adds one for them
that calls ``site.addsitedir()`` to allow some other directory to
contain ``.pth`` files, they won't be able to install newer versions of
anything that's installed in the systemwide ``site-packages``, because
their paths will still be added *after* ``site-packages``.

So EasyInstall applies two workarounds to solve these problems.

The first is that EasyInstall leverages ``.pth`` files' "import" feature
to manipulate ``sys.path`` and ensure that anything EasyInstall adds
to a ``.pth`` file will always appear before both the standard library
and the local ``site-packages`` directories.  Thus, it is always
possible for a user who can write a Python-read ``.pth`` file to ensure
that their packages come first in their own environment.

Second, when installing to a ``PYTHONPATH`` directory (as opposed to
a "site" directory like ``site-packages``) EasyInstall will also install
a special version of the ``site`` module.  Because it's in a
``PYTHONPATH`` directory, this module will get control before the
standard library version of ``site`` does.  It will record the state of
``sys.path`` before invoking the "real" ``site`` module, and then
afterwards it processes any ``.pth`` files found in ``PYTHONPATH``
directories, including all the fixups needed to ensure that eggs always
appear before the standard library in sys.path, but are in a relative
order to one another that is defined by their ``PYTHONPATH`` and
``.pth``-prescribed sequence.

The net result of these changes is that ``sys.path`` order will be
as follows at runtime:

1. The ``sys.argv[0]`` directory, or an empty string if no script
   is being executed.

2. All eggs installed by EasyInstall in any ``.pth`` file in each
   ``PYTHONPATH`` directory, in order first by ``PYTHONPATH`` order,
   then normal ``.pth`` processing order (which is to say alphabetical
   by ``.pth`` filename, then by the order of listing within each
   ``.pth`` file).

3. All eggs installed by EasyInstall in any ``.pth`` file in each "site"
   directory (such as ``site-packages``), following the same ordering
   rules as for the ones on ``PYTHONPATH``.

4. The ``PYTHONPATH`` directories themselves, in their original order

5. Any paths from ``.pth`` files found on ``PYTHONPATH`` that were *not*
   eggs installed by EasyInstall, again following the same relative
   ordering rules.

6. The standard library and "site" directories, along with the contents
   of any ``.pth`` files found in the "site" directories.

Notice that sections 1, 4, and 6 comprise the "normal" Python setup for
``sys.path``.  Sections 2 and 3 are inserted to support eggs, and
section 5 emulates what the "normal" semantics of ``.pth`` files on
``PYTHONPATH`` would be if Python natively supported them.

For further discussion of the tradeoffs that went into this design, as
well as notes on the actual magic inserted into ``.pth`` files to make
them do these things, please see also the following messages to the
distutils-SIG mailing list:

* http://mail.python.org/pipermail/distutils-sig/2006-February/006026.html
* http://mail.python.org/pipermail/distutils-sig/2006-March/006123.html


Script Wrappers
---------------

EasyInstall never directly installs a project's original scripts to
a script installation directory.  Instead, it writes short wrapper
scripts that first ensure that the project's dependencies are active
on sys.path, before invoking the original script.  These wrappers
have a #! line that points to the version of Python that was used to
install them, and their second line is always a comment that indicates
the type of script wrapper, the project version required for the script
to run, and information identifying the script to be invoked.

The format of this marker line is::

    "# EASY-INSTALL-" script_type ": " tuple_of_strings "\n"

The ``script_type`` is one of ``SCRIPT``, ``DEV-SCRIPT``, or
``ENTRY-SCRIPT``.  The ``tuple_of_strings`` is a comma-separated
sequence of Python string constants.  For ``SCRIPT`` and ``DEV-SCRIPT``
wrappers, there are two strings: the project version requirement, and
the script name (as a filename within the ``scripts`` metadata
directory).  For ``ENTRY-SCRIPT`` wrappers, there are three:
the project version requirement, the entry point group name, and the
entry point name.  (See the "Automatic Script Creation" section in the
setuptools manual for more information about entry point scripts.)

In each case, the project version requirement string will be a string
parseable with the ``pkg_resources`` modules' ``Requirement.parse()``
classmethod.  The only difference between a ``SCRIPT`` wrapper and a
``DEV-SCRIPT`` is that a ``DEV-SCRIPT`` actually executes the original
source script in the project's source tree, and is created when the
"setup.py develop" command is run.  A ``SCRIPT`` wrapper, on the other
hand, uses the "installed" script written to the ``EGG-INFO/scripts``
subdirectory of the corresponding ``.egg`` zipfile or directory.
(``.egg-info`` eggs do not have script wrappers associated with them,
except in the "setup.py develop" case.)

The purpose of including the marker line in generated script wrappers is
to facilitate introspection of installed scripts, and their relationship
to installed eggs.  For example, an uninstallation tool could use this
data to identify what scripts can safely be removed, and/or identify
what scripts would stop working if a particular egg is uninstalled.
alt-python312-setuptools/docs/deprecated/distutils-legacy.rst000064400000004601150410147370020363 0ustar00Porting from Distutils
======================

Setuptools and the PyPA have a `stated goal <https://github.com/pypa/packaging-problems/issues/127>`_ to make Setuptools the reference API for distutils.

Since the 60.0.0 release, Setuptools includes a local, vendored copy of distutils (from late copies of CPython) that is enabled by default. To disable the use of this copy of distutils when invoking setuptools, set the environment variable:

    SETUPTOOLS_USE_DISTUTILS=stdlib

.. warning::
   Please note that this also affects how ``distutils.cfg`` files inside stdlib's ``distutils``
   package directory are processed.
   Unless ``SETUPTOOLS_USE_DISTUTILS=stdlib``, they will have no effect on the build process.

   You can still use a global user config file, ``~/.pydistutils.cfg`` (POSIX) or ``%USERPROFILE%/pydistutils.cfg`` (Windows),
   or use the environment variable :ref:`DIST_EXTRA_CONFIG <setup-config>` to point to another
   supplementary configuration file.


Prefer Setuptools
-----------------

As Distutils is deprecated, any usage of functions or objects from distutils is similarly discouraged, and Setuptools aims to replace or deprecate all such uses. This section describes the recommended replacements.

``distutils.core.setup`` → ``setuptools.setup``

``distutils.cmd.Command`` or ``distutils.core.Command`` → ``setuptools.Command``

``distutils.command.{build_clib,build_ext,build_py,sdist}`` → ``setuptools.command.*``

``distutils.dep_util`` → ``setuptools.modified``

``distutils.log`` → :mod:`logging` (standard library)

``distutils.version.*`` → :doc:`packaging.version.* <packaging:version>`

``distutils.errors.*`` → ``setuptools.errors.*`` [#errors]_


Migration advice is also provided by :pep:`PEP 632 <632#migration-advice>`.

If a project relies on uses of ``distutils`` that do not have a suitable replacement above, please search the `Setuptools issue tracker <https://github.com/pypa/setuptools/issues/>`_ and file a request, describing the use-case so that Setuptools' maintainers can investigate. Please provide enough detail to help the maintainers understand how distutils is used, what value it provides, and why that behavior should be supported.


.. [#errors] Please notice errors related to the command line usage of
   ``setup.py``, such as ``DistutilsArgError``, are intentionally not exposed
   by setuptools, since this is considered a deprecated practice.
alt-python312-setuptools/docs/deprecated/index.rst000064400000001537150410147370016211 0ustar00======================================================
Guides on backward compatibility & deprecated practice
======================================================

``Setuptools`` has undergone tremendous changes since its first debut. As its
development continues to roll forward, many of the practice and mechanisms it
had established are now considered deprecated. But they still remain relevant
as a plethora of libraries continue to depend on them. Many people also find
it necessary to equip themselves with the knowledge to better support backward
compatibility. This guide aims to provide the essential information for such
objectives.

.. toctree::
    :maxdepth: 1

    changed_keywords
    dependency_links
    python_eggs
    easy_install
    zip_safe
    resource_extraction
    distutils/index
    distutils-legacy
    functionalities
    commands
alt-python312-setuptools/docs/deprecated/easy_install.rst000064400000145452150410147370017576 0ustar00============
Easy Install
============

.. warning::
    Easy Install is deprecated. Do not use it. Instead use pip. If
    you think you need Easy Install, please reach out to the PyPA
    team (a ticket to pip or setuptools is fine), describing your
    use-case.

Easy Install is a python module (``easy_install``) bundled with ``setuptools``
that lets you automatically download, build, install, and manage Python
packages.

Please share your experiences with us! If you encounter difficulty installing
a package, please contact us via the `distutils mailing list
<http://mail.python.org/pipermail/distutils-sig/>`_.  (Note: please DO NOT send
private email directly to the author of setuptools; it will be discarded.  The
mailing list is a searchable archive of previously-asked and answered
questions; you should begin your research there before reporting something as a
bug -- and then do so via list discussion first.)

(Also, if you'd like to learn about how you can use ``setuptools`` to make your
own packages work better with EasyInstall, or provide EasyInstall-like features
without requiring your users to use EasyInstall directly, you'll probably want
to check out the full documentation as well.)

Using "Easy Install"
====================


.. _installation instructions:

Installing "Easy Install"
-------------------------

Please see the :pypi:`setuptools` on the package index
for download links and basic installation instructions for each of the
supported platforms.

You will need at least Python 3.5 or 2.7.  An ``easy_install`` script will be
installed in the normal location for Python scripts on your platform.

Note that the instructions on the setuptools PyPI page assume that you are
are installing to Python's primary ``site-packages`` directory.  If this is
not the case, you should consult the section below on `Custom Installation
Locations`_ before installing.  (And, on Windows, you should not use the
``.exe`` installer when installing to an alternate location.)

Note that ``easy_install`` normally works by downloading files from the
internet.  If you are behind an NTLM-based firewall that prevents Python
programs from accessing the net directly, you may wish to first install and use
the `APS proxy server <http://ntlmaps.sf.net/>`_, which lets you get past such
firewalls in the same way that your web browser(s) do.

(Alternately, if you do not wish easy_install to actually download anything, you
can restrict it from doing so with the ``--allow-hosts`` option; see the
sections on `restricting downloads with --allow-hosts`_ and `command-line
options`_ for more details.)


Troubleshooting
~~~~~~~~~~~~~~~

If EasyInstall/setuptools appears to install correctly, and you can run the
``easy_install`` command but it fails with an ``ImportError``, the most likely
cause is that you installed to a location other than ``site-packages``,
without taking any of the steps described in the `Custom Installation
Locations`_ section below.  Please see that section and follow the steps to
make sure that your custom location will work correctly.  Then re-install.

Similarly, if you can run ``easy_install``, and it appears to be installing
packages, but then you can't import them, the most likely issue is that you
installed EasyInstall correctly but are using it to install packages to a
non-standard location that hasn't been properly prepared.  Again, see the
section on `Custom Installation Locations`_ for more details.


Windows Notes
~~~~~~~~~~~~~

Installing setuptools will provide an ``easy_install`` command according to
the techniques described in `Executables and Launchers`_. If the
``easy_install`` command is not available after installation, that section
provides details on how to configure Windows to make the commands available.


Downloading and Installing a Package
------------------------------------

For basic use of ``easy_install``, you need only supply the filename or URL of
a source distribution or .egg file (`Python Egg`__).

__ http://peak.telecommunity.com/DevCenter/PythonEggs

**Example 1**. Install a package by name, searching PyPI for the latest
version, and automatically downloading, building, and installing it::

    easy_install SQLObject

**Example 2**. Install or upgrade a package by name and version by finding
links on a given "download page"::

    easy_install -f http://pythonpaste.org/package_index.html SQLObject

**Example 3**. Download a source distribution from a specified URL,
automatically building and installing it::

    easy_install http://example.com/path/to/MyPackage-1.2.3.tgz

**Example 4**. Install an already-downloaded .egg file::

    easy_install /my_downloads/OtherPackage-3.2.1-py2.3.egg

**Example 5**.  Upgrade an already-installed package to the latest version
listed on PyPI::

    easy_install --upgrade PyProtocols

**Example 6**.  Install a source distribution that's already downloaded and
extracted in the current directory (New in 0.5a9)::

    easy_install .

**Example 7**.  (New in 0.6a1) Find a source distribution or Subversion
checkout URL for a package, and extract it or check it out to
``~/projects/sqlobject`` (the name will always be in all-lowercase), where it
can be examined or edited.  (The package will not be installed, but it can
easily be installed with ``easy_install ~/projects/sqlobject``.  See `Editing
and Viewing Source Packages`_ below for more info.)::

    easy_install --editable --build-directory ~/projects SQLObject

**Example 7**. (New in 0.6.11) Install a distribution within your home dir::

    easy_install --user SQLAlchemy

Easy Install accepts URLs, filenames, PyPI package names (i.e., ``distutils``
"distribution" names), and package+version specifiers.  In each case, it will
attempt to locate the latest available version that meets your criteria.

When downloading or processing downloaded files, Easy Install recognizes
distutils source distribution files with extensions of .tgz, .tar, .tar.gz,
.tar.bz2, or .zip.  And of course it handles already-built .egg
distributions as well as ``.win32.exe`` installers built using distutils.

By default, packages are installed to the running Python installation's
``site-packages`` directory, unless you provide the ``-d`` or ``--install-dir``
option to specify an alternative directory, or specify an alternate location
using distutils configuration files.  (See `Configuration Files`_, below.)

By default, any scripts included with the package are installed to the running
Python installation's standard script installation location.  However, if you
specify an installation directory via the command line or a config file, then
the default directory for installing scripts will be the same as the package
installation directory, to ensure that the script will have access to the
installed package.  You can override this using the ``-s`` or ``--script-dir``
option.

Installed packages are added to an ``easy-install.pth`` file in the install
directory, so that Python will always use the most-recently-installed version
of the package.  If you would like to be able to select which version to use at
runtime, you should use the ``-m`` or ``--multi-version`` option.


Upgrading a Package
-------------------

You don't need to do anything special to upgrade a package: just install the
new version, either by requesting a specific version, e.g.::

    easy_install "SomePackage==2.0"

a version greater than the one you have now::

    easy_install "SomePackage>2.0"

using the upgrade flag, to find the latest available version on PyPI::

    easy_install --upgrade SomePackage

or by using a download page, direct download URL, or package filename::

    easy_install -f http://example.com/downloads ExamplePackage

    easy_install http://example.com/downloads/ExamplePackage-2.0-py2.4.egg

    easy_install my_downloads/ExamplePackage-2.0.tgz

If you're using ``-m`` or ``--multi-version`` , using the ``require()``
function at runtime automatically selects the newest installed version of a
package that meets your version criteria.  So, installing a newer version is
the only step needed to upgrade such packages.

If you're installing to a directory on PYTHONPATH, or a configured "site"
directory (and not using ``-m``), installing a package automatically replaces
any previous version in the ``easy-install.pth`` file, so that Python will
import the most-recently installed version by default.  So, again, installing
the newer version is the only upgrade step needed.

If you haven't suppressed script installation (using ``--exclude-scripts`` or
``-x``), then the upgraded version's scripts will be installed, and they will
be automatically patched to ``require()`` the corresponding version of the
package, so that you can use them even if they are installed in multi-version
mode.

``easy_install`` never actually deletes packages (unless you're installing a
package with the same name and version number as an existing package), so if
you want to get rid of older versions of a package, please see `Uninstalling
Packages`_, below.


Changing the Active Version
---------------------------

If you've upgraded a package, but need to revert to a previously-installed
version, you can do so like this::

    easy_install PackageName==1.2.3

Where ``1.2.3`` is replaced by the exact version number you wish to switch to.
If a package matching the requested name and version is not already installed
in a directory on ``sys.path``, it will be located via PyPI and installed.

If you'd like to switch to the latest installed version of ``PackageName``, you
can do so like this::

    easy_install PackageName

This will activate the latest installed version.  (Note: if you have set any
``find_links`` via distutils configuration files, those download pages will be
checked for the latest available version of the package, and it will be
downloaded and installed if it is newer than your current version.)

Note that changing the active version of a package will install the newly
active version's scripts, unless the ``--exclude-scripts`` or ``-x`` option is
specified.


Uninstalling Packages
---------------------

If you have replaced a package with another version, then you can just delete
the package(s) you don't need by deleting the PackageName-versioninfo.egg file
or directory (found in the installation directory).

If you want to delete the currently installed version of a package (or all
versions of a package), you should first run::

    easy_install -m PackageName

This will ensure that Python doesn't continue to search for a package you're
planning to remove. After you've done this, you can safely delete the .egg
files or directories, along with any scripts you wish to remove.


Managing Scripts
----------------

Whenever you install, upgrade, or change versions of a package, EasyInstall
automatically installs the scripts for the selected package version, unless
you tell it not to with ``-x`` or ``--exclude-scripts``.  If any scripts in
the script directory have the same name, they are overwritten.

Thus, you do not normally need to manually delete scripts for older versions of
a package, unless the newer version of the package does not include a script
of the same name.  However, if you are completely uninstalling a package, you
may wish to manually delete its scripts.

EasyInstall's default behavior means that you can normally only run scripts
from one version of a package at a time.  If you want to keep multiple versions
of a script available, however, you can simply use the ``--multi-version`` or
``-m`` option, and rename the scripts that EasyInstall creates.  This works
because EasyInstall installs scripts as short code stubs that ``require()`` the
matching version of the package the script came from, so renaming the script
has no effect on what it executes.

For example, suppose you want to use two versions of the ``rst2html`` tool
provided by the `docutils <http://docutils.sf.net/>`_ package.  You might
first install one version::

    easy_install -m docutils==0.3.9

then rename the ``rst2html.py`` to ``r2h_039``, and install another version::

    easy_install -m docutils==0.3.10

This will create another ``rst2html.py`` script, this one using docutils
version 0.3.10 instead of 0.3.9.  You now have two scripts, each using a
different version of the package.  (Notice that we used ``-m`` for both
installations, so that Python won't lock us out of using anything but the most
recently-installed version of the package.)


Executables and Launchers
-------------------------

On Unix systems, scripts are installed with as natural files with a "#!"
header and no extension and they launch under the Python version indicated in
the header.

On Windows, there is no mechanism to "execute" files without extensions, so
EasyInstall provides two techniques to mirror the Unix behavior. The behavior
is indicated by the SETUPTOOLS_LAUNCHER environment variable, which may be
"executable" (default) or "natural".

Regardless of the technique used, the script(s) will be installed to a Scripts
directory (by default in the Python installation directory). It is recommended
for EasyInstall that you ensure this directory is in the PATH environment
variable. The easiest way to ensure the Scripts directory is in the PATH is
to run ``Tools\Scripts\win_add2path.py`` from the Python directory.

Note that instead of changing your ``PATH`` to include the Python scripts
directory, you can also retarget the installation location for scripts so they
go on a directory that's already on the ``PATH``.  For more information see
`Command-Line Options`_ and `Configuration Files`_.  During installation,
pass command line options (such as ``--script-dir``) to control where
scripts will be installed.


Windows Executable Launcher
~~~~~~~~~~~~~~~~~~~~~~~~~~~

If the "executable" launcher is used, EasyInstall will create a '.exe'
launcher of the same name beside each installed script (including
``easy_install`` itself). These small .exe files launch the script of the
same name using the Python version indicated in the '#!' header.

This behavior is currently default. To force
the use of executable launchers, set ``SETUPTOOLS_LAUNCHER`` to "executable".

Natural Script Launcher
~~~~~~~~~~~~~~~~~~~~~~~

EasyInstall also supports deferring to an external launcher such as
`pylauncher <https://bitbucket.org/pypa/pylauncher>`_ for launching scripts.
Enable this experimental functionality by setting the
``SETUPTOOLS_LAUNCHER`` environment variable to "natural". EasyInstall will
then install scripts as simple
scripts with a .pya (or .pyw) extension appended. If these extensions are
associated with the pylauncher and listed in the PATHEXT environment variable,
these scripts can then be invoked simply and directly just like any other
executable. This behavior may become default in a future version.

EasyInstall uses the .pya extension instead of simply
the typical '.py' extension. This distinct extension is necessary to prevent
Python
from treating the scripts as importable modules (where name conflicts exist).
Current releases of pylauncher do not yet associate with .pya files by
default, but future versions should do so.


Tips & Techniques
-----------------

Multiple Python Versions
~~~~~~~~~~~~~~~~~~~~~~~~

EasyInstall installs itself under two names:
``easy_install`` and ``easy_install-N.N``, where ``N.N`` is the Python version
used to install it.  Thus, if you install EasyInstall for both Python 3.2 and
2.7, you can use the ``easy_install-3.2`` or ``easy_install-2.7`` scripts to
install packages for the respective Python version.

Setuptools also supplies easy_install as a runnable module which may be
invoked using ``python -m easy_install`` for any Python with Setuptools
installed.

Restricting Downloads with ``--allow-hosts``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can use the ``--allow-hosts`` (``-H``) option to restrict what domains
EasyInstall will look for links and downloads on.  ``--allow-hosts=None``
prevents downloading altogether.  You can also use wildcards, for example
to restrict downloading to hosts in your own intranet.  See the section below
on `Command-Line Options`_ for more details on the ``--allow-hosts`` option.

By default, there are no host restrictions in effect, but you can change this
default by editing the appropriate `configuration files`_ and adding:

.. code-block:: ini

    [easy_install]
    allow_hosts = *.myintranet.example.com,*.python.org

The above example would then allow downloads only from hosts in the
``python.org`` and ``myintranet.example.com`` domains, unless overridden on the
command line.


Installing on Un-networked Machines
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Just copy the eggs or source packages you need to a directory on the target
machine, then use the ``-f`` or ``--find-links`` option to specify that
directory's location.  For example::

    easy_install -H None -f somedir SomePackage

will attempt to install SomePackage using only eggs and source packages found
in ``somedir`` and disallowing all remote access.  You should of course make
sure you have all of SomePackage's dependencies available in somedir.

If you have another machine of the same operating system and library versions
(or if the packages aren't platform-specific), you can create the directory of
eggs using a command like this::

    easy_install -zmaxd somedir SomePackage

This will tell EasyInstall to put zipped eggs or source packages for
SomePackage and all its dependencies into ``somedir``, without creating any
scripts or .pth files.  You can then copy the contents of ``somedir`` to the
target machine.  (``-z`` means zipped eggs, ``-m`` means multi-version, which
prevents .pth files from being used, ``-a`` means to copy all the eggs needed,
even if they're installed elsewhere on the machine, and ``-d`` indicates the
directory to place the eggs in.)

You can also build the eggs from local development packages that were installed
with the ``setup.py develop`` command, by including the ``-l`` option, e.g.::

    easy_install -zmaxld somedir SomePackage

This will use locally-available source distributions to build the eggs.


Packaging Others' Projects As Eggs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Need to distribute a package that isn't published in egg form?  You can use
EasyInstall to build eggs for a project.  You'll want to use the ``--zip-ok``,
``--exclude-scripts``, and possibly ``--no-deps`` options (``-z``, ``-x`` and
``-N``, respectively).  Use ``-d`` or ``--install-dir`` to specify the location
where you'd like the eggs placed.  By placing them in a directory that is
published to the web, you can then make the eggs available for download, either
in an intranet or to the internet at large.

If someone distributes a package in the form of a single ``.py`` file, you can
wrap it in an egg by tacking an ``#egg=name-version`` suffix on the file's URL.
So, something like this::

    easy_install -f "http://some.example.com/downloads/foo.py#egg=foo-1.0" foo

will install the package as an egg, and this::

    easy_install -zmaxd. \
        -f "http://some.example.com/downloads/foo.py#egg=foo-1.0" foo

will create a ``.egg`` file in the current directory.


Creating your own Package Index
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In addition to local directories and the Python Package Index, EasyInstall can
find download links on most any web page whose URL is given to the ``-f``
(``--find-links``) option.  In the simplest case, you can simply have a web
page with links to eggs or Python source packages, even an automatically
generated directory listing (such as the Apache web server provides).

If you are setting up an intranet site for package downloads, you may want to
configure the target machines to use your download site by default, adding
something like this to their `configuration files`_:

.. code-block:: ini

    [easy_install]
    find_links = http://mypackages.example.com/somedir/
                 http://turbogears.org/download/
                 http://peak.telecommunity.com/dist/

As you can see, you can list multiple URLs separated by whitespace, continuing
on multiple lines if necessary (as long as the subsequent lines are indented.

If you are more ambitious, you can also create an entirely custom package index
or PyPI mirror.  See the ``--index-url`` option under `Command-Line Options`_,
below, and also the section on `Package Index "API"`_.


Password-Protected Sites
------------------------

If a site you want to download from is password-protected using HTTP "Basic"
authentication, you can specify your credentials in the URL, like so::

    http://some_userid:some_password@some.example.com/some_path/

You can do this with both index page URLs and direct download URLs.  As long
as any HTML pages read by easy_install use *relative* links to point to the
downloads, the same user ID and password will be used to do the downloading.

Using .pypirc Credentials
-------------------------

In additional to supplying credentials in the URL, ``easy_install`` will also
honor credentials if present in the .pypirc file. Teams maintaining a private
repository of packages may already have defined access credentials for
uploading packages according to the distutils documentation. ``easy_install``
will attempt to honor those if present. Refer to the distutils documentation
for Python 2.5 or later for details on the syntax.

Controlling Build Options
~~~~~~~~~~~~~~~~~~~~~~~~~

EasyInstall respects standard distutils `Configuration Files`_, so you can use
them to configure build options for packages that it installs from source.  For
example, if you are on Windows using the MinGW compiler, you can configure the
default compiler by putting something like this:

.. code-block:: ini

    [build]
    compiler = mingw32

into the appropriate distutils configuration file.  In fact, since this is just
normal distutils configuration, it will affect any builds using that config
file, not just ones done by EasyInstall.  For example, if you add those lines
to ``distutils.cfg`` in the ``distutils`` package directory, it will be the
default compiler for *all* packages you build.  See `Configuration Files`_
below for a list of the standard configuration file locations, and links to
more documentation on using distutils configuration files.


Editing and Viewing Source Packages
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Sometimes a package's source distribution  contains additional documentation,
examples, configuration files, etc., that are not part of its actual code.  If
you want to be able to examine these files, you can use the ``--editable``
option to EasyInstall, and EasyInstall will look for a source distribution
or Subversion URL for the package, then download and extract it or check it out
as a subdirectory of the ``--build-directory`` you specify.  If you then wish
to install the package after editing or configuring it, you can do so by
rerunning EasyInstall with that directory as the target.

Note that using ``--editable`` stops EasyInstall from actually building or
installing the package; it just finds, obtains, and possibly unpacks it for
you.  This allows you to make changes to the package if necessary, and to
either install it in development mode using ``setup.py develop`` (if the
package uses setuptools, that is), or by running ``easy_install projectdir``
(where ``projectdir`` is the subdirectory EasyInstall created for the
downloaded package.

In order to use ``--editable`` (``-e`` for short), you *must* also supply a
``--build-directory`` (``-b`` for short).  The project will be placed in a
subdirectory of the build directory.  The subdirectory will have the same
name as the project itself, but in all-lowercase.  If a file or directory of
that name already exists, EasyInstall will print an error message and exit.

Also, when using ``--editable``, you cannot use URLs or filenames as arguments.
You *must* specify project names (and optional version requirements) so that
EasyInstall knows what directory name(s) to create.  If you need to force
EasyInstall to use a particular URL or filename, you should specify it as a
``--find-links`` item (``-f`` for short), and then also specify
the project name, e.g.::

    easy_install -eb ~/projects \
     -fhttp://prdownloads.sourceforge.net/ctypes/ctypes-0.9.6.tar.gz?download \
     ctypes==0.9.6


Dealing with Installation Conflicts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(NOTE: As of 0.6a11, this section is obsolete; it is retained here only so that
people using older versions of EasyInstall can consult it.  As of version
0.6a11, installation conflicts are handled automatically without deleting the
old or system-installed packages, and without ignoring the issue.  Instead,
eggs are automatically shifted to the front of ``sys.path`` using special
code added to the ``easy-install.pth`` file.  So, if you are using version
0.6a11 or better of setuptools, you do not need to worry about conflicts,
and the following issues do not apply to you.)

EasyInstall installs distributions in a "managed" way, such that each
distribution can be independently activated or deactivated on ``sys.path``.
However, packages that were not installed by EasyInstall are "unmanaged",
in that they usually live all in one directory and cannot be independently
activated or deactivated.

As a result, if you are using EasyInstall to upgrade an existing package, or
to install a package with the same name as an existing package, EasyInstall
will warn you of the conflict.  (This is an improvement over ``setup.py
install``, because the ``distutils`` just install new packages on top of old
ones, possibly combining two unrelated packages or leaving behind modules that
have been deleted in the newer version of the package.)

EasyInstall will stop the installation if it detects a conflict
between an existing, "unmanaged" package, and a module or package in any of
the distributions you're installing.  It will display a list of all of the
existing files and directories that would need to be deleted for the new
package to be able to function correctly.  To proceed, you must manually
delete these conflicting files and directories and re-run EasyInstall.

Of course, once you've replaced all of your existing "unmanaged" packages with
versions managed by EasyInstall, you won't have any more conflicts to worry
about!


Compressed Installation
~~~~~~~~~~~~~~~~~~~~~~~

EasyInstall tries to install packages in zipped form, if it can.  Zipping
packages can improve Python's overall import performance if you're not using
the ``--multi-version`` option, because Python processes zipfile entries on
``sys.path`` much faster than it does directories.

As of version 0.5a9, EasyInstall analyzes packages to determine whether they
can be safely installed as a zipfile, and then acts on its analysis.  (Previous
versions would not install a package as a zipfile unless you used the
``--zip-ok`` option.)

The current analysis approach is fairly conservative; it currently looks for:

 * Any use of the ``__file__`` or ``__path__`` variables (which should be
   replaced with ``pkg_resources`` API calls)

 * Possible use of ``inspect`` functions that expect to manipulate source files
   (e.g. ``inspect.getsource()``)

 * Top-level modules that might be scripts used with ``python -m`` (Python 2.4)

If any of the above are found in the package being installed, EasyInstall will
assume that the package cannot be safely run from a zipfile, and unzip it to
a directory instead.  You can override this analysis with the ``-zip-ok`` flag,
which will tell EasyInstall to install the package as a zipfile anyway.  Or,
you can use the ``--always-unzip`` flag, in which case EasyInstall will always
unzip, even if its analysis says the package is safe to run as a zipfile.

Normally, however, it is simplest to let EasyInstall handle the determination
of whether to zip or unzip, and only specify overrides when needed to work
around a problem.  If you find you need to override EasyInstall's guesses, you
may want to contact the package author and the EasyInstall maintainers, so that
they can make appropriate changes in future versions.

(Note: If a package uses ``setuptools`` in its setup script, the package author
has the option to declare the package safe or unsafe for zipped usage via the
``zip_safe`` argument to ``setup()``.  If the package author makes such a
declaration, EasyInstall believes the package's author and does not perform its
own analysis.  However, your command-line option, if any, will still override
the package author's choice.)


Reference Manual
================

Configuration Files
-------------------

(New in 0.4a2)

You may specify default options for EasyInstall using the standard
distutils configuration files, under the command heading ``easy_install``.
EasyInstall will look first for a ``setup.cfg`` file in the current directory,
then a ``~/.pydistutils.cfg`` or ``$HOME\\pydistutils.cfg`` (on Unix-like OSes
and Windows, respectively), and finally a ``distutils.cfg`` file in the
``distutils`` package directory.  Here's a simple example:

.. code-block:: ini

    [easy_install]

    # set the default location to install packages
    install_dir = /home/me/lib/python

    # Notice that indentation can be used to continue an option
    # value; this is especially useful for the "--find-links"
    # option, which tells easy_install to use download links on
    # these pages before consulting PyPI:
    #
    find_links = http://sqlobject.org/
                 http://peak.telecommunity.com/dist/

In addition to accepting configuration for its own options under
``[easy_install]``, EasyInstall also respects defaults specified for other
distutils commands.  For example, if you don't set an ``install_dir`` for
``[easy_install]``, but *have* set an ``install_lib`` for the ``[install]``
command, this will become EasyInstall's default installation directory.  Thus,
if you are already using distutils configuration files to set default install
locations, build options, etc., EasyInstall will respect your existing settings
until and unless you override them explicitly in an ``[easy_install]`` section.

For more information, see also the current Python documentation on the `use and
location of distutils configuration files <https://docs.python.org/install/index.html#inst-config-files>`_.

Notice that ``easy_install`` will use the ``setup.cfg`` from the current
working directory only if it was triggered from ``setup.py`` through the
``install_requires`` option. The standalone command will not use that file.

Command-Line Options
--------------------

``--zip-ok, -z``
    Install all packages as zip files, even if they are marked as unsafe for
    running as a zipfile.  This can be useful when EasyInstall's analysis
    of a non-setuptools package is too conservative, but keep in mind that
    the package may not work correctly.  (Changed in 0.5a9; previously this
    option was required in order for zipped installation to happen at all.)

``--always-unzip, -Z``
    Don't install any packages as zip files, even if the packages are marked
    as safe for running as a zipfile.  This can be useful if a package does
    something unsafe, but not in a way that EasyInstall can easily detect.
    EasyInstall's default analysis is currently very conservative, however, so
    you should only use this option if you've had problems with a particular
    package, and *after* reporting the problem to the package's maintainer and
    to the EasyInstall maintainers.

    (Note: the ``-z/-Z`` options only affect the installation of newly-built
    or downloaded packages that are not already installed in the target
    directory; if you want to convert an existing installed version from
    zipped to unzipped or vice versa, you'll need to delete the existing
    version first, and re-run EasyInstall.)

``--multi-version, -m``
    "Multi-version" mode. Specifying this option prevents ``easy_install`` from
    adding an ``easy-install.pth`` entry for the package being installed, and
    if an entry for any version the package already exists, it will be removed
    upon successful installation. In multi-version mode, no specific version of
    the package is available for importing, unless you use
    ``pkg_resources.require()`` to put it on ``sys.path``. This can be as
    simple as::

        from pkg_resources import require
        require("SomePackage", "OtherPackage", "MyPackage")

    which will put the latest installed version of the specified packages on
    ``sys.path`` for you. (For more advanced uses, like selecting specific
    versions and enabling optional dependencies, see the ``pkg_resources`` API
    doc.)

    Changed in 0.6a10: this option is no longer silently enabled when
    installing to a non-PYTHONPATH, non-"site" directory.  You must always
    explicitly use this option if you want it to be active.

``--upgrade, -U``   (New in 0.5a4)
    By default, EasyInstall only searches online if a project/version
    requirement can't be met by distributions already installed
    on sys.path or the installation directory.  However, if you supply the
    ``--upgrade`` or ``-U`` flag, EasyInstall will always check the package
    index and ``--find-links`` URLs before selecting a version to install.  In
    this way, you can force EasyInstall to use the latest available version of
    any package it installs (subject to any version requirements that might
    exclude such later versions).

``--install-dir=DIR, -d DIR``
    Set the installation directory. It is up to you to ensure that this
    directory is on ``sys.path`` at runtime, and to use
    ``pkg_resources.require()`` to enable the installed package(s) that you
    need.

    (New in 0.4a2) If this option is not directly specified on the command line
    or in a distutils configuration file, the distutils default installation
    location is used.  Normally, this would be the ``site-packages`` directory,
    but if you are using distutils configuration files, setting things like
    ``prefix`` or ``install_lib``, then those settings are taken into
    account when computing the default installation directory, as is the
    ``--prefix`` option.

``--script-dir=DIR, -s DIR``
    Set the script installation directory.  If you don't supply this option
    (via the command line or a configuration file), but you *have* supplied
    an ``--install-dir`` (via command line or config file), then this option
    defaults to the same directory, so that the scripts will be able to find
    their associated package installation.  Otherwise, this setting defaults
    to the location where the distutils would normally install scripts, taking
    any distutils configuration file settings into account.

``--exclude-scripts, -x``
    Don't install scripts.  This is useful if you need to install multiple
    versions of a package, but do not want to reset the version that will be
    run by scripts that are already installed.

``--user`` (New in 0.6.11)
    Use the user-site-packages as specified in :pep:`370`
    instead of the global site-packages.

``--always-copy, -a``   (New in 0.5a4)
    Copy all needed distributions to the installation directory, even if they
    are already present in a directory on sys.path.  In older versions of
    EasyInstall, this was the default behavior, but now you must explicitly
    request it.  By default, EasyInstall will no longer copy such distributions
    from other sys.path directories to the installation directory, unless you
    explicitly gave the distribution's filename on the command line.

    Note that as of 0.6a10, using this option excludes "system" and
    "development" eggs from consideration because they can't be reliably
    copied.  This may cause EasyInstall to choose an older version of a package
    than what you expected, or it may cause downloading and installation of a
    fresh copy of something that's already installed.  You will see warning
    messages for any eggs that EasyInstall skips, before it falls back to an
    older version or attempts to download a fresh copy.

``--find-links=URLS_OR_FILENAMES, -f URLS_OR_FILENAMES``
    Scan the specified "download pages" or directories for direct links to eggs
    or other distributions.  Any existing file or directory names or direct
    download URLs are immediately added to EasyInstall's search cache, and any
    indirect URLs (ones that don't point to eggs or other recognized archive
    formats) are added to a list of additional places to search for download
    links.  As soon as EasyInstall has to go online to find a package (either
    because it doesn't exist locally, or because ``--upgrade`` or ``-U`` was
    used), the specified URLs will be downloaded and scanned for additional
    direct links.

    Eggs and archives found by way of ``--find-links`` are only downloaded if
    they are needed to meet a requirement specified on the command line; links
    to unneeded packages are ignored.

    If all requested packages can be found using links on the specified
    download pages, the Python Package Index will not be consulted unless you
    also specified the ``--upgrade`` or ``-U`` option.

    (Note: if you want to refer to a local HTML file containing links, you must
    use a ``file:`` URL, as filenames that do not refer to a directory, egg, or
    archive are ignored.)

    You may specify multiple URLs or file/directory names with this option,
    separated by whitespace.  Note that on the command line, you will probably
    have to surround the URL list with quotes, so that it is recognized as a
    single option value.  You can also specify URLs in a configuration file;
    see `Configuration Files`_, above.

    Changed in 0.6a10: previously all URLs and directories passed to this
    option were scanned as early as possible, but from 0.6a10 on, only
    directories and direct archive links are scanned immediately; URLs are not
    retrieved unless a package search was already going to go online due to a
    package not being available locally, or due to the use of the ``--update``
    or ``-U`` option.

``--no-find-links`` Blocks the addition of any link.
    This parameter is useful if you want to avoid adding links defined in a
    project easy_install is installing (whether it's a requested project or a
    dependency). When used, ``--find-links`` is ignored.

    Added in Distribute 0.6.11 and Setuptools 0.7.

``--index-url=URL, -i URL`` (New in 0.4a1; default changed in 0.6c7)
    Specifies the base URL of the Python Package Index.  The default is
    https://pypi.org/simple/ if not specified.  When a package is requested
    that is not locally available or linked from a ``--find-links`` download
    page, the package index will be searched for download pages for the needed
    package, and those download pages will be searched for links to download
    an egg or source distribution.

``--editable, -e`` (New in 0.6a1)
    Only find and download source distributions for the specified projects,
    unpacking them to subdirectories of the specified ``--build-directory``.
    EasyInstall will not actually build or install the requested projects or
    their dependencies; it will just find and extract them for you.  See
    `Editing and Viewing Source Packages`_ above for more details.

``--build-directory=DIR, -b DIR`` (UPDATED in 0.6a1)
    Set the directory used to build source packages.  If a package is built
    from a source distribution or checkout, it will be extracted to a
    subdirectory of the specified directory.  The subdirectory will have the
    same name as the extracted distribution's project, but in all-lowercase.
    If a file or directory of that name already exists in the given directory,
    a warning will be printed to the console, and the build will take place in
    a temporary directory instead.

    This option is most useful in combination with the ``--editable`` option,
    which forces EasyInstall to *only* find and extract (but not build and
    install) source distributions.  See `Editing and Viewing Source Packages`_,
    above, for more information.

``--verbose, -v, --quiet, -q`` (New in 0.4a4)
    Control the level of detail of EasyInstall's progress messages.  The
    default detail level is "info", which prints information only about
    relatively time-consuming operations like running a setup script, unpacking
    an archive, or retrieving a URL.  Using ``-q`` or ``--quiet`` drops the
    detail level to "warn", which will only display installation reports,
    warnings, and errors.  Using ``-v`` or ``--verbose`` increases the detail
    level to include individual file-level operations, link analysis messages,
    and distutils messages from any setup scripts that get run.  If you include
    the ``-v`` option more than once, the second and subsequent uses are passed
    down to any setup scripts, increasing the verbosity of their reporting as
    well.

``--dry-run, -n`` (New in 0.4a4)
    Don't actually install the package or scripts.  This option is passed down
    to any setup scripts run, so packages should not actually build either.
    This does *not* skip downloading, nor does it skip extracting source
    distributions to a temporary/build directory.

``--optimize=LEVEL``, ``-O LEVEL`` (New in 0.4a4)
    If you are installing from a source distribution, and are *not* using the
    ``--zip-ok`` option, this option controls the optimization level for
    compiling installed ``.py`` files to ``.pyo`` files.  It does not affect
    the compilation of modules contained in ``.egg`` files, only those in
    ``.egg`` directories.  The optimization level can be set to 0, 1, or 2;
    the default is 0 (unless it's set under ``install`` or ``install_lib`` in
    one of your distutils configuration files).

``--record=FILENAME``  (New in 0.5a4)
    Write a record of all installed files to FILENAME.  This is basically the
    same as the same option for the standard distutils "install" command, and
    is included for compatibility with tools that expect to pass this option
    to "setup.py install".

``--site-dirs=DIRLIST, -S DIRLIST``   (New in 0.6a1)
    Specify one or more custom "site" directories (separated by commas).
    "Site" directories are directories where ``.pth`` files are processed, such
    as the main Python ``site-packages`` directory.  As of 0.6a10, EasyInstall
    automatically detects whether a given directory processes ``.pth`` files
    (or can be made to do so), so you should not normally need to use this
    option.  It is is now only necessary if you want to override EasyInstall's
    judgment and force an installation directory to be treated as if it
    supported ``.pth`` files.

``--no-deps, -N``  (New in 0.6a6)
    Don't install any dependencies.  This is intended as a convenience for
    tools that wrap eggs in a platform-specific packaging system.  (We don't
    recommend that you use it for anything else.)

``--allow-hosts=PATTERNS, -H PATTERNS``   (New in 0.6a6)
    Restrict downloading and spidering to hosts matching the specified glob
    patterns.  E.g. ``-H *.python.org`` restricts web access so that only
    packages listed and downloadable from machines in the ``python.org``
    domain.  The glob patterns must match the *entire* user/host/port section of
    the target URL(s).  For example, ``*.python.org`` will NOT accept a URL
    like ``http://python.org/foo`` or ``http://www.python.org:8080/``.
    Multiple patterns can be specified by separating them with commas.  The
    default pattern is ``*``, which matches anything.

    In general, this option is mainly useful for blocking EasyInstall's web
    access altogether (e.g. ``-Hlocalhost``), or to restrict it to an intranet
    or other trusted site.  EasyInstall will do the best it can to satisfy
    dependencies given your host restrictions, but of course can fail if it
    can't find suitable packages.  EasyInstall displays all blocked URLs, so
    that you can adjust your ``--allow-hosts`` setting if it is more strict
    than you intended.  Some sites may wish to define a restrictive default
    setting for this option in their `configuration files`_, and then manually
    override the setting on the command line as needed.

``--prefix=DIR`` (New in 0.6a10)
    Use the specified directory as a base for computing the default
    installation and script directories.  On Windows, the resulting default
    directories will be ``prefix\\Lib\\site-packages`` and ``prefix\\Scripts``,
    while on other platforms the defaults will be
    ``prefix/lib/python2.X/site-packages`` (with the appropriate version
    substituted) for libraries and ``prefix/bin`` for scripts.

    Note that the ``--prefix`` option only sets the *default* installation and
    script directories, and does not override the ones set on the command line
    or in a configuration file.

``--local-snapshots-ok, -l`` (New in 0.6c6)
    Normally, EasyInstall prefers to only install *released* versions of
    projects, not in-development ones, because such projects may not
    have a currently-valid version number.  So, it usually only installs them
    when their ``setup.py`` directory is explicitly passed on the command line.

    However, if this option is used, then any in-development projects that were
    installed using the ``setup.py develop`` command, will be used to build
    eggs, effectively upgrading the "in-development" project to a snapshot
    release.  Normally, this option is used only in conjunction with the
    ``--always-copy`` option to create a distributable snapshot of every egg
    needed to run an application.

    Note that if you use this option, you must make sure that there is a valid
    version number (such as an SVN revision number tag) for any in-development
    projects that may be used, as otherwise EasyInstall may not be able to tell
    what version of the project is "newer" when future installations or
    upgrades are attempted.


.. _non-root installation:

Custom Installation Locations
-----------------------------

By default, EasyInstall installs python packages into Python's main ``site-packages`` directory,
and manages them using a custom ``.pth`` file in that same directory.

Very often though, a user or developer wants ``easy_install`` to install and manage python packages
in an alternative location, usually for one of 3 reasons:

1. They don't have access to write to the main Python site-packages directory.

2. They want a user-specific stash of packages, that is not visible to other users.

3. They want to isolate a set of packages to a specific python application, usually to minimize
   the possibility of version conflicts.

Historically, there have been many approaches to achieve custom installation.
The following section lists only the easiest and most relevant approaches [1]_.

`Use the "--user" option`_

`Use the "--user" option and customize "PYTHONUSERBASE"`_

`Use "virtualenv"`_

.. [1] There are older ways to achieve custom installation using various ``easy_install`` and ``setup.py install`` options, combined with ``PYTHONPATH`` and/or ``PYTHONUSERBASE`` alterations, but all of these are effectively deprecated by the User scheme brought in by :pep:`370`.


Use the "--user" option
~~~~~~~~~~~~~~~~~~~~~~~
Python provides a User scheme for installation, which means that all
python distributions support an alternative install location that is specific to a user [3]_.
The Default location for each OS is explained in the python documentation
for the ``site.USER_BASE`` variable.  This mode of installation can be turned on by
specifying the ``--user`` option to ``setup.py install`` or ``easy_install``.
This approach serves the need to have a user-specific stash of packages.

.. [3] Prior to the User scheme, there was the Home scheme, which is still available, but requires more effort than the User scheme to get packages recognized.

Use the "--user" option and customize "PYTHONUSERBASE"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The User scheme install location can be customized by setting the ``PYTHONUSERBASE`` environment
variable, which updates the value of ``site.USER_BASE``.  To isolate packages to a specific
application, simply set the OS environment of that application to a specific value of
``PYTHONUSERBASE``, that contains just those packages.

Use "virtualenv"
~~~~~~~~~~~~~~~~
"virtualenv" is a 3rd-party python package that effectively "clones" a python installation, thereby
creating an isolated location to install packages.  The evolution of "virtualenv" started before the existence
of the User installation scheme.  "virtualenv" provides a version of ``easy_install`` that is
scoped to the cloned python install and is used in the normal way. "virtualenv" does offer various features
that the User installation scheme alone does not provide, e.g. the ability to hide the main python site-packages.

Please refer to the :pypi:`virtualenv` documentation for more details.


Package Index "API"
-------------------

Custom package indexes (and PyPI) must follow the following rules for
EasyInstall to be able to look up and download packages:

1. Except where stated otherwise, "pages" are HTML or XHTML, and "links"
   refer to ``href`` attributes.

2. Individual project version pages' URLs must be of the form
   ``base/projectname/version``, where ``base`` is the package index's base URL.

3. Omitting the ``/version`` part of a project page's URL (but keeping the
   trailing ``/``) should result in a page that is either:

   a) The single active version of that project, as though the version had been
      explicitly included, OR

   b) A page with links to all of the active version pages for that project.

4. Individual project version pages should contain direct links to downloadable
   distributions where possible.  It is explicitly permitted for a project's
   "long_description" to include URLs, and these should be formatted as HTML
   links by the package index, as EasyInstall does no special processing to
   identify what parts of a page are index-specific and which are part of the
   project's supplied description.

5. Where available, MD5 information should be added to download URLs by
   appending a fragment identifier of the form ``#md5=...``, where ``...`` is
   the 32-character hex MD5 digest.  EasyInstall will verify that the
   downloaded file's MD5 digest matches the given value.

6. Individual project version pages should identify any "homepage" or
   "download" URLs using ``rel="homepage"`` and ``rel="download"`` attributes
   on the HTML elements linking to those URLs. Use of these attributes will
   cause EasyInstall to always follow the provided links, unless it can be
   determined by inspection that they are downloadable distributions. If the
   links are not to downloadable distributions, they are retrieved, and if they
   are HTML, they are scanned for download links. They are *not* scanned for
   additional "homepage" or "download" links, as these are only processed for
   pages that are part of a package index site.

7. The root URL of the index, if retrieved with a trailing ``/``, must result
   in a page containing links to *all* projects' active version pages.

   (Note: This requirement is a workaround for the absence of case-insensitive
   ``safe_name()`` matching of project names in URL paths. If project names are
   matched in this fashion (e.g. via the PyPI server, mod_rewrite, or a similar
   mechanism), then it is not necessary to include this all-packages listing
   page.)

8. If a package index is accessed via a ``file://`` URL, then EasyInstall will
   automatically use ``index.html`` files, if present, when trying to read a
   directory with a trailing ``/`` on the URL.
alt-python312-setuptools/docs/deprecated/functionalities.rst000064400000002653150410147370020302 0ustar00"Eggsecutable" Scripts
----------------------

.. deprecated:: 45.3.0

Occasionally, there are situations where it's desirable to make an ``.egg``
file directly executable.  You can do this by including an entry point such
as the following::

    setup(
        # other arguments here...
        entry_points={
            "setuptools.installation": [
                "eggsecutable = my_package.some_module:main_func",
            ]
        }
    )

Any eggs built from the above setup script will include a short executable
prelude that imports and calls ``main_func()`` from ``my_package.some_module``.
The prelude can be run on Unix-like platforms (including Mac and Linux) by
invoking the egg with ``/bin/sh``, or by enabling execute permissions on the
``.egg`` file.  For the executable prelude to run, the appropriate version of
Python must be available via the ``PATH`` environment variable, under its
"long" name.  That is, if the egg is built for Python 2.3, there must be a
``python2.3`` executable present in a directory on ``PATH``.

IMPORTANT NOTE: Eggs with an "eggsecutable" header cannot be renamed, or
invoked via symlinks.  They *must* be invoked using their original filename, in
order to ensure that, once running, ``pkg_resources`` will know what project
and version is in use.  The header script will check this and exit with an
error if the ``.egg`` file has been renamed or is invoked via a symlink that
changes its base name.
alt-python312-libs/README.rst000064400000020777150410147400011520 0ustar00This is Python version 3.12.11
==============================

.. image:: https://github.com/python/cpython/workflows/Tests/badge.svg
   :alt: CPython build status on GitHub Actions
   :target: https://github.com/python/cpython/actions

.. image:: https://dev.azure.com/python/cpython/_apis/build/status/Azure%20Pipelines%20CI?branchName=main
   :alt: CPython build status on Azure DevOps
   :target: https://dev.azure.com/python/cpython/_build/latest?definitionId=4&branchName=main

.. image:: https://img.shields.io/badge/discourse-join_chat-brightgreen.svg
   :alt: Python Discourse chat
   :target: https://discuss.python.org/


Copyright © 2001-2024 Python Software Foundation.  All rights reserved.

See the end of this file for further copyright and license information.

.. contents::

General Information
-------------------

- Website: https://www.python.org
- Source code: https://github.com/python/cpython
- Issue tracker: https://github.com/python/cpython/issues
- Documentation: https://docs.python.org
- Developer's Guide: https://devguide.python.org/

Contributing to CPython
-----------------------

For more complete instructions on contributing to CPython development,
see the `Developer Guide`_.

.. _Developer Guide: https://devguide.python.org/

Using Python
------------

Installable Python kits, and information about using Python, are available at
`python.org`_.

.. _python.org: https://www.python.org/

Build Instructions
------------------

On Unix, Linux, BSD, macOS, and Cygwin::

    ./configure
    make
    make test
    sudo make install

This will install Python as ``python3``.

You can pass many options to the configure script; run ``./configure --help``
to find out more.  On macOS case-insensitive file systems and on Cygwin,
the executable is called ``python.exe``; elsewhere it's just ``python``.

Building a complete Python installation requires the use of various
additional third-party libraries, depending on your build platform and
configure options.  Not all standard library modules are buildable or
usable on all platforms.  Refer to the
`Install dependencies <https://devguide.python.org/getting-started/setup-building.html#build-dependencies>`_
section of the `Developer Guide`_ for current detailed information on
dependencies for various Linux distributions and macOS.

On macOS, there are additional configure and build options related
to macOS framework and universal builds.  Refer to `Mac/README.rst
<https://github.com/python/cpython/blob/main/Mac/README.rst>`_.

On Windows, see `PCbuild/readme.txt
<https://github.com/python/cpython/blob/main/PCbuild/readme.txt>`_.

If you wish, you can create a subdirectory and invoke configure from there.
For example::

    mkdir debug
    cd debug
    ../configure --with-pydebug
    make
    make test

(This will fail if you *also* built at the top-level directory.  You should do
a ``make clean`` at the top-level first.)

To get an optimized build of Python, ``configure --enable-optimizations``
before you run ``make``.  This sets the default make targets up to enable
Profile Guided Optimization (PGO) and may be used to auto-enable Link Time
Optimization (LTO) on some platforms.  For more details, see the sections
below.

Profile Guided Optimization
^^^^^^^^^^^^^^^^^^^^^^^^^^^

PGO takes advantage of recent versions of the GCC or Clang compilers.  If used,
either via ``configure --enable-optimizations`` or by manually running
``make profile-opt`` regardless of configure flags, the optimized build
process will perform the following steps:

The entire Python directory is cleaned of temporary files that may have
resulted from a previous compilation.

An instrumented version of the interpreter is built, using suitable compiler
flags for each flavor. Note that this is just an intermediary step.  The
binary resulting from this step is not good for real-life workloads as it has
profiling instructions embedded inside.

After the instrumented interpreter is built, the Makefile will run a training
workload.  This is necessary in order to profile the interpreter's execution.
Note also that any output, both stdout and stderr, that may appear at this step
is suppressed.

The final step is to build the actual interpreter, using the information
collected from the instrumented one.  The end result will be a Python binary
that is optimized; suitable for distribution or production installation.


Link Time Optimization
^^^^^^^^^^^^^^^^^^^^^^

Enabled via configure's ``--with-lto`` flag.  LTO takes advantage of the
ability of recent compiler toolchains to optimize across the otherwise
arbitrary ``.o`` file boundary when building final executables or shared
libraries for additional performance gains.


What's New
----------

We have a comprehensive overview of the changes in the `What's New in Python
3.12 <https://docs.python.org/3.12/whatsnew/3.12.html>`_ document.  For a more
detailed change log, read `Misc/NEWS
<https://github.com/python/cpython/tree/main/Misc/NEWS.d>`_, but a full
accounting of changes can only be gleaned from the `commit history
<https://github.com/python/cpython/commits/main>`_.

If you want to install multiple versions of Python, see the section below
entitled "Installing multiple versions".


Documentation
-------------

`Documentation for Python 3.12 <https://docs.python.org/3.12/>`_ is online,
updated daily.

It can also be downloaded in many formats for faster access.  The documentation
is downloadable in HTML, PDF, and reStructuredText formats; the latter version
is primarily for documentation authors, translators, and people with special
formatting requirements.

For information about building Python's documentation, refer to `Doc/README.rst
<https://github.com/python/cpython/blob/main/Doc/README.rst>`_.


Testing
-------

To test the interpreter, type ``make test`` in the top-level directory.  The
test set produces some output.  You can generally ignore the messages about
skipped tests due to optional features which can't be imported.  If a message
is printed about a failed test or a traceback or core dump is produced,
something is wrong.

By default, tests are prevented from overusing resources like disk space and
memory.  To enable these tests, run ``make testall``.

If any tests fail, you can re-run the failing test(s) in verbose mode.  For
example, if ``test_os`` and ``test_gdb`` failed, you can run::

    make test TESTOPTS="-v test_os test_gdb"

If the failure persists and appears to be a problem with Python rather than
your environment, you can `file a bug report
<https://github.com/python/cpython/issues>`_ and include relevant output from
that command to show the issue.

See `Running & Writing Tests <https://devguide.python.org/testing/run-write-tests.html>`_
for more on running tests.

Installing multiple versions
----------------------------

On Unix and Mac systems if you intend to install multiple versions of Python
using the same installation prefix (``--prefix`` argument to the configure
script) you must take care that your primary python executable is not
overwritten by the installation of a different version.  All files and
directories installed using ``make altinstall`` contain the major and minor
version and can thus live side-by-side.  ``make install`` also creates
``${prefix}/bin/python3`` which refers to ``${prefix}/bin/python3.X``.  If you
intend to install multiple versions using the same prefix you must decide which
version (if any) is your "primary" version.  Install that version using ``make
install``.  Install all other versions using ``make altinstall``.

For example, if you want to install Python 2.7, 3.6, and 3.12 with 3.12 being the
primary version, you would execute ``make install`` in your 3.12 build directory
and ``make altinstall`` in the others.


Release Schedule
----------------

See :pep:`693` for Python 3.12 release details.


Copyright and License Information
---------------------------------


Copyright © 2001-2024 Python Software Foundation.  All rights reserved.

Copyright © 2000 BeOpen.com.  All rights reserved.

Copyright © 1995-2001 Corporation for National Research Initiatives.  All
rights reserved.

Copyright © 1991-1995 Stichting Mathematisch Centrum.  All rights reserved.

See the `LICENSE <https://github.com/python/cpython/blob/main/LICENSE>`_ for
information on the history of this software, terms & conditions for usage, and a
DISCLAIMER OF ALL WARRANTIES.

This Python distribution contains *no* GNU General Public License (GPL) code,
so it may be used in proprietary projects.  There are interfaces to some GNU
code but these are entirely optional.

All trademarks referenced herein are property of their respective holders.alt-python312-devel/README.valgrind000064400000011257150410147400012655 0ustar00This document describes some caveats about the use of Valgrind with
Python.  Valgrind is used periodically by Python developers to try
to ensure there are no memory leaks or invalid memory reads/writes.

If you want to enable valgrind support in Python, you will need to
configure Python --with-valgrind option or an older option
--without-pymalloc.

UPDATE: Python 3.6 now supports PYTHONMALLOC=malloc environment variable which
can be used to force the usage of the malloc() allocator of the C library.

If you don't want to read about the details of using Valgrind, there
are still two things you must do to suppress the warnings.  First,
you must use a suppressions file.  One is supplied in
Misc/valgrind-python.supp.  Second, you must uncomment the lines in 
Misc/valgrind-python.supp that suppress the warnings for PyObject_Free and
PyObject_Realloc.

If you want to use Valgrind more effectively and catch even more
memory leaks, you will need to configure python --without-pymalloc.
PyMalloc allocates a few blocks in big chunks and most object
allocations don't call malloc, they use chunks doled about by PyMalloc
from the big blocks.  This means Valgrind can't detect
many allocations (and frees), except for those that are forwarded
to the system malloc.  Note: configuring python --without-pymalloc
makes Python run much slower, especially when running under Valgrind.
You may need to run the tests in batches under Valgrind to keep
the memory usage down to allow the tests to complete.  It seems to take
about 5 times longer to run --without-pymalloc.

Apr 15, 2006:
  test_ctypes causes Valgrind 3.1.1 to fail (crash).
  test_socket_ssl should be skipped when running valgrind.
	The reason is that it purposely uses uninitialized memory.
	This causes many spurious warnings, so it's easier to just skip it.


Details:
--------
Python uses its own small-object allocation scheme on top of malloc,
called PyMalloc.

Valgrind may show some unexpected results when PyMalloc is used.
Starting with Python 2.3, PyMalloc is used by default.  You can disable
PyMalloc when configuring python by adding the --without-pymalloc option.
If you disable PyMalloc, most of the information in this document and
the supplied suppressions file will not be useful.  As discussed above,
disabling PyMalloc can catch more problems.

PyMalloc uses 256KB chunks of memory, so it can't detect anything
wrong within these blocks.  For that reason, compiling Python
--without-pymalloc usually increases the usefulness of other tools.

If you use valgrind on a default build of Python,  you will see
many errors like:

        ==6399== Use of uninitialised value of size 4
        ==6399== at 0x4A9BDE7E: PyObject_Free (obmalloc.c:711)
        ==6399== by 0x4A9B8198: dictresize (dictobject.c:477)

These are expected and not a problem.  Tim Peters explains
the situation:

        PyMalloc needs to know whether an arbitrary address is one
	that's managed by it, or is managed by the system malloc.
	The current scheme allows this to be determined in constant
	time, regardless of how many memory areas are under pymalloc's
	control.

        The memory pymalloc manages itself is in one or more "arenas",
	each a large contiguous memory area obtained from malloc.
	The base address of each arena is saved by pymalloc
	in a vector.  Each arena is carved into "pools", and a field at
	the start of each pool contains the index of that pool's arena's
	base address in that vector.

        Given an arbitrary address, pymalloc computes the pool base
	address corresponding to it, then looks at "the index" stored
	near there.  If the index read up is out of bounds for the
	vector of arena base addresses pymalloc maintains, then
	pymalloc knows for certain that this address is not under
	pymalloc's control.  Otherwise the index is in bounds, and
	pymalloc compares

            the arena base address stored at that index in the vector

        to

            the arbitrary address pymalloc is investigating

        pymalloc controls this arbitrary address if and only if it lies
        in the arena the address's pool's index claims it lies in.

        It doesn't matter whether the memory pymalloc reads up ("the
	index") is initialized.  If it's not initialized, then
	whatever trash gets read up will lead pymalloc to conclude
	(correctly) that the address isn't controlled by it, either
	because the index is out of bounds, or the index is in bounds
	but the arena it represents doesn't contain the address.

        This determination has to be made on every call to one of
	pymalloc's free/realloc entry points, so its speed is critical
	(Python allocates and frees dynamic memory at a ferocious rate
	-- everything in Python, from integers to "stack frames",
	lives in the heap).
alt-python312-devel/valgrind-python.supp000064400000022345150410147400014226 0ustar00#
# This is a valgrind suppression file that should be used when using valgrind.
#
#  Here's an example of running valgrind:
#
#	cd python/dist/src
#	valgrind --tool=memcheck --suppressions=Misc/valgrind-python.supp \
#		./python -E ./Lib/test/regrtest.py -u gui,network
#
# You must edit Objects/obmalloc.c and uncomment Py_USING_MEMORY_DEBUGGER
# to use the preferred suppressions with address_in_range.
#
# If you do not want to recompile Python, you can uncomment
# suppressions for _PyObject_Free and _PyObject_Realloc.
#
# See Misc/README.valgrind for more information.

# all tool names: Addrcheck,Memcheck,cachegrind,helgrind,massif
{
   ADDRESS_IN_RANGE/Invalid read of size 4
   Memcheck:Addr4
   fun:address_in_range
}

{
   ADDRESS_IN_RANGE/Invalid read of size 4
   Memcheck:Value4
   fun:address_in_range
}

{
   ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64 aka amd64)
   Memcheck:Value8
   fun:address_in_range
}

{
   ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value
   Memcheck:Cond
   fun:address_in_range
}

#
# Leaks (including possible leaks)
#    Hmmm, I wonder if this masks some real leaks.  I think it does.
#    Will need to fix that.
#

{
   Suppress leaking the GIL.  Happens once per process, see comment in ceval.c.
   Memcheck:Leak
   fun:malloc
   fun:PyThread_allocate_lock
   fun:PyEval_InitThreads
}

{
   Suppress leaking the GIL after a fork.
   Memcheck:Leak
   fun:malloc
   fun:PyThread_allocate_lock
   fun:PyEval_ReInitThreads
}

{
   Suppress leaking the autoTLSkey.  This looks like it shouldn't leak though.
   Memcheck:Leak
   fun:malloc
   fun:PyThread_create_key
   fun:_PyGILState_Init
   fun:Py_InitializeEx
   fun:Py_Main
}

{
   Hmmm, is this a real leak or like the GIL?
   Memcheck:Leak
   fun:malloc
   fun:PyThread_ReInitTLS
}

{
   Handle PyMalloc confusing valgrind (possibly leaked)
   Memcheck:Leak
   fun:realloc
   fun:_PyObject_GC_Resize
   fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING
}

{
   Handle PyMalloc confusing valgrind (possibly leaked)
   Memcheck:Leak
   fun:malloc
   fun:_PyObject_GC_New
   fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING
}

{
   Handle PyMalloc confusing valgrind (possibly leaked)
   Memcheck:Leak
   fun:malloc
   fun:_PyObject_GC_NewVar
   fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING
}

#
# Leaks: dlopen() called without dlclose()
#

{
   dlopen() called without dlclose()
   Memcheck:Leak
   fun:malloc
   fun:malloc
   fun:strdup
   fun:_dl_load_cache_lookup
}
{
   dlopen() called without dlclose()
   Memcheck:Leak
   fun:malloc
   fun:malloc
   fun:strdup
   fun:_dl_map_object
}
{
   dlopen() called without dlclose()
   Memcheck:Leak
   fun:malloc
   fun:*
   fun:_dl_new_object
}
{
   dlopen() called without dlclose()
   Memcheck:Leak
   fun:calloc
   fun:*
   fun:_dl_new_object
}
{
   dlopen() called without dlclose()
   Memcheck:Leak
   fun:calloc
   fun:*
   fun:_dl_check_map_versions
}


#
# Non-python specific leaks
#

{
   Handle pthread issue (possibly leaked)
   Memcheck:Leak
   fun:calloc
   fun:allocate_dtv
   fun:_dl_allocate_tls_storage
   fun:_dl_allocate_tls
}

{
   Handle pthread issue (possibly leaked)
   Memcheck:Leak
   fun:memalign
   fun:_dl_allocate_tls_storage
   fun:_dl_allocate_tls
}

###{
###   ADDRESS_IN_RANGE/Invalid read of size 4
###   Memcheck:Addr4
###   fun:_PyObject_Free
###}
###
###{
###   ADDRESS_IN_RANGE/Invalid read of size 4
###   Memcheck:Value4
###   fun:_PyObject_Free
###}
###
###{
###   ADDRESS_IN_RANGE/Use of uninitialised value of size 8
###   Memcheck:Addr8
###   fun:_PyObject_Free
###}
###
###{
###   ADDRESS_IN_RANGE/Use of uninitialised value of size 8
###   Memcheck:Value8
###   fun:_PyObject_Free
###}
###
###{
###   ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value
###   Memcheck:Cond
###   fun:_PyObject_Free
###}

###{
###   ADDRESS_IN_RANGE/Invalid read of size 4
###   Memcheck:Addr4
###   fun:_PyObject_Realloc
###}
###
###{
###   ADDRESS_IN_RANGE/Invalid read of size 4
###   Memcheck:Value4
###   fun:_PyObject_Realloc
###}
###
###{
###   ADDRESS_IN_RANGE/Use of uninitialised value of size 8
###   Memcheck:Addr8
###   fun:_PyObject_Realloc
###}
###
###{
###   ADDRESS_IN_RANGE/Use of uninitialised value of size 8
###   Memcheck:Value8
###   fun:_PyObject_Realloc
###}
###
###{
###   ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value
###   Memcheck:Cond
###   fun:_PyObject_Realloc
###}

###
### All the suppressions below are for errors that occur within libraries
### that Python uses.  The problems to not appear to be related to Python's
### use of the libraries.
###

{
   Generic ubuntu ld problems
   Memcheck:Addr8
   obj:/lib/ld-2.4.so
   obj:/lib/ld-2.4.so
   obj:/lib/ld-2.4.so
   obj:/lib/ld-2.4.so
}

{
   Generic gentoo ld problems
   Memcheck:Cond
   obj:/lib/ld-2.3.4.so
   obj:/lib/ld-2.3.4.so
   obj:/lib/ld-2.3.4.so
   obj:/lib/ld-2.3.4.so
}

{
   DBM problems, see test_dbm
   Memcheck:Param
   write(buf)
   fun:write
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   fun:dbm_close
}

{
   DBM problems, see test_dbm
   Memcheck:Value8
   fun:memmove
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   fun:dbm_store
   fun:dbm_ass_sub
}

{
   DBM problems, see test_dbm
   Memcheck:Cond
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   fun:dbm_store
   fun:dbm_ass_sub
}

{
   DBM problems, see test_dbm
   Memcheck:Cond
   fun:memmove
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   obj:/usr/lib/libdb1.so.2
   fun:dbm_store
   fun:dbm_ass_sub
}

{
   GDBM problems, see test_gdbm
   Memcheck:Param
   write(buf)
   fun:write
   fun:gdbm_open

}

{
   Uninitialised byte(s) false alarm, see bpo-35561
   Memcheck:Param
   epoll_ctl(event)
   fun:epoll_ctl
   fun:pyepoll_internal_ctl
}

{
   ZLIB problems, see test_gzip
   Memcheck:Cond
   obj:/lib/libz.so.1.2.3
   obj:/lib/libz.so.1.2.3
   fun:deflate
}

{
   Avoid problems w/readline doing a putenv and leaking on exit
   Memcheck:Leak
   fun:malloc
   fun:xmalloc
   fun:sh_set_lines_and_columns
   fun:_rl_get_screen_size
   fun:_rl_init_terminal_io
   obj:/lib/libreadline.so.4.3
   fun:rl_initialize
}

# Valgrind emits "Conditional jump or move depends on uninitialised value(s)"
# false alarms on GCC builtin strcmp() function. The GCC code is correct.
#
# Valgrind bug: https://bugs.kde.org/show_bug.cgi?id=264936
{
   bpo-38118: Valgrind emits false alarm on GCC builtin strcmp()
   Memcheck:Cond
   fun:PyUnicode_Decode
}


###
### These occur from somewhere within the SSL, when running
###  test_socket_sll.  They are too general to leave on by default.
###
###{
###   somewhere in SSL stuff
###   Memcheck:Cond
###   fun:memset
###}
###{
###   somewhere in SSL stuff
###   Memcheck:Value4
###   fun:memset
###}
###
###{
###   somewhere in SSL stuff
###   Memcheck:Cond
###   fun:MD5_Update
###}
###
###{
###   somewhere in SSL stuff
###   Memcheck:Value4
###   fun:MD5_Update
###}

# Fedora's package "openssl-1.0.1-0.1.beta2.fc17.x86_64" on x86_64
# See http://bugs.python.org/issue14171
{
   openssl 1.0.1 prng 1
   Memcheck:Cond
   fun:bcmp
   fun:fips_get_entropy
   fun:FIPS_drbg_instantiate
   fun:RAND_init_fips
   fun:OPENSSL_init_library
   fun:SSL_library_init
   fun:init_hashlib
}

{
   openssl 1.0.1 prng 2
   Memcheck:Cond
   fun:fips_get_entropy
   fun:FIPS_drbg_instantiate
   fun:RAND_init_fips
   fun:OPENSSL_init_library
   fun:SSL_library_init
   fun:init_hashlib
}

{
   openssl 1.0.1 prng 3
   Memcheck:Value8
   fun:_x86_64_AES_encrypt_compact
   fun:AES_encrypt
}

#
# All of these problems come from using test_socket_ssl
#
{
   from test_socket_ssl
   Memcheck:Cond
   fun:BN_bin2bn
}

{
   from test_socket_ssl
   Memcheck:Cond
   fun:BN_num_bits_word
}

{
   from test_socket_ssl
   Memcheck:Value4
   fun:BN_num_bits_word
}

{
   from test_socket_ssl
   Memcheck:Cond
   fun:BN_mod_exp_mont_word
}

{
   from test_socket_ssl
   Memcheck:Cond
   fun:BN_mod_exp_mont
}

{
   from test_socket_ssl
   Memcheck:Param
   write(buf)
   fun:write
   obj:/usr/lib/libcrypto.so.0.9.7
}

{
   from test_socket_ssl
   Memcheck:Cond
   fun:RSA_verify
}

{
   from test_socket_ssl
   Memcheck:Value4
   fun:RSA_verify
}

{
   from test_socket_ssl
   Memcheck:Value4
   fun:DES_set_key_unchecked
}

{
   from test_socket_ssl
   Memcheck:Value4
   fun:DES_encrypt2
}

{
   from test_socket_ssl
   Memcheck:Cond
   obj:/usr/lib/libssl.so.0.9.7
}

{
   from test_socket_ssl
   Memcheck:Value4
   obj:/usr/lib/libssl.so.0.9.7
}

{
   from test_socket_ssl
   Memcheck:Cond
   fun:BUF_MEM_grow_clean
}

{
   from test_socket_ssl
   Memcheck:Cond
   fun:memcpy
   fun:ssl3_read_bytes
}

{
   from test_socket_ssl
   Memcheck:Cond
   fun:SHA1_Update
}

{
   from test_socket_ssl
   Memcheck:Value4
   fun:SHA1_Update
}

{
   test_buffer_non_debug
   Memcheck:Addr4
   fun:PyUnicodeUCS2_FSConverter
}

{
   test_buffer_non_debug
   Memcheck:Addr4
   fun:PyUnicode_FSConverter
}

{
   wcscmp_false_positive
   Memcheck:Addr8
   fun:wcscmp
   fun:_PyOS_GetOpt
   fun:Py_Main
   fun:main
}

# Additional suppressions for the unified decimal tests:
{
   test_decimal
   Memcheck:Addr4
   fun:PyUnicodeUCS2_FSConverter
}

{
   test_decimal2
   Memcheck:Addr4
   fun:PyUnicode_FSConverter
}

alt-python312/README.rst000064400000020777150410147400010571 0ustar00This is Python version 3.12.11
==============================

.. image:: https://github.com/python/cpython/workflows/Tests/badge.svg
   :alt: CPython build status on GitHub Actions
   :target: https://github.com/python/cpython/actions

.. image:: https://dev.azure.com/python/cpython/_apis/build/status/Azure%20Pipelines%20CI?branchName=main
   :alt: CPython build status on Azure DevOps
   :target: https://dev.azure.com/python/cpython/_build/latest?definitionId=4&branchName=main

.. image:: https://img.shields.io/badge/discourse-join_chat-brightgreen.svg
   :alt: Python Discourse chat
   :target: https://discuss.python.org/


Copyright © 2001-2024 Python Software Foundation.  All rights reserved.

See the end of this file for further copyright and license information.

.. contents::

General Information
-------------------

- Website: https://www.python.org
- Source code: https://github.com/python/cpython
- Issue tracker: https://github.com/python/cpython/issues
- Documentation: https://docs.python.org
- Developer's Guide: https://devguide.python.org/

Contributing to CPython
-----------------------

For more complete instructions on contributing to CPython development,
see the `Developer Guide`_.

.. _Developer Guide: https://devguide.python.org/

Using Python
------------

Installable Python kits, and information about using Python, are available at
`python.org`_.

.. _python.org: https://www.python.org/

Build Instructions
------------------

On Unix, Linux, BSD, macOS, and Cygwin::

    ./configure
    make
    make test
    sudo make install

This will install Python as ``python3``.

You can pass many options to the configure script; run ``./configure --help``
to find out more.  On macOS case-insensitive file systems and on Cygwin,
the executable is called ``python.exe``; elsewhere it's just ``python``.

Building a complete Python installation requires the use of various
additional third-party libraries, depending on your build platform and
configure options.  Not all standard library modules are buildable or
usable on all platforms.  Refer to the
`Install dependencies <https://devguide.python.org/getting-started/setup-building.html#build-dependencies>`_
section of the `Developer Guide`_ for current detailed information on
dependencies for various Linux distributions and macOS.

On macOS, there are additional configure and build options related
to macOS framework and universal builds.  Refer to `Mac/README.rst
<https://github.com/python/cpython/blob/main/Mac/README.rst>`_.

On Windows, see `PCbuild/readme.txt
<https://github.com/python/cpython/blob/main/PCbuild/readme.txt>`_.

If you wish, you can create a subdirectory and invoke configure from there.
For example::

    mkdir debug
    cd debug
    ../configure --with-pydebug
    make
    make test

(This will fail if you *also* built at the top-level directory.  You should do
a ``make clean`` at the top-level first.)

To get an optimized build of Python, ``configure --enable-optimizations``
before you run ``make``.  This sets the default make targets up to enable
Profile Guided Optimization (PGO) and may be used to auto-enable Link Time
Optimization (LTO) on some platforms.  For more details, see the sections
below.

Profile Guided Optimization
^^^^^^^^^^^^^^^^^^^^^^^^^^^

PGO takes advantage of recent versions of the GCC or Clang compilers.  If used,
either via ``configure --enable-optimizations`` or by manually running
``make profile-opt`` regardless of configure flags, the optimized build
process will perform the following steps:

The entire Python directory is cleaned of temporary files that may have
resulted from a previous compilation.

An instrumented version of the interpreter is built, using suitable compiler
flags for each flavor. Note that this is just an intermediary step.  The
binary resulting from this step is not good for real-life workloads as it has
profiling instructions embedded inside.

After the instrumented interpreter is built, the Makefile will run a training
workload.  This is necessary in order to profile the interpreter's execution.
Note also that any output, both stdout and stderr, that may appear at this step
is suppressed.

The final step is to build the actual interpreter, using the information
collected from the instrumented one.  The end result will be a Python binary
that is optimized; suitable for distribution or production installation.


Link Time Optimization
^^^^^^^^^^^^^^^^^^^^^^

Enabled via configure's ``--with-lto`` flag.  LTO takes advantage of the
ability of recent compiler toolchains to optimize across the otherwise
arbitrary ``.o`` file boundary when building final executables or shared
libraries for additional performance gains.


What's New
----------

We have a comprehensive overview of the changes in the `What's New in Python
3.12 <https://docs.python.org/3.12/whatsnew/3.12.html>`_ document.  For a more
detailed change log, read `Misc/NEWS
<https://github.com/python/cpython/tree/main/Misc/NEWS.d>`_, but a full
accounting of changes can only be gleaned from the `commit history
<https://github.com/python/cpython/commits/main>`_.

If you want to install multiple versions of Python, see the section below
entitled "Installing multiple versions".


Documentation
-------------

`Documentation for Python 3.12 <https://docs.python.org/3.12/>`_ is online,
updated daily.

It can also be downloaded in many formats for faster access.  The documentation
is downloadable in HTML, PDF, and reStructuredText formats; the latter version
is primarily for documentation authors, translators, and people with special
formatting requirements.

For information about building Python's documentation, refer to `Doc/README.rst
<https://github.com/python/cpython/blob/main/Doc/README.rst>`_.


Testing
-------

To test the interpreter, type ``make test`` in the top-level directory.  The
test set produces some output.  You can generally ignore the messages about
skipped tests due to optional features which can't be imported.  If a message
is printed about a failed test or a traceback or core dump is produced,
something is wrong.

By default, tests are prevented from overusing resources like disk space and
memory.  To enable these tests, run ``make testall``.

If any tests fail, you can re-run the failing test(s) in verbose mode.  For
example, if ``test_os`` and ``test_gdb`` failed, you can run::

    make test TESTOPTS="-v test_os test_gdb"

If the failure persists and appears to be a problem with Python rather than
your environment, you can `file a bug report
<https://github.com/python/cpython/issues>`_ and include relevant output from
that command to show the issue.

See `Running & Writing Tests <https://devguide.python.org/testing/run-write-tests.html>`_
for more on running tests.

Installing multiple versions
----------------------------

On Unix and Mac systems if you intend to install multiple versions of Python
using the same installation prefix (``--prefix`` argument to the configure
script) you must take care that your primary python executable is not
overwritten by the installation of a different version.  All files and
directories installed using ``make altinstall`` contain the major and minor
version and can thus live side-by-side.  ``make install`` also creates
``${prefix}/bin/python3`` which refers to ``${prefix}/bin/python3.X``.  If you
intend to install multiple versions using the same prefix you must decide which
version (if any) is your "primary" version.  Install that version using ``make
install``.  Install all other versions using ``make altinstall``.

For example, if you want to install Python 2.7, 3.6, and 3.12 with 3.12 being the
primary version, you would execute ``make install`` in your 3.12 build directory
and ``make altinstall`` in the others.


Release Schedule
----------------

See :pep:`693` for Python 3.12 release details.


Copyright and License Information
---------------------------------


Copyright © 2001-2024 Python Software Foundation.  All rights reserved.

Copyright © 2000 BeOpen.com.  All rights reserved.

Copyright © 1995-2001 Corporation for National Research Initiatives.  All
rights reserved.

Copyright © 1991-1995 Stichting Mathematisch Centrum.  All rights reserved.

See the `LICENSE <https://github.com/python/cpython/blob/main/LICENSE>`_ for
information on the history of this software, terms & conditions for usage, and a
DISCLAIMER OF ALL WARRANTIES.

This Python distribution contains *no* GNU General Public License (GPL) code,
so it may be used in proprietary projects.  There are interfaces to some GNU
code but these are entirely optional.

All trademarks referenced herein are property of their respective holders.alt-python312-setuptools-wheel/LICENSE000064400000001777150410147400013427 0ustar00Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
alt-openldap11/CHANGES000064400000265775150410163160010304 0ustar00OpenLDAP 2.4 Change Log

OpenLDAP 2.4.46 Release (2018/03/22)
	Fixed libldap connection delete callbacks when TLS fails to start (ITS#8717)
	Fixed libldap to not reuse tls_session if TLS hostname check fails (ITS#7373)
	Fixed libldap cross-compiling with OpenSSL 1.1 (ITS#8687)
	Fixed libldap OpenSSL 1.1.1 compatibility with BIO_method (ITS#8791)
	Fixed libldap MozNSS CA certificate hash matching (ITS#7374)
	Fixed libldap MozNSS with PEM certs when also using an NSS cert db (ITS#7389)
	Fixed libldap MozNSS initialization (ITS#8484)
	Fixed libldap GnuTLS with GNUTLS_E_AGAIN (ITS#8650)
	Fixed libldap memory leak with cancel operations (ITS#8782)
	Fixed slapd Eventlog registry key creation on 64-bit Windows (ITS#8705)
	Fixed slapd to maintain SSF across SASL binds (ITS#8796)
	Fixed slapd syncrepl deadlock when updating cookie (ITS#8752)
	Fixed slapd syncrepl callback to always be last in the stack (ITS#8752)
	Fixed slapd telephoneNumberNormalize when the value is spaces and hyphens (ITS#8778)
	Fixed slapd CSN queue processing (ITS#8801)
	Fixed slapd-ldap TLS connection timeout with high latency connections (ITS#8720)
	Fixed slapd-ldap to ignore unknown schema when omit-unknown-schema is set (ITS#7520)
	Fixed slapd-mdb with an optimization for long lived read transactions (ITS#8226)
	Fixed slapd-meta assert when olcDbRewrite is modified (ITS#8404)
	Fixed slapd-sock with LDAP_MOD_INCREMENT operations (ITS#8692)
	Fixed slapo-accesslog cleanup to only occur on failed operations (ITS#8752)
	Fixed slapo-dds entryTTL to actually decrease as per RFC 2589 (ITS#7100)
	Fixed slapo-syncprov memory leak with delete operations (ITS#8690)
	Fixed slapo-syncprov to not clear pending operation when checkpointing (ITS#8444)
	Fixed slapo-syncprov to correctly record contextCSN values in the accesslog (ITS#8100)
	Fixed slapo-syncprov not to log checkpoints to accesslog db (ITS#8607)
	Fixed slapo-syncprov to process changes from this SID on REFRESH (ITS#8800)
	Fixed slapo-syncprov session log parsing to not block other operations (ITS#8486)
	Build Environment
		Fixed Windows build with newer MINGW version (ITS#8697)
		Fixed compiler warnings and removed unused variables (ITS#8578)
	Contrib
		Fixed ldapc++ Control structure (ITS#8583)
	Documentation
		Delete stub manpage for back-ldbm (ITS#8713)
		Fixed ldap_bind(3) to mention the LDAP_SASL_SIMPLE mechanism (ITS#8121)
		Fixed ldap.conf(5) to note SASL_MECH/SASL_REALM are no longer user-only (ITS#8818)
		Fixed slapd-config(5) typo for olcTLSCipherSuite (ITS#8715)
		Fixed slapo-syncprov(5) indexing requirements (ITS#5048)

OpenLDAP 2.4.45 Release (2017/06/01)
	Added slapd support for OpenSSL 1.1.0 series (ITS#8353, ITS#8533, ITS#8634)
	Fixed libldap to fail ldap_result if the handle is already bad (ITS#8585)
	Fixed libldap to expose error if user specified CA doesn't exist (ITS#8529)
	Fixed libldap handling of Diffie-Hellman parameters (ITS#7506)
	Fixed libldap GnuTLS use after free (ITS#8385)
	Fixed libldap SASL initialization (ITS#8648)
	Fixed slapd bconfig rDN escape handling (ITS#8574)
	Fixed slapd segfault with invalid hostname (ITS#8631)
	Fixed slapd sasl SEGV rebind in same session (ITS#8568)
	Fixed slapd syncrepl filter handling (ITS#8413)
	Fixed slapd syncrepl infinite looping mods with delta-sync MMR (ITS#8432)
	Fixed slapd callback struct so older modules without writewait should function.
                    Custom modules may need to be updated for sc_writewait callback (ITS#8435)
	Fixed slapd-ldap/meta broken LDAP_TAILQ macro (ITS#8576)
	Fixed slapd-mdb so it passes ITS6794 regression test (ITS#6794)
	Fixed slapd-mdb double free with size zero paged result (ITS#8655)
	Fixed slapd-meta uninitialized diagnostic message (ITS#8442)
	Fixed slapo-accesslog to honor pauses during purge for cn=config update (ITS#8423)
	Fixed slapo-accesslog with multiple modifications to the same attribute (ITS#6545)
	Fixed slapo-relay to correctly initialize sc_writewait (ITS#8428)
	Fixed slapo-sssvlv double free (ITS#8592)
	Fixed slapo-unique with empty modifications (ITS#8266)
	Build Environment
		Added test065 for proxyauthz (ITS#8571)
		Fix test008 to be portable (ITS#8414)
		Fix test064 to wait for slapd to start (ITS#8644)
		Fix its4336 regression test (ITS#8534)
		Fix its4337 regression test (ITS#8535)
		Fix regression tests to execute on all backends (ITS#8539)
	Contrib
		Added slapo-autogroup(5) man page (ITS#8569)
		Added passwd missing conversion scripts for apr1 (ITS#6826)
		Fixed contrib modules where the writewait callback was not correctly initialized (ITS#8435)
		Fixed smbk5pwd to build with newer OpenSSL releases (ITS#8525)
	Documentation
		admin24 fixed tls_cipher_suite bindconf option (ITS#8099)
		admin24 fixed typo cn=config to be slapd.d (ITS#8449)
		admin24 fixed slapo-syncprov information to be current (ITS#8253)
		admin24 fixed typo in access control docs (ITS#7341, ITS#8391)
		admin24 fixed minor typo in tuning guide (ITS#8499)
		admin24 fixed information about the limits option (ITS#7700)
		admin24 fixed missing options for syncrepl configuration (ITS#7700)
		admin24 fixed accesslog documentation to note it should not be replicated (ITS#8344)
		Fixed ldap.conf(5) missing information on SASL_NOCANON option (ITS#7177)
		Fixed ldapsearch(1) information on the V[V] flag behavior (ITS#7177, ITS#6339)
		Fixed slapd-config(5), slapd.conf(5) clarification on interval keyword for refreshAndPersist (ITS#8538)
		Fixed slapd-config(5), slapd.conf(5) clarify serverID requirements (ITS#8635)
		Fixed slapd-config(5), slapd.conf(5) clarification on loglevel settings (ITS#8123)
		Fixed slapo-ppolicy(5) to clearly note rootdn requirement (ITS#8565)
		Fixed slapo-memberof(5) to note it is not safe to use with replication (ITS#8613)
		Fixed slapo-syncprov(5) documentation to be current (ITS#8253)
		Fixed slapadd(8) manpage to note slapd-mdb (ITS#8215)
		Fixed various minor grammar issues in the man pages (ITS#8544)
		Fixed various typos (ITS#8587)

OpenLDAP 2.4.44 Release (2016/02/05)
	Fixed slapd-bdb/hdb missing olcDbChecksum config attr (ITS#8337)
	Fixed slapd-mdb behavior with long lived read transactions (ITS#8226)
	Fixed slapd-mdb cleanup after failed transaction (ITS#8360)
	Fixed slapd-sql missing id_query/olcSqlIdQuery (ITS#8329)
	Fixed slapo-accesslog callback initialization (ITS#8351)
	Fixed slapo-ppolicy pwdMaxRecordedFailure must never be zero (ITS#8327)
	Fixed slapo-syncprov abandon processing (ITS#8354)
	Fixed slapo-syncprov ctxcsn snapshot on refresh (ITS#8281, ITS#8365)
	Documentation
		admin24 Stop linking to Berkeley DB downloads (ITS#8362)
		admin24 Update documentation for LMDB preference

OpenLDAP 2.4.43 Release (2015/11/30)
	Fixed liblber remove obsolete assert (ITS#8240, ITS#8301)
	Fixed libldap file URLs on windows (ITS#8273)
	Fixed libldap microsecond timer for windows (ITS#8295)
	Fixed slap tools minor one time memory leak (ITS#8082)
	Fixed slapd to avoid redundant processing of abandon ops (ITS#8232)
	Fixed slapd syncrepl SEGV when present list is NULL (ITS#8231, ITS#8042)
	Fixed slapd segfault with invalid SASL URI (ITS#8218)
	Fixed slapd configuration parser with unbalanced quotes (ITS#8233)
	Fixed slapd syncrepl check with config db on windows (ITS#8277)
	Fixed slapd with mod Increment and inherited attribute type (ITS#8289)
	Fixed slapd-ldap SEGV after failed retry (ITS#8173)
	Fixed slapd-ldap to skip client controls in ldap_back_entry_get (ITS#8244)
	Fixed slapd-null to have an option to return a search entry (ITS#8249)
	Fixed slapd-relay to correctly handle quoted options (ITS#8284)
	Fixed slapo-accesslog delta-sync MMR with interrupted refresh phase (ITS#8281)
	Fixed slapo-dds segfault when using slapo-memberof (ITS#8133)
	Fixed slapo-ppolicy to allow purging of stale pwdFailureTime attributes (ITS#8185)
	Fixed slapo-ppolicy to release entry on failure (ITS#7537)
	Fixed slapo-ppolicy to fall back to default policy if there is a parsing error (ITS#8234)
	Fixed slapo-syncprov with interrupted refresh phase (ITS#8281)
	Fixed slapo-refint with subtree renames (ITS#8220)
	Fixed slapo-rwm missing olcDropUnrequested attribute (ITS#7889)
	Fixed slapo-rwm parsing to avoid double-escaping rewrite rules (ITS#7964)
	Build Environment
		Fixed ldif-filter option parsing (ITS#8292)
		Fixed slapd-tester EOL handling in test output for windows (ITS#8280)
		Fixed slapd-tester executable suffix for windows (ITS#8216)
		Fixed test061 timing issues (ITS#8297)
	Contrib
		Added libnettle support to pw-pbkdf2 (ITS#8198)
		Fixed smbk5pwd compiler warnings with libnettle (ITS#8235)
		Fixed passwd symbol collisions with other crypto libraries (ITS#8294)
	Documentation
		Updated guide to reflect changes to how TLS is handled with syncrepl (ITS#7897)

OpenLDAP 2.4.42 Release (2015/08/14)
	Fixed liblber address length for CLDAP (ITS#8158)
	Fixed libldap dnssrv potential overflow with port number (ITS#7027,ITS#8195)
	Fixed slapd cn=config when updating olcAttributeTypes (ITS#8199)
	Fixed slapd-mdb to correctly update search candidates for scoped searches (ITS#8203)
	Fixed slapo-ppolicy with redundant mod ops on glued trees (ITS#8184)
	Fixed slapo-rwm crash when deleting rewrite rules (ITS#8213)
	Build Environment
		Fixed libdb detection with gcc 5.x (ITS#8056)

OpenLDAP 2.4.41 Release (2015/06/21)
	Fixed ldapsearch to explicitly flush its buffer (ITS#8118)
	Fixed libldap async connections (ITS#8090)
	Fixed libldap double free of request during abandon (ITS#7967)
	Fixed libldap error string for LDAP_X_CONNECTING (ITS#8093)
	Fixed libldap segfault in ldap_sync_initialize (ITS#8001)
	Fixed libldap ldif-wrap off by one error (ITS#8003)
	Fixed libldap handling of TLS in async mode (ITS#8022)
	Fixed libldap null pointer dereference (ITS#8028)
	Fixed libldap mutex handling with LDAP_OPT_SESSION_REFCNT (ITS#8050)
	Fixed slapd slapadd config db import of minimal frontend entry (ITS#8150)
	Fixed slapd slapadd onetime leak with -w (ITS#8014)
	Fixed slapd sasl auxprop crash with invalid config (ITS#8092)
	Fixed slapd syncrepl delta-mmr issue with overlays and slapd.conf (ITS#7976)
	Fixed slapd syncrepl mutex for cookie state (ITS#7968)
	Fixed slapd syncrepl memory leaks (ITS#8035)
	Fixed slapd syncrepl to free presentlist at end of refresh mode (ITS#8038)
	Fixed slapd syncrepl to streamline presentlist (ITS#8042)
	Fixed slapd syncrepl concurrency when CHECK_CSN is enabled (ITS#8120)
	Fixed slapd rootdn checks for hidden backends (ITS#8108)
	Fixed slapd segfault when using matched values control (ITS#8046)
	Fixed slapd-ldap reconnection behavior on remote failure (ITS#8142)
	Fixed slapd-mdb minor case typo (ITS#8049)
	Fixed slapd-mdb one-level search (ITS#7975)
	Fixed slapd-mdb heap corruption (ITS#7965)
	Fixed slapd-mdb crash after deleting in-use schema (ITS#7995)
	Fixed slapd-mdb minor code cleanup (ITS#8011)
	Fixed slapd-mdb to return errors when using incorrect env flags (ITS#8016)
	Fixed slapd-mdb to correctly update search candidates (ITS#8036, ITS#7904)
	Fixed slapd-mdb when there were more than 65535 aliases in scope (ITS#8103)
	Fixed slapd-mdb alias deref when objectClass is not indexed (ITS#8146)
	Fixed slapd-meta TLS initialization with ldaps URIs (ITS#8022)
	Fixed slapd-meta to have better error logging (ITS#8131)
	Fixed slapd-perl conversion to cn=config (ITS#8105)
	Fixed slapd-sql autocommit config variable (ITS#8129,ITS#6613)
	Fixed slapo-collect segfault (ITS#7797)
	Fixed slapo-constraint with 0 count constraint (ITS#7780,ITS#7781)
	Fixed slapo-deref with empty attribute list (ITS#8027)
	Fixed slapo-memberof to correctly reject invalid members (ITS#8107)
	Fixed slapo-sock result parser for CONTINUE (ITS#8048)
	Fixed slapo-syncprov synprov_matchops usage of test_filter (ITS#8013)
	Fixed slapo-syncprov segfault on disconnect/abandon (ITS#5452,ITS#8012)
	Fixed slapo-syncprov memory leak (ITS#8039)
	Fixed slapo-syncprov segfault on disconnect/abandon (ITS#8043)
	Fixed slapo-syncprov deadlock when autogroup is in use (ITS#8063)
	Fixed slapo-syncprov potential loss of changes when under load (ITS#8081)
	Fixed slapo-unique enforcement of uniqueness with manageDSAit control (ITS#8057)
	Build Environment
		Fixed ftello reference for Win32 (ITS#8127)
		Enhanced contrib modules build paths (ITS#7782)
		Fixed contrib/autogroup internal operation identity (ITS#8006)
		Fixed contrib/autogroup to skip internal ops with accesslog (ITS#8065)
		Fixed contrib/passwd/sha2 compiler warning (ITS#8000)
		Fixed contrib/noopsrch compiler warning (ITS#7998)
		Fixed contrib/dupent compiler warnings (ITS#7997)
		Test suite: Added vrFilter test (ITS#8046)
	Contrib
		Added pbkdf2 sha256 and sha512 schemes (ITS#7977)
		Fixed autogroup modification callback responses (ITS#6970)
		Fixed nssov compare with usergroup (ITS#8079)
		Fixed nssov password change behavior (ITS#8080)
		Fixed nssov updated to 0.9.4 (ITS#8097)
	Documentation
		Added ldap_get_option(3) LDAP_FEATURE_INFO_VERSION information (ITS#8032)
		Added ldap_get_option(3) LDAP_OPT_API_INFO_VERSION information (ITS#8032)
		Fixed slapd-config(5), slapd.conf(5) tls_cipher_suite option (ITS#8099)
		Fixed slapd-meta(5), slapd-ldap(5) tls_cipher_suite option (ITS#8099)
		Fixed slapd-meta(5) fix minor typo (ITS#7769)

OpenLDAP 2.4.40 Release (2014/09/20)
	Fixed libldap DNS SRV priority handling (ITS#7027)
	Fixed libldap don't leak libldap err codes (ITS#7676)
	Fixed libldap CR/LF handling (ITS#4635)
	Fixed libldap ldif-wrap length (ITS#7871)
	Fixed libldap GnuTLS ciphersuite parsing (ITS#7500)
	Fixed libldap GnuTLS with newer versions (ITS#7430,ITS#6359)
	Fixed libldif to correctly handle 4096 character lines (ITS#7859)
	Fixed librewrite reference counting (ITS#7723)
	Fixed slapacl with back-mdb reader transactions (ITS#7920)
	Fixed slapd syncrepl to send cookie on fallback (ITS#7849)
	Fixed slapd syncrepl SEGV when abandoning a connection (ITS#7928)
	Fixed slapd slapcat with external schema (ITS#7895)
	Fixed slapd schema RDN normalization (ITS#7935)
	Fixed slapd with repeated language tags (ITS#7941)
	Fixed slapd modrdn crash on naming attr with no matching rule (ITS#7850)
	Fixed slapd memory leak in control handling (ITS#7942)
	Fixed slapd-ldap removed dead code (ITS#7922)
	Fixed slapd-mdb to work concurrently with slapadd (ITS#7798)
	Fixed slapd-mdb with paged results (ITS#7705, ITS#7800)
	Fixed slapd-mdb slapcat with nonexistent indices (ITS#7870)
	Fixed slapd-mdb long lived reader transactions (ITS#7904)
	Fixed slapd-mdb memory leak on matchedDN (ITS#7872)
	Fixed slapd-mdb sorting of attribute values (ITS#7902)
	Fixed slapd-mdb to flag attribute values as sorted (ITS#7903)
	Fixed slapd-mdb index config handling (ITS#7912)
	Fixed slapd-mdb entry release handling (ITS#7915)
	Fixed slapd-mdb with aliases and referrals (ITS#7927)
	Fixed slapd-mdb alias dereferencing (ITS#7702)
	Fixed slapd-sock socket flushing (ITS#7937)
	Fixed slapo-accesslog attribute normalization (ITS#7934)
	Fixed slapo-accesslog internal search logging (ITS#7929)
	Fixed slapo-auditlog connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapo-chain interaction with slapo-rwm (ITS#7930)
	Fixed slapo-constraint connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapo-dds connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapo-dyngroup connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapo-memberof attr count (ITS#7893)
	Fixed slapo-memberof frontendDB handling (ITS#7249)
	Fixed slapo-memberof internal search logging (ITS#7929)
	Fixed slapo-pcache config processing (ITS#7919)
	Fixed slapo-pcache connection destroy logic (ITS#7906,ITS#7923)
	Added slapo-ppolicy ORDERING rules (ITS#7838)
	Fixed slapo-ppolicy timestamp resolution to use microseconds (ITS#7161)
	Fixed slapo-ppolicy connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapo-refint to check for pauses in cn=config (ITS#7873)
	Fixed slapo-refint internal search logging (ITS#7929)
	Fixed slapo-refint connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapo-seqmod connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapo-slapover connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapo-sock db_init (ITS#7868)
	Fixed slapo-sssvlv fix olcSssVlvMaxPerConn (ITS#7908)
	Fixed slapo-translucent double free (ITS#7587)
	Fixed slapo-translucent to work with manageDSAit (ITS#7864)	
	Fixed slapo-translucent to use local backend with local entries (ITS#7915)
	Fixed slapo-unique connection destroy logic (ITS#7906,ITS#7923)
	Fixed slapcacl with invalid suffix (ITS#7827)
	Build Environment
		Remove support for gcrypt (ITS#7877)
		BDB 6.0.20 and later is not supported (ITS#7890)
		Fixed ODBC link check (ITS#7891)
		Fixed slapd.ldif frontend config (ITS#7933)
	Contrib
		Added pbkdf2 module (ITS#7742)
		Fixed autogroup double free (ITS#7831)
		Fixed autogroup modification callback responses (ITS#6970)
		Fixed ldapc++ memory leak in Async connection (ITS#7806)
		Fixed nssov install path (ITS#7858)
		Fixed passwd rpath (ITS#7885)
		Fixed apr1 do_phk_hash argument order (ITS#7869)
		Fixed slapd-sha2 buffer overrun (ITS#7851)
	Documentation
		Fixed slapd.ldif man page reference (ITS#7803)
		Fixed slapd.conf(5) man page to reference exattrs (ITS#7847)
		Fixed guide to work with mkrelease (ITS#7887)
		Fixed ldap_get_dn(3) ldap_ava definition (ITS#7860)

OpenLDAP 2.4.39 Release (2014/01/26)
	Fixed libldap MozNSS crash (ITS#7783)
	Fixed libldap memory leak with SASL (ITS#7757)
	Fixed libldap assert in parse_passwdpolicy_control (ITS#7759)
	Fixed libldap shortcut NULL RDNs (ITS#7762)
	Fixed libldap deref to use correct control
	Fixed liblmdb keysizes with mdb_update_key (ITS#7756)
	Fixed slapd cn=config olcDbConfig modification (ITS#7750)
	Fixed slapd-bdb/hdb to bail out of search if config is paused (ITS#7761)
	Fixed slapd-bdb/hdb indexing issue with derived attributes (ITS#7778)
	Fixed slapd-mdb to bail out of search if config is paused (ITS#7761)
	Fixed slapd-mdb indexing issue with derived attributes (ITS#7778)
	Fixed slapd-perl to bail out of search if config is paused (ITS#7761)
	Fixed slapd-sql to bail out of search if config is paused (ITS#7761)
	Fixed slapo-constraint handling of softadd/softdel (ITS#7773)
	Fixed slapo-syncprov assert with findbase (ITS#7749)
	Build Environment
		Test suite: Use $(MAKE) for tests (ITS#7753)
	Documentation
		admin24 fix TLSDHParamFile to be correct (ITS#7684)

OpenLDAP 2.4.38 Release (2013/11/16)
	Fixed liblmdb nordahead flag (ITS#7734)
	Fixed liblmdb to check cursor index before cursor_del (ITS#7733)
	Fixed liblmdb wasted space on split (ITS#7589)
	Fixed slapd for certs with a NULL issuerDN (ITS#7746)
	Fixed slapd cn=config with empty nested includes (ITS#7739)
	Fixed slapd syncrepl memory leak with delta-sync MMR (ITS#7735)
	Fixed slapd-bdb/hdb to stop processing on dn not found (ITS#7741)
	Fixed slapd-bdb/hdb with indexed ANDed filters (ITS#7743)
	Fixed slapd-mdb to stop processing on dn not found (ITS#7741)
	Fixed slapd-mdb dangling reader (ITS#7662)
	Fixed slapd-mdb matching rule for OlcDbEnvFlags (ITS#7737)
	Fixed slapd-mdb with indexed ANDed filters (ITS#7743)
	Fixed slapd-meta from blocking other threads (ITS#7740)
	Fixed slapo-syncprov assert with findbase (ITS#7749)

OpenLDAP 2.4.37 Release (2013/10/27)
	Added liblmdb nordahead environment flag (ITS#7725)
	Fixed client tools CLDAP with IPv6 (ITS#7695)
	Fixed libldap CLDAP with IPv6 (ITS#7695)
	Fixed libldap lock ordering with abandon op (ITS#7712)
	Fixed liblmdb segfault with mdb_cursor_del (ITS#7718)
	Fixed liblmdb when converting to writemap (ITS#7715)
	Fixed liblmdb assert on MDB_NEXT with delete (ITS#7722)
	Fixed liblmdb wasted space on split (ITS#7589)
	Fixed slapd cn=config with olcTLSProtocolMin (ITS#7685)
	Fixed slapd-bdb/hdb optimize index updates (ITS#7329)
	Fixed slapd-ldap chaining with cn=config (ITS#7381, ITS#7434)
	Fixed slapd-ldap chaining with controls (ITS#7687)
	Fixed slapd-mdb optimize index updates (ITS#7329)
	Fixed slapd-meta chaining with cn=config (ITS#7381, ITS#7434)
	Fixed slapo-constraint to no-op on nonexistent entries (ITS#7692)
	Fixed slapo-dds assert on startup (ITS#7699)
	Fixed slapo-memberof to not replicate internal ops (ITS#7710)
	Fixed slapo-refint to not replicate internal ops (ITS#7710)
	Build Environment
		Fixed slapd-mdb ptr arithmetic on void *s (ITS#7720)
	Documentation
		ldapsearch(1) minor typo fix (ITS#7680)
		slapd-passwd(5) minor typo fix (ITS#7680)

OpenLDAP 2.4.36 Release (2013/08/17)
	Added back-meta target filter patterns (ITS#7609)
	Added liblmdb mdb_txn_env to API (ITS#7660)
	Fixed libldap CLDAP with uninit'd memory (ITS#7582)
	Fixed libldap with UDP (ITS#7583)
	Fixed libldap OpenSSL TLS versions (ITS#7645)
	Fixed liblmdb MDB_PREV behavior (ITS#7556)
	Fixed liblmdb transaction issues (ITS#7515)
	Fixed liblmdb mdb_drop overflow page return (ITS#7561)
	Fixed liblmdb nested split (ITS#7592)
	Fixed liblmdb overflow page behavior (ITS#7620)
	Fixed liblmdb race condition with read and write txns (ITS#7635)
	Fixed liblmdb mdb_del behavior with MDB_DUPSORT and mdb_del (ITS#7658)
	Fixed slapd cn=config with unknown schema elements (ITS#7608)
	Fixed slapd cn=config with loglevel 0 (ITS#7611)
	Fixed slapd slapi filterlist free behavior (ITS#7636)
	Fixed slapd slapi control free behavior (ITS#7641)
	Fixed slapd schema countryString as directoryString (ITS#7659)
	Fixed slapd schema telephoneNumber as directoryString (ITS#7659)
	Fixed slapd-bdb/hdb to wait for read locks in tool mode (ITS#6365)
	Fixed slapd-mdb behavior with alias dereferencing (ITS#7577)
	Fixed slapd-mdb modrdn and base-scoped searches (ITS#7604)
	Fixed slapd-mdb refcount behavior (ITS#7628)
	Fixed slapd-meta binding flag is set (ITS#7524)
	Fixed slapd-meta with minimal config (ITS#7581)
	Fixed slapd-meta missing results messages (ITS#7591)
	Added slapd-meta TCP keepalive support (ITS#7513)
	Fixed slapo-sssvlv double free (ITS#7588)
	Fixed slaptest to list -Q option (ITS#7568)
	Build Environment
		Fixed slapd-meta declaration warnings (ITS#7654)
	Contrib
		Fixed nssov group enumeration bug (ITS#7569)
		Fixed autogroup when URI has no attrs (ITS#7580)
	Documentation
		admin24 Update database backend notes (ITS#7590)
		ldap.conf(5) fixed typos (ITS#7568)
		ldapmodify(1) remove replog reference (ITS#7562)
		ldif(5) remove replog reference (ITS#7562)
		slapd-config(5) remove replog reference (ITS#7562)
		slapd.conf(5) remove replog reference (ITS#7562)
		slapd-config(5) document TLSProtocolMin (ITS#5655,ITS#7645)
		slapd.conf(5) document TLSProtocolMin (ITS#5655,ITS#7645)

OpenLDAP 2.4.35 Release (2013/03/31)
	Fixed liblmdb mdb_cursor_put with MDB_MULTIPLE (ITS#7551)
	Fixed liblmdb page rebalance (ITS#7536)
	Fixed liblmdb missing parens (ITS#7377)
	Fixed liblmdb mdb_cursor_del crash (ITS#7553)
	Fixed slapd syncrepl updateCookie status (ITS#7531)
	Fixed slapd connection logging (ITS#7543)
	Fixed slapd segfault on modify (ITS#7542, ITS#7432)
	Fixed slapd-mdb to reject undefined attrs (ITS#7540)
	Fixed slapo-pcache with +/- attrsets (ITS#7552)
	Build Environment
		don't install DB_CONFIG if no BDB backends (ITS#7533)
	Documentation
		slapschema(8) fix tool name (ITS#7534)
		admin24 fixed pcache example (ITS#7546)
		admin24 fixed config examples (ITS#7522)

OpenLDAP 2.4.34 Release (2013/03/01)
	Fixed libldap connections with EINTR (ITS#7476)
	Fixed libldap lineno overflow in ldif_read_record (ITS#7497)
	Fixed liblmdb mdb_env_open flag handling (ITS#7453)
	Fixed liblmdb mdb_midl_sort array optimization (ITS#7432)
	Fixed liblmdb freelist with large entries (ITS#7455)
	Fixed liblmdb to check for filled dirty page list (ITS#7491)
	Fixed liblmdb to validate data limits (ITS#7485)
	Fixed liblmdb mdb_update_key for large keys (ITS#7505)
	Fixed ldapmodify to not core dump with invalid LDIF (ITS#7477)
	Fixed slapd syncrepl for old entries in MMR setup (ITS#7427)
	Fixed slapd signedness for index_substr_any_* (ITS#7449)
	Fixed slapd enforce SLAPD_MAX_DAEMON_THREADS (ITS#7450)
	Fixed slapd mutex in send_ldap_ber (ITS#6164)
	Added slapd-ldap onerr option (ITS#7492)
	Added slapd-ldap keepalive support (ITS#7501)
	Fixed slapd-ldif with empty dir (ITS#7451)
	Fixed slapd-mdb to reopen attr DBs after env reopen (ITS#7416)
	Fixed slapd-mdb handling of missing entries (ITS#7483,7496)
	Fixed slapd-mdb environment flag setting (ITS#7452)
	Fixed slapd-mdb with sub db slapcat (ITS#7469)
	Fixed slapd-mdb to correctly work with toolthreads > 2 (ITS#7488,ITS#7527)
	Fixed slapd-mdb subtree search speed (ITS#7473)
	Fixed slapd-meta conversion to cn=config (ITS#7525)
	Fixed slapd-meta segfault when modifying olcDbUri (ITS#7526)
	Fixed slapd-sql back-config support (ITS#7499)
	Fixed slapo-constraint handle uri and restrict correctly (ITS#7418)
	Fixed slapo-constraint with multi-master replication (ITS#7426)
	Fixed slapo-constraint segfault (ITS#7431)
	Fixed slapo-deref control initialization (ITS#7436)
	Fixed slapo-deref control exposure (ITS#7445)
	Fixed slapo-memberof with internal ops (ITS#7487)
	Fixed slapo-pcache matching rules for config db (ITS#7459)
	Fixed slapo-rwm modrdn cleanup (ITS#7414)
	Fixed slapo-sssvlv maxperconn parameter (ITS#7484)
	Build Environment
		Fixed slapo-constraint test suite (ITS#7423)
	Contrib
		Added nssov nssov_config support (ITS#7518)
		Added nssov password_prohibit_message (ITS#7518)
		Fixed ldapc++ with gcc-4.7 (ITS#7281,ITS#7304)
		Fixed nssov olcNssPamSession handling (ITS#7481)
		Fixed nssov connection DN (ITS#7518)
		Add missing Makefile for various modules (ITS#7308)
		Unify Makefile structure for modules (ITS#7309)
		Fixed slapo-allowed attribute replication (ITS#7493)
		Fixed slapo-passwd SHA2 to correctly zero buffer (ITS#7490)
	Documentation
		ldapurl(1) fix example usage (ITS#7454)
		ldap_get_option(3) fixed trailing whitespace (ITS#7411)
		slapd-config(5) olcExtraAttrs is per db (ITS#7421)
		slapd-overlays(5) update manpage index (ITS#7489)
		slapo-dynlist(5) Search behavior notes (ITS#7486)
		slapo-valsort(5) Document valsort control syntax (ITS#7523)

OpenLDAP 2.4.33 Release (2012/10/10)
	Added slapd-meta cn=config support
	Fixed libldap MozNSS slot picking (ITS#7359)
	Fixed libldap MozNSS with tokenname:certnickname format (ITS#7360)
	Fixed liblmdb POSIX semaphore cleanup on environment close (ITS#7364)
	Fixed liblmdb mdb_page_split (ITS#7385, ITS#7229)
	Fixed slapd alock handling on Windows (ITS#7361)
	Fixed slapd acl handling with zero-length values (ITS#7350)
	Fixed slapd syncprov to not reference ops inside a lock (ITS#7172)
	Fixed slapd delta-syncrepl MMR with large attribute values (ITS#7354)
	Fixed slapd slapd_rw_destroy function (ITS#7390)
	Fixed slapd-ldap idassert bind handling (ITS#7403)
	Fixed slapd-mdb slapadd -q -w double free (ITS#7356)
	Fixed slapd-mdb to close read txn in reindex commit (ITS#7386)
	Fixed slapo-constraint with multiple modifications (ITS#7168)
	Build Environment
		Fixed build with Visual Studio (ITS#7358)
		Fixed liblmdb posix semaphore use on BSD system (ITS#7363)
		Add slapo-constraint test suite (ITS#7344, ITS#7366)
	Contrib
		Updated radius passwd module for NAS-Identifier (ITS#7357)
	Documentation
		slapo-refint(5) Note that refint is not replicated (ITS#7405)

OpenLDAP 2.4.32 Release (2012/07/31)
	Added slappasswd loadable module support (ITS#7284)
	Fixed tools to not clobber SASL_NOCANON (ITS#7271)
	Fixed libldap function declarations (ITS#7293)
	Fixed libldap double free (ITS#7270)
	Fixed libldap debug level setting (ITS#7290)
	Fixed libldap MozNSS PEM/certdb handling (ITS#7276)
	Fixed libldap MozNSS cipher suite selection (ITS#7285)
	Fixed libldap MozNSS error handling (ITS#7287)
	Fixed libldap MozNSS cipher suite being ignored (ITS#7289)
	Fixed libldap MozNSS infinite loop (ITS#7291)
	Fixed libldap MozNSS context token for certdb (ITS#7312)
	Fixed libldap MozNSS store certificate object (ITS#7313)
	Fixed libldap MozNSS fix init and cleanup (ITS#7314)
	Fixed libldap MozNSS slot and pin usage (ITS#7315)
	Fixed libldap MozNSS to avoid infinite loop (ITS#7316)
	Fixed libldap MozNSS untrusted issuer error (ITS#7331)
	Fixed libldap gettime() regression (ITS#6262)
	Fixed libldap sasl handling (ITS#7118, ITS#7133)
	Fixed libldap to correctly free socket with TLS (ITS#7241)
	Fixed liblmdb leaf node handling (ITS#7266)
	Fixed liblmdb mutexes on Apple/Windows (ITS#7251)
	Fixed slapd config index renumbering (ITS#6987)
	Fixed slapd duplicate error response (ITS#7076)
	Fixed slapd parsing of PermissiveModify control (ITS#7298)
	Fixed slapd-bdb/hdb cache hang under high load (ITS#7222)
	Fixed slapd-bdb/hdb alias checking (ITS#7303)
	Fixed slapd-bdb/hdb olcDbConfig changes work immediately (ITS#7338)
	Fixed slapd-ldap to encode user DN during password change (ITS#7319)
	Fixed slapd-ldap assertion when proxying to MS AD (ITS#6851)
	Fixed slapd-ldap monitoring (ITS#7182, ITS#7225)
	Fixed slapd-mdb with tool mode (ITS#7255)
	Fixed slapd-mdb with approx indexing (ITS#7279)
	Fixed slapd-mdb dn2id delete (ITS#7302)
	Fixed slapd-mdb memory leak in online indexer (ITS#7323)
	Fixed slapd-mdb db corruption when hitting maxsize (ITS#7337)
	Fixed slapd-mdb aborts with online indexing (ITS#7339)
	Fixed slapd-perl panic (ITS#7325)
	Fixed slapo-accesslog memory leaks with sync replication (ITS#7292)
	Fixed slapo-syncprov memory leaks with sync replication (ITS#7292)
	Fixed contrib/smbk5pwd to not compile with MozNSS (ITS#7327)
	Fixed contrib/sha2 portability (ITS#7267)
	Fixed contrib/sha2 thread safety (ITS#7269)
	Added contrib/sha2 {SSHA256}, {SSHA384}, {SSHA512} support (ITS#7278)
	Build Environment
		Fixed test057 timing issues (ITS#7317)
		Fixed compilation with MS Visual Studio (ITS#7332)
	Contrib
		Added slapi_[get|free]_client_ip() (ITS#7305)
	Documentation
		slapo-sssvlv Added note about criticality (ITS#7253)
		admin24 Fix peername.regex typo (ITS#7282)
		Fixed slapd-config file include example (ITS#7318)
		slapd-ldap(5) Reference RFC4526 (ITS#7294)
		slapd-meta(5) Reference RFC4526 (ITS#7294)

OpenLDAP 2.4.31 Release (2012/04/21)
	Added slapo-accesslog support for reqEntryUUID (ITS#6656)
	Fixed libldap IPv6 URL detection (ITS#7194)
	Fixed libldap rebinding on failed connection (ITS#7207)
	Fixed liblmdb alignment of MDB_db members (ITS#7191)
	Fixed liblmdb branch page merging on deletes (ITS#7190)
	Fixed liblmdb page split with MDB_APPEND (ITS#7213)
	Fixed liblmdb free page usage with entry deletion (ITS#7210)
	Fixed liblmdb to use IOV_MAX if it is defined and small (ITS#7196)
	Fixed liblmdb key alignment (ITS#7219)
	Fixed liblmdb mdb_page_split (ITS#7229)
	Fixed liblmdb with zero length IDLs (ITS#7230)
	Fixed slapd listener initialization (ITS#7233)
	Fixed slapd cn=config with olcTLSVerifyClient (ITS#7197)
	Fixed slapd delta-syncrepl fallback on non-leaf error (ITS#7195)
	Fixed slapd to reject MMR setups with bad serverID setting (ITS#7200)
	Fixed slapd approxIndexer key generation (ITS#7203)
	Fixed slapd modification of olcSuffix (ITS#7205)
	Fixed slapd schema validation with missing definitions (ITS#7224)
	Fixed slapd syncrepl -c with supplied CSN values (ITS#7245)
	Fixed slapd-bdb/hdb idlcache with only one element (ITS#7231)
	Fixed slapd-perl modify with binary values (ITS#7149)
	Fixed slapd-shell cn=config support (ITS#7201)
	Fixed slapd-shell modify with binary values (ITS#7149)
	Fixed slapo-accesslog deadlock with non-logged write ops (ITS#7088)
	Fixed slapo-syncprov sessionlog check (ITS#7218)
	Fixed slapo-syncprov entry leak (ITS#7234)
	Fixed slapo-syncprov startup initialization (ITS#7235)
	Build Environment
		Fixed test022 to check ldapsearch results (ITS#7228)
		Fixed test044 when back-monitor is disabled (ITS#7204)
	Documentation
		Fixed slapschema(8) formatting (ITS#7188)
		Fixed limdb functionality documentation (ITS#7238)
		Fixed ldap_get_option(3) note inheritance behavior (ITS#7240)

OpenLDAP 2.4.30 Release (2012/02/29)
	Fixed libldap socket polling for writes (ITS#7167)
	Fixed liblutil string modifications (ITS#7174)
	Fixed slapd crash when attrsOnly is true (ITS#7143)
	Fixed slapd syncrepl delete handling (ITS#7052,ITS#7162)
	Fixed slapd-mdb slapadd with -q (ITS#7170)
	Fixed slapd-mdb slapadd with -w (ITS#7180)
	Fixed slapd-mdb slapindex with -q and -t (ITS#7176)
	Fixed slapo-pcache time-to-refesh handling (ITS#7178)
	Fixed slapo-syncprov loop detection (ITS#6024)
	Build Environment
		Fixed POSIX make support (ITS#7160)
		Fixed slapd-mdb build on POSIX (ITS#7160)
	Documentation
		Added option "-o" to ldap*(1) pages  (ITS#7152)
		Fixed ldap*(1) page cleanup (ITS#7177)
		Fixed ldap_modify(3) prototypes (ITS#7173)

OpenLDAP 2.4.29 Release (2012/02/12)
	Fixed libldap MozNSS deferred initialization handling (ITS#7136)
	Fixed libldap MozNSS with TLSCertificateKeyFile not set (ITS#7135)
	Fixed slapd cn=config modification of first schema element (ITS#7098)
	Fixed slapd operation reuse (ITS#7107)
	Fixed slapd blocked writers to not interfere with pool pause (ITS#7115)
	Fixed slapd connection loop connindex usage (ITS#7131)
	Fixed slapd double mutex unlock via connection_done (ITS#7125)
	Fixed slapd check order in connection_write (ITS#7113)
	Fixed slapd slapadd to exit on failure (ITS#7142)
	Fixed slapd syncrepl reference to freed memory (ITS#7127,ITS#7132)
	Fixed slapd syncrepl to ignore some errors on delete (ITS#7052)
	Fixed slapd syncrepl to handle missing oldRDN (ITS#7144)
	Fixed slapd-mdb to handle overlays in tool mode (ITS#7099)
	Fixed slapd-mdb segfaults with page splits (ITS#7121)
	Fixed slapd-mdb cleanup on transaction abort (ITS#7140)
	Fixed slapd-mdb with attribute descriptions (ITS#7146)
	Fixed slapd-meta to correctly handle multiple targets (ITS#7050)
	Fixed slapd-monitor compare op to update cached entry (ITS#7123)
	Fixed slapd-perl initialization (ITS#7075)
	Fixed slapd-sql to properly initialize be_cf_ocs (ITS#7158)
	Fixed slapo-dds to properly exit when in tool mode (ITS#7099)
	Fixed slapo-rwm not leave empty lots with normalized attrs (ITS#7143)
	Fixed slapo-syncprov with already abandoned operation (ITS#7150)
	Fixed contrib/smbk5pwd uninitialized keys in shadowLastChange (ITS#7138)
	Build Environment
		Fixed ldapsearch build on windows (ITS#7156)
		Fixed test001 to skip back-ldif (ITS#7101)
	Documentation
		admin24 Fix typo (ITS#7117)

OpenLDAP 2.4.28 Release (2011/11/26)
	Fixed back-mdb out of order slapadd (ITS#7090)

OpenLDAP 2.4.27 Release (2011/11/24)
	Added libldap support for draft-wahl-ldap-session (ITS#6984)
	Added slapd support for draft-wahl-ldap-session (ITS#6984)
	Added slapadd pipelining capability (ITS#7078)
	Added slapd Add-if-not-present (ITS#6561)
	Added slapd delta-syncrepl MMR (ITS#6734,ITS#7029,ITS#7031)
	Added slapd-mdb experimental backend (ITS#7079)
	Added slapd-passwd dynamic config support
	Added slapd-perl dynamic config support
	Added slapd-shell dynamic config support
	Added slapd-sock support as an overlay (ITS#6666)
	Added slapd-sql dynamic config support
	Added contrib/passwd APR1 support (ITS#6826)
	Fixed slapi linking on AIX (ITS#3272)
	Fixed ldapmodify crash with LDIF controls (ITS#7039)
	Fixed ldapsearch to honor timeout and timelimit (ITS#7009)
	Fixed libldap endless looping (ITS#7035)
	Fixed libldap TLS to not check hostname when using 'allow' (ITS#7014)
	Fixed libldap GnuTLS cert dn parse (ITS#7051)
	Fixed libldap MozNSS correctly destroy SSL_PeerCertificate (ITS#6980)
	Fixed libldap MozNSS with issuer expiration and verify never (ITS#6998)
	Fixed libldap MozNSS memory leak (ITS#7001)
	Fixed libldap MozNSS allow/try behavior (ITS#7002)
	Fixed libldap MozNSS to be thread safe (ITS#7022)
	Fixed libldap MozNSS SSL_ForceHandshake to use a mutex (ITS#7034)
	Fixed libldap MozNSS with wildcard certs (ITS#7006)
	Fixed liblutil MD5 initialization (ITS#6982)
	Fixed slapadd common code into slapcommon (ITS#6737)
	Fixed slapd backend connection initialization (ITS#6993)
	Fixed slapd frontend DB parsing in cn=config (ITS#7016)
	Fixed slapd hang with {numbered} overlay insertion (ITS#7030)
	Fixed slapd inet_ntop usage (ITS#6925)
	Fixed slapd cn=config deletion of bitmasks (ITS#7083)
	Fixed slapd cn=config modify replace/delete crash (ITS#7065)
	Fixed slapd schema UTF8StringNormalize with 0 length values (ITS#7059)
	Fixed slapd with dynamic acls for cn=config (ITS#7066)
	Fixed slapd response callbacks (ITS#6059,ITS#7062)
	Fixed slapd no_connection warnings with ldapi (ITS#6548,ITS#7092)
	Fixed slapd return code processing (ITS#7060)
	Fixed slapd sl_malloc various issues (ITS#6437)
	Fixed slapd startup behavior (ITS#6848)
	Fixed slapd syncrepl crash with non-replicated ops (ITS#6892)
	Fixed slapd syncrepl with modrdn (ITS#7000,ITS#6472)
	Fixed slapd syncrepl timeout when using refreshAndPersist (ITS#6999)
	Fixed slapd syncrepl deletes need a non-empty CSN (ITS#7052)
	Fixed slapd syncrepl glue for empty suffix (ITS#7037)
	Fixed slapd results cleanup (ITS#6763,ITS#7053)
	Fixed slapd validation of args for TLSCertificateFile (ITS#7012)
	Fixed slapd-bdb/hdb to build entry DN based on parent DN (ITS#5326)
	Fixed slapd-hdb with zero-length entries (ITS#7073)
	Fixed slapd-hdb duplicate entries in subtree IDL cache (ITS#6983)
	Fixed slapo-constraint conversion to back-config (ITS#6986)
	Fixed slapo-dds tag in refresh response (ITS#6886)
	Fixed slapo-dds TTL tolerance (ITS#7017)
	Fixed slapo-lastbind so authTimestamp is manageable (ITS#6873)
	Fixed slapo-pcache response cleanup (ITS#6981)
	Fixed slapo-ppolicy pwdAllowUserChange behavior (ITS#7021)
	Fixed slapo-sssvlv issue with greaterThanorEqual (ITS#6985)
	Fixed slapo-sssvlv to only return requested attrs (ITS#7061)
	Fixed slapo-syncprov DSA attribute filtering for Persist mode (ITS#7019)
	Fixed slapo-syncprov when consumer has newer state of our SID (ITS#7040)
	Fixed slapo-syncprov crash (ITS#7025)
	Fixed slapo-unique URI checking of "host" portion (ITS#7018)
	Fixed contrib/autogroup double-free (ITS#6972)
	Fixed contrib/smbk5pwd cn=config deletion of bitmasks (ITS#7083)
	Fixed contrib/smbk5pwd on 64-bit systems (ITS#7082)
	Build Environment
		Added missing LDIF form of schema files (ITS#7063)
		Fixed build for Solaris native compilers (ITS#6992)
		Fixed creation and installation of slapd.ldif (ITS#7015)
		Fixed libnet linking (ITS#7071)
	Documentation
		admin24 Fix table numbering (ITS#7003)
		slapd.conf(5) Fixed TLSCACertificateFile information (ITS#7023)
		ldapmodify(1) Fixed minor typo in -S option description (ITS#7086)
		ldap_sync(3) Document ldap_sync_destroy (ITS#7028)
		slapo-unique(5) Fix keyword quoting (ITS#7028)

OpenLDAP 2.4.26 Release (2011/06/30)
	Added libldap LDAP_OPT_X_TLS_PACKAGE (ITS#6969)
	Fixed libldap MozNSS with CACertDir (ITS#6975)
	Fixed libldap MozNSS with PR_SetEnv (ITS#6862)
	Fixed libldap descriptor leak (ITS#6929)
	Fixed libldap socket leak (ITS#6930)
	Fixed libldap get option crash (ITS#6931)
	Fixed libldap lockup (ITS#6898)
	Fixed libldap ASYNC TLS setup (ITS#6828)
	Fixed libldap with missing \n terminations (ITS#6947)
	Fixed tools double free (ITS#6946)
	Fixed tools verbose output (ITS#6977)
	Fixed ldapmodify SEGV on invalid LDIF (ITS#6978)
	Added slapd extra_attrs database option (ITS#6513)
	Fixed slapd asserts (ITS#6932)
	Fixed slapd configfile param on windows (ITS#6933)
	Fixed slapd config with global chaining (ITS#6843)
	Fixed slapd uninitialized variables (ITS#6935)
	Fixed slapd config objectclass is readonly (ITS#6963)
	Fixed slapd entry response with control (ITS#6899)
	Fixed slapd with unknown attrs (ITS#6819)
	Fixed slapd normalization of schema RDN (ITS#6967)
	Fixed slapd operations cache to 10 op limit (ITS#6944)
	Fixed slapd syncrepl crash with non-replicated ops (ITS#6892)
	Fixed slapd-bdb/hdb with sparse index ranges (ITS#6961)
	Fixed slapd-monitor stray code cleanup (ITS#6974)
	Fixed back-ldap ppolicy updates (ITS#6711)
	Fixed back-ldap with id-assert (ITS#6817)
	Fixed slapd-meta reentry issues (ITS#6909)
	Fixed slapd-sql length of data type (ITS#6657,ITS#6691)
	Added slapo-accesslog filter matching (ITS#6815)
	Fixed slapo-accesslog with invalid attrs (ITS#6819)
	Added slapo-auditlog connID and peername logging (ITS#6936)
	Fixed slapo-memberof with accesslog (ITS#6329,ITS#6766,ITS#6915)
	Fixed slapo-pcache with unknown attrs (ITS#6823)
	Fixed slapo-pcache with '1.1', '+', and '*' attrs (ITS#6950)
	Fixed slapo-pcache buffersize issues (ITS#6951)
	Fixed slapo-pcache refresh (ITS#6953)
	Fixed slapo-pcache with pCacheBind (ITS#6954)
	Fixed slapo-pcache database corruption (ITS#6831)
	Fixed slapo-rwm with attributes with no equality rule (ITS#6943)
	Fixed slapo-sssvlv limits check when global (ITS#6973)
	Fixed slapo-syncprov with replicated subtrees (ITS#6872)
	Fixed slapo-unique with managedsait (ITS#6641)
	Fixed slapo-unique filter with zero-length values (ITS#6901)
	Added contrib/acl GSS naming extensions ACL module
	Fixed contrib/smbk5pwd with shadowLastChange (ITS#6955)
	Build Environment
		Fixed builds that do not have GETTIMEOFDAY (ITS#6885)
		Fixed libldap libfetch dependancy (ITS#6889)
	Documentation
		ldap_get_dn(3) add man page (ITS#6959)
		slapd-backends(5) update recommended database backend (ITS#6904)
		slapd-bdb(5) update recommended database backend (ITS#6904)
		slapd-hdb(5) update recommended database backend (ITS#6904)
		slapo-nssov(5) Fixed typo (ITS#6934)
		admin24 update that cn=config is preferred (ITS#6905)
		admin24 update information about indexes (ITS#6906)
		admin24 fix --enable-wrappers option (ITS#6971)
		admin24 fix typos (ITS#8562)
		admin24 fix replication sections to include back-mdb (ITS#8563)

OpenLDAP 2.4.25 Release (2011/03/26)
	Fixed ldapsearch pagedresults loop (ITS#6755)
	Fixed tools for incompatible args (ITS#6849)
	Fixed libldap MozNSS crash (ITS#6863)
	Fixed slapd add objectclasses in order (ITS#6837)
	Added slapd ordering for uidNumber and gidNumber (ITS#6852)
	Fixed slapd segfault when adding values out of order (ITS#6858)
	Fixed slapd sortval handling (ITS#6845)
	Fixed slapd-bdb with slapadd/index quick option (ITS#6853)
	Fixed slapd-ldap chain cn=config support (ITS#6837)
	Fixed slapd-ldap chain with slapd.conf (ITS#6857)
	Fixed slapd-meta deadlock (ITS#6846)
	Fixed slapo-sssvlv with multiple requests (ITS#6850)
	Fixed contrib/lastbind install rules (ITS#6238)
	Fixed contrib/cloak install rules (ITS#6877)
	Build Environment
		Fixed windows NT threads build (ITS#6859)
		Fixed libldap/lberl/util if/else usage (ITS#6832)
		Fixed Windows odbc32 detection (ITS#6125)
		Fixed Windows msys build (ITS#6870)
		Fixed test020 exit codes (ITS#6404)
	Documentation
		admin24 guide ldapi usage (ITS#6839)
		admin24 guide conversion notes (ITS#6834)
		admin24 guide fix drawback math for syncrepl (ITS#6866)
		admin24 guide note manpages are definitive (ITS#6855)

OpenLDAP 2.4.24 Release (2011/02/10)
	Added LDIF line wrapping setting (ITS#6645)
	Added MozNSS support (ITS#6714,ITS#6742,ITS#6790,ITS#6791)
	Added MozNSS support (ITS#6802,ITS#6811,ITS#6816,ITS#5696)
	Added libldap cert x500UniqueIdentifier handling (ITS#6741)
	Added libldap_r,libldap formal concurrency API (ITS#6625,ITS#5421)
	Added slapadd attribute value checking (ITS#6592)
	Added slapcat continue mode for problematic DBs (ITS#6482)
	Added slapd syncrepl suffixmassage support (ITS#6781)
	Added slapd multiple listener threads (ITS#6780)
	Added slapd extensible match for ordering rules (ITS#6532)
	Added slapd-meta paged results control forwarding (ITS#6664)
	Added slapd-meta subtree-include support (ITS#6801)
	Added slapd-null back-config support (ITS#6624)
	Added slapd-sql autocommit support (ITS#6612)
	Added slapd-sql support for long long keys (ITS#6617)
	Added slapo-sssvlv multiple sorts per connection (ITS#6686)
	Added contrib/autogroup LDAP URI with attribute filter (ITS#6536)
	Added contrib/dupent module (ITS#6630)
	Added contrib/lastbind (ITS#6238)
	Added contrib/kinit for kerberos tickets
	Added contrib/noopsrch for entry counting (ITS#6598)
	Fixed client tools control logging (ITS#6775)
	Fixed client tools one time leak (ITS#6778)
	Fixed liblber to not close invalid sockets (ITS#6585)
	Fixed liblber unmatched brace handling (ITS#6764)
	Fixed liblber error setting (ITS#6732)
	Fixed liblber memory debugging (ITS#6733)
	Fixed libldap connectionless warnings (ITS#6747)
	Fixed libldap dnssrv port format specifier (ITS#6644)
	Fixed libldap EOF handling (ITS#6723)
	Fixed libldap GnuTLS hang on socket close (ITS#6673)
	Fixed libldap sasl partial write handling (ITS#6639)
	Fixed libldap search leak (ITS#6453)
	Fixed libldap referral chasing (ITS#6602)
	Fixed libldap leak when chasing referrals (ITS#6744)
	Fixed libldap url parsing with NULL host (ITS#6653)
	Fixed libldap ldap_open_internal_connection (ITS#6788)
	Fixed libldap sync checking for BER errors (ITS#6738)	
	Fixed libldap variable usage (ITS#6813)
	Fixed liblutil getpass prompts (ITS#6702)
	Fixed ldapsearch segfault with deref (ITS#6638)
	Fixed ldapsearch multiple controls parsing (ITS#6651)
	Fixed slapd SlapReply usage (ITS#6758)
	Fixed slapd acl parsing overflow (ITS#6611)
	Fixed slapd acl when resuming parsing (ITS#6804)
	Fixed slapd Compare operation (ITS#6753)
	Fixed slapd default config acls with overlays (ITS#6822)
	Fixed slapd assert control (ITS#5862)
	Fixed slapd assertions and debugging (ITS#6759)
	Fixed slapd config leak with olcDbDirectory (ITS#6634)
	Fixed slapd connectionless warnings (ITS#6747)
	Fixed slapd listeners destruction (ITS#6736)
	Fixed slapd to free controls if needed (ITS#6629)
	Fixed slapd to stop if given unknown options (ITS#6754)
	Fixed slapd filter leak (ITS#6635)
	Fixed slapd matching rules for strict ordering (ITS#6722)
	Fixed slapd when first acl is value dependent (ITS#6693)
	Fixed slapd modify to return actual error (ITS#6581)
	Fixed slapd modrdn with empty DN (ITS#6768)
	Fixed slapd c_authz_backend setting (ITS#6824)
	Fixed slapd sortvals of attributes with 1 value (ITS#6715)
	Fixed slapd syncrepl reuse of presence list (ITS#6707)
	Fixed slapd syncrepl uninitialized return code (ITS#6719)
	Fixed slapd syncrepl variable initialization (ITS#6739)
	Fixed slapd syncrepl refresh to use complete cookie (ITS#6807)
	Fixed slapd-bdb hasSubordinates generation (ITS#6712)
	Fixed slapd-bdb entry cache delete failure (ITS#6577)
	Fixed slapd-bdb entry cache leak on multi-core systems (ITS#6660)
	Fixed slapd-bdb error propagation to overlays (ITS#6633)
	Fixed slapd-bdb slapadd -q with glued dbs (ITS#6794)
	Fixed slapd-ldap debug output of timeout (ITS#6721)
	Fixed slapd-ldap DNSSRV referral chaining (ITS#6565)
	Fixed slapd-ldap chaining with bind failures (ITS#6607)
	Fixed slapd-ldap chaining with onelevel scope (ITS#6699)
	Fixed slapd-ldap chaining with ppolicy (ITS#6540)
	Fixed slapd-ldap with SASL/EXTERNAL (ITS#6642)
	Fixed slapd-ldap crasher on matchedDN (ITS#6793)
	Fixed slapd-ldap with unknown objectClasses (ITS#6814)
	Fixed slapd-ldif error strings (ITS#6731)
	Fixed slapd-ndb to honor rootpw setting (ITS#6661)
	Fixed slapd-ndb hasSubordinates generation (ITS#6712)
	Fixed slapd-ndb variable initialization (ITS#6806)
	Fixed slapd-ndb with out of order attributes (ITS#6821)
	Fixed slapd-meta anon retry with failed auth method (ITS#6643)
	Fixed slapd-meta rebind proc (ITS#6665)
	Fixed slapd-meta to correctly rebind as user (ITS#6574)
	Fixed slapd-meta with SASL/EXTERNAL (ITS#6642)
	Fixed slapd-meta matchedDN return code (ITS#6774)
	Fixed slapd-meta candidate selection (ITS#6799)
	Fixed slapd-meta attribute normalization (ITS#6818)
	Fixed slapd-monitor hasSubordinates generation (ITS#6712)
	Fixed slapd-monitor abandon processing (ITS#6783)
	Fixed slapd-monitor entry locks (ITS#6787)
	Fixed slapd-sock missing newline in Compare operation (ITS#6809)
	Fixed slapd-sql with null objectClass (ITS#6616)
	Fixed slapd-sql hasSubordinates generation (ITS#6712)
	Fixed slapo-accesslog with controls (ITS#6652)
	Fixed slapo-dynlist Compare operation (ITS#6752)
	Fixed slapo-dynlist entry handling (ITS#6752)
	Fixed slapo-memberof CSN generation (ITS#6766)
	Fixed slapo-memberof log messages (ITS#6748)
	Fixed slapo-memberof with an empty groupOfNames (ITS#6670)
	Fixed slapo-memberof with modrdn operations (ITS#6700)
	Fixed slapo-pcache callback freeing (ITS#6640)
	Fixed slapo-pcache to ignore undefined attrs (ITS#6600)
	Fixed slapo-pcache pointer freeing (ITS#6797)
	Fixed slapo-pcache with negative caching (ITS#6796)
	Fixed slapo-pcache monitoring cleanup (ITS#6808)
	Fixed slapo-ppolicy don't update opattrs on consumers (ITS#6608)
	Fixed slapo-ppolicy to allow userPassword deletion (ITS#6620)
	Fixed slapo-refint when last group member is deleted (ITS#6663)
	Fixed slapo-refint with subtree rename (ITS#6730)
	Fixed slapo-rwm double free (ITS#6720)
	Fixed slapo-rwm crasher (ITS#6632,ITS#6727)
	Fixed slapo-rwm entry handling (ITS#6760)
	Fixed slapo-rwm response hang (ITS#6792)
	Fixed slapo-sssvlv initialization (ITS#6649)
	Fixed slapo-sssvlv to not advertise when unused (ITS#6647)
	Fixed slapo-sssvlv result code (ITS#6685)
	Fixed slapo-syncprov to send error if consumer is newer (ITS#6606)
	Fixed slapo-syncprov filter race condition (ITS#6708)
	Fixed slapo-syncprov active mod race (ITS#6709)
	Fixed slapo-syncprov to refresh if context is dirty (ITS#6710)
	Fixed slapo-syncprov CSN updates to all replicas (ITS#6718)
	Fixed slapo-syncprov sessionlog ordering (ITS#6716)
	Fixed slapo-syncprov sessionlog with adds (ITS#6503)
	Fixed slapo-syncprov mutex (ITS#6438)
	Fixed slapo-syncprov mincsn check with MMR (ITS#6717)
	Fixed slapo-syncprov control leak (ITS#6795)
	Fixed slapo-syncprov error codes (ITS#6812)
	Fixed slapo-translucent entry leak (ITS#6746)
	Fixed contrib/autogroup install location (ITS#6684)
	Fixed contrib/autogroup crash with ppolicy (ITS#6684)
	Fixed contrib/autogroup with non-DN URIs (ITS#6684)
	Fixed contrib/autogroup with memberOf overlay (ITS#6684)
	Fixed contrib/cloak when returning multiple entries (ITS#6762)
	Fixed contrib/nssov to only close socket on shutdown (ITS#6676)
	Fixed contrib/nssov multi platform support (ITS#6604)
	Build Environment
		Added support for [unsigned] long long (ITS#6622)
		Added slapd support for BDB 5.0+ (ITS#6698)
		Fixed config.guess/sub to pick up newer OSes (ITS#6547)
		Fixed libldap mutex code - cleanup (ITS#6672)
		Fixed libldap unnecessary ifdef's (ITS#6603)
		Fixed slapd-tester EOF handling (ITS#6723)
		Fixed slapd-tester filter initialization (ITS#6735)
		Fixed test scripts with alternate testdir (ITS#6782)
		Removed antiquated SunOS LWP support (ITS#6669)
	Documentation
		admin24 guide fix examples (ITS#6681)
		admin24 guide typo fixes (ITS#6609)
		admin24 guide refint rootdn requirement (ITS#6364)
		admin24 add pcache overlay section (ITS#6521)
		ldap_open(3) document ldap_set_urllist_proc (ITS#6601)
		ldap.conf(5) GnuTLS cipher spec info (ITS#6525)
		slapd.conf(5) GnlTLS cipher spec info (ITS#6525)
		slapd.conf(5) multi-listener support (ITS#6780)
		slapd-config(5) GnuTLS cipher spec info (ITS#6525)
		slapd-config(5) multi-listener support (ITS#6780)
		slapd-meta(5) note deprecated items (ITS#6800)
		slapd-meta(5) document subtree-include (ITS#6801)
		slapo-pcache(5) note rootdn requirement (ITS#6522)
		slapo-refint(5) rootdn requirement (ITS#6364)

OpenLDAP 2.4.23 Release (2010/06/30)
	Fixed libldap to return server's error code (ITS#6569)
	Fixed libldap memleaks (ITS#6568)
	Fixed liblutil off-by-one with delta (ITS#6541)
	Fixed slapd acls with glued databases (ITS#6468)
	Fixed slapd syncrepl rid logging (ITS#6533)
	Fixed slapd modrdn handling of invalid values (ITS#6570)
	Fixed slapd-bdb hasSubordinates computation (ITS#6549)
	Fixed slapd-bdb to use memcpy instead for strcpy (ITS#6474)
	Fixed slapd-bdb entry cache delete failure (ITS#6577)
	Fixed slapd-ldap to return control responses (ITS#6530)
	Fixed slapo-ppolicy to use Debug (ITS#6566)
	Fixed slapo-refint to zero out freed DN vals (ITS#6572)
	Fixed slapo-rwm to use Debug (ITS#6566)
	Fixed slapo-sssvlv to use Debug (ITS#6566)
	Fixed slapo-syncprov lost deletes in refresh phase (ITS#6555)
	Fixed slapo-valsort to use Debug (ITS#6566)
 	Fixed contrib/nssov network.c missing patch (ITS#6562)
	Build Environment
		Fixed test043 attribute sorting (ITS#6553)
	Documentation
	        slapd-config(5) note default rootdn (ITS#6546)

OpenLDAP 2.4.22 Release (2010/04/24)
	Added slapd SLAP_SCHEMA_EXPOSE flag for hidden schema elements (ITS#6435)
	Added slapd tools selective iterations (ITS#6442)
	Added slapd syncrepl TCP keepalive (ITS#6389)
	Added slapo-ldap idassert-passthru (ITS#6456)
	Added slapo-pbind
	Fixed libldap gmtime re-entrancy (ITS#6262)
	Fixed libldap gssapi off by one error (ITS#6223)
	Fixed libldap GnuTLS serial length (ITS#6460)
	Fixed libldap MozNSS context and PEM support (ITS#6432)
	Fixed libldap referral on bind behavior(ITS#6510)
	Fixed slapd acl non-entry internal searches (ITS#6481)
	Fixed slapd acl attrval style initialization (ITS#6520)
	Fixed slapd certificateListValidate (ITS#6466)
	Fixed slapd empty URI parsing (ITS#6465)
	Fixed slapd glued misplaced entries (ITS#6506)
	Fixed slapd glued paged cookies (ITS#6507)
	Fixed slapd glued paged results (ITS#6504)
	Fixed slapd gmtime re-entrancy (ITS#6262)
	Fixed slapd to ignore controls with unrecognized flags (ITS#6480)
	Fixed slapd entry ownership (ITS#5340)
	Fixed slapd sasl auxprop_lookup (ITS#6441)
	Fixed slapd sasl auxprop ssf (ITS#5195)
	Fixed slapd syncrepl for attributes with no matching rule (ITS#6458)
	Fixed slapd syncrepl for unknown attrs and delta-sync (ITS#6473)
	Fixed slapd syncrepl loop with moddn (ITS#6472)
	Fixed slapo-accesslog to not replicate internal purges (ITS#6519)
	Fixed slapd-bdb contextCSN updates from updatedn (ITS#6469)
	Fixed slapd-bdb lockobj zeroing (ITS#6501)
	Fixed slapd-ldap/meta control criticality (ITS#6523)
	Fixed slapd-ldap/meta with ordered values (ITS#6516)
	Fixed slapo-collect entry ownership (ITS#5340,ITS#6423)
	Fixed slapo-dds with NULL backend (ITS#6490)
	Fixed slapo-dynlist entry ownership (ITS#5340,ITS#6423)
	Fixed slapo-memberof attr count (ITS#6508)
	Fixed slapo-pcache to release its own entries (ITS#6484)
	Fixed slapo-pcache with NULL backend (ITS#6490)
	Fixed slapo-rwm entry release handling (ITS#6484)
	Fixed slapo-rwm memory handling with rewrites (ITS#6526)
	Fixed slapo-rwm olcRwmMap handling (ITS#6436)
	Fixed slapo-rwm entry ownership (ITS#5340,ITS#6423)
	Fixed slapo-syncprov memory leak (ITS#6459)
	Fixed slapo-translucent counter increment (ITS#6497)
	Fixed slapo-valsort entry ownership (ITS#5340,ITS#6423)	
	Fixed contrib/sha2 adds mechs for more hashes (ITS#6433)
	Fixed contrib/nssov to use nss-pam-ldapd (ITS#6488)
	Build Environment
		Added back-ldif, back-null test support (ITS#5810)
	Documentation
		admin24 avoid explicit moduleload statements (ITS#6486)
		admin24 broken link fixes (ITS#6493,ITS#6515)
	        slapd.access(5) val.regex explanation (ITS#5804)

OpenLDAP 2.4.21 Release (2009/12/20)
	Fixed liblutil for negative microsecond offsets (ITS#6405)
	Fixed slapd global settings to work without restart (ITS#6428)
	Fixed slapd looping with SSL/TLS connections (ITS#6412)
	Fixed slapd syncrepl freeing tasks from queue (ITS#6413)
	Fixed slapd syncrepl parsing of tls defaults (ITS#6419)
	Fixed slapd syncrepl uninitialized variables (ITS#6425)
	Fixed slapd-config Adds with Abstract classes (ITS#6408)
	Fixed slapo-dynlist behavior with simple filters (ITS#6421)
	Fixed slapd-ldif access outside database directory (ITS#6414)
	Fixed slapd-null extraneous assert (ITS#6403)
	Fixed slapo-translucent with back-null (ITS#6403)
	Fixed slapo-unique criteria checking (ITS#6270)
	Build Environment
		Deleted broken LBER_INVALID macro (ITS#6402)
		Fixed test058 kill usage (ITS#6420)
		Fixed meta regression test (ITS#6418)
	Documentation
		slapd-meta(5) Note deprecated functions (ITS#6424)
		admin24 fix set example for group of groups (ITS#6382)
		admin24 fix dynamic group documentation (ITS#6290)

OpenLDAP 2.4.20 Release (2009/11/27)
	Fixed client tools with LDAP options (ITS#6283)
	Fixed liblber embedded NUL values in BerValues (ITS#6353)
	Fixed liblber inverted LBER_USE_DER test (ITS#6348)
	Fixed liblber to return failure on certain failures (ITS#6344)
	Fixed libldap connection initialization (ITS#6386)
	Fixed libldap sasl buffer sizing (ITS#6327,ITS#6334)
	Fixed libldap uninitialized return value (ITS#6355)
	Fixed libldap unlimited timeout (ITS#6388)
	Added slapd handling of hex server IDs (ITS#6297)
	Added slapd syncrepl contextCSN storing in subentry (ITS#6373)
	Fixed slapd asserts in minimal environment (ITS#6361)
	Fixed slapd authid-rewrite parsing (ITS#6392)
	Fixed slapd checks of str2filter (ITS#6391)
	Fixed slapd configArgs initialization (ITS#6363)
	Fixed slapd debug handling of LDAP_DEBUG_ANY (ITS#6324)
	Fixed slapd db_open with connection_fake_init (ITS#6381)
	Fixed slapd with embedded \0 in bervals (ITS#6378,ITS#6379)
	Fixed slapd inclusion of ac/unistd.h (ITS#6342)
	Fixed slapd invalid dn log message (ITS#6309)
	Fixed slapd lockup on shutdown (ITS#6372)
	Fixed slapd onetime leak (ITS#6398)
	Fixed slapd RID range to be decimal only (ITS#6394)
	Fixed slapd sl_free to better reclaim memory (ITS#6380)
	Fixed slapd syncrepl deletes in MirrorMode (ITS#6368)
	Fixed slapd syncrepl to use correct SID (ITS#6367)
	Fixed slapd termination for one level DNs (ITS#6338)
	Fixed slapd tls_accept to retry in certain cases (ITS#6304)
	Fixed slapd-bdb/hdb cache corruption (ITS#6341)
	Fixed slapd-bdb/hdb entry cache (ITS#6360)
	Fixed slapd-ldap leak (ITS#6326)
	Fixed slapd-relay bind segfault (ITS#6337)
	Fixed slapo-accesslog ensure CSNs are normalized (ITS#6400)
	Fixed slapo-memberof operational attr updates (ITS#6329)
	Fixed slapo-pcache entry dupe (ITS#6310)
	Fixed slapo-syncprov checkpoint conversion (ITS#6370)
	Fixed slapo-syncprov deadlock (ITS#6335)
	Fixed slapo-syncprov memory leak (ITS#6376)
	Fixed slapo-syncprov out of order changes (ITS#6346)
	Fixed slapo-syncprov psearch with stale cookie (ITS#6397)
	Build Environment
		Added additional operations for ITS#6332
		Fixed memrchr define (ITS#6351)
		Fixed slapd MAXPATHLEN handling (ITS#6342)
		Added test050 rapid add/mod/del sequence (ITS#6368)
		Fixed test057 handling of memberof/refint (ITS#6343)
		Fixed slapd test error ignoring (ITS#6345)
		Fixed liblutil constant (ITS#5909)
	Documentation
		admin24 fix RFC4511 and other references (ITS#6399)
		ldap_get_dn(3) typos (ITS#5366)
		ldap.conf(5) clarify comment usage (ITS#6384)
		slapd.conf(5) note hex server IDs (ITS#6297)
		slapd-config(5) note hex server IDs (ITS#6297)

OpenLDAP 2.4.19 Release (2009/10/06)
	Fixed client tools with null timeouts (ITS#6282)
	Fixed slapadd to warn about missing attrs for replicas (ITS#6281)
	Fixed slapd acl cache (ITS#6287)
	Fixed slapd tools to allow -n for conversion (ITS#6258)
	Fixed slapd-ldap with null timeouts (ITS#6282)
	Fixed slapd-ldap with strong binds with relay/translucent (ITS#6296)
	Fixed slapd-ldif buffer overflow (ITS#6303)
	Fixed slapo-auditlog comments when modifying (ITS#6286)
	Fixed slapo-dynlist lock leak (ITS#6308)
	Fixed slapo-pcache cache corruption (ITS#6242)
	Fixed slapo-sssvlv sort control dereferencing (ITS#6288)
	Fixed contrib/autogroup segfaults (ITS#6279)
	Fixed contrib/nssov getgroupbymembers (ITS#6291)
	Fixed contrib/smbk5pwd rpath linking (ITS#6323)
	Build Environment
		Fixed --enable-deref support (ITS#6311)
		Fixed contrib/autogroup default libtool path (ITS#6284)
		Deleted nadf.schema (ITS#6140)

OpenLDAP 2.4.18 Release (2009/09/06)
	Fixed client tools common options (ITS#6049)
	Fixed liblber speed and other problems (ITS#6215)
	Added libldap MozNSS PEM support (ITS#6278)
	Added libldap option for SASL_USERNAME (ITS#6257)
	Fixed libldap error parsing (ITS#6197)
	Fixed libldap native getpass usage (ITS#4643)
	Fixed libldap tls_check_hostname for OpenSSL and MozNSS (ITS#6239)
	Added slapd tcp buffers support (ITS#6234)
	Fixed slapd allow mirrormode to be set to FALSE (ITS#5946)
	Fixed slapd certificate list parsing (ITS#6241)
	Fixed slapd writers blocking (ITS#6276)
	Fixed slapd dncachesize behavior to unlimited by default (ITS#6222)
	Fixed slapd incorrectly applying writetimeout when not set (ITS#6220)
	Fixed slapd with duplicate empty lines for olcDbConfig (ITS#6240)
	Fixed slapd server URL matching (ITS#5942)
	Fixed slapd subordinate needs a suffix (ITS#6216)
	Fixed slapd syncrepl decrement on possible NULL value (ITS#6256)
	Fixed slapd tools to properly close database (ITS#6214)
	Fixed slapd uninitialized SlapReply components (ITS#6101)
	Fixed slapd-meta starttls with targets (ITS#6190)
	Fixed slapd-monitor stats with glued subordinates (ITS#6243)
	Fixed slapd-ndb startup (ITS#6203)
	Fixed slapd-relay various issues (ITS#6133)
	Fixed slapd-relay response/cleanup callback mismatch (ITS#6154)
	Fixed slapd-sql with baseObject query (ITS#6172)
	Fixed slapd-sql with empty attribute (ITS#6163)
	Fixed slapo-dynlist uninitialized var (ITS#6266)
	Fixed slapo-pcache multiple enhancements (ITS#6152,ITS#5178)
	Fixed slapo-ppolicy updating operational attributes (ITS#6265)
	Fixed slapo-translucent attribute return (ITS#6254)
	Fixed slapo-translucent filter matching (ITS#6255)
	Fixed slapo-translucent to honor sizelimit (ITS#6253)
	Fixed slapo-unique filter matching (ITS#6077)
	Fixed tools off by one error (ITS#6233)
	Fixed tools resource leaks (ITS#6145)
	Added contrib/allowed (ITS#4730)
	Fixed contrib/autogroup with RE24 (ITS#6227)
	Fixed contrib/nss symbols (ITS#6273)
	Build Environment
		Tests note which backend is being tested (ITS#5810)
		Fixed test056-monitor with custom ports (ITS#6213)
	Documentation
		admin24 fix broken link (ITS#6264)
		ldap_open(3) document URI (ITS#6261)
		ldap_set/get_option(3) SASL/TLS options added (ITS#6260)
		man page format updates (ITS#6023)

OpenLDAP 2.4.17 Release (2009/07/13)
	Fixed liblber to use ber_strnlen (ITS#6080)
	Fixed libldap GnuTLS private key init (ITS#6053)
	Fixed libldap openssl digest initialization (ITS#6192)
	Fixed libldap tls NULL error messages (ITS#6079)
	Fixed libldap_r missing stub (ITS#6188)
	Fixed liblutil opendir/closedir on windows (ITS#6041)
	Fixed liblutil for _GNU_SOURCE (ITS#5464,ITS#5666)
	Added slapd sasl auxprop support (ITS#6147)
	Added slapd schema checking tool (ITS#6150)
	Added slapd writetimeout keyword (ITS#5836)
	Fixed slapd abandon/cancel handling for some ops (ITS#6157)
	Fixed slapd access setstyle to expand (ITS#6179)
	Fixed slapd assert with closing connections (ITS#6111)
	Fixed slapd bind race condition (ITS#6189)
	Fixed slapd cancel behavior (ITS#6137)
	Fixed slapd cert validation (ITS#6098)
	Fixed slapd connection_destroy assert (ITS#6089)
	Fixed slapd csn normalization (ITS#6195)
	Fixed slapd errno handling (ITS#6037)
	Fixed slapd global alloc handling (ITS#6054)
	Fixed slapd hung writers (ITS#5836)
	Fixed slapd ldapi issues (ITS#6056)
	Fixed slapd moduleload with static backends and modules (ITS#6016)
	Fixed slapd normalization of updated schema attributes (ITS#5540)
	Fixed slapd olcLimits handling (ITS#6159)
	Fixed slapd olcLogLevel with hex levels (ITS#6162)
	Fixed slapd pagedresults stacked control with overlays (ITS#6056)
	Fixed slapd password-hash incorrect limit on arg length (ITS#6139)
	Fixed slapd readonly restrictions (ITS#6109)
	Fixed slapd sending cancelled operations results (ITS#6103)
	Fixed slapd slapi_entry_has_children (ITS#6132)
	Fixed slapd sockets usage on windows (ITS#6039)
	Fixed slapd some abandon and cancel race conditions (ITS#6104)
	Fixed slapd tls context after changes (ITS#6135)
	Fixed slapd-bdb/hdb adjust dncachesize if too low (ITS#6176)
	Fixed slapd-bdb/hdb crashes during delete (ITS#6177)
	Fixed slapd-bdb/hdb multiple olcIndex for same attr (ITS#6196)
	Fixed slapd-hdb freeing of already freed entries (ITS#6074)
	Fixed slapd-hdb entryinfo cleanup (ITS#6088)
	Fixed slapd-hdb dncache lockups (ITS#6095)
	Fixed slapd-ldap deadlock with non-responsive TLS URIs (ITS#6167)
	Fixed slapd-relay to return failure on failure (ITS#5328)
	Fixed slapd-sql with BACKSQL_ARBITRARY_KEY defined (ITS#6100)
	Fixed slapo-collect collectinfo ordering (ITS#6076)
	Fixed slapo-collect missing equality match rule (ITS#6075)
	Fixed slapo-dds entry expiration (ITS#6169)
	Fixed slapo-perl symbols (ITS#5658)
	Fixed slapo-ppolicy to honor pwdLockout (ITS#6168)
	Fixed slapo-ppolicy to return check modules error message (ITS#6082)
	Fixed slapo-refint refint_repair handling (ITS#6056)
	Added slapo-rwm rwm-drop-unrequested-attrs config option (ITS#6057)
	Fixed slapo-rwm dn passing (ITS#6070)
	Fixed slapo-rwm entry free (ITS#6058)
	Fixed slapo-rwm entry release (ITS#6081)
	Fixed slapo-translucent entry gathering (ITS#6156)
	Fixed tools returning ldif errors (ITS#5892)
	Fixed contrib/smbk5pwd use of private functions (ITS#5535)
	Build Environment
		Added test056-monitor (ITS#5540)
		Added test057-memberof-refint (ITS#5395)
		Fixed winsock detection for windows (ITS#6102, ITS#6078)
		Removed GSSAPI configure option (ITS#6091,ITS#6092,ITS#6093,ITS#5369)
	Documentation
		admin24 relocate configuration examples (ITS#6183)
		admin24 fixed example regex (ITS#6052)
		admin24 removed temporary back-monitor note (ITS#6130)
		admin24 slapd.conf to cn=config conversion process (ITS#6060)
		man page consistency fixes (ITS#6023)
		ldapcompare(1) note -e option (ITS#6107)
		ldapdelete(1) note -e option (ITS#6107)
		ldapmodify(1) note -e option (ITS#6107)
		ldapmodrdn(1) note -e option (ITS#6107)
		ldapsearch(1) output format description (ITS#6146)
		ldapurl(1) note -e option (ITS#6107)
		ldapwhoami(1) note -e option (ITS#6107)
		ldap_result(3) Add RETURN VALUE heading (ITS#6180)
		ldap.conf(5) improve sizelimit/timelimit limits (ITS#6127)
		slapd.access(5) Fix <setstyle> to use expand (ITS#6179)
		slapd.conf(5) document default modulepath (ITS#5829)
		slapd.conf(5) pidfile/argsfile description fix (ITS#5975)
		slapd-config(5) document default modulepath (ITS#5829)
		slapd-config(5) pidfile/argsfile description fix (ITS#5975)
		slapo-constraint(5) clarify URI example (ITS#6118)
		slapo-unique(5) explicitly note rootdn requirement (ITS#6108)
		slapadd(8) note it does indexing (ITS#6160)

OpenLDAP 2.4.16 Release (2009/04/05)
	Fixed libldap GnuTLS with x509v1 CA certs (ITS#5992)
	Fixed libldap GnuTLS with CA chains (ITS#5991)
	Fixed libldap GnuTLS TLSVerifyClient try (ITS#5981)
	Fixed libldap segfault in checking cert/DN (ITS#5976)
	Fixed libldap peer cert double free (ITS#5849)
	Fixed libldap referral chasing (ITS#5980)
	Fixed slapd backglue with empty DBs (ITS#5986)
	Fixed slapd ctxcsn race condition (ITS#6001)
	Fixed slapd debug message (ITS#6027)
	Fixed slapd redundant module loading (ITS#6030)
	Fixed slapd schema_init freed value (ITS#6036)
	Fixed slapd syncrepl newCookie sync messages (ITS#5972)
	Fixed slapd syncrepl hang during shutdown (ITS#6011)
	Fixed slapd syncrepl too many MMR messages (ITS#6020)
	Fixed slapd syncrepl skipped entries with MMR (ITS#5988)
	Fixed slapd-bdb/hdb cachesize handling (ITS#5860)
	Fixed slapd-bdb/hdb with slapcat with empty dn (ITS#6006)
	Fixed slapd-bdb/hdb with NULL transactions (ITS#6012)
	Fixed slapd-ldap incorrect referral handling (ITS#6003,ITS#5916)
	Fixed slapd-ldap/meta with broken AD results (ITS#5977)
	Fixed slapd-ldap/meta with invalid attrs again (ITS#5959)
	Fixed slapo-accesslog interaction with ppolicy (ITS#5979)
	Fixed slapo-dynlist conversion to cn=config (ITS#6002)
	Fixed slapo-syncprov newCookie sync messages (ITS#5972)
	Fixed slapd-syncprov too many MMR messages (ITS#6020)
	Fixed slapo-syncprov replica lockout (ITS#5985)
	Fixed slapo-syncprov modtarget tracking (ITS#5999)
	Fixed slapo-syncprov multiple CSN propagation (ITS#5973)
	Fixed slapo-syncprov race condition (ITS#6045)
	Fixed slapo-syncprov sending cookies without CSN (ITS#6024)
	Fixed slapo-syncprov skipped entries with MMR (ITS#5988)
	Fixed tools passphrase free (ITS#6014)
	Build Environment
		Cleaned up alloc/free functions for Windows (ITS#6005)
		Fixed running of autosave files in testsuite (ITS#6026)
	Documentation
		admin24 clarified MMR URI requirements (ITS#5942,ITS#5987)
		Added ldapexop(1) manual page (ITS#5982)
		slapd-ldap/meta(5) added missing TLS options (ITS#5989)

OpenLDAP 2.4.15 Release (2009/02/24)
	Fixed libldap alias dereferencing in C API again (ITS#5916)
	Fixed libldap GnuTLS compilation (ITS#5955)
	Fixed slapd bconfig conversion again (ITS#5346)
	Fixed slapd behavior with superior objectClasses again (ITS#5517)
	Fixed slapd RFC4512 behavior with same attr in RDN (ITS#5968)
	Fixed slapd corrupt contextCSN (ITS#5947)
	Fixed slapd syncrepl order to match on add/delete (ITS#5954)
	Fixed slapd adding rdn with other values (ITS#5965)
	Fixed slapd-bdb/hdb behavior with unallocatable shm (ITS#5956)
	Fixed slapd-ldap/meta with entries with invalid attrs (ITS#5959)
	Fixed slapd-relay control initialization (ITS#5724)
	Fixed slapo-pcache caching invalid entries (ITS#5927)
	Fixed slapo-syncprov csn updates (ITS#5969)
	Fixed slapo-rwm objectClass preservation (ITS#5760)
	Fixed slapo-rwm rwm_bva_rewrite handling (ITS#5960)
	Build Environment
		Fixed tester library linking for windows (ITS#5740)

OpenLDAP 2.4.14 Release (2009/02/14)
	Added libldap option to disable SASL host canonicalization (ITS#5812)
	Added libldap TLS_PROTOCOL_MIN (ITS#5655)
	Added libldap GnuTLS support for TLS_CIPHER_SUITE (ITS#5887)
	Added libldap GnuTLS setting random file (ITS#5462)
	Added libldap alias dereferencing in C API (ITS#5916)
	Fixed libldap chasing multiple referrals (ITS#5853)
	Fixed libldap deref handling (ITS#5768)
	Fixed libldap NULL pointer deref (ITS#5934)
	Fixed libldap peer cert memory leak (ITS#5849)
	Fixed libldap interaction with GnuTLS CN IP-based matches (ITS#5789)
	Fixed libldap intermediate response behavior (ITS#5896)
	Fixed libldap IPv6 address handling (ITS#5937)
	Fixed libldap_r deref building (ITS#5768)
	Fixed libldap_r slapd lockup when paused during shutdown (ITS#5841)
	Added slapd syncrepl default retry setting (ITS#5825)
	Added slapd val.regex expansion (ITS#5804)
	Added slapd TLS_PROTOCOL_MIN (ITS#5655)
	Added slapd slapi_pw_find (ITS#2615,ITS#4359)
	Added slapd compatibility with MSAD ranged values (ITS#5927)
	Fixed slapd bconfig to return error codes (ITS#5867)
	Fixed slapd bconfig encoding incorrectly (ITS#5897)
	Fixed slapd bconfig dangling pointers (ITS#5924)
	Fixed slapd behavior with superior objectClasses (ITS#5517)
	Fixed slapd connection assert (ITS#5835)
	Fixed slapd epoll handling (ITS#5886)
	Fixed slapd frontend/backend options handling (ITS#5857)
	Fixed slapd glue with MMR (ITS#5925)
	Fixed slapd logging on Windows (ITS#5392)
	Fixed slapd listener comparison (ITS#5613)
	Fixed slapd manageDSAit with glue entries (ITS#5921)
	Fixed slapd relax behavior with structuralObjectClass (ITS#5792)
	Fixed slapd syncrepl rename handling (ITS#5809)
	Fixed slapd syncrepl MMR when adding new server (ITS#5850)
	Fixed slapd syncrepl MMR with deleted entries (ITS#5843)
	Fixed slapd syncrepl replication with glued DB (ITS#5866)
	Fixed slapd syncrepl replication with moddn (ITS#5901)
	Fixed slapd syncrepl replication with referrals (ITS#5881)
	Fixed slapd syncrepl replication with config tree (ITS#5935)
	Fixed slapd wake_sds close on Windows (ITS#5855)
	Fixed slapd-bdb/hdb dncachesize handling (ITS#5860)
	Fixed slapd-bdb/hdb RFC4528 control support (ITS#5861)
	Fixed slapd-bdb/hdb trickle task usage (ITS#5864)
	Fixed slapd-hdb idlcache with empty suffix (ITS#5859)
	Fixed slapd-ldap idassert-bind validity checking (ITS#5863)
	Fixed slapd-ldap/meta RFC4525 increment support (ITS#5912)
	Fixed slapd-ldap/meta search dereferencing (ITS#5916)
	Fixed slapd-ldap/meta with intermediate response (ITS#5931)
	Fixed slapd-ldif numerous bugs (ITS#5408)
	Fixed slapd-ldif rename on same DN (ITS#5319)
	Fixed slapd-ldif deadlock (ITS#5329)
	Fixed slapd-meta double response sending (ITS#5854)
	Fixed slapd-meta alias deref for retry (ITS#5889)
	Fixed slapd-relay recursion detection (ITS#5943)
	Fixed slapd-sock descriptor leak (ITS#5939)
	Fixed slapo-accesslog on glued dbs (ITS#5907)
	Fixed slapo-dynlist handling of flags (ITS#5898)
	Fixed slapo-memberof multiple instantiation (ITS#5903)
	Fixed slapo-pcache filter sorting (ITS#5756)
	Fixed slapo-ppolicy to not be global (ITS#5858)
	Fixed slapo-rwm double free (ITS#5923)
	Fixed slapo-rwm with back-config (ITS#5906)
	Fixed slapo-rwm olcRwmRewrite modification (ITS#5940)
	Added slapo-rwm newRDN rewriting (ITS#5834)
	Added slapadd progress meter (ITS#5922)
	Updated contrib/addpartial module (ITS#5764)
	Added contrib/cloak module (ITS#5872)
	Added contrib/smbk5pwd gcrypt support (ITS#5410)
	Added contrib/passwd sha2 support (ITS#5660)
	Build Environment
		Fixed test006 appending to log file (ITS#5910)
		Fixed test036,test039 behavior on error (ITS#5893)
		Fixed test048 sed pathname substitution (ITS#5910)
		Fixed test049,test050 to work on windows (ITS#5842)
		Updated test017,test018,test019 to cover more cases (ITS#5883)
		Removed patch for BerkeleyDB 4.7.25 (Official patch available)
		Fixed MSVC 9.0 build issues (ITS#5888)
		Fixed gss detection on Solaris (ITS#5846)
		Fixed uuid_create/uuid_unparse_lower detection (ITS#5905)
		Fixed liblutil tavl_delete to macroize constants (ITS#5909)
	Documentation
		admin24 added limits chapter (ITS#5818)
		admin24 access-control clarify global ACLS (ITS#5851,ITS#5852)
		admin24 search on nested naming contexts (ITS#5788)
		admin24 consistent loglevel documentation (ITS#5904)
		slapd-bdb/hdb expansion on dncachesize behavior (ITS#5721)
		slapo-constraint(5) example fix (ITS#5895)
		slap*(8) man pages should mention slapd-config (ITS#5828)
		slapacl(8c) fix wording (ITS#5918)
		slapd(8) document sid (ITS#5873)
		slapd.access(5) clarify global ACLS (ITS#5851,ITS#5852)
		slapadd/cat/index(8) note -n 0 for slapd-config (ITS#5891)
		Added SEE ALSO slapd-config(5) to relevant man pages (ITS#5914)

OpenLDAP 2.4.13 Release (2008/11/24)
	Added libldap dereference control support (ITS#5768)
	Fixed libldap parameter checking (ITS#5817)
	Fixed liblutil hex conversion (ITS#5699)
	Fixed liblutil returning undefined data (ITS#5748)
	Fixed libldap error code return (ITS#5762)
	Fixed libldap interaction with GnuTLS CN IP-based matches (ITS#5789)
	Fixed libldap MAXHOSTNAMELEN typo (ITS#5815)
	Fixed libldap Ipv6 detection (ITS#5739)
	Fixed libldap setuid usage with .ldaprc (ITS#4750)
	Fixed slapacl crasher (ITS#5820)
	Fixed slapd acl checks on ADD (ITS#4556,ITS#5723)
	Fixed slapd acl application to newly created backends (ITS#5572)
	Fixed slapd #if/#elif issues in thread includes (ITS#5824)
	Added slapd keyword add_content_acl for add checks (ITS#4556,ITS#5723)
	Fixed slapd concurrent access to connections (ITS#5814)
	Fixed slapd config backend olcLogFile support (ITS#5765)
	Fixed slapd contextCSN pending list (ITS#5709)
	Fixed slapd control criticality (ITS#5785)
	Added slapd dn.this search limits (ITS#5734)
	Fixed slapd error status on shutdown (ITS#5745)
	Fixed slapd filter substring handling (ITS#5803)
	Fixed slapd nameUIDPretty bitstring parsing (ITS#5750)
	Fixed slapd null termination of password (ITS#5794)
	Fixed slapd overlay/database open with real structure (ITS#5724)
	Fixed slapd parsing of read entry control (ITS#5741)
	Added slapd PMI schema (ITS#5695)
	Added slapd private databases in global overlays (ITS#5735,ITS#5736)
	Fixed slapd rdn generation when it isn't specified (ITS#5819)
	Fixed slapd slapd.conf validation to LDIF (ITS#5755)
	Fixed slapd startup scan for CSN (ITS#5640)
	Fixed slapd statslog printing of released entry (ITS#5775)
	Added slapd support for certificateListExactMatch (ITS#5700)
	Fixed slapd syncrepl event loss (ITS#5710)
	Fixed slapd syncrepl MOD of attrs with no EQ rule (ITS#5781)
	Fixed slapd syncrepl rename handling (ITS#5809)
	Fixed slapd syncrepl schema checking (ITS#5798)
	Fixed slapd syncrepl filter leak (ITS#5826)
	Fixed slapd undef promote (ITS#5783,ITS#5795)
	Added slapd What failed? control (ITS#5784)
	Fixed slapd-bdb/hdb invalid db crash (ITS#5698)
	Added slapd-bdb/hdb dbpagesize keyword
	Added slapd-bdb/hdb checksum keyword
	Fixed slapd-bdb/hdb indexing of entryDN (ITS#5790)
	Fixed slapd-bdb/hdb lookup of entryDN with equality (ITS#5791)
	Fixed slapd-bdb/hdb uninitialized bli_flag
	Fixed slapd-ldap snprintf buffer overflow test (ITS#4467)
	Fixed slapd-ldap search stop on minor failure (ITS#5816)
	Fixed slapd-ldif file rename on windows (ITS#5774)
	Fixed slapd-null read controls support (ITS#5757)
	Fixed slapd-sql value length with right index (ITS#5779)
	Fixed slapo-chain/translucent back-config support (ITS#5736)
	Fixed slapo-chain SEGV with search references (ITS#5742)
	Fixed slapo-collect compile with C89 (ITS#5747)
	Added slapo-constraint support for LDAP URI constraints (ITS#5704)
	Added slapo-constraint support for constraining rename (ITS#5703)
	Added slapo-constraint support for relax control (ITS#5705)
	Added slapo-constraint "set" type (ITS#5702)
	Fixed slapo-constraint filter parsing error (ITS#5751)
	Added slapo-dynlist URI restriction ability (ITS#5761)
	Fixed slapo-ppolicy unaligned BerElement (ITS#5770)
	Fixed slapo-rwm objectClass preservation (ITS#5760)
	Fixed slapo-rwm rewriting undefined filter (ITS#5731)
	Fixed slapo-rwm rewritten DN-valued attrs (ITS#5772)
	Fixed slapo-rwm reusing freed filter (ITS#5732)
	Fixed slapo-rwm entry get (ITS#5773)
	Fixed slapo-syncprov runqueue removal (ITS#5776)
	Fixed slapo-syncprov unreplicatable ops (ITS#5709)
	Fixed slapo-syncprov psearch leak (ITS#5827)
	Added slapo-translucent try local bind when remote fails (ITS#5656)
	Added slapo-translucent support for PasswordModify exop (ITS#5656)
	Fixed tools simple bind without SASL (ITS#5753)
	Fixed tools unaligned BerElement (ITS#5770)
	Fixed contrib nssov crash on empty groups (ITS#5800)
	Fixed contrib nssov crash with nssov-map (ITS#5801)
	Fixed contrib nssov filter and search limits (ITS#5802)
	Added contrib smbk5pwd honor principal expiration (ITS#5766)
	Build Environment
		Added ldapurl command
		Added slapd GSSAPI refactoring (ITS#5369)
		Added slapo-deref overlay (ITS#5768)
	Documentation
		admin24 added olcLimits to example (ITS#5746)
		admin24 consolidated on whitespace (ITS#5759)
		slapd.conf,config(5) subordinate/olcSubordinate keyword (ITS#5788)
		slapd.conf(5) fixed disable keyword for limits (ITS#5821)
		slapo-dds(5) manageDIT to relax (ITS#5780)
		slapo-dds(5) rootdn requirement added (ITS#5811)
		slapo-syncprov(5) sessionlog clarification (ITS#5806)

OpenLDAP 2.4.12 Release (2008/10/12)
	Fixed libldap ldap_utf8_strchar arguments (ITS#5720)
	Fixed libldap TLS_CRLFILE (ITS#5677)
	Fixed liblutil executables on Windows (ITS#5604)
	Fixed liblutil microsecond overflows on Windows (ITS#5668)
	Fixed librewrite memory handling (ITS#5691)
	Fixed slapd aci performance (ITS#5636)
	Fixed slapd aci's with sets (ITS#5627)
	Fixed slapd attribute leak (ITS#5683)
	Fixed slapd config backend with index greater than sibs (ITS#5684)
	Fixed slapd custom attribute inheritance (ITS#5642)
	Fixed slapd dynacl mask handling (ITS#5637)
	Fixed slapd firstComponentMatch normalization (ITS#5634)
	Added slapd caseIgnoreListMatch (ITS#5608)
	Fixed slapd connection events enabled twice (ITS#5725)
	Fixed slapd memory handling (ITS#5691)
	Fixed slapd objectClass canonicalization (ITS#5681)
	Fixed slapd objectClass termination (ITS#5682)
	Fixed slapd overlay control registration (ITS#5649)
	Fixed slapd runqueue checking (ITS#5726)
	Fixed slapd spurious text output (ITS#5688)
	Fixed slapd socket closing on Windows (ITS#5606)
	Fixed slapd sortvals comparison (ITS#5578)
	Added slapd substitute syntax support (ITS#5663)
	Fixed slapd syncrepl contextCSN detection (ITS#5675)
	Fixed slapd syncrepl error logging (ITS#5618)
	Fixed slapd syncrepl runqueue interval (ITS#5719)
	Fixed slapd-bdb entry return if attr not present (ITS#5650)
	Fixed slapd-bdb olcDbMode syntax (ITS#5713)
	Fixed slapd-bdb/hdb release search entries earlier (ITS#5728,ITS#5730)
	Fixed slapd-bdb/hdb subtree search with empty suffix (ITS#5729)
	Fixed slapd-dnssrv memory handling (ITS#5691)
	Fixed slapd-ldap,slapd-meta invalid filter behavior (ITS#5614)
	Fixed slapd-meta memory handling (ITS#5691)
	Fixed slapd-meta objectClass filtering (ITS#5647)
	Fixed slapd-meta quarantine behavior (ITS#5592)
	Added slapd-ndb experimental backend
	Fixed slapd-relay initialization (ITS#5643)
	Fixed slapd-sql freeing of connection (ITS#5607)
	Fixed slapd-sql fault on NULL fields (ITS#5653)
	Fixed slapo-accesslog entryCSN generation on purge (ITS#5694)
	Fixed slapo-constraint string termination (ITS#5609)
	Fixed slapo-dynlist expansion with mapped attributes (ITS#5717)
	Fixed slapo-memberof internal operations DN (ITS#5622)
	Fixed slapo-pcache attrset crash (ITS#5665)
	Fixed slapo-pcache caching with invalid schema (ITS#5680)
	Fixed slapo-ppolicy control return on password modify exop (ITS#5711)
	Fixed slapo-rwm callback cleanup (ITS#5601,ITS#5687)
	Fixed slapo-rwm attr mapping and merging (ITS#5624)
	Fixed slapo-rwm objectClass filtering (ITS#5647)
	Fixed slapo-translucent back-config support (ITS#5689)
	Fixed slapo-translucent filter usage on merged entries (ITS#5679)
	Fixed slapo-unique filter validation (ITS#5581)
	Fixed slapo-unique suffix testing (ITS#5641)
	Build Environment
		Fixed ODBC library detection (ITS#5602)
		Removed pre-BerkeleyDB 4.4 support
		Added BerkeleyDB 4.7 support (ITS#5523)
		Included patch for BerkeleyDB 4.7.25 (build/db.4.7.25.patch)
		Added slapo-collect overlay with enhancements(ITS#5659)
	Documentation
		Added slapd-ldap(5), slapd-meta(5) noundeffilter (ITS#5614)
		Fixed slapd-ldap(5), slapd-meta(5), slapo-pcache(5) schema requirements (ITS#5680)
		Added slapo-collect(5) man page (ITS#5706)
		Added slapo-pcache(5) proxycheckcacheability option (ITS#5680)
		Added slapo-retcode(5) retcode.conf location (ITS#5633)
		admin24 dontusecopy control update (ITS#5718)
		admin24 guide updates (ITS#5616)
		admin24 octetString fix (ITS#5670)

OpenLDAP 2.4.11 Release (2008/07/16)
	Fixed liblber ber_get_next length decoding (ITS#5580)
	Added libldap assertion control (ITS#5560)
	Fixed libldap GnuTLS CRL result handling (ITS#5577)
	Fixed libldap GnuTLS SSF computation (ITS#5585)
	Fixed liblutil missing return code (ITS#5615)
	Fixed slapd cert serial number parsing (ITS#5588)
	Fixed slapd check for structural_class failures (ITS#5540)
	Fixed slapd config backend renumbering (ITS#5571)
	Fixed slapd configContext OID (ITS#5383)
	Fixed slapd crash with no listeners (ITS#5563)
	Fixed slapd equality rules for olcRootDN/olcSchemaDN (ITS#5540)
	Fixed slapd sets memory leak (ITS#5557)
	Fixed slapd sortvals binary search (ITS#5578)
	Fixed slapd syncrepl updates with multiple masters (ITS#5597)
	Fixed slapd syncrepl superior objectClass delete/add (ITS#5600)
	Fixed slapd syncrepl/slapo-syncprov contextCSN updates as internal ops (ITS#5596)
	Added slapd-ldap/slapd-meta option to filter out search references (ITS#5593)
	Fixed slapd-meta link to slapd-ldap (ITS#5355)
	Fixed slapd-sock, back-shell buffer count (ITS#5558)
	Fixed slapo-dynlist dg attrs lookup (ITS#5583)
	Fixed slapo-dynlist entry release (ITS#5135)
	Fixed slapo-memberof replace handling (ITS#5584)
	Added slapo-nssov contrib module
	Fixed slapo-pcache handling of negative search caches (ITS#5546)
	Fixed slapo-ppolicy DNs with whitespaces (ITS#5552)
	Fixed slapo-ppolicy modify with internal ops (ITS#5569)
	Fixed slapo-syncprov ACL evaluation (ITS#5548)
	Fixed slapo-syncprov crash with delcsn (ITS#5589)
	Fixed slapo-syncprov full reload (ITS#5564)
	Fixed slapo-syncprov missing olcSpReloadHint attr(ITS#5591)
	Fixed slapo-unique filter normalization (ITS#5581)
	Fixed contrib smbk5pwd terminator (ITS#5575)
	Build Environment
		Fixed test048 to skip if threads is not available (ITS#5529)
	Documentation
		Added slapo-pcache(5) sizelimit caching (ITS#5559)
		Added slapd-access(5) add and delete privs (ITS#5566)
		admin24 GnuTLS documentation (ITS#5554)

OpenLDAP 2.4.10 Release (2008/06/08)
	Fixed libldap file descriptor leak with SELinux (ITS#5507)
	Fixed libldap ld_defconn cleanup if it was freed (ITS#5518, ITS#5525)
	Fixed libldap msgid handling (ITS#5318)
	Fixed libldap t61 infinite loop (ITS#5542)
	Fixed libldap_r missing stubs (ITS#5519)
	Fixed slapd initialization of sr_msgid, rs->sr_tag (ITS#5461)
	Fixed slapd missing termination of integerFilter keys (ITS#5503)
	Fixed slapd multiple attrs in URI (ITS#5516)
	Fixed slapd sasl_ssf retrieval (ITS#5403)
	Fixed slapd socket assert (ITS#5489)
	Fixed slapd syncrepl cookie (ITS#5536)
	Fixed slapd-bdb/hdb MAXPATHLEN (ITS#5531)
	Fixed slapd-bdb indexing in single ADD/MOD (ITS#5521)
	Fixed slapd-ldap entry_get() op-dependent behavior (ITS#5513)
	Fixed slapd-meta quarantine crasher (ITS#5522)
	Fixed slapo-refint to allow setting modifiers name (ITS#5505)
	Fixed slapo-syncprov contextCSN passing on syncprov consumers (ITS#5488)
	Fixed slapo-syncprov csn update with delta-syncrepl (ITS#5493)
	Fixed slapo-syncprov op2.o_extra reset (ITS#5501, #5506)
	Fixed slapo-syncprov searching wrong backend (ITS#5487)
	Fixed slapo-syncprov sending ops without queued CSNs (ITS#5465)
	Fixed slapo-syncprov max csn search on startup (ITS#5537)
	Fixed slapo-unique config structs (ITS#5526)
	Fixed slapo-unique filter terminator (ITS#5511)
	Documentation
		Add search privileges documentation (ITS#5512)
		admin24 security document updates (ITS#5524)

OpenLDAP 2.4.9 Release (2008/05/07)
	Fixed libldap to use unsigned port (ITS#5436)
	Fixed libldap error message for missing close paren (ITS#5458)
	Fixed libldap_r tpool pause checks (ITS#5364, #5407)
	Fixed slapcat error checking (ITS#5387)
	Fixed slapd abstract objectClass inheritance check (ITS#5474)
	Fixed slapd add operations requiring naming attrs (ITS#5412)
	Fixed slapd connection handling (ITS#5469)
	Fixed slapd delta-syncrepl resync (ITS#5378)
	Fixed slapd frontendDB backend selection (ITS#5419)
	Fixed slapd pagedresults stale state (ITS#5409)
	Fixed slapd pointer dereference (ITS#5388)
	Fixed slapd null argument dereference (ITS#5435)
	Fixed slapd REP_ENTRY flags (ITS#5340)
	Fixed slapd sets attribute description parsing (ITS#5402)
	Fixed slapd syncrepl hang on back-config (ITS#5407)
	Fixed slapd syncrepl compare_csns crash (ITS#5413)
	Fixed slapd syncrepl contextCSN update clash (ITS#5426)
	Fixed slapd syncrepl/glue failure (ITS#5430)
	Fixed slapd syncrepl crash on empty CSN (ITS#5432)
	Fixed slapd syncrepl refreshAndPersist (ITS#5454)
	Fixed slapd syncrepl modrdn processing (ITS#5397)
	Fixed slapd syncrepl MMR partial refresh (ITS#5470)
	Fixed slapd value list termination (ITS#5450)
	Fixed slapd/slapo-accesslog rq mutex usage (ITS#5442)
	Fixed slapd-bdb ID_NOCACHE handling (ITS#5439)
	Fixed slapd-bdb entryinfo state if db_lock fails (ITS#5455)
	Fixed slapd-bdb referral rewrite (ITS#5339)
	Fixed slapd-config overlay stacking (ITS#5346)
	Fixed slapd-config attribute publishing (ITS#5383)
	Fixed slapd-ldap connection handler (ITS#5404)
	Fixed slapd-ldif file name handling & multi-suffix/dir catch (ITS#5408)
	Fixed slapd-meta connections on error (ITS#5440)
	Fixed slapd-meta crash on search (ITS#5481)
	Fixed slapo-accesslog null callback stack crash (ITS#5490)
	Fixed slapo-auditlog unnecessary syscall (ITS#5441)
	Added slapo-dynlist mapping to dynamic attrs generation (ITS#5466)
	Fixed slapo-refint dnSubtreeMatch (ITS#5427)
	Fixed slapo-refint global referential integrity (ITS#5428)
	Fixed slapo-syncprov psearch on closed connection (ITS#5401)
	Fixed slapo-syncprov psearch task delay (ITS#5405)
	Fixed slapo-syncprov psearch filter identity (ITS#5418, #5486)
	Fixed slapo-syncprov/glue contextCSN update (ITS#5433)
	Fixed slapo-syncprov/glue search ops (ITS#5434)
	Fixed slapo-syncprov null cookie (ITS#5437,#5444)
	Fixed slapo-syncprov double-free (ITS#5445)
	Fixed slapo-syncprov free syncop correctly (ITS#5484)
	Fixed slapo-syncprov glue deadlock (ITS#5451)
	Build Environment
		Fixed leave function naming for OSF1 (ITS#5411)
	Documentation
		Fixed slapd.access(5) authz-regexp documented behavior (ITS#5400)
		Fixed slapd.meta(5) idassert-* documentation (ITS#5406)
		admin24 delta-syncrepl documentation (ITS#5476)
		admin24 set documentation (ITS#5278,ITS#5279,ITS#5281)
		admin24 slapo-ppolicy documentation (ITS#5479)
		admin24 syncrepl directives update (ITS#5425)

OpenLDAP 2.4.8 Release (2008/02/19)
	Fixed ldapmodify verbose logging (ITS#5247)
	Fixed ldapdelete with sizelimit (ITS#5294)
	Fixed ldapdelete with subentries control (ITS#5293)
	Fixed ldapsearch exit code init (ITS#5317)
	Fixed libldap extended decoding (ITS#5304)
	Fixed libldap filter abort (ITS#5300)
	Fixed libldap ldap_parse_sasl_bind_result (ITS#5263)
	Fixed libldap result codes for open (ITS#5338)
	Fixed libldap search timeout crash (ITS#5291)
	Fixed libldap paged results crash (ITS#5315)
	Fixed libldap cipher suite with GnuTLS (ITS#5341)
	Fixed slapd support for 2.1 CSN (ITS#5348)
	Fixed slapd include handling (ITS#5276)
	Fixed slapd modrdn check for valid new DN (ITS#5344)
	Fixed slapd multi-step SASL binds (ITS#5298)
	Fixed slapd non-atomic signal variables (ITS#5248)
	Fixed slapd overlay ordering when moving to slapd.d (ITS#5284)
	Fixed slapd NULL printf (ITS#5264)	
	Fixed slapd NULL set values (ITS#5286)
	Fixed slapd SEGV with SASL/OTP (ITS#5259)
	Fixed slapd timestamp race condition (ITS#5370)
	Fixed slapd cn=config crash on delete (ITS#5343)
	Fixed slapd cn=config global acls (ITS#5352)
	Fixed slapd truncated cookie (ITS#5362)
	Fixed slapd sasl with CLEARTEXT (ITS#5368)
	Fixed slapd str2entry with no attrs (ITS#5308)
	Fixed slapd TLSVerifyClient default (ITS#5360)
	Fixed slapd HAVE_TLS dependency (ITS#5379)
	Fixed slapd delta-syncrepl refresh mode (ITS#5376)
	Fixed slapd ACL sets URI attrs (ITS#5384)
	Fixed slapd invalid entryUUID filter (ITS#5386)
	Fixed slapd-bdb idlcache on adds (ITS#5086)
	Fixed slapd-bdb crash with modrdn (ITS#5358)
	Fixed slapd-bdb SEGV with bdb4.6 (ITS#5322)
	Fixed slapd-bdb modrdn to same dn (ITS#5319)
	Fixed slapd-bdb MMR (ITS#5332)
	Added slapd-bdb/slapd-hdb DB encryption (ITS#5359)
	Fixed slapd-ldif delete (ITS#5265)
	Fixed slapd-meta link to slapd-ldap (ITS#5355)
	Fixed slapd-meta setting of sm_nvalues (ITS#5375)
	Fixed slapd-monitor crash (ITS#5311)
	Fixed slapd-relay compare (ITS#4937)
	Added slapd-sock (ITS#4094)
	Fixed slapo-accesslog cleanup on successful response (ITS#5374)
	Added slapo-autogroup contrib module (ITS#5145)
	Added slapo-constraint cross-attribute constraints (ITS#4987)
	Fixed slapo-memberof objectClass inheritance (ITS#5299)
	Added slapo-memberof global overlay support (ITS#5301)
	Fixed slapo-memberof leak (ITS#5302)
	Fixed slapo-ppolicy only password check with policy (ITS#5285)
	Fixed slapo-ppolicy del/replace password without new one (ITS#5373)
	Fixed slapo-syncprov hang on checkpoint (ITS#5261)
	Added slapo-translucent local searching (ITS#5283)
	Removed lint
	Build Environment
		Fixed libldap_r threaded library linking (ITS#4982)
		Fixed libldap use of %n (ITS#5324)
		Fixed test047 to skip if rwm is not available (ITS#5292)
	Documentation
		DB_CONFIG.example URL wrong in comments (ITS#5288)
		Add cn=config example for auditlog (ITS#5245)
		ldapmodify(1) clarification for RFC2849 (ITS#5312)

OpenLDAP 2.4.7 Release (2007/12/14)
	Added slapd ordered indexing of integer attributes (ITS#5239)
	Fixed slapd paged results control handling (ITS#5191)
	Fixed slapd sasl-host parsing (ITS#5209)
	Fixed slapd filter normalization (ITS#5212)
	Fixed slapd multiple suffix checking (ITS#5186)
	Fixed slapd paged results handling when using rootdn (ITS#5230)
	Fixed slapd syncrepl presentlist handling (ITS#5231)
	Fixed slapd core schema 'c' definition for RFC4519 (ITS#5236)
	Fixed slapd 3-way Multi-Master Replication (ITS#5238)
	Fixed slapd hash collisions in index slots (ITS#5183)
	Fixed slapd replication of dSAOperation attributes (ITS#5268)
	Fixed slapadd contextCSN updating (ITS#5225)
	Fixed slapd-bdb/hdb to report and fail on internal errors (ITS#5232)
	Fixed slapd-bdb/hdb dn2entry lock bug (ITS#5257)
	Fixed slapd-bdb/hdb dn2id lock bug (ITS#5262)
	Fixed slapd-hdb caching on rename ops (ITS#5221)
	Fixed slapo-accesslog abandoned op cleanup (ITS#5161)
	Fixed slapo-dds deleting from nonexistent db (ITS#5267)
	Fixed slapo-memberOf deleted values saving (ITS#5258)
	Fixed slapo-pcache op->o_abandon handling (ITS#5187)
	Fixed slapo-ppolicy single password check on modify (ITS#5146)
	Fixed slapo-ppolicy internal search (ITS#5235)
	Fixed slapo-syncprov refresh and persist cookie sending (ITS#5210)
	Fixed slapo-syncprov ignore invalid cookies (ITS#5211)
	Fixed slapo-translucent interaction with slapo-rwm (ITS#4889)
	Updated contrib addpartial module (ITS#3593)
	Build Environment
		Fixed liblber socket library linking (ITS#5224)
		Fixed Windows slapd.def rules (ITS#5215)
	Documentation
		Fixed grammar errors (ITS#5223)
		Refint overlay doc contribution (ITS#5217)
		Dynamic Lists doc contribution to the admin guide (ITS#5216)
		Fixed ldappasswd(1) and ldapmodify(1) typos (ITS#5269)
		Fixed domain factor typos (ITS#5237)
		Fixed slapd.conf(5) maxderefdepth default value typo (ITS#5200)
		Clarified slapd.conf(5) limits issues in syncrepl (ITS#5243)
		Fixed slapd-config(5) maxderefdepth default value typo (ITS#5200)
		Patches for minor typos in man pages (ITS#5228)
		admin24/replication.sdf spelling (ITS#5270)


OpenLDAP 2.4.6 Release (2007/10/31)
	Initial release for "general use".
alt-openldap11/ANNOUNCEMENT000064400000007374150410163160011113 0ustar00A N N O U N C E M E N T -- OpenLDAP 2.4

    The OpenLDAP Project is pleased to announce the availability
    of OpenLDAP Software 2.4, a suite of the Lightweight Directory
    Access Protocol (v3) servers, clients, utilities, and
    development tools.

    This release contains the following major enhancements:

        * Slapd(8) enhancements
            - Syncrepl enhancements, including push-mode and
              Multi-Master support
            - Dynamic configuration enhancements, including
              online schema editing and full access control
            - Dynamic monitoring enhancements, including
              cache usage information
        * New overlays
            - Attribute value constraints
            - Dynamic Directory Services (RFC2589)
            - Reverse Group Membership maintenance (memberof)
        * Clients and tools
            - Full support of request/response controls
            - New ldapexop tool for arbitrary extend operations
            - Support of DNS SRV records for default server
        * Significant performance enhancements throughout
            the client and server code base
        * Multiple new features in libldap and liblber
        * Expanded documentation
            - Function-complete manual pages
            - Numerous new examples in the Admin Guide

    This release includes the following major components:

        * slapd - a stand-alone LDAP directory server
        * -lldap - a LDAP client library
        * -llber - a lightweight BER/DER encoding/decoding library
        * LDIF tools - data conversion tools for use with slapd
        * LDAP tools - A collection of command line LDAP utilities
        * Admin Guide, Manual Pages - associated documentation

    In addition, there are some contributed components:

        * LDAPC++ - a LDAP C++ SDK
        * Various slapd modules and slapi plugins


ACKNOWLEDGEMENTS

    OpenLDAP Software is developed by the OpenLDAP Project.  The
    Project consists of a team of volunteers who use the
    Internet to coordinate their activities.  The Project is
    an organized activity of the OpenLDAP Foundation.

    OpenLDAP Software is derived from University of Michigan LDAP,
    release 3.3.


AVAILABILITY

    This software is available under the OpenLDAP Public License,
    an non-restrictive, "free", open-source license.  Download
    information is available at:

        http://www.OpenLDAP.org/software/download/


SUPPORT

    OpenLDAP Software is user supported:

        http://www.openldap.org/support/

    The OpenLDAP Administrator's Guide, which includes quick
    start instructions, is available at:

        http://www.openldap.org/doc/admin/

    The project maintains a FAQ which you may find useful:

        http://www.openldap.org/faq/

    In addition, there are also a number of discussion lists
    related to OpenLDAP Software.  A list of mailing lists is
    available at:

        http://www.OpenLDAP.org/lists/

    To report bugs, please use project's Issue Tracking System:

        http://www.openldap.org/its/

    The OpenLDAP home page containing lots of interesting information
    and online documentation is available at this URL:

        http://www.OpenLDAP.org/


SUPPORTED PLATFORMS

    This release has been ported to many UNIX (and UNIX-like)
    platforms including Darwin, FreeBSD, Linux, NetBSD, OpenBSD
    and most commercial UNIX systems.  The release has also been
    ported (in part or in whole) to other platforms including
    Apple MacOS X, IBM zOS, and Microsoft Windows NT/2000/etc.

---
OpenLDAP is a registered trademark of the OpenLDAP Foundation.

Copyright 1999-2018 The OpenLDAP Foundation, Redwood City,
California, USA.  All Rights Reserved.  Permission to copy and
distribute verbatim copies of this document is granted.
alt-openldap11/README000064400000006646150410163160010157 0ustar00OpenLDAP 2.4 README
    For a description of what this distribution contains, see the
    ANNOUNCEMENT file in this directory.  For a description of
    changes from previous releases, see the CHANGES file in this
    directory.

    This is 2.4 release, it includes significant changes from prior
    releases.

REQUIRED SOFTWARE
    Building OpenLDAP Software requires a number of software packages
    to be preinstalled.  Additional information regarding prerequisite
    software can be found in the OpenLDAP Administrator's Guide.

    Base system (libraries and tools):
        Standard C compiler (required)
        Cyrus SASL 2.1.21+ (recommended)
        OpenSSL 0.9.7+ (recommended)
        Reentrant POSIX REGEX software (required)

    SLAPD:
        BDB and HDB backends require Oracle Berkeley DB 4.4 - 4.8,
	or 5.0 - 5.1.  It is highly recommended to apply the
        patches from Oracle for a given release.

    CLIENTS/CONTRIB ware:
        Depends on package.  See per package README.


MAKING AND INSTALLING THE DISTRIBUTION
    Please see the INSTALL file for basic instructions.  More
    detailed instructions can be found in the OpenLDAP Admnistrator's
    Guide (see DOCUMENTATION section).


DOCUMENTATION
    The OpenLDAP Administrator's Guide is available in the
    guide.html file in the doc/guide/admin directory.  The
    guide and a number of other documents are available at
    <http://www.openldap.org/doc/admin/guide.html>.

    The distribution also includes manual pages for most programs
    and library APIs.  See ldap(3) for details.

    The OpenLDAP website is available and contains the latest LDAP
    news, releases announcements, pointers to other LDAP resources,
    etc..  It is located at <http://www.OpenLDAP.org/>.

    The OpenLDAP Software FAQ is available at
    <http://www.openldap.org/faq/>.


SUPPORT / FEEDBACK / PROBLEM REPORTS / DISCUSSIONS
    OpenLDAP Software is user supported.  If you have problems, please
    review the OpenLDAP FAQ <http://www.openldap.org/faq/> and
    archives of the OpenLDAP-software and OpenLDAP-bugs mailing lists
    <http://www.openldap.org/lists/>.  If you cannot find the answer,
    please enquire on the OpenLDAP-software list.

    Issues, such as bug reports, should be reported using our
    Issue Tracking System <http://www.OpenLDAP.org/its/>.  Do not
    use this system for software enquiries.  Please direct these
    to an appropriate mailing list.


CONTRIBUTING
    See <http://www.openldap.org/devel/contributing.html> for
    information regarding how to contribute code or documentation
    to the OpenLDAP Project for inclusion in OpenLDAP Software.
    While you are encouraged to coordinate and discuss the development
    activities on the <openldap-devel@openldap.org> mailing list
    prior to submission, it is noted that contributions must be
    submitted using the Issue Tracking System
    <http://www.openldap.org/its/> to be considered.

---
$OpenLDAP$

This work is part of OpenLDAP Software <http://www.openldap.org/>.

Copyright 1998-2018 The OpenLDAP Foundation.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted only as authorized by the OpenLDAP
Public License.

A copy of this license is available in the file LICENSE in the
top-level directory of the distribution or, alternatively, at
<http://www.OpenLDAP.org/license.html>.

OpenLDAP is a registered trademark of the OpenLDAP Foundation.
alt-openldap11-devel/rfc/rfc2294.txt000064400000053053150410163160012774 0ustar00





Network Working Group                                            S. Kille
Request for Comments: 2294                                     Isode Ltd.
Obsoletes: 1836                                                March 1998
Category: Standards Track


             Representing the O/R Address hierarchy in the
                    X.500 Directory Information Tree

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

Abstract

   This document defines a representation of the O/R Address hierarchy
   in the Directory Information Tree [6, 1].  This is useful for a range
   of purposes, including:

    o  Support for MHS Routing [4].

    o  Support for X.400/RFC 822 address mappings [2, 5].

   Please send comments to the author or to the discussion group <mhs-
   ds@mercury.udev.cdc.com>.


















Kille                       Standards Track                     [Page 1]

RFC 2294               Directory Information Tree             March 1998


                 Object Class               Mandatory
                 ------------               ---------
                 mHSCountry                 M
                 aDMD                       M
                 pRMD                       O
                 mHSX121                    O
                 mHSNumericUserIdentifier   O
                 mHSOrganization            O
                 mHSOrganizationalUnit      O
                 mHSPerson                  O
                 mHSNamedObject             O
                 mHSTerminalID              O
                 mHSDomainDefinedAttribute  O

         Table 1:  Order of O/R Address Directory Components

1  The O/R Address Hierarchy

   An O/R Address hierarchy is represented in the X.500 directory by
   associating directory name components with O/R Address components.
   An example of this is given in Figure 1.  The object classes and
   attributes required to support this representation are defined in
   Figure 2.  The schema, which defines the hierarchy in which these
   objects are represented in the directory information tree is
   specified in Table 1.  A given object class defined in the table will
   always be higher in the DIT than an object class defined lower down
   the table.  Valid combinations of O/R Address components are defined
   in X.400.























Kille                       Standards Track                     [Page 2]

RFC 2294               Directory Information Tree             March 1998


                                  /\
                                 /   \
                    C=GB        /      \   Numeric-C=234
                               /         \
                              /            \
                             /               \
                +------------+<----------------+----+
                | Country    |                 |    |
                +------------+                 +----+
                     /\
                    /   \
                   /      \
                  /         \
     ADMD=" "    /            \  ADMD=Gold 400
     +-------------+         +------------+
     |   ADMD      |         |   ADMD     |
     +-------------+         +------------+
           \                     \
             \                     \
               \ PRMD=UK.AC          \ PRMD=UK.AC
                 \                     \
                +----------+             +----+
                |  PRMD    |< -----------|    |
                +----------+             +----+
                     /
                    /
                 O=UCL
                  /
                 /
     +------------+
     | MHS-Org    |
     +------------+
          \
            \  OU=CS
              \
                \
              +-----------+
              | MHS-OU    |
              +-----------+


                    Figure 1:  Example O/R Address Tree









Kille                       Standards Track                     [Page 3]

RFC 2294               Directory Information Tree             March 1998


IMPORTS
  ub-domain-name-length, ub-organization-name-length,
  ub-organizational-unit-name-length, ub-common-name-length,
  ub-x121-address-length, ub-domain-defined-attribute-type-length,
  ub-domain-defined-attribute-value-length, ub-terminal-id-length,
  ub-numeric-user-id-length, ub-country-name-numeric-length,
  ub-surname-length, ub-given-name-length,  ub-initials-length,
  ub-generation-qualifier-length

    FROM MTSUpperBounds {joint-iso-ccitt mhs-motis(6) mts(3)        10
        modules(0) upper-bounds(3) };

mHSCountry OBJECT-CLASS ::= {
    SUBCLASS OF {country}
    MAY CONTAIN {mHSNumericCountryName}
    ID oc-mhs-country}

mHSNumericCountryName ATTRIBUTE ::= {
    WITH SYNTAX NumericString (SIZE (1..ub-country-name-numeric-length))
    SINGLE VALUE                                                    20
    ID at-mhs-numeric-country-name}

aDMD OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {aDMDName}
    ID oc-admd}

aDMDName ATTRIBUTE ::= {
    SUBTYPE OF name
    WITH SYNTAX DirectoryString {ub-domain-name-length}             30
    ID at-admd-name}

pRMD OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {pRMDName}
    ID oc-prmd}

pRMDName ATTRIBUTE ::= {
    SUBTYPE OF name
    WITH SYNTAX DirectoryString {ub-domain-name-length}             40
    ID at-prmd-name}

mHSOrganization OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {mHSOrganizationName }
    ID oc-mhs-organization}





Kille                       Standards Track                     [Page 4]

RFC 2294               Directory Information Tree             March 1998


mHSOrganizationName ATTRIBUTE ::= {
    SUBTYPE OF organizationName
    WITH SYNTAX DirectoryString {ub-organization-name-length}       50
    ID at-mhs-organization-name}

mHSOrganizationalUnit OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {mHSOrganizationalUnitName}
    ID oc-mhs-organizational-unit}

mHSOrganizationalUnitName ATTRIBUTE ::= {
    SUBTYPE OF organizationalUnitName                               60
    WITH SYNTAX DirectoryString {ub-organizational-unit-name-length}
    ID at-mhs-organizational-unit-name}

mHSPerson OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {mHSSurname}
    MAY CONTAIN {mHSGivenName|
                mHSInitials|
                mHSGenerationalQualifier}
    ID oc-mhs-person}                                               70

mHSSurname ATTRIBUTE ::= {
    SUBTYPE OF surname
    WITH SYNTAX DirectoryString {ub-surname-length}
    ID at-mhs-surname}

mHSGivenName ATTRIBUTE ::= {
    SUBTYPE OF givenName
    WITH SYNTAX DirectoryString {ub-given-name-length}
    ID at-mhs-given-name}                                           80

mHSInitials ATTRIBUTE ::= {
    SUBTYPE OF initials
    WITH SYNTAX DirectoryString {ub-initials-length}
    ID at-mhs-initials}

mHSGenerationQualifier ATTRIBUTE ::= {
    SUBTYPE OF generationQualifier
    WITH SYNTAX DirectoryString {ub-generation-qualifier-length}
    ID at-mhs-generation-qualifier}                                 90

mHSNamedObject OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {mHSCommonName}
    ID oc-mhs-named-object}




Kille                       Standards Track                     [Page 5]

RFC 2294               Directory Information Tree             March 1998


mHSCommonName ATTRIBUTE ::= {
    SUBTYPE OF commonName
    WITH SYNTAX DirectoryString {ub-common-name-length}
    ID at-mhs-common-name}                                         100

mHSX121 OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {mHSX121Address}
    ID oc-mhs-x121}

mHSX121Address ATTRIBUTE ::= {
    SUBTYPE OF name
    WITH SYNTAX DirectoryString {ub-x121-address-length}
    ID at-x121-address}                                            110

mHSDomainDefinedAttribute OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {
        mHSDomainDefinedAttributeType|
        mHSDomainDefinedAttributeValue}
    ID oc-mhs-domain-defined-attribute}

mHSDomainDefinedAttributeType ATTRIBUTE ::= {
    SUBTYPE OF name                                                120
    WITH SYNTAX DirectoryString {ub-domain-defined-attribute-type-length}
    SINGLE VALUE
    ID at-mhs-domain-defined-attribute-type}

mHSDomainDefinedAttributeValue ATTRIBUTE ::= {
    SUBTYPE OF name
    WITH SYNTAX DirectoryString {ub-domain-defined-attribute-value-length}
    SINGLE VALUE
    ID at-mhs-domain-defined-attribute-value}
                                                                   130

mHSTerminalID OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {mHSTerminalIDName}
    ID oc-mhs-terminal-id}

mHSTerminalIDName ATTRIBUTE ::= {
    SUBTYPE OF name
    WITH SYNTAX DirectoryString {ub-terminal-id-length}
    ID at-mhs-terminal-id-name}                                    140







Kille                       Standards Track                     [Page 6]

RFC 2294               Directory Information Tree             March 1998


mHSNumericUserIdentifier OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {mHSNumericUserIdentifierName}
    ID oc-mhs-numeric-user-id}

mHSNumericeUserIdentifierName ATTRIBUTE ::= {
    SUBTYPE OF name
    WITH SYNTAX DirectoryString {ub-numeric-user-id-length}        150
    ID at-mhs-numeric-user-id-name}

                    Figure 2:  O/R Address Hierarchy

   The hierarchy is defined so that:

   1.  The representation is defined so that it is straightforward to
       make a mechanical transformation in either direction.  This
       requires that each node is named by an attribute whose type can
       determine the mapping.

   2.  Where there are multiple domain defined attributes, the first
       in the sequence is the most significant.

   3.  Physical Delivery (postal) addresses are not represented in
       this hierarchy.  This is primarily because physical delivery can
       be handled by the Access Unit routing mechanisms defined in [4],
       and there is no need for this representation.

   4.  Terminal and network forms of address are not handled, except
       for X.121 form, which is useful for addressing faxes.

   5.  MHSCountry is defined as a subclass of Country, and so the
       same entry will be used for MHS Routing as for the rest of the
       DIT.

   6.  The numeric country code will be an alias.

   7.  ADMD will always be present in the hierarchy.  This is true
       in the case of " " and of "0".  This facilitates an easy
       mechanical transformation between the two forms of address.

   8.  Each node is named by the relevant part of the O/R Address.

   9.  Aliases may be used in other parts of the tree, in order to
       normalize alternate values.  Where an alias is used, the value of
       the alias should be present as an alternate value in the node
       aliased to.  Aliases may not be used for domain defined
       attributes.




Kille                       Standards Track                     [Page 7]

RFC 2294               Directory Information Tree             March 1998


   10. Domain Defined Attributes are named by a multi-valued RDN
       (Relative Distinguished Name), consisting of the type and value.
       This is done so that standard attribute syntaxes can be used.

   11. Where an O/R Address has a valid Printable String and T.61 form,
       both must be present, with one as an alias for the other.  This
       is so that direct lookup of the name will work, independent of
       the variant used.  When both are present in an O/R Address being
       looked up, either may be used to construct the distinguished
       name.

   12. Personal name is handled by use of the mHSPerson object class.
       Each of the components of the personal name will be present in
       the relative distinguished name, which will usually be multi-
       valued.

   The relationship between X.400 O/R Addresses and the X.400 Entries
   (Attribute Type and Object Class) are given in Table 2.  Where there
   are multiple Organizational Units or Domain Defined Attributes, each
   component is mapped onto a single X.500 entry.

   Note: When an X.121 address is used for addressing fax transmission,
       this may only be done relative to the PRMD or ADMD. This is in
       line with the current X.400 standards position.  This means that
       it is not possible to use this form of addressing for an
       organizational or departmental fax gateway service.

O/R Address  Object Class               Naming Attribute
-----------  ------------               ----------------
C            mHSCountry                 countryName
                                        or
                                        mHSNumericCountryName
A            aDMD                       aDMDName
P            pRMD                       pRMDName
O            mHSOrganization            mHSOrganizationName
OU/OU1/OU2   mHSOrganizationalUnit      mHSOrganizationalUnitName
OU3/OU4
PN           mHSPerson                  personName
CN           mHSNamedObject             mHSCommonName
X121         mHSX121                    mHSX121Address
T-ID         mHSTerminalID              mHSTerminalIDName
UA-ID        mHSNumericUserIdentifier   mHSNumericUserIdentifierName
DDA          mHSDomainDefinedAttribute  mHSDomainDefinedAttributeType
                                        and
                                        mHSDomainDefinedAttributeValue


          Table 2:  O/R Address relationship to Directory Name



Kille                       Standards Track                     [Page 8]

RFC 2294               Directory Information Tree             March 1998


2  Notation

   O/R Addresses are written in the standard X.400 Notation.
   Distinguished Names use the string representation of distinguished
   names defined in [3].  The keywords used for the attributes defined
   in this specification are given in Table 3.

3  Example Representation

   The O/R Address:

   I=S; S=Kille; OU1=CS; O=UCL,
   P=UK.AC; A=Gold 400; C=GB;


   would be represented in the directory as:

   MHS-I=S + MHS-S=Kille, MHS-OU=CS, MHS-O=UCL,


            Attribute                       Keyword
            ---------                       -------
            mHSNumericCountryName           MHS-Numeric-Country
            aDMDName                        ADMD
            pRMDName                        PRMD
            mHSOrganizationName             MHS-O
            mHSOrganizationalUnitName       MHS-OU
            mHSSurname                      MHS-S
            mHSGivenName                    MHS-G
            mHSInitials                     MHS-I
            mHSGenerationalQualifier        MHS-GQ
            mHSCommonName                   MHS-CN
            mHSX121Address                  MHS-X121
            mHSDomainDefinedAttributeType   MHS-DDA-Type
            mHSDomainDefinedAttributeValue  MHS-DDA-Value
            mHSTerminalIDName               MHS-T-ID
            mHSNumericeUserIdentifierName   MHS-UA-ID

              Table 3:  Keywords for String DN Representation


   PRMD=UK.AC, ADMD=Gold 400, C=GB

4  Mapping from O/R Address to Directory Name

   The primary application of this mapping is to take an X.400 encoded
   O/R Address and to generate an equivalent directory name.  This
   mapping is only used for selected types of O/R Address:



Kille                       Standards Track                     [Page 9]

RFC 2294               Directory Information Tree             March 1998


    o  Mnemonic form

    o  Numeric form

    o  Terminal form, where country is present and X121 addressing
       is used

   Other forms of O/R address are handled by Access Unit mechanisms.
   The O/R Address is treated as an ordered list, with the order as
   defined in Table 1.  For each O/R Address attribute, generate the
   equivalent directory naming attribute.  In most cases, the mapping is
   mechanical.  Printable String or Teletex encodings are chosen as
   appropriate.  Where both forms are present in the O/R Address, either
   form may be used to generate the distinguished name.  Both will be
   represented in the DIT. There are two special cases:

   1.  A DDA generates a multi-valued RDN

   2.  The Personal Name is mapped to a multi-valued RDN

   In many cases, an O/R Address will be provided, and only the higher
   components of the address will be represented in the DIT. In this
   case, the "longest possible match" should be returned.

5  Mapping from Directory Name to O/R Address

   The reverse mapping is also needed in some cases.  All of the naming
   attributes are unique, so the mapping is mechanically reversible.

6  Acknowledgments

   Acknowledgments for work on this document are given in [4].

References

   [1] The Directory --- overview of concepts, models and services,
       1993. CCITT X.500 Series Recommendations.

   [2] Kille, S., "MIXER (Mime Internet X.400 Enhanced Relay): Mapping
       between X.400 and RFC 822/MIME", RFC 2156, January 1998.

   [3] Kille, S., "A String Representation of Distinguished Names",
       RFC 1779, March 1995.

   [4] Kille, S., "Use of an X.500/LDAP directory to support MIXER address
       mapping", RFC 2164, January 1998.





Kille                       Standards Track                    [Page 10]

RFC 2294               Directory Information Tree             March 1998


   [5] Kille, S., "X.400-MHS use of the X.500 directory to support
       X.400-MHS routing", RFC 1801, June 1995.

   [6] CCITT recommendations X.400 / ISO 10021, April 1988. CCITT
       SG 5/VII / ISO/IEC JTC1, Message Handling:  System and Service
       Overview.

7  Security Considerations

   This protocol introduces no known security risks.

8  Author's Address

   Steve Kille
   Isode Ltd.
   The Dome
   The Square
   Richmond
   TW9 1DT
   England

   Phone:  +44-181-332-9091
   EMail:  S.Kille@ISODE.COM

   X.400:  I=S; S=Kille; P=ISODE; A=Mailnet; C=FI;


























Kille                       Standards Track                    [Page 11]

RFC 2294               Directory Information Tree             March 1998


A  Object Identifier Assignment

mhs-ds OBJECT IDENTIFIER ::= {iso(1) org(3) dod(6) internet(1) private(4)
          enterprises(1) isode-consortium (453) mhs-ds (7)}


tree OBJECT IDENTIFIER ::= {mhs-ds 2}

oc OBJECT IDENTIFIER ::= {tree 1}
at OBJECT IDENTIFIER ::= {tree 2}

oc-admd OBJECT IDENTIFIER ::= {oc 1}                                10
oc-mhs-country OBJECT IDENTIFIER ::= {oc 2}
oc-mhs-domain-defined-attribute OBJECT IDENTIFIER ::= {oc 3}
oc-mhs-named-object OBJECT IDENTIFIER ::= {oc 4}
oc-mhs-organization OBJECT IDENTIFIER ::= {oc 5}
oc-mhs-organizational-unit OBJECT IDENTIFIER ::= {oc 6}
oc-mhs-person OBJECT IDENTIFIER ::= {oc 7}
oc-mhs-x121 OBJECT IDENTIFIER ::= {oc 8}
oc-prmd OBJECT IDENTIFIER ::= {oc 9}
oc-mhs-terminal-id OBJECT IDENTIFIER ::= {oc 10}
oc-mhs-numeric-user-id OBJECT IDENTIFIER ::= {oc 11}                20

at-admd-name OBJECT IDENTIFIER ::= {at 1}
at-mhs-common-name OBJECT IDENTIFIER ::= {at 2}
at-mhs-domain-defined-attribute-type OBJECT IDENTIFIER ::= {at 3}
at-mhs-domain-defined-attribute-value OBJECT IDENTIFIER ::= {at 4}
at-mhs-numeric-country-name OBJECT IDENTIFIER ::= {at 5}
at-mhs-organization-name OBJECT IDENTIFIER ::= {at 6}
at-mhs-organizational-unit-name OBJECT IDENTIFIER ::= {at 7}
at-prmd-name OBJECT IDENTIFIER ::= {at 10}
at-x121-address OBJECT IDENTIFIER ::= {at 12}                       30
at-mhs-terminal-id-name OBJECT IDENTIFIER ::= {at 13}
at-mhs-numeric-user-id-name  OBJECT IDENTIFIER ::= {at 14}
at-mhs-surname OBJECT IDENTIFIER ::= {at 15}
at-mhs-given-name OBJECT IDENTIFIER ::= {at 16}
at-mhs-initials OBJECT IDENTIFIER ::= {at 17}
at-mhs-generation-qualifier OBJECT IDENTIFIER ::= {at 18}

                Figure 3:  Object Identifier Assignment











Kille                       Standards Track                    [Page 12]

RFC 2294               Directory Information Tree             March 1998


Full Copyright Statement

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
























Kille                       Standards Track                    [Page 13]

alt-openldap11-devel/rfc/rfc4523.txt000064400000125351150410163160012772 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4523                           OpenLDAP Foundation
Obsoletes: 2252, 2256, 2587                                    June 2006
Category: Standards Track


             Lightweight Directory Access Protocol (LDAP)
               Schema Definitions for X.509 Certificates

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

   Abstract

   This document describes schema for representing X.509 certificates,
   X.521 security information, and related elements in directories
   accessible using the Lightweight Directory Access Protocol (LDAP).
   The LDAP definitions for these X.509 and X.521 schema elements
   replace those provided in RFCs 2252 and 2256.

1.  Introduction

   This document provides LDAP [RFC4510] schema definitions [RFC4512]
   for a subset of elements specified in X.509 [X.509] and X.521
   [X.521], including attribute types for certificates, cross
   certificate pairs, and certificate revocation lists; matching rules
   to be used with these attribute types; and related object classes.
   LDAP syntax definitions are also provided for associated assertion
   and attribute values.

   As the semantics of these elements are as defined in X.509 and X.521,
   knowledge of X.509 and X.521 is necessary to make use of the LDAP
   schema definitions provided herein.

   This document, together with [RFC4510], obsoletes RFCs 2252 and 2256
   in their entirety.  The changes (in this document) made since RFC
   2252 and RFC 2256 include:

      -  addition of pkiUser, pkiCA, and deltaCRL classes;



Zeilenga                    Standards Track                     [Page 1]

RFC 4523                   LDAP X.509 Schema                   June 2006


      -  update of attribute types to include equality matching rules in
         accordance with their X.500 specifications;

      -  addition of certificate, certificate pair, certificate list,
         and algorithm identifier matching rules; and

      -  addition of LDAP syntax for assertion syntaxes for these
         matching rules.

   This document obsoletes RFC 2587.  The X.509 schema descriptions for
   LDAPv2 [RFC1777] are Historic, as is LDAPv2 [RFC3494].

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

   Schema definitions are provided using LDAP description formats
   [RFC4512].  Definitions provided here are formatted (line wrapped)
   for readability.

2.  Syntaxes

   This section describes various syntaxes used in LDAP to transfer
   certificates and related data types.

2.1.  Certificate

      ( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'X.509 Certificate' )

   A value of this syntax is an X.509 Certificate [X.509, clause 7].

   Due to changes made to the definition of a Certificate through time,
   no LDAP-specific encoding is defined for this syntax.  Values of this
   syntax SHOULD be encoded using Distinguished Encoding Rules (DER)
   [X.690] and MUST only be transferred using the ;binary transfer
   option [RFC4522]; that is, by requesting and returning values using
   attribute descriptions such as "userCertificate;binary".

   As values of this syntax contain digitally signed data, values of
   this syntax and the form of each value MUST be preserved as
   presented.

2.2.  CertificateList

      ( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'X.509 Certificate List' )

   A value of this syntax is an X.509 CertificateList [X.509, clause
   7.3].



Zeilenga                    Standards Track                     [Page 2]

RFC 4523                   LDAP X.509 Schema                   June 2006


   Due to changes made to the definition of a CertificateList through
   time, no LDAP-specific encoding is defined for this syntax.  Values
   of this syntax SHOULD be encoded using DER [X.690] and MUST only be
   transferred using the ;binary transfer option [RFC4522]; that is, by
   requesting and returning values using attribute descriptions such as
   "certificateRevocationList;binary".

   As values of this syntax contain digitally signed data, values of
   this syntax and the form of each value MUST be preserved as
   presented.

2.3.  CertificatePair

      ( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'X.509 Certificate Pair' )

   A value of this syntax is an X.509 CertificatePair [X.509, clause
   11.2.3].

   Due to changes made to the definition of an X.509 CertificatePair
   through time, no LDAP-specific encoding is defined for this syntax.
   Values of this syntax SHOULD be encoded using DER [X.690] and MUST
   only be transferred using the ;binary transfer option [RFC4522]; that
   is, by requesting and returning values using attribute descriptions
   such as "crossCertificatePair;binary".

   As values of this syntax contain digitally signed data, values of
   this syntax and the form of each value MUST be preserved as
   presented.

2.4.  SupportedAlgorithm

      ( 1.3.6.1.4.1.1466.115.121.1.49
           DESC 'X.509 Supported Algorithm' )

   A value of this syntax is an X.509 SupportedAlgorithm [X.509, clause
   11.2.7].

   Due to changes made to the definition of an X.509 SupportedAlgorithm
   through time, no LDAP-specific encoding is defined for this syntax.
   Values of this syntax SHOULD be encoded using DER [X.690] and MUST
   only be transferred using the ;binary transfer option [RFC4522]; that
   is, by requesting and returning values using attribute descriptions
   such as "supportedAlgorithms;binary".

   As values of this syntax contain digitally signed data, values of
   this syntax and the form of the value MUST be preserved as presented.





Zeilenga                    Standards Track                     [Page 3]

RFC 4523                   LDAP X.509 Schema                   June 2006


2.5.  CertificateExactAssertion

      ( 1.3.6.1.1.15.1 DESC 'X.509 Certificate Exact Assertion' )

   A value of this syntax is an X.509 CertificateExactAssertion [X.509,
   clause 11.3.1].  Values of this syntax MUST be encoded using the
   Generic String Encoding Rules (GSER) [RFC3641].  Appendix A.1
   provides an equivalent Augmented Backus-Naur Form (ABNF) [RFC4234]
   grammar for this syntax.

2.6.  CertificateAssertion

      ( 1.3.6.1.1.15.2 DESC 'X.509 Certificate Assertion' )

   A value of this syntax is an X.509 CertificateAssertion [X.509,
   clause 11.3.2].  Values of this syntax MUST be encoded using GSER
   [RFC3641].  Appendix A.2 provides an equivalent ABNF [RFC4234]
   grammar for this syntax.

2.7.  CertificatePairExactAssertion

      ( 1.3.6.1.1.15.3
           DESC 'X.509 Certificate Pair Exact Assertion' )

   A value of this syntax is an X.509 CertificatePairExactAssertion
   [X.509, clause 11.3.3].  Values of this syntax MUST be encoded using
   GSER [RFC3641].  Appendix A.3 provides an equivalent ABNF [RFC4234]
   grammar for this syntax.

2.8.  CertificatePairAssertion

      ( 1.3.6.1.1.15.4 DESC 'X.509 Certificate Pair Assertion' )

   A value of this syntax is an X.509 CertificatePairAssertion [X.509,
   clause 11.3.4].  Values of this syntax MUST be encoded using GSER
   [RFC3641].  Appendix A.4 provides an equivalent ABNF [RFC4234]
   grammar for this syntax.

2.9.  CertificateListExactAssertion

      ( 1.3.6.1.1.15.5
           DESC 'X.509 Certificate List Exact Assertion' )

   A value of this syntax is an X.509 CertificateListExactAssertion
   [X.509, clause 11.3.5].  Values of this syntax MUST be encoded using
   GSER [RFC3641].  Appendix A.5 provides an equivalent ABNF grammar for
   this syntax.




Zeilenga                    Standards Track                     [Page 4]

RFC 4523                   LDAP X.509 Schema                   June 2006


2.10.  CertificateListAssertion

      ( 1.3.6.1.1.15.6 DESC 'X.509 Certificate List Assertion' )

   A value of this syntax is an X.509 CertificateListAssertion [X.509,
   clause 11.3.6].  Values of this syntax MUST be encoded using GSER
   [RFC3641].  Appendix A.6 provides an equivalent ABNF [RFC4234]
   grammar for this syntax.

2.11.  AlgorithmIdentifier

      ( 1.3.6.1.1.15.7 DESC 'X.509 Algorithm Identifier' )

   A value of this syntax is an X.509 AlgorithmIdentifier [X.509, Clause
   7].  Values of this syntax MUST be encoded using GSER [RFC3641].

   Appendix A.7 provides an equivalent ABNF [RFC4234] grammar for this
   syntax.

3.  Matching Rules

   This section introduces a set of certificate and related matching
   rules for use in LDAP.  These rules are intended to act in accordance
   with their X.500 counterparts.

3.1.  certificateExactMatch

   The certificateExactMatch matching rule compares the presented
   certificate exact assertion value with an attribute value of the
   certificate syntax as described in clause 11.3.1 of [X.509].

      ( 2.5.13.34 NAME 'certificateExactMatch'
           DESC 'X.509 Certificate Exact Match'
           SYNTAX 1.3.6.1.1.15.1 )

3.2.  certificateMatch

   The certificateMatch matching rule compares the presented certificate
   assertion value with an attribute value of the certificate syntax as
   described in clause 11.3.2 of [X.509].

      ( 2.5.13.35 NAME 'certificateMatch'
           DESC 'X.509 Certificate Match'
           SYNTAX 1.3.6.1.1.15.2 )







Zeilenga                    Standards Track                     [Page 5]

RFC 4523                   LDAP X.509 Schema                   June 2006


3.3.  certificatePairExactMatch

   The certificatePairExactMatch matching rule compares the presented
   certificate pair exact assertion value with an attribute value of the
   certificate pair syntax as described in clause 11.3.3 of [X.509].

      ( 2.5.13.36 NAME 'certificatePairExactMatch'
           DESC 'X.509 Certificate Pair Exact Match'
           SYNTAX 1.3.6.1.1.15.3 )

3.4.  certificatePairMatch

   The certificatePairMatch matching rule compares the presented
   certificate pair assertion value with an attribute value of the
   certificate pair syntax as described in clause 11.3.4 of [X.509].

      ( 2.5.13.37 NAME 'certificatePairMatch'
           DESC 'X.509 Certificate Pair Match'
           SYNTAX 1.3.6.1.1.15.4 )

3.5.  certificateListExactMatch

   The certificateListExactMatch matching rule compares the presented
   certificate list exact assertion value with an attribute value of the
   certificate pair syntax as described in clause 11.3.5 of [X.509].

      ( 2.5.13.38 NAME 'certificateListExactMatch'
           DESC 'X.509 Certificate List Exact Match'
           SYNTAX 1.3.6.1.1.15.5 )

3.6.  certificateListMatch

   The certificateListMatch matching rule compares the presented
   certificate list assertion value with an attribute value of the
   certificate pair syntax as described in clause 11.3.6 of [X.509].

      ( 2.5.13.39 NAME 'certificateListMatch'
           DESC 'X.509 Certificate List Match'
           SYNTAX 1.3.6.1.1.15.6 )












Zeilenga                    Standards Track                     [Page 6]

RFC 4523                   LDAP X.509 Schema                   June 2006


3.7.  algorithmIdentifierMatch

   The algorithmIdentifierMatch mating rule compares a presented
   algorithm identifier with an attribute value of the supported
   algorithm as described in clause 11.3.7 of [X.509].

      ( 2.5.13.40 NAME 'algorithmIdentifier'
           DESC 'X.509 Algorithm Identifier Match'
           SYNTAX 1.3.6.1.1.15.7 )

4.  Attribute Types

   This section details a set of certificate and related attribute types
   for use in LDAP.

4.1.  userCertificate

   The userCertificate attribute holds the X.509 certificates issued to
   the user by one or more certificate authorities, as discussed in
   clause 11.2.1 of [X.509].

      ( 2.5.4.36 NAME 'userCertificate'
           DESC 'X.509 user certificate'
           EQUALITY certificateExactMatch
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )

   As required by this attribute type's syntax, values of this attribute
   are requested and transferred using the attribute description
   "userCertificate;binary".

4.2.  cACertificate

   The cACertificate attribute holds the X.509 certificates issued to
   the certificate authority (CA), as discussed in clause 11.2.2 of
   [X.509].

      ( 2.5.4.37 NAME 'cACertificate'
           DESC 'X.509 CA certificate'
           EQUALITY certificateExactMatch
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )

   As required by this attribute type's syntax, values of this attribute
   are requested and transferred using the attribute description
   "cACertificate;binary".







Zeilenga                    Standards Track                     [Page 7]

RFC 4523                   LDAP X.509 Schema                   June 2006


4.3.  crossCertificatePair

   The crossCertificatePair attribute holds an X.509 certificate pair,
   as discussed in clause 11.2.3 of [X.509].

      ( 2.5.4.40 NAME 'crossCertificatePair'
           DESC 'X.509 cross certificate pair'
           EQUALITY certificatePairExactMatch
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.10 )

   As required by this attribute type's syntax, values of this attribute
   are requested and transferred using the attribute description
   "crossCertificatePair;binary".

4.4.  certificateRevocationList

   The certificateRevocationList attribute holds certificate lists, as
   discussed in 11.2.4 of [X.509].

      ( 2.5.4.39 NAME 'certificateRevocationList'
           DESC 'X.509 certificate revocation list'
           EQUALITY certificateListExactMatch
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )

   As required by this attribute type's syntax, values of this attribute
   are requested and transferred using the attribute description
   "certificateRevocationList;binary".

4.5.  authorityRevocationList

   The authorityRevocationList attribute holds certificate lists, as
   discussed in 11.2.5 of [X.509].

      ( 2.5.4.38 NAME 'authorityRevocationList'
           DESC 'X.509 authority revocation list'
           EQUALITY certificateListExactMatch
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )

   As required by this attribute type's syntax, values of this attribute
   are requested and transferred using the attribute description
   "authorityRevocationList;binary".










Zeilenga                    Standards Track                     [Page 8]

RFC 4523                   LDAP X.509 Schema                   June 2006


4.6.  deltaRevocationList

   The deltaRevocationList attribute holds certificate lists, as
   discussed in 11.2.6 of [X.509].

      ( 2.5.4.53 NAME 'deltaRevocationList'
           DESC 'X.509 delta revocation list'
           EQUALITY certificateListExactMatch
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )

   As required by this attribute type's syntax, values of this attribute
   MUST be requested and transferred using the attribute description
   "deltaRevocationList;binary".

4.7.  supportedAlgorithms

   The supportedAlgorithms attribute holds supported algorithms, as
   discussed in 11.2.7 of [X.509].

      ( 2.5.4.52 NAME 'supportedAlgorithms'
           DESC 'X.509 supported algorithms'
           EQUALITY algorithmIdentifierMatch
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )

   As required by this attribute type's syntax, values of this attribute
   MUST be requested and transferred using the attribute description
   "supportedAlgorithms;binary".

5.  Object Classes

   This section details a set of certificate-related object classes for
   use in LDAP.

5.1.  pkiUser

   This object class is used in augment entries for objects that may be
   subject to certificates, as defined in clause 11.1.1 of [X.509].

      ( 2.5.6.21 NAME 'pkiUser'
           DESC 'X.509 PKI User'
           SUP top AUXILIARY
           MAY userCertificate )









Zeilenga                    Standards Track                     [Page 9]

RFC 4523                   LDAP X.509 Schema                   June 2006


5.2.  pkiCA

   This object class is used to augment entries for objects that act as
   certificate authorities, as defined in clause 11.1.2 of [X.509]

      ( 2.5.6.22 NAME 'pkiCA'
           DESC 'X.509 PKI Certificate Authority'
           SUP top AUXILIARY
           MAY ( cACertificate $ certificateRevocationList $
                authorityRevocationList $ crossCertificatePair ) )

5.3.  cRLDistributionPoint

   This class is used to represent objects that act as CRL distribution
   points, as discussed in clause 11.1.3 of [X.509].

      ( 2.5.6.19 NAME 'cRLDistributionPoint'
           DESC 'X.509 CRL distribution point'
           SUP top STRUCTURAL
           MUST cn
           MAY ( certificateRevocationList $
                authorityRevocationList $ deltaRevocationList ) )

5.4.  deltaCRL

   The deltaCRL object class is used to augment entries to hold delta
   revocation lists, as discussed in clause 11.1.4 of [X.509].

      ( 2.5.6.23 NAME 'deltaCRL'
           DESC 'X.509 delta CRL'
           SUP top AUXILIARY
           MAY deltaRevocationList )

5.5.  strongAuthenticationUser

   This object class is used to augment entries for objects
   participating in certificate-based authentication, as defined in
   clause 6.15 of [X.521].  This object class is deprecated in favor of
   pkiUser.

      ( 2.5.6.15 NAME 'strongAuthenticationUser'
           DESC 'X.521 strong authentication user'
           SUP top AUXILIARY
           MUST userCertificate )







Zeilenga                    Standards Track                    [Page 10]

RFC 4523                   LDAP X.509 Schema                   June 2006


5.6.  userSecurityInformation

   This object class is used to augment entries with needed additional
   associated security information, as defined in clause 6.16 of
   [X.521].

      ( 2.5.6.18 NAME 'userSecurityInformation'
           DESC 'X.521 user security information'
           SUP top AUXILIARY
           MAY ( supportedAlgorithms ) )

5.7.  certificationAuthority

   This object class is used to augment entries for objects that act as
   certificate authorities, as defined in clause 6.17 of [X.521].  This
   object class is deprecated in favor of pkiCA.

      ( 2.5.6.16 NAME 'certificationAuthority'
           DESC 'X.509 certificate authority'
           SUP top AUXILIARY
           MUST ( authorityRevocationList $
                certificateRevocationList $ cACertificate )
           MAY crossCertificatePair )

5.8.  certificationAuthority-V2

   This object class is used to augment entries for objects that act as
   certificate authorities, as defined in clause 6.18 of [X.521].  This
   object class is deprecated in favor of pkiCA.

      ( 2.5.6.16.2 NAME 'certificationAuthority-V2'
           DESC 'X.509 certificate authority, version 2'
           SUP certificationAuthority AUXILIARY
           MAY deltaRevocationList )

6.  Security Considerations

   General certificate considerations [RFC3280] apply to LDAP-aware
   certificate applications.  General LDAP security considerations
   [RFC4510] apply as well.

   While elements of certificate information are commonly signed, these
   signatures only protect the integrity of the signed information.  In
   the absence of data integrity protections in LDAP (or lower layer,
   e.g., IPsec), a server is not assured that client certificate request
   (or other request) was unaltered in transit.  Likewise, a client
   cannot be assured that the results of the query were unaltered in




Zeilenga                    Standards Track                    [Page 11]

RFC 4523                   LDAP X.509 Schema                   June 2006


   transit.  Hence, it is generally recommended that implementations
   make use of authentication and data integrity services in LDAP
   [RFC4513][RFC4511].

7.  IANA Considerations

7.1.  Object Identifier Registration

   The IANA has registered an LDAP Object Identifier [RFC4520] for use
   in this technical specification.

      Subject: Request for LDAP OID Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <kurt@OpenLDAP.org>
      Specification: RFC 4523
      Author/Change Controller: IESG
      Comments:
          Identifies the LDAP X.509 Certificate schema elements
           introduced in this document.

7.2.  Descriptor Registration

   The IANA has updated the LDAP
   Descriptor registry [RFC44520] as indicated below.

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): see table
      Object Identifier: see table
      Person & email address to contact for further information:
          Kurt Zeilenga <kurt@OpenLDAP.org>
      Usage: see table
      Specification: RFC 4523
      Author/Change Controller: IESG

      algorithmIdentifierMatch     M 2.5.13.40
      authorityRevocationList      A 2.5.4.38 *
      cACertificate                A 2.5.4.37 *
      cRLDistributionPoint         O 2.5.6.19 *
      certificateExactMatch        M 2.5.13.34
      certificateListExactMatch    M 2.5.13.38
      certificateListMatch         M 2.5.13.39
      certificateMatch             M 2.5.13.35
      certificatePairExactMatch    M 2.5.13.36
      certificatePairMatch         M 2.5.13.37
      certificateRevocationList    A 2.5.4.39 *
      certificationAuthority       O 2.5.6.16 *
      certificationAuthority-V2    O 2.5.6.16.2 *
      crossCertificatePair         A 2.5.4.40 *



Zeilenga                    Standards Track                    [Page 12]

RFC 4523                   LDAP X.509 Schema                   June 2006


      deltaCRL                     O 2.5.6.23 *
      deltaRevocationList          A 2.5.4.53 *
      pkiCA                        O 2.5.6.22 *
      pkiUser                      O 2.5.6.21 *
      strongAuthenticationUser     O 2.5.6.15 *
      supportedAlgorithms          A 2.5.4.52 *
      userCertificate              A 2.5.4.36 *
      userSecurityInformation      O 2.5.6.18 *

      * Updates previous registration

8.  Acknowledgements

   This document is based on X.509, a product of the ITU-T.  A number of
   LDAP schema definitions were based on those found in RFCs 2252 and
   2256, both products of the IETF ASID WG.  The ABNF productions in
   Appendix A were provided by Steven Legg.  Additional material was
   borrowed from prior works by David Chadwick and Steven Legg to refine
   the LDAP X.509 schema.

9.  References

9.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3641]  Legg, S., "Generic String Encoding Rules (GSER) for ASN.1
              Types", RFC 3641, October 2003.

   [RFC4510]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC 4510, June
              2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512, June
              2006.

   [RFC4522]  Legg, S., "Lightweight Directory Access Protocol (LDAP):
              The Binary Encoding Option", RFC 4522, June 2006.

   [X.509]    International Telecommunication Union - Telecommunication
              Standardization Sector, "The Directory: Authentication
              Framework", X.509(2000).







Zeilenga                    Standards Track                    [Page 13]

RFC 4523                   LDAP X.509 Schema                   June 2006


   [X.521]    International Telecommunication Union - Telecommunication
              Standardization Sector, "The Directory: Selected Object
              Classes", X.521(2000).

   [X.690]    International Telecommunication Union - Telecommunication
              Standardization Sector, "Specification of ASN.1 encoding
              rules: Basic Encoding Rules (BER), Canonical Encoding
              Rules (CER), and Distinguished Encoding Rules (DER)",
              X.690(2002) (also ISO/IEC 8825-1:2002).

9.2.  Informative References

   [RFC1777]  Yeong, W., Howes, T., and S. Kille, "Lightweight Directory
              Access Protocol", RFC 1777, March 1995.

   [RFC2156]  Kille, S., "MIXER (Mime Internet X.400 Enhanced Relay):
              Mapping between X.400 and RFC 822/MIME", RFC 2156, January
              1998.

   [RFC3280]  Housley, R., Polk, W., Ford, W., and D. Solo, "Internet
              X.509 Public Key Infrastructure Certificate and
              Certificate Revocation List (CRL) Profile", RFC 3280,
              April 2002.

   [RFC3494]  Zeilenga, K., "Lightweight Directory Access Protocol
              version 2 (LDAPv2) to Historic Status", RFC 3494, March
              2003.

   [RFC3642]  Legg, S., "Common Elements of Generic String Encoding
              Rules (GSER) Encodings", RFC 3642, October 2003.

   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", RFC 4234, October 2005.

   [RFC4511]  Sermersheim, J., Ed., "Lightweight Directory Access
              Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4513]  Harrison, R. Ed., "Lightweight Directory Access Protocol
              (LDAP): Authentication Methods and Security Mechanisms",
              RFC 4513, June 2006.

   [RFC4520]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 4520, June 2006.







Zeilenga                    Standards Track                    [Page 14]

RFC 4523                   LDAP X.509 Schema                   June 2006


Appendix A.

   This appendix is informative.

   This appendix provides ABNF [RFC4234] grammars for GSER-based
   [RFC3641] LDAP-specific encodings specified in this document.  These
   grammars where produced using, and relying on, Common Elements for
   GSER Encodings [RFC3642].

A.1.  CertificateExactAssertion

   CertificateExactAssertion = "{" sp cea-serialNumber ","
        sp cea-issuer sp "}"

   cea-serialNumber = id-serialNumber msp CertificateSerialNumber
   cea-issuer = id-issuer msp Name

   id-serialNumber =
        %x73.65.72.69.61.6C.4E.75.6D.62.65.72 ; 'serialNumber'
   id-issuer = %x69.73.73.75.65.72 ; 'issuer'

   Name = id-rdnSequence ":" RDNSequence
   id-rdnSequence = %x72.64.6E.53.65.71.75.65.6E.63.65 ; 'rdnSequence'

   CertificateSerialNumber = INTEGER

A.2.  CertificateAssertion

CertificateAssertion = "{" [ sp ca-serialNumber ]
     [ sep sp ca-issuer ]
     [ sep sp ca-subjectKeyIdentifier ]
     [ sep sp ca-authorityKeyIdentifier ]
     [ sep sp ca-certificateValid ]
     [ sep sp ca-privateKeyValid ]
     [ sep sp ca-subjectPublicKeyAlgID ]
     [ sep sp ca-keyUsage ]
     [ sep sp ca-subjectAltName ]
     [ sep sp ca-policy ]
     [ sep sp ca-pathToName ]
     [ sep sp ca-subject ]
     [ sep sp ca-nameConstraints ] sp "}"

ca-serialNumber = id-serialNumber msp CertificateSerialNumber
ca-issuer = id-issuer msp Name
ca-subjectKeyIdentifier = id-subjectKeyIdentifier msp
     SubjectKeyIdentifier
ca-authorityKeyIdentifier = id-authorityKeyIdentifier msp
     AuthorityKeyIdentifier



Zeilenga                    Standards Track                    [Page 15]

RFC 4523                   LDAP X.509 Schema                   June 2006


ca-certificateValid = id-certificateValid msp Time
ca-privateKeyValid = id-privateKeyValid msp GeneralizedTime
ca-subjectPublicKeyAlgID = id-subjectPublicKeyAlgID msp
     OBJECT-IDENTIFIER
ca-keyUsage = id-keyUsage msp KeyUsage
ca-subjectAltName = id-subjectAltName msp AltNameType
ca-policy = id-policy msp CertPolicySet
ca-pathToName = id-pathToName msp Name
ca-subject = id-subject msp Name
ca-nameConstraints = id-nameConstraints msp NameConstraintsSyntax

id-subjectKeyIdentifier =
     %x73.75.62.6A.65.63.74.4B.65.79.49.64.65.6E.74.69.66.69.65.72
     ; 'subjectKeyIdentifier'
id-authorityKeyIdentifier =
     %x61.75.74.68.6F.72.69.74.79.4B.65.79.49.64.65.6E.74.69.66.69.65.72
     ; 'authorityKeyIdentifier'
id-certificateValid = %x63.65.72.74.69.66.69.63.61.74.65.56.61.6C.69.64
     ; 'certificateValid'
id-privateKeyValid = %x70.72.69.76.61.74.65.4B.65.79.56.61.6C.69.64
     ; 'privateKeyValid'
id-subjectPublicKeyAlgID  =
     %x73.75.62.6A.65.63.74.50.75.62.6C.69.63.4B.65.79.41.6C.67.49.44
     ; 'subjectPublicKeyAlgID'
id-keyUsage = %x6B.65.79.55.73.61.67.65 ; 'keyUsage'
id-subjectAltName = %x73.75.62.6A.65.63.74.41.6C.74.4E.61.6D.65
     ; 'subjectAltName'
id-policy = %x70.6F.6C.69.63.79 ; 'policy'
id-pathToName = %x70.61.74.68.54.6F.4E.61.6D.65 ; 'pathToName'
id-subject = %x73.75.62.6A.65.63.74 ; 'subject'
id-nameConstraints = %x6E.61.6D.65.43.6F.6E.73.74.72.61.69.6E.74.73
     ; 'nameConstraints'

SubjectKeyIdentifier = KeyIdentifier

KeyIdentifier = OCTET-STRING

AuthorityKeyIdentifier = "{" [ sp aki-keyIdentifier ]
     [ sep sp aki-authorityCertIssuer ]
     [ sep sp aki-authorityCertSerialNumber ] sp "}"

aki-keyIdentifier = id-keyIdentifier msp KeyIdentifier
aki-authorityCertIssuer = id-authorityCertIssuer msp GeneralNames

GeneralNames = "{" sp GeneralName *( "," sp GeneralName ) sp "}"
GeneralName  = gn-otherName
     / gn-rfc822Name
     / gn-dNSName



Zeilenga                    Standards Track                    [Page 16]

RFC 4523                   LDAP X.509 Schema                   June 2006


     / gn-x400Address
     / gn-directoryName
     / gn-ediPartyName
     / gn-uniformResourceIdentifier
     / gn-iPAddress
     / gn-registeredID

gn-otherName = id-otherName ":" OtherName
gn-rfc822Name = id-rfc822Name ":" IA5String
gn-dNSName = id-dNSName ":" IA5String
gn-x400Address = id-x400Address ":" ORAddress
gn-directoryName = id-directoryName ":" Name
gn-ediPartyName = id-ediPartyName ":" EDIPartyName
gn-iPAddress = id-iPAddress ":" OCTET-STRING
gn-registeredID = gn-id-registeredID ":" OBJECT-IDENTIFIER

gn-uniformResourceIdentifier = id-uniformResourceIdentifier
     ":" IA5String

id-otherName = %x6F.74.68.65.72.4E.61.6D.65 ; 'otherName'
gn-id-registeredID = %x72.65.67.69.73.74.65.72.65.64.49.44
     ; 'registeredID'

OtherName = "{" sp on-type-id "," sp on-value sp "}"
on-type-id = id-type-id msp OBJECT-IDENTIFIER
on-value = id-value msp Value
     ;; <Value> as defined in Section 3 of [RFC3641]

id-type-id = %x74.79.70.65.2D.69.64 ; 'type-id'
id-value = %x76.61.6C.75.65 ; 'value'

ORAddress = dquote *SafeIA5Character dquote
SafeIA5Character = %x01-21 / %x23-7F / ; ASCII minus dquote
     dquote dquote ; escaped double quote
dquote = %x22 ; '"' (double quote)

;; Note: The <ORAddress> rule encodes the x400Address component
;; of a GeneralName as a character string between double quotes.
;; The character string is first derived according to Section 4.1
;; of [RFC2156], and then any embedded double quotes are escaped
;; by being repeated. This resulting string is output between
;; double quotes.

EDIPartyName = "{" [ sp nameAssigner "," ] sp partyName sp "}"
nameAssigner = id-nameAssigner msp DirectoryString
partyName = id-partyName msp DirectoryString
id-nameAssigner = %x6E.61.6D.65.41.73.73.69.67.6E.65.72
     ; 'nameAssigner'



Zeilenga                    Standards Track                    [Page 17]

RFC 4523                   LDAP X.509 Schema                   June 2006


id-partyName    = %x70.61.72.74.79.4E.61.6D.65 ; 'partyName'

aki-authorityCertSerialNumber = id-authorityCertSerialNumber
     msp CertificateSerialNumber

id-keyIdentifier = %x6B.65.79.49.64.65.6E.74.69.66.69.65.72
     ; 'keyIdentifier'
id-authorityCertIssuer =
     %x61.75.74.68.6F.72.69.74.79.43.65.72.74.49.73.73.75.65.72
     ; 'authorityCertIssuer'

id-authorityCertSerialNumber = %x61.75.74.68.6F.72.69.74.79.43
     %x65.72.74.53.65.72.69.61.6C.4E.75.6D.62.65.72
     ; 'authorityCertSerialNumber'

Time = time-utcTime / time-generalizedTime
time-utcTime = id-utcTime ":" UTCTime
time-generalizedTime = id-generalizedTime ":" GeneralizedTime
id-utcTime = %x75.74.63.54.69.6D.65 ; 'utcTime'
id-generalizedTime = %x67.65.6E.65.72.61.6C.69.7A.65.64.54.69.6D.65
     ; 'generalizedTime'

KeyUsage = BIT-STRING / key-usage-bit-list
key-usage-bit-list = "{" [ sp key-usage *( "," sp key-usage ) ] sp "}"

;; Note: The <key-usage-bit-list> rule encodes the one bits in
;; a KeyUsage value as a comma separated list of identifiers.

key-usage = id-digitalSignature
     / id-nonRepudiation
     / id-keyEncipherment
     / id-dataEncipherment
     / id-keyAgreement
     / id-keyCertSign
     / id-cRLSign
     / id-encipherOnly
     / id-decipherOnly

id-digitalSignature = %x64.69.67.69.74.61.6C.53.69.67.6E.61.74
     %x75.72.65 ; 'digitalSignature'
id-nonRepudiation   = %x6E.6F.6E.52.65.70.75.64.69.61.74.69.6F.6E
     ; 'nonRepudiation'
id-keyEncipherment  = %x6B.65.79.45.6E.63.69.70.68.65.72.6D.65.6E.74
     ; 'keyEncipherment'
id-dataEncipherment = %x64.61.74.61.45.6E.63.69.70.68.65.72.6D.65.6E
     %x74 ; "dataEncipherment'
id-keyAgreement     = %x6B.65.79.41.67.72.65.65.6D.65.6E.74
     ; 'keyAgreement'



Zeilenga                    Standards Track                    [Page 18]

RFC 4523                   LDAP X.509 Schema                   June 2006


id-keyCertSign      = %x6B.65.79.43.65.72.74.53.69.67.6E
     ; 'keyCertSign'
id-cRLSign          = %x63.52.4C.53.69.67.6E ; "cRLSign"
id-encipherOnly     = %x65.6E.63.69.70.68.65.72.4F.6E.6C.79
     ; 'encipherOnly'
id-decipherOnly     = %x64.65.63.69.70.68.65.72.4F.6E.6C.79
     ; 'decipherOnly'

AltNameType = ant-builtinNameForm / ant-otherNameForm

ant-builtinNameForm = id-builtinNameForm ":" BuiltinNameForm
ant-otherNameForm = id-otherNameForm ":" OBJECT-IDENTIFIER

id-builtinNameForm = %x62.75.69.6C.74.69.6E.4E.61.6D.65.46.6F.72.6D
     ; 'builtinNameForm'
id-otherNameForm   = %x6F.74.68.65.72.4E.61.6D.65.46.6F.72.6D
     ; 'otherNameForm'

BuiltinNameForm  = id-rfc822Name
     / id-dNSName
     / id-x400Address
     / id-directoryName
     / id-ediPartyName
     / id-uniformResourceIdentifier
     / id-iPAddress
     / id-registeredId

id-rfc822Name = %x72.66.63.38.32.32.4E.61.6D.65 ; 'rfc822Name'
id-dNSName = %x64.4E.53.4E.61.6D.65 ; 'dNSName'
id-x400Address  = %x78.34.30.30.41.64.64.72.65.73.73 ; 'x400Address'
id-directoryName = %x64.69.72.65.63.74.6F.72.79.4E.61.6D.65
     ; 'directoryName'
id-ediPartyName  = %x65.64.69.50.61.72.74.79.4E.61.6D.65
     ; 'ediPartyName'
id-iPAddress = %x69.50.41.64.64.72.65.73.73 ; 'iPAddress'
id-registeredId = %x72.65.67.69.73.74.65.72.65.64.49.64
     ; 'registeredId'

id-uniformResourceIdentifier = %x75.6E.69.66.6F.72.6D.52.65.73.6F.75
     %x72.63.65.49.64.65.6E.74.69.66.69.65.72
     ; 'uniformResourceIdentifier'

CertPolicySet = "{" sp CertPolicyId *( "," sp CertPolicyId ) sp "}"
CertPolicyId = OBJECT-IDENTIFIER

NameConstraintsSyntax = "{" [ sp ncs-permittedSubtrees ]
     [ sep sp ncs-excludedSubtrees ] sp "}"




Zeilenga                    Standards Track                    [Page 19]

RFC 4523                   LDAP X.509 Schema                   June 2006


ncs-permittedSubtrees = id-permittedSubtrees msp GeneralSubtrees
ncs-excludedSubtrees = id-excludedSubtrees  msp GeneralSubtrees

id-permittedSubtrees =
     %x70.65.72.6D.69.74.74.65.64.53.75.62.74.72.65.65.73
     ; 'permittedSubtrees'
id-excludedSubtrees =
     %x65.78.63.6C.75.64.65.64.53.75.62.74.72.65.65.73
     ; 'excludedSubtrees'

GeneralSubtrees = "{" sp GeneralSubtree
     *( "," sp GeneralSubtree ) sp "}"
GeneralSubtree  = "{" sp gs-base
     [ "," sp gs-minimum ]
     [ "," sp gs-maximum ] sp "}"

gs-base = id-base msp GeneralName
gs-minimum = id-minimum msp BaseDistance
gs-maximum = id-maximum msp BaseDistance

id-base = %x62.61.73.65 ; 'base'
id-minimum = %x6D.69.6E.69.6D.75.6D ; 'minimum'
id-maximum = %x6D.61.78.69.6D.75.6D ; 'maximum'

BaseDistance = INTEGER-0-MAX

A.3.  CertificatePairExactAssertion

  CertificatePairExactAssertion = "{" [ sp cpea-issuedTo ]
       [sep sp cpea-issuedBy ] sp "}"
  ;; At least one of <cpea-issuedTo> or <cpea-issuedBy> MUST be present.

  cpea-issuedTo = id-issuedToThisCAAssertion msp
       CertificateExactAssertion
  cpea-issuedBy = id-issuedByThisCAAssertion msp
       CertificateExactAssertion

  id-issuedToThisCAAssertion = %x69.73.73.75.65.64.54.6F.54.68.69.73
       %x43.41.41.73.73.65.72.74.69.6F.6E ; 'issuedToThisCAAssertion'
  id-issuedByThisCAAssertion = %x69.73.73.75.65.64.42.79.54.68.69.73
       %x43.41.41.73.73.65.72.74.69.6F.6E ; 'issuedByThisCAAssertion'










Zeilenga                    Standards Track                    [Page 20]

RFC 4523                   LDAP X.509 Schema                   June 2006


A.4.  CertificatePairAssertion

   CertificatePairAssertion = "{" [ sp cpa-issuedTo ]
        [sep sp cpa-issuedBy ] sp "}"
   ;; At least one of <cpa-issuedTo> and <cpa-issuedBy> MUST be present.

   cpa-issuedTo = id-issuedToThisCAAssertion msp CertificateAssertion
   cpa-issuedBy = id-issuedByThisCAAssertion msp CertificateAssertion

A.5.  CertificateListExactAssertion

   CertificateListExactAssertion = "{" sp clea-issuer ","
        sp clea-thisUpdate
        [ "," sp clea-distributionPoint ] sp "}"

   clea-issuer = id-issuer msp Name
   clea-thisUpdate = id-thisUpdate msp Time
   clea-distributionPoint = id-distributionPoint msp
        DistributionPointName

   id-thisUpdate = %x74.68.69.73.55.70.64.61.74.65 ; 'thisUpdate'
   id-distributionPoint =
        %x64.69.73.74.72.69.62.75.74.69.6F.6E.50.6F.69.6E.74
        ; 'distributionPoint'

   DistributionPointName = dpn-fullName / dpn-nameRelativeToCRLIssuer

   dpn-fullName = id-fullName ":" GeneralNames
   dpn-nameRelativeToCRLIssuer = id-nameRelativeToCRLIssuer ":"
        RelativeDistinguishedName

   id-fullName = %x66.75.6C.6C.4E.61.6D.65 ; 'fullName'
   id-nameRelativeToCRLIssuer = %x6E.61.6D.65.52.65.6C.61.74.69.76.65
        %x54.6F.43.52.4C.49.73.73.75.65.72 ; 'nameRelativeToCRLIssuer'

A.6.  CertificateListAssertion

   CertificateListAssertion = "{" [ sp cla-issuer ]
        [ sep sp cla-minCRLNumber ]
        [ sep sp cla-maxCRLNumber ]
        [ sep sp cla-reasonFlags ]
        [ sep sp cla-dateAndTime ]
        [ sep sp cla-distributionPoint ]
        [ sep sp cla-authorityKeyIdentifier ] sp "}"

   cla-issuer = id-issuer msp Name
   cla-minCRLNumber = id-minCRLNumber msp CRLNumber
   cla-maxCRLNumber = id-maxCRLNumber msp CRLNumber



Zeilenga                    Standards Track                    [Page 21]

RFC 4523                   LDAP X.509 Schema                   June 2006


   cla-reasonFlags = id-reasonFlags msp ReasonFlags
   cla-dateAndTime = id-dateAndTime msp Time

   cla-distributionPoint = id-distributionPoint msp
        DistributionPointName

   cla-authorityKeyIdentifier = id-authorityKeyIdentifier msp
        AuthorityKeyIdentifier

   id-minCRLNumber = %x6D.69.6E.43.52.4C.4E.75.6D.62.65.72
        ; 'minCRLNumber'
   id-maxCRLNumber = %x6D.61.78.43.52.4C.4E.75.6D.62.65.72
        ; 'maxCRLNumber'
   id-reasonFlags = %x72.65.61.73.6F.6E.46.6C.61.67.73 ; 'reasonFlags'
   id-dateAndTime = %x64.61.74.65.41.6E.64.54.69.6D.65 ; 'dateAndTime'

   CRLNumber = INTEGER-0-MAX

   ReasonFlags = BIT-STRING
        / "{" [ sp reason-flag *( "," sp reason-flag ) ] sp "}"

   reason-flag = id-unused
        / id-keyCompromise
        / id-cACompromise
        / id-affiliationChanged
        / id-superseded
        / id-cessationOfOperation
        / id-certificateHold
        / id-privilegeWithdrawn
        / id-aACompromise

   id-unused = %x75.6E.75.73.65.64 ; 'unused'
   id-keyCompromise = %x6B.65.79.43.6F.6D.70.72.6F.6D.69.73.65
        ; 'keyCompromise'
   id-cACompromise = %x63.41.43.6F.6D.70.72.6F.6D.69.73.65
        ; 'cACompromise'
   id-affiliationChanged =
        %x61.66.66.69.6C.69.61.74.69.6F.6E.43.68.61.6E.67.65.64
        ; 'affiliationChanged'
   id-superseded = %x73.75.70.65.72.73.65.64.65.64 ; 'superseded'
   id-cessationOfOperation =
        %x63.65.73.73.61.74.69.6F.6E.4F.66.4F.70.65.72.61.74.69.6F.6E
        ; 'cessationOfOperation'
   id-certificateHold = %x63.65.72.74.69.66.69.63.61.74.65.48.6F.6C.64
        ; 'certificateHold'
   id-privilegeWithdrawn =
        %x70.72.69.76.69.6C.65.67.65.57.69.74.68.64.72.61.77.6E
        ; 'privilegeWithdrawn'



Zeilenga                    Standards Track                    [Page 22]

RFC 4523                   LDAP X.509 Schema                   June 2006


   id-aACompromise = %x61.41.43.6F.6D.70.72.6F.6D.69.73.65
        ; 'aACompromise'

A.7.  AlgorithmIdentifier

   AlgorithmIdentifier = "{" sp ai-algorithm
        [ "," sp ai-parameters ] sp "}"

   ai-algorithm = id-algorithm msp OBJECT-IDENTIFIER
   ai-parameters = id-parameters msp Value
   id-algorithm = %x61.6C.67.6F.72.69.74.68.6D ; 'algorithm'
   id-parameters = %x70.61.72.61.6D.65.74.65.72.73 ; 'parameters'

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org
































Zeilenga                    Standards Track                    [Page 23]

RFC 4523                   LDAP X.509 Schema                   June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                    [Page 24]

alt-openldap11-devel/rfc/rfc2247.txt000064400000030173150410163170012771 0ustar00





Network Working Group                                           S. Kille
Request for Comments: 2247                                    Isode Ltd.
Category: Standards Track                                        M. Wahl
                                                     Critical Angle Inc.
                                                             A. Grimstad
                                                                    AT&T
                                                                R. Huber
                                                                    AT&T
                                                             S. Sataluri
                                                                    AT&T
                                                            January 1998



            Using Domains in LDAP/X.500 Distinguished Names


Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

1. Abstract

   The Lightweight Directory Access Protocol (LDAP) uses X.500-
   compatible distinguished names [3] for providing unique
   identification of entries.

   This document defines an algorithm by which a name registered with
   the Internet Domain Name Service [2] can be represented as an LDAP
   distinguished name.

2. Background

   The Domain (Nameserver) System (DNS) provides a hierarchical resource
   labeling system.   A name is made up of an ordered set of components,
   each of which are short strings. An example domain name with two
   components would be "CRITICAL-ANGLE.COM".






Kille, et. al.              Standards Track                     [Page 1]

RFC 2247              Using Domains in LDAP/X.500           January 1998


   LDAP-based directories provide a more general hierarchical naming
   framework. A primary difference in specification of distinguished
   names from domain names is that each component of an distinguished
   name has an explicit attribute type indication.

   X.500 does not mandate any particular naming structure.  It does
   contain suggested naming structures which are based on geographic and
   national regions, however there is not currently an established
   registration infrastructure in many regions which would be able to
   assign or ensure uniqueness of names.

   The mechanism described in this document automatically provides an
   enterprise a distinguished name for each domain name it has obtained
   for use in the Internet.  These distinguished names may be used to
   identify objects in an LDAP directory.

   An example distinguished name represented in the LDAP string format
   [3] is "DC=CRITICAL-ANGLE,DC=COM".  As with a domain name, the most
   significant component, closest to the root of the namespace, is
   written last.

   This document does not define how to represent objects which do not
   have domain names.  Nor does this document define the procedure to
   locate an enterprise's LDAP directory server, given their domain
   name.  Such procedures may be defined in future RFCs.

3. Mapping Domain Names into Distinguished Names

   This section defines a subset of the possible distinguished name
   structures for use in representing names allocated in the Internet
   Domain Name System.  It is possible to algorithmically transform any
   Internet domain name into a distinguished name, and to convert these
   distinguished names back into the original domain names.

   The algorithm for transforming a domain name is to begin with an
   empty distinguished name (DN) and then attach Relative Distinguished
   Names (RDNs) for each component of the domain, most significant (e.g.
   rightmost) first. Each of these RDNs is a single
   AttributeTypeAndValue, where the type is the attribute "DC" and the
   value is an IA5 string containing the domain name component.

   Thus the domain name "CS.UCL.AC.UK" can be transformed into

        DC=CS,DC=UCL,DC=AC,DC=UK







Kille, et. al.              Standards Track                     [Page 2]

RFC 2247              Using Domains in LDAP/X.500           January 1998


   Distinguished names in which there are one or more RDNs, all
   containing only the attribute type DC, can be mapped back into domain
   names. Note that this document does not define a domain name
   equivalence for any other distinguished names.

4. Attribute Type Definition

   The DC (short for domainComponent) attribute type is defined as
   follows:

    ( 0.9.2342.19200300.100.1.25 NAME 'dc' EQUALITY caseIgnoreIA5Match
     SUBSTR caseIgnoreIA5SubstringsMatch
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )

   The value of this attribute is a string holding one component of a
   domain name.  The encoding of IA5String for use in LDAP is simply the
   characters of the string itself.  The equality matching rule is case
   insensitive, as is today's DNS.

5. Object Class Definitions

   An object with a name derived from its domain name using the
   algorithm of section 3 is represented as an entry in the directory.
   The "DC" attribute is present in the entry and used as the RDN.

   An attribute can only be present in an entry held by an LDAP server
   when that attribute is permitted by the entry's object class.

   This section defines two object classes.  The first, dcObject, is
   intended to be used in entries for which there is an appropriate
   structural object class.  For example, if the domain represents a
   particular organization, the entry would have as its structural
   object class 'organization', and the 'dcObject' class would be an
   auxiliary class.  The second, domain, is a structural object class
   used for entries in which no other information is being stored. The
   domain object class is typically used for entries that are
   placeholders or whose domains do not correspond to real-world
   entities.

5.1. The dcObject object class

   The dcObject object class permits the dc attribute to be present in
   an entry.  This object class is defined as auxiliary, as it would
   typically be used in conjunction with an existing structural object
   class, such as organization, organizationalUnit or locality.

   The following object class, along with the dc attribute, can be added
   to any entry.



Kille, et. al.              Standards Track                     [Page 3]

RFC 2247              Using Domains in LDAP/X.500           January 1998


   ( 1.3.6.1.4.1.1466.344 NAME 'dcObject' SUP top AUXILIARY MUST dc )

   An example entry would be:

   dn: dc=critical-angle,dc=com
   objectClass: top
   objectClass: organization
   objectClass: dcObject
   dc: critical-angle
   o: Critical Angle Inc.

5.2. The domain object class

   If the entry does not correspond to an organization, organizational
   unit or other type of object for which an object class has been
   defined, then the "domain" object class can be used.  The "domain"
   object class requires that the "DC" attribute be present, and permits
   several other attributes to be present in the entry.

   The entry will have as its structural object class the "domain"
   object class.

( 0.9.2342.19200300.100.4.13 NAME 'domain' SUP top STRUCTURAL
 MUST dc
 MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
 x121Address $ registeredAddress $ destinationIndicator $
 preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
 telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $
 street $ postOfficeBox $ postalCode $ postalAddress $
 physicalDeliveryOfficeName $ st $ l $ description $ o $
 associatedName ) )

   The optional attributes of the domain class are used for describing
   the object represented by this domain, and may also be useful when
   searching.  These attributes are already defined for use with LDAP
   [4].

   An example entry would be:

   dn: dc=tcp,dc=critical-angle,dc=com
   objectClass: top
   objectClass: domain
   dc: tcp
   description: a placeholder entry used with SRV records

   The DC attribute is used for naming entries of the domain class, and
   this can be represented in X.500 servers by the following name form
   rule.



Kille, et. al.              Standards Track                     [Page 4]

RFC 2247              Using Domains in LDAP/X.500           January 1998


    ( 1.3.6.1.4.1.1466.345 NAME 'domainNameForm' OC domain MUST ( dc ) )

6. References

   [1] The Directory: Selected Attribute Types. ITU-T Recommendation
       X.520, 1993.

   [2] Mockapetris, P., " Domain Names - Concepts and Facilities,"
       STD 13, RFC 1034, November 1987.

   [3] Kille, S., and M. Wahl, " Lightweight Directory Access Protocol
       (v3): UTF-8 String Representation of Distinguished Names", RFC
       2253, December 1997.

   [4] Wahl, M., "A Summary of the X.500(96) User Schema for use with
       LDAP", RFC 2256, December 1997.

7. Security Considerations

   This memo describes how attributes of objects may be discovered and
   retrieved.  Servers should ensure that an appropriate security policy
   is maintained.

   An enterprise is not restricted in the information which it may store
   in DNS or LDAP servers.  A client which contacts an untrusted server
   may have incorrect or misleading information returned (e.g. an
   organization's server may claim to hold naming contexts representing
   domain names which have not been delegated to that organization).

8. Authors' Addresses

   Steve Kille
   Isode Ltd.
   The Dome
   The Square
   Richmond, Surrey
   TW9 1DT
   England

   Phone:  +44-181-332-9091
   EMail:  S.Kille@ISODE.COM










Kille, et. al.              Standards Track                     [Page 5]

RFC 2247              Using Domains in LDAP/X.500           January 1998


   Mark Wahl
   Critical Angle Inc.
   4815 W. Braker Lane #502-385
   Austin, TX 78759
   USA

   Phone:  (1) 512 372 3160
   EMail:  M.Wahl@critical-angle.com


   Al Grimstad
   AT&T
   Room 1C-429, 101 Crawfords Corner Road
   Holmdel, NJ 07733-3030
   USA

   EMail: alg@att.com


   Rick Huber
   AT&T
   Room 1B-433, 101 Crawfords Corner Road
   Holmdel, NJ 07733-3030
   USA

   EMail: rvh@att.com


   Sri Sataluri
   AT&T
   Room 4G-202, 101 Crawfords Corner Road
   Holmdel, NJ 07733-3030
   USA

   EMail: sri@att.com
















Kille, et. al.              Standards Track                     [Page 6]

RFC 2247              Using Domains in LDAP/X.500           January 1998


9.  Full Copyright Statement

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
























Kille, et. al.              Standards Track                     [Page 7]

alt-openldap11-devel/rfc/rfc2849.txt000064400000062641150410163170013006 0ustar00





Network Working Group                                             G. Good
Request for Comments: 2849                   iPlanet e-commerce Solutions
Category: Standards Track                                       June 2000


   The LDAP Data Interchange Format (LDIF) - Technical Specification

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2000).  All Rights Reserved.

Abstract

   This document describes a file format suitable for describing
   directory information or modifications made to directory information.
   The file format, known as LDIF, for LDAP Data Interchange Format, is
   typically used to import and export directory information between
   LDAP-based directory servers, or to describe a set of changes which
   are to be applied to a directory.

Background and Intended Usage

   There are a number of situations where a common interchange format is
   desirable.  For example, one might wish to export a copy of the
   contents of a directory server to a file, move that file to a
   different machine, and import the contents into a second directory
   server.

   Additionally, by using a well-defined interchange format, development
   of data import tools from legacy systems is facilitated.  A fairly
   simple set of tools written in awk or perl can, for example, convert
   a database of personnel information into an LDIF file. This file can
   then be imported into a directory server, regardless of the internal
   database representation the target directory server uses.

   The LDIF format was originally developed and used in the University
   of Michigan LDAP implementation.  The first use of LDIF was in
   describing directory entries.  Later, the format was expanded to
   allow representation of changes to directory entries.




Good                        Standards Track                     [Page 1]

RFC 2849              LDAP Data Interchange Format             June 2000


   Relationship to the application/directory MIME content-type:

   The application/directory MIME content-type [1] is a general
   framework and format for conveying directory information, and is
   independent of any particular directory service.  The LDIF format is
   a simpler format which is perhaps easier to create, and may also be
   used, as noted, to describe a set of changes to be applied to a
   directory.

   The key words "MUST", "MUST NOT", "MAY", "SHOULD", and "SHOULD NOT"
   used in this document are to be interpreted as described in [7].

Definition of the LDAP Data Interchange Format

   The LDIF format is used to convey directory information, or a
   description of a set of changes made to directory entries.  An LDIF
   file consists of a series of records separated by line separators.  A
   record consists of a sequence of lines describing a directory entry,
   or a sequence of lines describing a set of changes to a directory
   entry.  An LDIF file specifies a set of directory entries, or a set
   of changes to be applied to directory entries, but not both.

   There is a one-to-one correlation between LDAP operations that modify
   the directory (add, delete, modify, and modrdn), and the types of
   changerecords described below ("add", "delete", "modify", and
   "modrdn" or "moddn").  This correspondence is intentional, and
   permits a straightforward translation from LDIF changerecords to
   protocol operations.

Formal Syntax Definition of LDIF

   The following definition uses the augmented Backus-Naur Form
   specified in RFC 2234 [2].

ldif-file                = ldif-content / ldif-changes

ldif-content             = version-spec 1*(1*SEP ldif-attrval-record)

ldif-changes             = version-spec 1*(1*SEP ldif-change-record)

ldif-attrval-record      = dn-spec SEP 1*attrval-spec

ldif-change-record       = dn-spec SEP *control changerecord

version-spec             = "version:" FILL version-number






Good                        Standards Track                     [Page 2]

RFC 2849              LDAP Data Interchange Format             June 2000


version-number           = 1*DIGIT
                           ; version-number MUST be "1" for the
                           ; LDIF format described in this document.

dn-spec                  = "dn:" (FILL distinguishedName /
                                  ":" FILL base64-distinguishedName)

distinguishedName        = SAFE-STRING
                           ; a distinguished name, as defined in [3]

base64-distinguishedName = BASE64-UTF8-STRING
                           ; a distinguishedName which has been base64
                           ; encoded (see note 10, below)

rdn                      = SAFE-STRING
                           ; a relative distinguished name, defined as
                           ; <name-component> in [3]

base64-rdn               = BASE64-UTF8-STRING
                           ; an rdn which has been base64 encoded (see
                           ; note 10, below)

control                  = "control:" FILL ldap-oid        ; controlType
                           0*1(1*SPACE ("true" / "false")) ; criticality
                           0*1(value-spec)                ; controlValue
                           SEP
                           ; (See note 9, below)

ldap-oid                 = 1*DIGIT 0*1("." 1*DIGIT)
                           ; An LDAPOID, as defined in [4]

attrval-spec             = AttributeDescription value-spec SEP

value-spec               = ":" (    FILL 0*1(SAFE-STRING) /
                                ":" FILL (BASE64-STRING) /
                                "<" FILL url)
                           ; See notes 7 and 8, below

url                      = <a Uniform Resource Locator,
                            as defined in [6]>
                                   ; (See Note 6, below)

AttributeDescription     = AttributeType [";" options]
                           ; Definition taken from [4]

AttributeType            = ldap-oid / (ALPHA *(attr-type-chars))

options                  = option / (option ";" options)



Good                        Standards Track                     [Page 3]

RFC 2849              LDAP Data Interchange Format             June 2000


option                   = 1*opt-char

attr-type-chars          = ALPHA / DIGIT / "-"

opt-char                 = attr-type-chars

changerecord             = "changetype:" FILL
                           (change-add / change-delete /
                            change-modify / change-moddn)

change-add               = "add"                SEP 1*attrval-spec

change-delete            = "delete"             SEP

change-moddn             = ("modrdn" / "moddn") SEP
                            "newrdn:" (    FILL rdn /
                                       ":" FILL base64-rdn) SEP
                            "deleteoldrdn:" FILL ("0" / "1")  SEP
                            0*1("newsuperior:"
                            (    FILL distinguishedName /
                             ":" FILL base64-distinguishedName) SEP)

change-modify            = "modify"             SEP *mod-spec

mod-spec                 = ("add:" / "delete:" / "replace:")
                           FILL AttributeDescription SEP
                           *attrval-spec
                           "-" SEP

SPACE                    = %x20
                           ; ASCII SP, space

FILL                     = *SPACE

SEP                      = (CR LF / LF)

CR                       = %x0D
                           ; ASCII CR, carriage return

LF                       = %x0A
                           ; ASCII LF, line feed

ALPHA                    = %x41-5A / %x61-7A
                           ; A-Z / a-z

DIGIT                    = %x30-39
                           ; 0-9




Good                        Standards Track                     [Page 4]

RFC 2849              LDAP Data Interchange Format             June 2000


UTF8-1                   = %x80-BF

UTF8-2                   = %xC0-DF UTF8-1

UTF8-3                   = %xE0-EF 2UTF8-1

UTF8-4                   = %xF0-F7 3UTF8-1

UTF8-5                   = %xF8-FB 4UTF8-1

UTF8-6                   = %xFC-FD 5UTF8-1

SAFE-CHAR                = %x01-09 / %x0B-0C / %x0E-7F
                           ; any value <= 127 decimal except NUL, LF,
                           ; and CR

SAFE-INIT-CHAR           = %x01-09 / %x0B-0C / %x0E-1F /
                           %x21-39 / %x3B / %x3D-7F
                           ; any value <= 127 except NUL, LF, CR,
                           ; SPACE, colon (":", ASCII 58 decimal)
                           ; and less-than ("<" , ASCII 60 decimal)

SAFE-STRING              = [SAFE-INIT-CHAR *SAFE-CHAR]

UTF8-CHAR                = SAFE-CHAR / UTF8-2 / UTF8-3 /
                           UTF8-4 / UTF8-5 / UTF8-6

UTF8-STRING              = *UTF8-CHAR

BASE64-UTF8-STRING       = BASE64-STRING
                           ; MUST be the base64 encoding of a
                           ; UTF8-STRING

BASE64-CHAR              = %x2B / %x2F / %x30-39 / %x3D / %x41-5A /
                           %x61-7A
                           ; +, /, 0-9, =, A-Z, and a-z
                           ; as specified in [5]

BASE64-STRING            = [*(BASE64-CHAR)]


   Notes on LDIF Syntax

      1)  For the LDIF format described in this document, the version
          number MUST be "1". If the version number is absent,
          implementations MAY choose to interpret the contents as an
          older LDIF file format, supported by the University of
          Michigan ldap-3.3 implementation [8].



Good                        Standards Track                     [Page 5]

RFC 2849              LDAP Data Interchange Format             June 2000


      2)  Any non-empty line, including comment lines, in an LDIF file
          MAY be folded by inserting a line separator (SEP) and a SPACE.
          Folding MUST NOT occur before the first character of the line.
          In other words, folding a line into two lines, the first of
          which is empty, is not permitted. Any line that begins with a
          single space MUST be treated as a continuation of the previous
          (non-empty) line. When joining folded lines, exactly one space
          character at the beginning of each continued line must be
          discarded. Implementations SHOULD NOT fold lines in the middle
          of a multi-byte UTF-8 character.

      3)  Any line that begins with a pound-sign ("#", ASCII 35) is a
          comment line, and MUST be ignored when parsing an LDIF file.

      4)  Any dn or rdn that contains characters other than those
          defined as "SAFE-UTF8-CHAR", or begins with a character other
          than those defined as "SAFE-INIT-UTF8-CHAR", above, MUST be
          base-64 encoded.  Other values MAY be base-64 encoded.  Any
          value that contains characters other than those defined as
          "SAFE-CHAR", or begins with a character other than those
          defined as "SAFE-INIT-CHAR", above, MUST be base-64 encoded.
          Other values MAY be base-64 encoded.

      5)  When a zero-length attribute value is to be included directly
          in an LDIF file, it MUST be represented as
          AttributeDescription ":" FILL SEP.  For example, "seeAlso:"
          followed by a newline represents a zero-length "seeAlso"
          attribute value.  It is also permissible for the value
          referred to by a URL to be of zero length.

      6) When a URL is specified in an attrval-spec, the following
          conventions apply:

         a) Implementations SHOULD support the file:// URL format.  The
            contents of the referenced file are to be included verbatim
            in the interpreted output of the LDIF file.
         b) Implementations MAY support other URL formats.  The
            semantics associated with each supported URL will be
            documented in an associated Applicability Statement.

      7)  Distinguished names, relative distinguished names, and
          attribute values of DirectoryString syntax MUST be valid UTF-8
          strings.  Implementations that read LDIF MAY interpret files
          in which these entities are stored in some other character set
          encoding, but implementations MUST NOT generate LDIF content
          which does not contain valid UTF-8 data.





Good                        Standards Track                     [Page 6]

RFC 2849              LDAP Data Interchange Format             June 2000


      8)  Values or distinguished names that end with SPACE SHOULD be
          base-64 encoded.

      9)  When controls are included in an LDIF file, implementations
          MAY choose to ignore some or all of them. This may be
          necessary if the changes described in the LDIF file are being
          sent on an LDAPv2 connection (LDAPv2 does not support
          controls), or the particular controls are not supported by the
          remote server. If the criticality of a control is "true", then
          the implementation MUST either include the control, or MUST
          NOT send the operation to a remote server.

      10) When an attrval-spec, distinguishedName, or rdn is base64-
          encoded, the encoding rules specified in [5] are used with the
          following exceptions:  a) The requirement that base64 output
          streams must be represented as lines of no more than 76
          characters is removed. Lines in LDIF files may only be folded
          according to the folding rules described in note 2, above.  b)
          Base64 strings in [5] may contain characters other than those
          defined in BASE64-CHAR, and are ignored. LDIF does not permit
          any extraneous characters, other than those used for line
          folding.

Examples of LDAP Data Interchange Format

Example 1: An simple LDAP file with two entries

version: 1
dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Barbara Jensen
cn: Barbara J Jensen
cn: Babs Jensen
sn: Jensen
uid: bjensen
telephonenumber: +1 408 555 1212
description: A big sailing fan.

dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Bjorn Jensen
sn: Jensen
telephonenumber: +1 408 555 1212




Good                        Standards Track                     [Page 7]

RFC 2849              LDAP Data Interchange Format             June 2000


Example 2: A file containing an entry with a folded attribute value

version: 1
dn:cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass:top
objectclass:person
objectclass:organizationalPerson
cn:Barbara Jensen
cn:Barbara J Jensen
cn:Babs Jensen
sn:Jensen
uid:bjensen
telephonenumber:+1 408 555 1212
description:Babs is a big sailing fan, and travels extensively in sea
 rch of perfect sailing conditions.
title:Product Manager, Rod and Reel Division

Example 3: A file containing a base-64-encoded value

version: 1
dn: cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Gern Jensen
cn: Gern O Jensen
sn: Jensen
uid: gernj
telephonenumber: +1 408 555 1212
description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVl
IGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdG
VyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQg
b3V0IG1vcmUu

Example 4: A file containing an entries with UTF-8-encoded attribute
values, including language tags.  Comments indicate the contents
of UTF-8-encoded attributes and distinguished names.

version: 1
dn:: b3U95Za25qWt6YOoLG89QWlyaXVz
# dn:: ou=<JapaneseOU>,o=Airius
objectclass: top
objectclass: organizationalUnit
ou:: 5Za25qWt6YOo
# ou:: <JapaneseOU>
ou;lang-ja:: 5Za25qWt6YOo
# ou;lang-ja:: <JapaneseOU>
ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2



Good                        Standards Track                     [Page 8]

RFC 2849              LDAP Data Interchange Format             June 2000


# ou;lang-ja:: <JapaneseOU_in_phonetic_representation>
ou;lang-en: Sales
description: Japanese office

dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
# dn:: uid=<uid>,ou=<JapaneseOU>,o=Airius
userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: rogasawara
mail: rogasawara@airius.co.jp
givenname;lang-ja:: 44Ot44OJ44OL44O8
# givenname;lang-ja:: <JapaneseGivenname>
sn;lang-ja:: 5bCP56yg5Y6f
# sn;lang-ja:: <JapaneseSn>
cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
# cn;lang-ja:: <JapaneseCn>
title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
# title;lang-ja:: <JapaneseTitle>
preferredlanguage: ja
givenname:: 44Ot44OJ44OL44O8
# givenname:: <JapaneseGivenname>
sn:: 5bCP56yg5Y6f
# sn:: <JapaneseSn>
cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
# cn:: <JapaneseCn>
title:: 5Za25qWt6YOoIOmDqOmVtw==
# title:: <JapaneseTitle>
givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
# givenname;lang-ja;phonetic::
<JapaneseGivenname_in_phonetic_representation_kana>
sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
# sn;lang-ja;phonetic:: <JapaneseSn_in_phonetic_representation_kana>
cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
# cn;lang-ja;phonetic:: <JapaneseCn_in_phonetic_representation_kana>
title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
# title;lang-ja;phonetic::
# <JapaneseTitle_in_phonetic_representation_kana>
givenname;lang-en: Rodney
sn;lang-en: Ogasawara
cn;lang-en: Rodney Ogasawara
title;lang-en: Sales, Director







Good                        Standards Track                     [Page 9]

RFC 2849              LDAP Data Interchange Format             June 2000


Example 5: A file containing a reference to an external file

version: 1
dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Horatio Jensen

cn: Horatio N Jensen
sn: Jensen
uid: hjensen
telephonenumber: +1 408 555 1212
jpegphoto:< file:///usr/local/directory/photos/hjensen.jpg

Example 6: A file containing a series of change records and comments

version: 1
# Add a new entry
dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
changetype: add
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Fiona Jensen
sn: Jensen
uid: fiona
telephonenumber: +1 408 555 1212
jpegphoto:< file:///usr/local/directory/photos/fiona.jpg

# Delete an existing entry
dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com
changetype: delete

# Modify an entry's relative distinguished name
dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
changetype: modrdn
newrdn: cn=Paula Jensen
deleteoldrdn: 1

# Rename an entry and move all of its children to a new location in
# the directory tree (only implemented by LDAPv3 servers).
dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
changetype: modrdn
newrdn: ou=Product Development Accountants
deleteoldrdn: 0
newsuperior: ou=Accounting, dc=airius, dc=com




Good                        Standards Track                    [Page 10]

RFC 2849              LDAP Data Interchange Format             June 2000


# Modify an entry: add an additional value to the postaladdress
# attribute, completely delete the description attribute, replace
# the telephonenumber attribute with two values, and delete a specific
# value from the facsimiletelephonenumber attribute
dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com
changetype: modify
add: postaladdress
postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
-

delete: description
-
replace: telephonenumber
telephonenumber: +1 408 555 1234
telephonenumber: +1 408 555 5678
-
delete: facsimiletelephonenumber
facsimiletelephonenumber: +1 408 555 9876
-

# Modify an entry: replace the postaladdress attribute with an empty
# set of values (which will cause the attribute to be removed), and
# delete the entire description attribute. Note that the first will
# always succeed, while the second will only succeed if at least
# one value for the description attribute is present.
dn: cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com
changetype: modify
replace: postaladdress
-
delete: description
-

Example 7: An LDIF file containing a change record with a control
version: 1
# Delete an entry. The operation will attach the LDAPv3
# Tree Delete Control defined in [9]. The criticality
# field is "true" and the controlValue field is
# absent, as required by [9].
dn: ou=Product Development, dc=airius, dc=com
control: 1.2.840.113556.1.4.805 true
changetype: delete










Good                        Standards Track                    [Page 11]

RFC 2849              LDAP Data Interchange Format             June 2000


Security Considerations

   Given typical directory applications, an LDIF file is likely to
   contain sensitive personal data.  Appropriate measures should be
   taken to protect the privacy of those persons whose data is contained
   in an LDIF file.

   Since ":<" directives can cause external content to be included when
   processing an LDIF file, one should be cautious of accepting LDIF
   files from external sources.  A "trojan" LDIF file could name a file
   with sensitive contents and cause it to be included in a directory
   entry, which a hostile entity could read via LDAP.

   LDIF does not provide any method for carrying authentication
   information with an LDIF file.  Users of LDIF files must take care to
   verify the integrity of an LDIF file received from an external
   source.

Acknowledgments

   The LDAP Interchange Format was developed as part of the University
   of Michigan LDAP reference implementation, and was developed by Tim
   Howes, Mark Smith, and Gordon Good.  It is based in part upon work
   supported by the National Science Foundation under Grant No.  NCR-
   9416667.

   Members of the IETF LDAP Extensions Working group provided many
   helpful suggestions. In particular, Hallvard B. Furuseth of the
   University of Oslo made many significant contributions to this
   document, including a thorough review and rewrite of the BNF.

References

   [1]  Howes, T. and M. Smith, "A MIME Content-Type for Directory
        Information", RFC 2425, September 1998.

   [2]  Crocker, D., and P. Overell, "Augmented BNF for Syntax
        Specifications: ABNF", RFC 2234, November 1997.

   [3]  Wahl, M., Kille, S. and T. Howes, "A String Representation of
        Distinguished Names", RFC 2253, December 1997.

   [4]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access
        Protocol (v3)", RFC 2251, July 1997.

   [5]  Freed, N. and N. Borenstein, "Multipurpose Internet Mail
        Extensions (MIME) Part One: Format of Internet Message Bodies",
        RFC 2045, November 1996.



Good                        Standards Track                    [Page 12]

RFC 2849              LDAP Data Interchange Format             June 2000


   [6]  Berners-Lee,  T., Masinter, L. and M. McCahill, "Uniform
        Resource Locators (URL)", RFC 1738, December 1994.

   [7]  Bradner, S., "Key Words for use in RFCs to Indicate Requirement
        Levels", BCP 14, RFC 2119, March 1997.

   [8]  The SLAPD and SLURPD Administrators Guide.  University of
        Michigan, April 1996.  <URL:
        http://www.umich.edu/~dirsvcs/ldap/doc/guides/slapd/toc.html>

   [9]  M. P. Armijo, "Tree Delete Control", Work in Progress.

Author's Address

   Gordon Good
   iPlanet e-commerce Solutions
   150 Network Circle
   Mailstop USCA17-201
   Santa Clara, CA 95054, USA

   Phone: +1 408 276 4351
   EMail:  ggood@netscape.com





























Good                        Standards Track                    [Page 13]

RFC 2849              LDAP Data Interchange Format             June 2000


Full Copyright Statement

   Copyright (C) The Internet Society (2000).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Good                        Standards Track                    [Page 14]

alt-openldap11-devel/rfc/rfc3673.txt000064400000023423150410163170012775 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 3673                           OpenLDAP Foundation
Category: Standards Track                                  December 2003


       Lightweight Directory Access Protocol version 3 (LDAPv3):
                       All Operational Attributes

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2003).  All Rights Reserved.

Abstract

   The Lightweight Directory Access Protocol (LDAP) supports a mechanism
   for requesting the return of all user attributes but not all
   operational attributes.  This document describes an LDAP extension
   which clients may use to request the return of all operational
   attributes.

1.  Overview

   X.500 [X.500] provides a mechanism for clients to request all
   operational attributes be returned with entries provided in response
   to a search operation.  This mechanism is often used by clients to
   discover which operational attributes are present in an entry.

   This documents extends the Lightweight Directory Access Protocol
   (LDAP) [RFC3377] to provide a simple mechanism which clients may use
   to request the return of all operational attributes.  The mechanism
   is designed for use with existing general purpose LDAP clients
   (including web browsers which support LDAP URLs) and existing LDAP
   APIs.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].






Zeilenga                    Standards Track                     [Page 1]

RFC 3673           LDAPv3: All Operational Attributes      December 2003


2.  All Operational Attributes

   The presence of the attribute description "+" (ASCII 43) in the list
   of attributes in a Search Request [RFC2251] SHALL signify a request
   for the return of all operational attributes.

   As with all search requests, client implementors should note that
   results may not include all requested attributes due to access
   controls or other restrictions.  Client implementors should also note
   that certain operational attributes may be returned only if requested
   by name even when "+" is present.  This is because some operational
   attributes are very expensive to return.

   Servers supporting this feature SHOULD publish the Object Identifier
   1.3.6.1.4.1.4203.1.5.1 as a value of the 'supportedFeatures'
   [RFC3674] attribute in the root DSE.

3.  Interoperability Considerations

   This mechanism is specifically designed to allow users to request all
   operational attributes using existing LDAP clients.  In particular,
   the mechanism is designed to be compatible with existing general
   purpose LDAP clients including those supporting LDAP URLs [RFC2255].

   The addition of this mechanism to LDAP is not believed to cause any
   significant interoperability issues (this has been confirmed through
   testing).  Servers which have yet to implement this specification
   should ignore the "+" as an unrecognized attribute description per
   [RFC2251, Section 4.5.1].  From the client's perspective, a server
   which does not return all operational attributes when "+" is
   requested should be viewed as having other restrictions.

   It is also noted that this mechanism is believed to require no
   modification of existing LDAP APIs.

4.  Security Considerations

   This document provides a general mechanism which clients may use to
   discover operational attributes.  Prior to the introduction of this
   mechanism, operational attributes were only returned when requested
   by name.  Some might have viewed this as obscurity feature.  However,
   this feature offers a false sense of security as the attributes were
   still transferable.

   Implementations SHOULD implement appropriate access controls
   mechanisms to restricts access to operational attributes.





Zeilenga                    Standards Track                     [Page 2]

RFC 3673           LDAPv3: All Operational Attributes      December 2003


5.  IANA Considerations

   This document uses the OID 1.3.6.1.4.1.4203.1.5.1 to identify the
   feature described above.  This OID was assigned [ASSIGN] by OpenLDAP
   Foundation, under its IANA-assigned private enterprise allocation
   [PRIVATE], for use in this specification.

   Registration of this feature has been completed by IANA [RFC3674],
   [RFC3383].

   Subject: Request for LDAP Protocol Mechanism Registration

   Object Identifier: 1.3.6.1.4.1.4203.1.5.1

   Description: All Op Attrs

   Person & email address to contact for further information:
        Kurt Zeilenga <kurt@openldap.org>

   Usage: Feature

   Specification: RFC3673

   Author/Change Controller: IESG

   Comments: none

6.  Acknowledgment

   The "+" mechanism is believed to have been first suggested by Bruce
   Greenblatt in a November 1998 post to the IETF LDAPext Working Group
   mailing list.

7.  Intellectual Property Statement

   The IETF takes no position regarding the validity or scope of any
   intellectual property or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; neither does it represent that it
   has made any effort to identify any such rights.  Information on the
   IETF's procedures with respect to rights in standards-track and
   standards-related documentation can be found in BCP-11.  Copies of
   claims of rights made available for publication and any assurances of
   licenses to be made available, or the result of an attempt made to
   obtain a general license or permission for the use of such
   proprietary rights by implementors or users of this specification can
   be obtained from the IETF Secretariat.



Zeilenga                    Standards Track                     [Page 3]

RFC 3673           LDAPv3: All Operational Attributes      December 2003


   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights which may cover technology that may be required to practice
   this standard.  Please address the information to the IETF Executive
   Director.

8.  References

8.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC3377]  Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

   [RFC3674]  Zeilenga, K., "Feature Discovery in Lightweight Directory
              Access Protocol (LDAP)", RFC 3674, December 2003.

8.2.  Informative References

   [RFC2255]  Howes, T. and M. Smith, "The LDAP URL Format", RFC 2255,
              December 1997.

   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [X.500]    ITU-T Rec.  X.500, "The Directory: Overview of Concepts,
              Models and Service", 1993.

   [ASSIGN]   OpenLDAP Foundation, "OpenLDAP OID Delegations",
              http://www.openldap.org/foundation/oid-delegate.txt.

   [PRIVATE]  IANA, "Private Enterprise Numbers",
              http://www.iana.org/assignments/enterprise-numbers.

9.  Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org




Zeilenga                    Standards Track                     [Page 4]

RFC 3673           LDAPv3: All Operational Attributes      December 2003


10.  Full Copyright Statement

   Copyright (C) The Internet Society (2003).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assignees.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Zeilenga                    Standards Track                     [Page 5]

alt-openldap11-devel/rfc/rfc3663.txt000064400000122424150410163170012775 0ustar00





Network Working Group                                          A. Newton
Request for Comments: 3663                                VeriSign, Inc.
Category: Experimental                                     December 2003


                       Domain Administrative Data
            in Lightweight Directory Access Protocol (LDAP)

Status of this Memo

   This memo defines an Experimental Protocol for the Internet
   community.  It does not specify an Internet standard of any kind.
   Discussion and suggestions for improvement are requested.
   Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2003).  All Rights Reserved.

Abstract

   Domain registration data has typically been exposed to the general
   public via Nicname/Whois for administrative purposes.  This document
   describes the Referral Lightweight Directory Access Protocol (LDAP)
   Service, an experimental service using LDAP and well-known LDAP types
   to make domain administrative data available.

























Newton                        Experimental                      [Page 1]

RFC 3663           Domain Administrative Data in LDAP      December 2003


Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
       1.1.  Historical Directory Services for Domain Registration
             Data . . . . . . . . . . . . . . . . . . . . . . . . . .  3
       1.2.  Motivations. . . . . . . . . . . . . . . . . . . . . . .  3
       1.3.  Abbreviations Used . . . . . . . . . . . . . . . . . . .  4
   2.  Service Description. . . . . . . . . . . . . . . . . . . . . .  4
   3.  Registry LDAP Service. . . . . . . . . . . . . . . . . . . . .  6
       3.1.  TLD DIT. . . . . . . . . . . . . . . . . . . . . . . . .  6
             3.1.1.  DIT Structure. . . . . . . . . . . . . . . . . .  6
             3.1.2.  Allowed Searches . . . . . . . . . . . . . . . .  7
             3.1.3.  Access Control . . . . . . . . . . . . . . . . .  7
       3.2.  Name Server DIT. . . . . . . . . . . . . . . . . . . . .  8
             3.2.1.  DIT Structure. . . . . . . . . . . . . . . . . .  8
             3.2.2.  Allowed Searches . . . . . . . . . . . . . . . .  8
       3.3.  Registrar Referral DIT . . . . . . . . . . . . . . . . .  9
             3.3.1.  DIT Structure. . . . . . . . . . . . . . . . . .  9
   4.  Registrar LDAP Service . . . . . . . . . . . . . . . . . . . . 10
       4.1.  TLD DIT. . . . . . . . . . . . . . . . . . . . . . . . . 10
             4.1.1.  DIT Structure. . . . . . . . . . . . . . . . . . 10
             4.1.2.  Allowed Searches . . . . . . . . . . . . . . . . 11
             4.1.3.  Access Control . . . . . . . . . . . . . . . . . 11
       4.2.  Name Server and Contact DIT. . . . . . . . . . . . . . . 12
             4.2.1.  DIT Structure. . . . . . . . . . . . . . . . . . 12
             4.2.2.  Allowed Searches . . . . . . . . . . . . . . . . 13
   5.  Clients. . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
   6.  Lessons Learned. . . . . . . . . . . . . . . . . . . . . . . . 14
       6.1.  Intra-Server Referrals . . . . . . . . . . . . . . . . . 14
       6.2.  Inter-Server Referrals . . . . . . . . . . . . . . . . . 15
       6.3.  Common DIT . . . . . . . . . . . . . . . . . . . . . . . 15
       6.4.  Universal Client . . . . . . . . . . . . . . . . . . . . 16
       6.5.  Targeting Searches by Tier . . . . . . . . . . . . . . . 16
       6.6.  Data Mining. . . . . . . . . . . . . . . . . . . . . . . 16
   7.  IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 16
   8.  Internationalization Considerations. . . . . . . . . . . . . . 16
   9.  Security Considerations. . . . . . . . . . . . . . . . . . . . 17
   10. Intellectual Property Statement. . . . . . . . . . . . . . . . 17
   11. Normative References . . . . . . . . . . . . . . . . . . . . . 18
   Appendix A.  Other Work. . . . . . . . . . . . . . . . . . . . . . 19
   Appendix B.  Acknowledgments . . . . . . . . . . . . . . . . . . . 19
   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 20
   Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 21








Newton                        Experimental                      [Page 2]

RFC 3663           Domain Administrative Data in LDAP      December 2003


1.  Introduction

   This document describes the Referral Lightweight Directory Access
   Protocol (LDAP) Service, an experimental project launched by
   VeriSign, Inc., to explore the use of LDAP and LDAP-related
   technologies for use as a directory service of administrative domain
   registration information.

1.1.  Historical Directory Services for Domain Registration Data

   The original National Science Foundation contract for the InterNIC
   called for the creation of an X.500 directory service for the
   administrative needs of the domain registration data and information.
   Due to problems with implementations of X.500 server software, a
   server based on the Nicname/Whois [1] protocol was temporarily
   erected.

   In 1994, the Rwhois [3] protocol was introduced to enhance the
   Nicname/Whois protocol.  This directory service never gained wide
   acceptance for use with domain data.

   Presently, ICANN requires the operation of Nicname/Whois servers by
   registries and registrars of generic Top-Level Domains (TLD's).

1.2.  Motivations

   With the recent split in functional responsibilities between
   registries and registrars, the constant misuse and data-mining of
   domain registration data, and the difficulties with machine-
   readability of Nicname/Whois output, the creation of the Referral
   LDAP Service had the following motivations:

   o  Use a mechanism native to the directory protocol to refer clients
      from inquiries about specific domains made at a registry to the
      appropriate domain within the appropriate directory service at a
      registrar.

   o  Limit access to domain data based on authentication of the client.

   o  Provide structured queries and well-known and structured results.

   o  Use a directory service technology already in general use.

   Given these general criteria, LDAP [5] was selected as the protocol
   for this directory service.  The decision was also made to restrict
   the use of LDAP to features most readily available in common
   implementations.  Therefore, a goal was set to not define any new
   object classes, syntaxes, or matching rules.



Newton                        Experimental                      [Page 3]

RFC 3663           Domain Administrative Data in LDAP      December 2003


   The experiment was successful in exploring how LDAP might be used in
   this context and demonstrating the level of customization required
   for an operational service.  Conclusions and observations about this
   experiment are outlined in Section 6.

1.3.  Abbreviations Used

   The following abbreviations are used to describe the nature of this
   experiment:

      TLD: Top-Level Domain.  Refers to the domain names just beneath
      the root in the Domain Name System.  This experiment used the
      TLD's .com, .net, .org, and .edu.

      SLD: Second-Level Domain.  Refers to the domain names just beneath
      a TLD in the Domain Name System.  An example of such a domain name
      would be "example.com".

      DIT: Directory Information Tree.  One of many hierarchies of data
      entries in an LDAP server.

      DN: Distinguished Name.  The unique name of an entry in a DIT.

      cn: common name.  See RFC 2256 [7].

      dc: domain component.  See RFC 2247 [4].

      uid: user id.  See RFC 2798 [9].

2.  Service Description

   The service is composed of three distinct server types: a registry
   LDAP server, registrar LDAP servers, and registrant LDAP servers.

   The registry LDAP server contains three Directory Information Trees
   (DIT's).

   o  The Top-Level Domain DIT's follow the DNS hierarchy for domains
      (e.g., dc=foo,dc=com).

   o  The name server DIT allows a view of the name servers, many of
      which serve multiple domains.

   o  The registrar-referral DIT provides referrals from the registry
      into the respective TLD DIT of the registrars (on a TLD basis).






Newton                        Experimental                      [Page 4]

RFC 3663           Domain Administrative Data in LDAP      December 2003


   The registrar LDAP server contains two types of DIT's.

   o  The TLD DIT follows the DNS hierarchy for domains (e.g.,
      dc=foo,dc=com) and parallels the TLD DIT of the registry.

   o  The name server and contact DIT allow a view of the name servers
      and contacts, many of which are associated and serve multiple
      domains.

   There is no specification on the DIT or schema for the registrant
   LDAP server.  Referrals from the registrar server to the registrant
   server are provided solely for the purpose of allowing the registrant
   direct control over extra administrative information as it relates to
   a particular domain.

   Access control for this service is merely a demonstration of using a
   Distinguished Name (DN) and password.  Should registries and
   registrars uniformly adopt LDAP as a means to disseminate domain
   registration data, standardization of these DN's would need to be
   undertaken based on each type of user base.































Newton                        Experimental                      [Page 5]

RFC 3663           Domain Administrative Data in LDAP      December 2003


3.  Registry LDAP Service

3.1.  TLD DIT

3.1.1.  DIT Structure

   The registry TLD DIT has the following structural hierarchy:

                          TLD (e.g., dc=net)
                                  |
                                  |
               -------------------------------------
               |                                   |
      SLD (e.g., dc=foo,dc=net)           SLD (e.g., dc=bar,dc=net)
               |                                   |
       ---------------------            ---------------------
       |           |       |            |           |       |
   name server     |       |        name server     |       |
   (e.g.,          |       |        (e.g.,          |       |
   cn=nameserver1, |       |        cn=nameserver1, |       |
   dc=foo,dc=net ) |       |        dc=bar,dc=net ) |       |
                   |       |                        |       |
          name server      |               name server      |
          (e.g.,           |               (e.g.,           |
          cn=nameserver2,  |               cn=nameserver2,  |
          dc=foo,dc=net )  |               dc=bar,dc=net )  |
                           |                                |
                registrar referral               registrar referral
                (e.g.,                           (e.g.,
                cn=registrar,                    cn=registrar,
                dc=foo,dc=net )                  dc=bar,dc=net )


                    Figure 1: Registry DIT Overview

   The root of a TLD DIT is an entry of objectclass domain as specified
   by RFC 2247 [4] and represents a top-level domain.

   The second tier of the DIT represents second-level domains.  Each of
   these entries is of objectclass domain as specified by RFC 2247 [4].
   The description attribute on these entries often contains descriptive
   text giving the name of the registrar through which these domains
   have been registered.

   The third tier contains entries specific to each second-level domain.
   Name server entries are of objectclass ipHost as specified by RFC
   2307 [8].  The distinguished names of these name server entries are
   algorithmically calculated, where the first component is the word



Newton                        Experimental                      [Page 6]

RFC 3663           Domain Administrative Data in LDAP      December 2003


   "nameserver" concatenated with an index number of the name server
   entry and the remaining components are the appropriate domain names.
   There is no specification relating the value of the name server entry
   to the index it may be assigned other than it is unique and
   consistent with respect to the client session.  This tier also
   contains the referral from the registry to the registrar.  This
   referral is a direct referral to the entry in the appropriate
   registrar LDAP server corresponding to the domain name that the
   referral falls beneath in this DIT.

3.1.2.  Allowed Searches

   Because of the vast number of entries contained within this DIT, only
   certain types of searches are allowed.  Allowing any search
   expressible via LDAP would lead to expensive searches that would be
   far too costly for a publicly available service.  The searches
   allowed are as follows:

   o  One-level scoped searches based at the root of the DIT.  Substring
      matching is allowed on dc attributes, but the substring must be at
      least be 3 characters in length.

   o  Base search based at the root of the DIT.

   o  Base, one-level, and sub-tree searches based at any second level
      domain name (the second tier) and below.

3.1.3.  Access Control

   The registry TLD DIT only has one access control type.  When a client
   binds with a DN of "cn=trademark" and password of "attorney", the
   second-level domain entries also take on an objectclass of
   extensibleObject with the added attributes of "createddate" and
   "registrationexpirationdate", which are of type Generalized Time, as
   specified by RFC 2252 [6].
















Newton                        Experimental                      [Page 7]

RFC 3663           Domain Administrative Data in LDAP      December 2003


3.2.  Name Server DIT

3.2.1.  DIT Structure

   The registry name server DIT has the following structural hierarchy:

                         (o=nsiregistry.com)
                                  |
                                  |
               -------------------------------------
               |                  |                |
           name server        name server      name server
         (cn=ns1.foo.net)   (cn=ns.bar.com)  (cn=named.acme.org)


                    Figure 2: Registry DIT Overview

   The root of a name server DIT is an entry of objectclass organization
   as specified by RFC 1617 [2].  It has no significance other than to
   serve as the root of the DIT.

   The second tier of this DIT represents name servers.  Each of these
   entries is of objectclass ipHost, as specified by RFC 2307 [8].

3.2.2.  Allowed Searches

   Because of the vast number of entries contained within this DIT, only
   certain types of searches are allowed.  Allowing any search
   expressible via LDAP would lead to searches far too costly for a
   publicly available service.  The searches allowed are as follows:

   o  One-level and sub-tree scoped searches based at the root of the
      DIT if a filter on the cn attribute is provided.

   o  Base search based at the root of the DIT.

   o  Base, one-level, and sub-tree searches based at any name server
      entry.













Newton                        Experimental                      [Page 8]

RFC 3663           Domain Administrative Data in LDAP      December 2003


3.3.  Registrar Referral DIT

3.3.1.  DIT Structure

   The registry registrar-referral DIT has the following structural
   hierarchy:

                        (o=tlds)
                           |
                           |
            -------------------------------
            |         |         |         |
           tld       tld       tld       tld
         (dc=net)  (dc=com)  (dc=org)  (dc=edu)
            |         |         |         |
            :         :         |         :
            :         :         |         :
                                |
                   ---------------------------
                   |            |            |
               referral to  referral to  referral to
               registrar 1  registrar 2  registrar n
               dc=org DIT   dc=org DIT   dc=org DIT


                Figure 3: Registry Referral DIT Overview

   The root of the registrar referral DIT is an entry of objectclass
   organization, as specified by RFC 1617 [2].  It has no significance
   other than to serve as the root of this DIT.

   The second tier of this DIT represents top-level domains.  Each of
   these entries is of objectclass domain, as specified by RFC 2247 [4].

   Underneath each TLD entry, the third tier contains referrals to the
   appropriate TLD DIT of each registrar.















Newton                        Experimental                      [Page 9]

RFC 3663           Domain Administrative Data in LDAP      December 2003


4.  Registrar LDAP Service

4.1.  TLD DIT

4.1.1.  DIT Structure

   The registrar TLD DIT, which is similar to the registry TLD DIT, has
   the following structural hierarchy:

                          TLD (e.g., dc=net)
                                  |
                                  |
               ------------------------------------------------
               |                                          |   |
      SLD (e.g., dc=foo,dc=net)                           :   :
               |                                          :   :
       ---------------------------------------------
       |                        |                  |
       |                        |                  |
   name server            contact             referral to
   (e.g., cn=nameserver1, (e.g., cn=contact1, registrant
   dc=foo,dc=net       )  dc=foo,dc=net    )
       |
       |
   name server contact
   (e.g., cn=contact,
   cn=nameserver1,
   dc=foo,dc=net     )

                    Figure 4: Registrar DIT Overview

   The root of a TLD DIT is an entry of objectclass domain, as specified
   by RFC 2247 [4] and represents a top-level domain.

   The second tier of the DIT represents second-level domains.  Each of
   these entries is of objectclass domain, as specified by RFC 2247 [4].

   The third tier contains entries specific to each second-level domain.
   The entries at this level are as follows:

   o  Name server entries are of objectclass ipHost, as specified by RFC
      2307 [8].  The distinguished names of these name server entries
      are algorithmically calculated where the first component is the
      word "nameserver" concatenated with an index number of the name
      server entry and the remaining components are the appropriate
      domain names.  There is no specification relating the value of the
      name server entry to the index it may be assigned other than it is
      unique and consistent with respect to the client session.



Newton                        Experimental                     [Page 10]

RFC 3663           Domain Administrative Data in LDAP      December 2003


   o  Contact entries are of objectclass inetOrgPerson, as specified by
      RFC 2798 [9].  The distinguished names of these contact entries
      are algorithmically calculated, where the first component is the
      word "contact" concatenated with an index number of the contact
      and the remaining components are the appropriate domain names.
      There is no specification relating the value of the contact entry
      to the index it may be assigned other than it is unique and
      consistent with respect to the client session.  The description
      attribute of the entry contains the role for which a contact is
      related to a domain.  These roles are identified as "Admin
      Contact", "Technical Contact", and "Billing Contact", and may
      appear in any order.

   o  Finally, this third tier contains the referral from the registrar
      to the registrant.

   The fourth tier only contains name server contact entries.  These
   entries are of objectclass inetOrgPerson, as specified by RFC 2798
   [9].

4.1.2.  Allowed Searches

   Because of the vast number of entries contained within this DIT, only
   certain types of searches are allowed.  Allowing any search
   expressible via LDAP would lead to searches far too costly for a
   publicly available service.  The searches allowed are as follows:

   o  One-level scoped searches based at the root of the DIT.  Substring
      matching is allowed on dc and o attributes, but the substring must
      be at least 3 characters in length.

   o  Base search based at the root of the DIT.

   o  Base, one-level, and sub-tree searches based at any second level
      domain name (the second tier) and below.

4.1.3.  Access Control

   The registrar TLD DIT has two access control types.  When binding
   anonymously, a client only sees dc, o, and c attributes of the
   second-level domain entries.  When a client binds with a DN of
   "cn=trademark" and password of "attorney", all of the other
   attributes normally available on entries of objectclass domain are
   visible if they have values.  In addition, if a client binds with the
   DN of a contact and password of "password", all attributes for
   second-level domain entries for which the bind DN has a relation are
   visible.




Newton                        Experimental                     [Page 11]

RFC 3663           Domain Administrative Data in LDAP      December 2003


4.2.  Name Server and Contact DIT

4.2.1.  DIT Structure

   The registrar name server and contact DIT has the following
   structural hierarchy:

                             (o=nsi.com)
                                  |
                                  |
               --------------------------------------
               |                                    |
            Contacts                           Name Servers
          (ou=contacts)                     (ou=name servers)
               |                                    |
        -----------------                ------------------------
        |             | |                |                    | |
     Contact          : :            Name Server              : :
   (uid=handle)       : :            (cn=handle)              : :
                                         |
                                     Name Server
                                       Contact
                                     (cn=contact1)

                    Figure 5: Registrar DIT Overview

   The first tier of the name server and contact DIT is an entry of
   objectclass organization, as specified by RFC 1617 [2].

   The second tier of the DIT contains two entries, each of which is of
   objectclass organizationalUnit, as specified by RFC 2256 [7].  One
   entry represents the part of the DIT containing contacts and the
   other entry represents the part of the DIT containing name servers.

   Entries underneath the contacts organizationalUnit entry are of
   objectclass inetOrgPerson and represent contacts registered with the
   registrar.  Their RDN is composed of the uid attribute.  The uid
   attribute's value is a unique identifier or handle that is registrar
   assigned.

   Entries underneath the name server organizationalUnit entry are of
   objectclass ipHost and represent name servers registered with the
   registrar.  Their RDN is composed of the cn attribute.  The cn
   attribute's value is a unique identifier or handle that is registrar
   assigned.  Each name server entry may optionally have children
   entries of objectclass inetOrgPerson.  These entries represent the
   contacts of the name server they fall beneath.




Newton                        Experimental                     [Page 12]

RFC 3663           Domain Administrative Data in LDAP      December 2003


4.2.2.  Allowed Searches

   Because of the vast number of entries contained within this DIT, only
   certain types of searches are allowed.  Allowing any search
   expressible via LDAP would lead to searches far too costly for a
   publicly available service.  The searches allowed are as follows:

   o  One-level and base searches at the root of the DIT.

   o  Sub-tree searches at the root of the DIT using cn and uid
      attributes as a filter.

   o  Base searches at either entry of the second tier.

   o  One-level and sub-tree searches at either entry of the second
      tier, using cn or uid attributes as a filter.

   o  Base, one-level, and sub-tree searches based at any contact or
      name server entry and below.

5.  Clients

   Early scoping and analysis of this project were based on the use of
   output from command line clients, specifically the "ldapsearch"
   command present with many implementations of LDAP servers.  Our
   survey of this tool, available from many vendors, showed that
   referral chasing was difficult to control or predict, and the
   behavior between these implementations with respect to referral
   chasing was inconsistent.

   Based on the limited nature of the expressive capabilities present
   with just command line tools, searches involving nested queries or
   advanced referral chasing were deemed the domain of clients making
   direct use of LDAP client libraries.  Three of these types of clients
   were produced: a web-based client, a cross-platform C-based client,
   and a Java client.  No significant deficiencies or problems were
   found with the LDAP client libraries in the construction of these
   clients, and the level of control provided by their programming
   interfaces was adequate to create the necessary searches.  Instead,
   most of the problems encountered with these clients were based on
   usability concerns.

   It was found that the web-based client caused a great amount of
   confusion for users not familiar with LDAP or Nicname/Whois with
   respect to the underlying technology and the network model.  Thus,
   many users believed the web-based client to be the only interface to
   the data and were unaware or confused by the intermediate LDAP
   protocol.  In addition, it was difficult to express to users the



Newton                        Experimental                     [Page 13]

RFC 3663           Domain Administrative Data in LDAP      December 2003


   registry-registrar-registrant service model in adequate terms from
   search results where the results could be rendered properly among the
   various common web browsers.

   Both the C and Java based clients were built to be both graphical and
   cross-platform (in the case of the C-based client, the Linux and
   Windows platforms were chosen as targets).  The LDAP client libraries
   chosen for both clients proved to be quite capable and offered the
   necessary levels of control for conducting nested queries and
   advanced referral chasing.  Expectations at the outset for
   construction of both clients, based on past experience, were that the
   C-based client would not only perform better than the Java client but
   also have a better appearance.  In reality, these assumptions were
   incorrect as there was no perceivable difference in performance and
   the look of the Java client was often considered to be far superior
   to its counter-part.  In addition, the Java client required much less
   time to create.  Both clients are available under the terms of an
   open source license.  Though it is impossible to have accurate
   measurements of their popularity, through monitoring and feedback it
   was perceived that the web-based client had far greater use.

6.  Lessons Learned

   Based on the experience of piloting this experimental service,
   feedback from users of the service, and general comments and
   observations of current and common opinions, the following items have
   been noted.

6.1.  Intra-Server Referrals

   Original analysis of the data set to be used revealed a high degree
   of relationships between name servers, contacts, and domains.
   Storing the data in non-normalized form according to the DIT outlined
   in this document would make an original relational dataset of roughly
   20 million objects explode to over 115 million objects.

   To combat this problem, the first pass at defining the DIT's made
   heavy use of referrals between the TLD DIT's and the name server and
   contact DIT's.  The use of the 'alias' objectclass was considered but
   ruled out in hopes of using referrals for load balancing across
   servers (i.e., placing each TLD DIT on a separate server, and
   separate servers for the name server and contact DIT's).  However,
   initial testing with the 'ldapsearch' command found inconsistencies
   with the interpretation of the referrals and how they were managed.
   Not only were the results inconsistent between implementations, but
   many of these clients would easily get caught in referral loops.





Newton                        Experimental                     [Page 14]

RFC 3663           Domain Administrative Data in LDAP      December 2003


   The final solution to the problem was to create a customized back-end
   data store containing the data in a normalized form.  This gave the
   client the appearance of having a non-normalized data set which
   required no intra-server referrals.  Aliases may have been a better
   solution, however our interpretation of their output with
   implementations of the 'ldapsearch' tool was not satisfactory.  It
   was also later learned that some LDAP server implementations place
   certain restrictions on aliases that would have conflicted with our
   overall DIT structure.  In the end, it was felt that a customized
   back-end would be required by any server with a large data-set, but
   smaller data-sets for less populated domains could easily use off-
   the-shelf implementations.

6.2.  Inter-Server Referrals

   The modeling of the overall service to provide the split in
   operational responsibility between registry and registrar required
   the use of referrals (i.e., the two servers would not be operated by
   the same organization, therefore would most likely not co-exist on
   the same physical machine or network).  The chief problem with LDAP
   referrals returned for this purpose grew out of the need to limit
   data returned to the client and the priority given to referrals.  It
   was quite easy to cause a sub-tree query at certain levels, for
   instance a TLD level, to return nothing but referrals.  This was true
   because referrals would be returned out of the scope of the supplied
   search filter and therefore would fill the result set to its limit,
   normally set to 50 entries.

   In certain use cases, a result set with nothing but referrals was
   desired (e.g., o=tlds).  However, even in these cases it was possible
   for some referrals to not be returned due to the size limit.  In this
   case, it was felt that a result set of 50 referrals, the default for
   the size limit in most cases, was too large for any practical use by
   a client and was a failing of query distribution in general rather
   than a limitation of LDAP.

6.3.  Common DIT

   Because of the nature of software development, the graphical and web
   clients were developed after the development of the server software.
   The 'ldapsearch' client was used for testing and development during
   server software creation.  It was not until the creation of more
   advanced clients that it was discovered that the design decision of
   uniform DIT naming should have been made.  Technically, this would
   have allowed for slightly better software modularization and re-use.
   In addition, the use of a company name in the DIT structure did not
   allow the easy integration of another domain registry, as in the
   registry-registrar model.  Not only would clients have to be



Newton                        Experimental                     [Page 15]

RFC 3663           Domain Administrative Data in LDAP      December 2003


   reconfigured for each new registry operator, but this would most
   likely have social implications as well.

6.4.  Universal Client

   The construction of the clients revealed yet another misconception.
   Though this project used a generic directory service technology, the
   clients required a high-degree of algorithmic knowledge about the DIT
   structure and schemas being used.  The graphical clients could not be
   used against an LDAP service with another DIT or schema.  Therefore,
   a generic or universal client, one that could be used for all LDAP
   applications, would either not be able to make full use of the data
   provided by the service or would be far too complex for operation by
   the average user.

6.5.  Targeting Searches by Tier

   The network model for this service was divided into three tiers:
   registry, registrar, and registrant.  Despite this, all searches
   needed to start at the registry level causing overhead for searches
   that could be targeted at a select tier.  This service did not
   implement a solution to this problem, such as using SRV and/or NAPTR
   records in DNS to allow a client to find a responsible LDAP server.

6.6.  Data Mining

   Section 3.1.2 and Section 4.1.2 describe the searches allowed by this
   service.  However, the most common question asked by users of the
   service revolved around getting around these restrictions.  Because
   browsing at the TLD level was not permitted, many users asked about
   the feasibility of using recursive dictionary queries to circumvent
   the search restrictions.

   It should be noted that many operators of Nicname/Whois server
   consider this practice to be data mining and often refer to it
   specifically as a dictionary attack.

7.  IANA Considerations

   There are no applicable IANA considerations presented in this
   document.

8.  Internationalization Considerations

   The domain administrative data in this service did not cover
   Internationalized Domain Names (IDN's).





Newton                        Experimental                     [Page 16]

RFC 3663           Domain Administrative Data in LDAP      December 2003


9.  Security Considerations

   This experiment did not endeavor to use security mechanisms beyond
   those readily available in LDAP [5].  Section 3.1.3 and Section 4.1.3
   describe the various access controls used within the scope of the
   defined security mechanisms.   While these mechanisms were adequate
   for this experimental deployment, they would not be adequate for a
   production environment, and they should not be taken as a model for
   those contemplating deployment on the Internet.

10.  Intellectual Property Statement

   The IETF takes no position regarding the validity or scope of any
   intellectual property or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; neither does it represent that it
   has made any effort to identify any such rights.  Information on the
   IETF's procedures with respect to rights in standards-track and
   standards-related documentation can be found in BCP-11.  Copies of
   claims of rights made available for publication and any assurances of
   licenses to be made available, or the result of an attempt made to
   obtain a general license or permission for the use of such
   proprietary rights by implementors or users of this specification can
   be obtained from the IETF Secretariat.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights which may cover technology that may be required to practice
   this standard.  Please address the information to the IETF Executive
   Director.




















Newton                        Experimental                     [Page 17]

RFC 3663           Domain Administrative Data in LDAP      December 2003


11.  Normative References

   [1]  Harrenstien, K., Stahl, M. and E. Feinler, "NICNAME/WHOIS", RFC
        954, October 1985.

   [2]  Barker, P., Kille, S. and T. Lenggenhager, "Naming and
        Structuring Guidelines for X.500 Directory Pilots", RFC 1617,
        May 1994.

   [3]  Williamson, S., Kosters, M., Blacka, D., Singh, J. and K.
        Zeilstra, "Referral Whois (RWhois) Protocol V1.5", RFC 2167,
        June 1997.

   [4]  Kille, S., Wahl, M., Grimstad, A., Huber, R. and S. Sataluri,
        "Using Domains in LDAP/X.500 Distinguished Names", RFC 2247,
        January 1998.

   [5]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access
        Protocol (v3)", RFC 2251, December 1997.

   [6]  Wahl, M., Coulbeck, A., Howes, T. and S. Kille, "Lightweight
        Directory Access Protocol (v3): Attribute Syntax Definitions",
        RFC 2252, December 1997.

   [7]  Wahl, M., "A Summary of the X.500(96) User Schema for use with
        LDAPv3", RFC 2256, December 1997.

   [8]  Howard, L., "An Approach for Using LDAP as a Network Information
        Service", RFC 2307, March 1998.

   [9]  Smith, M., "Definition of the inetOrgPerson LDAP Object Class",
        RFC 2798, April 2000.



















Newton                        Experimental                     [Page 18]

RFC 3663           Domain Administrative Data in LDAP      December 2003


Appendix A.  Other Work

   In addition to the deployment of servers and development of clients,
   VeriSign conducted two sub-projects related to this experiment.

   The first project was a Nicname/Whois-to-LDAP gateway.  The goal of
   the project was to create an LDAP server for use by registrars to
   deploy in front of their Nicname/Whois servers.  This gateway would
   take LDAP requests, translate them to Nicname/Whois requests, issue
   the request to a specific Nicname/Whois server deployed on port 43,
   interpret the response, and return LDAP result sets.  Because of the
   unspecified nature of Nicname/Whois result sets, the gateway was
   programmed to specifically recognize only the output of three
   distinct registrars.  While this gateway proved valuable enough to
   allow domain lookups and limited searches, it was unable to provide
   consistent contact lookups, nameserver lookups, or registrant
   referrals.  This software was also made publicly available under the
   terms of an open source license.

   The second project was an informal survey of registrants with
   deployed LDAP servers.  This was conducted by using the com, net,
   org, and edu zone files and testing for the existence of an LDAP
   server on port 389 using the name of the domain, a host named "ldap"
   in the domain, and a host named "dir" in the domain (e.g., "foo.com",
   "ldap.foo.com", and "dir.foo.com").  This survey did not attempt to
   resolve LDAP services using SRV records in DNS.

   The result of this survey found that roughly 0.5% of active domains
   had an LDAP server.  By profiling a server's root DSA-specific Entry
   (DSE), the survey found that about 90% of the servers were
   implementations provided by vendor A, 9% of the servers were
   implementations provided by vendor B, and 1% of the servers were
   implementations provided by other vendors.  Of the servers queried
   that were determined to be implementations provided by vendor A, it
   appeared that about only 10% contained public data (this also led to
   the assumption that the other 90% were not intended to be publicly
   queried).  Of the servers queried that were determined to be
   implementations provided by vendor B, it appears that nearly all
   contained public data.

Appendix B.  Acknowledgments

   Significant analysis, design, and implementation for this project
   were conducted by Brad McMillen, David Blacka, Anna Zhang, and
   Michael Schiraldi.  Mark Kosters and Leslie Daigle provided guidance
   by reviewing this project, the project's goals, and this document.





Newton                        Experimental                     [Page 19]

RFC 3663           Domain Administrative Data in LDAP      December 2003


Author's Address

   Andrew Newton
   VeriSign, Inc.
   21345 Ridgetop Circle
   Sterling, VA  20166
   USA

   Phone: +1 703 948 3382
   EMail: anewton@verisignlabs.com; anewton@ecotroph.net









































Newton                        Experimental                     [Page 20]

RFC 3663           Domain Administrative Data in LDAP      December 2003


Full Copyright Statement

   Copyright (C) The Internet Society (2003).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assignees.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Newton                        Experimental                     [Page 21]

alt-openldap11-devel/rfc/rfc3876.txt000064400000057251150410163170013010 0ustar00





Network Working Group                                        D. Chadwick
Request for Comments: 3876                         University of Salford
Category: Standards Track                                      S. Mullan
                                                        Sun Microsystems
                                                          September 2004


                   Returning Matched Values with the
        Lightweight Directory Access Protocol version 3 (LDAPv3)

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).

Abstract

   This document describes a control for the Lightweight Directory
   Access Protocol version 3 that is used to return a subset of
   attribute values from an entry.  Specifically, only those values that
   match a "values return" filter.  Without support for this control, a
   client must retrieve all of an attribute's values and search for
   specific values locally.

1.  Introduction

   When reading an attribute from an entry using the Lightweight
   Directory Access Protocol version 3 (LDAPv3) [2], it is normally only
   possible to read either the attribute type, or the attribute type and
   all its values.  It is not possible to selectively read just a few of
   the attribute values.  If an attribute holds many values, for
   example, the userCertificate attribute, or the subschema publishing
   operational attributes objectClasses and attributeTypes [3], then it
   may be desirable for the user to be able to selectively retrieve a
   subset of the values, specifically, those attribute values that match
   some user defined selection criteria.  Without the control specified
   in this document, a client must read all of the attribute's values
   and filter out the unwanted values, necessitating the client to
   implement the matching rules.  It also requires the client to





Chadwick & Mullan           Standards Track                     [Page 1]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


   potentially read and process many irrelevant values, which can be
   inefficient if the values are large or complex, or there are many
   values stored per attribute.

   This document specifies an LDAPv3 control to enable a user to return
   only those values that matched (i.e., returned TRUE to) one or more
   elements of a newly defined "values return" filter.  This control can
   be especially useful when used in conjunction with extensible
   matching rules that match on one or more components of complex binary
   attribute values.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14, RFC 2119 [4].

2.  The valuesReturnFilter Control

   The valuesReturnFilter control is either critical or non-critical as
   determined by the user.  It only has meaning for the Search
   operation, and SHOULD only be added to the Search operation by the
   client.  If the server supports the control and it is present on a
   Search operation, the server MUST obey the control, regardless of the
   value of the criticality flag.

   If the control is marked as critical, and either the server does not
   support the control or the control is applied to an operation other
   than Search, the server MUST return an unavailableCriticalExtension
   error.  If the control is not marked as critical, and either the
   server does not support the control or the control is applied to an
   operation other than Search, then the server MUST ignore the control.

   The object identifier for this control is 1.2.826.0.1.3344810.2.3.

   The controlValue is an OCTET STRING, whose value is the BER encoding
   [6], as per Section 5.1 of RFC 2251 [2], of a value of the ASN.1 [5]
   type ValuesReturnFilter.

           ValuesReturnFilter ::= SEQUENCE OF SimpleFilterItem

           SimpleFilterItem ::= CHOICE {
                   equalityMatch   [3] AttributeValueAssertion,
                   substrings      [4] SubstringFilter,
                   greaterOrEqual  [5] AttributeValueAssertion,
                   lessOrEqual     [6] AttributeValueAssertion,
                   present         [7] AttributeDescription,
                   approxMatch     [8] AttributeValueAssertion,
                   extensibleMatch [9] SimpleMatchingAssertion }




Chadwick & Mullan           Standards Track                     [Page 2]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


            SimpleMatchingAssertion ::= SEQUENCE {
                   matchingRule    [1] MatchingRuleId OPTIONAL,
                   type            [2] AttributeDescription OPTIONAL,
   --- at least one of the above must be present
                   matchValue      [3] AssertionValue}

   All the above data types have their standard meanings as defined in
   [2].

   If the server supports this control, the server MUST make use of the
   control as follows:

   1) The Search Filter is first executed in order to determine which
      entries satisfy the Search criteria (these are the filtered
      entries).  The control has no impact on this step.

   2) If the typesOnly parameter of the Search Request is TRUE, the
      control has no effect and the Search Request is processed as if
      the control had not been specified.

   3) If the attributes parameter of the Search Request consists of a
      list containing only the attribute with OID "1.1" (specifying that
      no attributes are to be returned), the control has no effect and
      the Search Request is processed as if the control had not been
      specified.

   4) For each attribute listed in the attributes parameter of the
      Search Request, the server MUST apply the control as follows to
      each entry in the set of filtered entries:

      i)  Every attribute value that evaluates TRUE against one or more
          elements of the ValuesReturnFilter is placed in the
          corresponding SearchResultEntry.

      ii) Every attribute value that evaluates FALSE or undefined
          against all elements of the ValuesReturnFilter is not placed
          in the corresponding SearchResultEntry.  An attribute that has
          no values selected is returned with an empty set of values.

   Note.  If the AttributeDescriptionList (see [2]) is empty or
   comprises "*", then the control MUST be applied against every user
   attribute.  If the AttributeDescriptionList contains a "+", then the
   control MUST be applied against every operational attribute.








Chadwick & Mullan           Standards Track                     [Page 3]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


3.  Relationship to X.500

   The control is a superset of the matchedValuesOnly (MVO) boolean of
   the X.500 Directory Access Protocol (DAP) [8] Search argument, as
   amended in the latest version [9].  Close examination of the
   matchedValuesOnly boolean by the LDAP Extensions (LDAPEXT) Working
   Group revealed ambiguities and complexities in the MVO boolean that
   could not easily be resolved.  For example, it was not clear if the
   MVO boolean governed only those attribute values that contributed to
   the overall truth of the filter, or all of the attribute values, even
   if the filter item containing the attribute was evaluated as false.
   For this reason the LDAPEXT group decided to replace the MVO boolean
   with a simple filter that removes any uncertainty as to whether an
   attribute value has been selected or not.

4.  Relationship to other LDAP Controls

   The purpose of this control is to select zero, one, or more attribute
   values from each requested attribute in a filtered entry, and to
   discard the remainder.  Once the attribute values have been discarded
   by this control, they MUST NOT be re-instated into the Search results
   by other controls.

   This control acts independently of other LDAP controls such as server
   side sorting [13] and duplicate entries [10].  However, there might
   be interactions between this control and other controls so that a
   different set of Search Result Entries are returned, or the entries
   are returned in a different order, depending upon the sequencing of
   this control and other controls in the LDAP request.  For example,
   with server side sorting, if sorting is done first, and value return
   filtering second, the set of Search Results may appear to be in the
   wrong order since the value filtering may remove the attribute values
   upon which the ordering was done.  (The sorting document specifies
   that entries without any sort key attribute values should be treated
   as coming after all other attribute values.)  Similarly with
   duplicate entries, if duplication is performed before value
   filtering, the set of Search Result Entries may contain identical
   duplicate entries, each with an empty set of attribute values,
   because the value filtering removed the attribute values that were
   used to duplicate the results.

   For these reasons, the ValuesReturnFilter control in a SearchRequest
   SHOULD precede other controls that affect the number and ordering of
   SearchResultEntrys.







Chadwick & Mullan           Standards Track                     [Page 4]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


5.  Examples

   All entries are provided in an LDAP Data Interchange Format
   (LDIF)[11].

   The string representation of the valuesReturnFilter in the examples
   below uses the following ABNF [15] notation:

   valuesReturnFilter = "(" 1*simpleFilterItem ")"
   simpleFilterItem = "(" item ")"

   where item is as defined below (adapted from RFC2254 [14]).

      item         = simple / present / substring / extensible
      simple       = attr filtertype value
      filtertype   = equal / approx / greater / less
      equal        = "="
      approx       = "~="
      greater      = ">="
      less         = "<="
      extensible   = attr [":" matchingrule] ":=" value
                     / ":" matchingrule ":=" value
      present      = attr "=*"
      substring    = attr "=" [initial] any [final]
      initial      = value
      any          = "*" *(value "*")
      final        = value
      attr         = AttributeDescription from Section 4.1.5 of [1]
      matchingrule = MatchingRuleId from Section 4.1.9 of [1]
      value        = AttributeValue from Section 4.1.6 of [1]

   1) The first example shows how the control can be set to return all
      attribute values from one attribute type (e.g., telephoneNumber)
      and a subset of values from another attribute type (e.g., mail).

   The entries below represent organizationalPerson object classes
   located somewhere beneath the distinguished name dc=ac,dc=uk.

   dn: cn=Sean Mullan,ou=people,dc=sun,dc=ac,dc=uk
   cn: Sean Mullan
   sn: Mullan
   objectClass: organizationalPerson
   objectClass: person
   objectClass: inetOrgPerson
   mail: sean.mullan@hotmail.com
   mail: mullan@east.sun.com
   telephoneNumber: + 781 442 0926
   telephoneNumber: 555-9999



Chadwick & Mullan           Standards Track                     [Page 5]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


   dn: cn=David Chadwick,ou=isi,o=salford,dc=ac,dc=uk
   cn: David Chadwick
   sn: Chadwick
   objectClass: organizationalPerson
   objectClass: person
   objectClass: inetOrgPerson
   mail: d.w.chadwick@salford.ac.uk

   An LDAP search operation is specified with a baseObject set to the DN
   of the search base (i.e., dc=ac,dc=uk), a subtree scope, a filter set
   to (sn=mullan), and the list of attributes to be returned set to
   "mail,telephoneNumber" or "*".  In addition, a ValuesReturnFilter
   control is set to ((mail=*hotmail.com)(telephoneNumber=*)).

   The search results returned by the server would consist of the
   following entry:

   dn: cn=Sean Mullan,ou=people,dc=sun,dc=ac,dc=uk
   mail: sean.mullan@hotmail.com
   telephoneNumber: + 781 442 0926
   telephoneNumber: 555-9999

   Note that the control has no effect on the values returned for the
   "telephoneNumber" attribute (all of the values are returned), since
   the control specified that all values should be returned.

   2) The second example shows how one might retrieve a single attribute
      type subschema definition for the "gunk" attribute with OID
      1.2.3.4.5 from the subschema subentry.

   Assume the subschema subentry is held below the root entry with DN
   cn=subschema subentry,o=myorg and this holds an attributeTypes
   operational attribute holding the descriptions of the 35 attributes
   known to this server (each description is held as a single attribute
   value of the attributeTypes attribute).

   dn: cn=subschema subentry,o=myorg
   cn: subschema subentry
   objectClass: subschema
   attributeTypes: ( 2.5.4.3 NAME 'cn' SUP name )
   attributeTypes: ( 2.5.4.6 NAME 'c' SUP name SINGLE-VALUE )
   attributeTypes: ( 2.5.4.0 NAME 'objectClass' EQUALITY obj
    ectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
   attributeTypes: ( 2.5.18.2 NAME 'modifyTimestamp' EQUALITY gen
    eralizedTimeMatch ORDERING generalizedTimeOrderingMatch SYN
    TAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-
    MODIFICATION USAGE directoryOperation )
   attributeTypes: ( 2.5.21.6 NAME 'objectClasses' EQUALITY obj



Chadwick & Mullan           Standards Track                     [Page 6]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


    ectIdentifierFirstComponentMatch SYNTAX 1.3.
    6.1.4.1.1466.115.121.1.37 USAGE directoryOperation )
   attributeTypes: ( 1.2.3.4.5 NAME 'gunk' EQUALITY caseIgnoreMat
    ch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.
    6.1.4.1.1466.115.121.1.44{64} )
   attributeTypes: ( 2.5.21.5 NAME 'attributeTypes' EQUALITY obj
    ectIdentifierFirstComponentMatch SYNTAX 1.3.
    6.1.4.1.1466.115.121.1.3 USAGE directoryOperation )

   plus another 28 - you get the idea.

   The user creates an LDAP search operation with a baseObject set to
   cn=subschema subentry,o=myorg, a scope of base, a filter set to
   (objectClass=subschema), the list of attributes to be returned set to
   "attributeTypes", and the ValuesReturnFilter set to
   ((attributeTypes=1.2.3.4.5))

   The search result returned by the server would consist of the
   following entry:

   dn: cn=subschema subentry,o=myorg
   attributeTypes: ( 1.2.3.4.5 NAME 'gunk' EQUALITY caseIgnoreMat
    ch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.
    6.1.4.1.1466.115.121.1.44{64} )

   3) The final example shows how the control can be used to match on a
      userCertificate attribute value.  Note that this example requires
      the LDAP server to support the certificateExactMatch matching rule
      defined in [12] as the EQUALITY matching rule for userCertificate.

   The entry below represents a pkiUser object class stored in the
   directory.

   dn: cn=David Chadwick,ou=people,o=University of Salford,c=gb
   cn: David Chadwick
   objectClass: person
   objectClass: organizationalPerson
   objectClass: pkiUser
   objectClass: inetOrgPerson
   sn: Chadwick
   mail: d.w.chadwick@salford.ac.uk
   userCertificate;binary: {binary representation of a certificate with
   a serial number of 2468 issued by o=truetrust ltd,c=gb}
   userCertificate;binary: {binary representation of certificate with a
   serial number of 1357 issued by o=truetrust ltd,c=gb}
   userCertificate;binary: {binary representation of certificate with a
   serial number of 1234 issued by dc=certsRus,dc=com}




Chadwick & Mullan           Standards Track                     [Page 7]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


   An LDAP search operation is specified with a baseObject set to
   o=University of Salford,c=gb, a subtree scope, a filter set to
   (sn=chadwick), and the list of attributes to be returned set to
   "userCertificate;binary".  In addition, a ValuesReturnFilter control
   is set to ((userCertificate=1357$o=truetrust ltd,c=gb)).

   The search result returned by the server would consist of the
   following entry:

   dn: cn=David Chadwick,ou=people,o=University of Salford,c=gb
   userCertificate;binary: {binary representation of certificate with a
   serial number of 1357 issued by o=truetrust ltd,c=gb}

6.  Security Considerations

   This document does not primarily discuss security issues.

   Note however that attribute values MUST only be returned if the
   access controls applied by the LDAP server allow them to be returned,
   and in this respect the effect of the ValuesReturnFilter control is
   of no consequence.

   Note that the ValuesReturnFilter control may have a positive effect
   on the deployment of public key infrastructures.  Certain PKI
   operations, like searching for specific certificates, become more
   scalable, and more practical when combined with X.509 certificate
   matching rules at the server, since the control avoids the
   downloading of potentially large numbers of irrelevant certificates
   which would have to be processed and filtered locally (which in some
   cases is very difficult to perform).

7.  IANA Considerations

   The Matched Values control as an LDAP Protocol Mechanism [7] has been
   registered as follows:

      Subject: Request for LDAP Protocol Mechanism Registration

      Object Identifier: 1.2.826.0.1.3344810.2.3
      Description: Matched Values Control
      Person & email address to contact for further information:
        David Chadwick <d.w.chadwick@salford.ac.uk>
      Usage: Control
      Specification: RFC3876
      Author/Change Controller: IESG
      Comments: none





Chadwick & Mullan           Standards Track                     [Page 8]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


   This document uses the OID 1.2.826.0.1.3344810.2.3 to identify the
   matchedValues control described here.  This OID was assigned by
   TrueTrust Ltd, under its BSI assigned English/Welsh Registered
   Company number [16].

8.  Acknowledgements

   The authors would like to thank members of the LDAPExt list for their
   constructive comments on earlier versions of this document, and in
   particular to Harald Alvestrand who first suggested having an
   attribute return filter and Bruce Greenblatt who first proposed a
   syntax for this control.

9.  References

9.1.  Normative References

   [1]  Bradner, S., "The Internet Standards Process -- Revision 3", BCP
        9, RFC 2026, October 1996.

   [2]  Wahl, M., Howes, T., and S. Kille, "Lightweight Directory Access
        Protocol (w3)", RFC 2251, December 1997.

   [3]  Wahl, M., Coulbeck, A., Howes, T., and S. Kille, "Lightweight
        Directory Access Protocol (v3): Attribute Syntax Definitions",
        RFC 2252, December 1997.

   [4]  Bradner, S., "Key words for use in RFCs to Indicate Requirement
        Levels", BCP 14, RFC 2119, March 1997.

   [5]  ITU-T Recommendation X.680 (1997) | ISO/IEC 8824-1:1998,
        Information Technology - Abstract Syntax Notation One (ASN.1):
        Specification of Basic Notation

   [6]  ITU-T Recommendation X.690 (1997) | ISO/IEC 8825-1,2,3:1998
        Information technology - ASN.1 encoding rules: Specification of
        Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and
        Distinguished Encoding Rules (DER)

   [7]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
        Considerations for the Lightweight Directory Access Protocol
        (LDAP)", BCP 64, RFC 3383, September 2002.









Chadwick & Mullan           Standards Track                     [Page 9]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


9.2.  Informative References

   [8]  ITU-T Rec. X.511, "The Directory: Abstract Service Definition",
        1993.

   [9]  ISO/IEC 9594 / ITU-T Rec X.511 (2001) The Directory: Abstract
        Service Definition.

   [10] Sermersheim, J., "LDAP Control for a Duplicate Entry
        Representation of Search Results", Work in Progress, October
        2000.

   [11] Good, G., "The LDAP Data Interchange Format (LDIF) - Technical
        Specification", RFC 2849, June 2000.

   [12] Chadwick, D. and S.Legg, "Internet X.509 Public Key
        Infrastructure - Additional LDAP Schema for PKIs", Work in
        Progress, June 2002

   [13] Howes, T., Wahl, M., and A. Anantha, "LDAP Control Extension for
        Server Side Sorting of Search Results", RFC 2891, August 2000.

   [14] Howes, T., "The String Representation of LDAP Search Filters",
        RFC 2254, December 1997.

   [15] Crocker, D. and P. Overell, "Augmented BNF for Syntax
        Specifications: ABNF", RFC 2234, November 1997.

   [16] BRITISH STANDARD BS 7453 Part 1. Procedures for UK Registration
        for Open System Standards Part 1: Procedures for the UK Name
        Registration Authority.




















Chadwick & Mullan           Standards Track                    [Page 10]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


10.  Authors' Addresses

   David Chadwick
   IS Institute
   University of Salford
   Salford M5 4WT
   England

   Phone: +44 161 295 5351
   EMail: d.w.chadwick@salford.ac.uk


   Sean Mullan
   Sun Microsystems
   One Network Drive
   Burlington, MA 01803
   USA

   EMail: sean.mullan@sun.com
































Chadwick & Mullan           Standards Track                    [Page 11]

RFC 3876          Returning Matched Values with LDAPv3    September 2004


11.  Full Copyright Statement

   Copyright (C) The Internet Society (2004).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE
   REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE
   INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the IETF's procedures with respect to rights in IETF Documents can
   be found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at ietf-
   ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.







Chadwick & Mullan           Standards Track                    [Page 12]

alt-openldap11-devel/rfc/rfc2798.txt000064400000100241150410163170012776 0ustar00





Network Working Group                                          M. Smith
Request for Comments: 2798                      Netscape Communications
Category: Informational                                      April 2000


           Definition of the inetOrgPerson LDAP Object Class

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2000).  All Rights Reserved.

Abstract

   While the X.500 standards define many useful attribute types [X520]
   and object classes [X521], they do not define a person object class
   that meets the requirements found in today's Internet and Intranet
   directory service deployments.  We define a new object class called
   inetOrgPerson for use in LDAP and X.500 directory services that
   extends the X.521 standard organizationalPerson class to meet these
   needs.

























Smith                        Informational                      [Page 1]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


Table of Contents

   1.     Background and Intended Usage...............................2
   2.     New Attribute Types Used in the inetOrgPerson Object Class..3
   2.1.      Vehicle license or registration plate....................3
   2.2.      Department number........................................3
   2.3.      Display Name.............................................4
   2.4.      Employee Number..........................................4
   2.5.      Employee Type............................................4
   2.6.      JPEG Photograph..........................................5
   2.7.      Preferred Language.......................................5
   2.8.      User S/MIME Certificate..................................5
   2.9.      User PKCS #12............................................6
   3.     Definition of the inetOrgPerson Object Class................6
   4.     Example of an inetOrgPerson Entry...........................7
   5.     Security Considerations.....................................8
   6.     Acknowledgments.............................................8
   7.     Bibliography................................................8
   8.     Author's Address............................................9
   9.     Appendix A - inetOrgPerson Schema Summary..................10
   9.1.     Attribute Types..........................................10
   9.1.1.      New attribute types that are defined in this document.10
   9.1.2.      Attribute types from RFC 2256.........................12
   9.1.3.      Attribute types from RFC 1274.........................15
   9.1.4.      Attribute type from RFC 2079..........................16
   9.2.     Syntaxes.................................................17
   9.2.1.      Syntaxes from RFC 2252................................17
   9.2.2.      Syntaxes from RFC 2256................................17
   9.3.     Matching Rules...........................................17
   9.3.1.      Matching rules from RFC 2252..........................17
   9.3.2.      Matching rule from RFC 2256...........................18
   9.3.3.      Additional matching rules from X.520..................18
   9.3.4.      Matching rules not defined in any referenced document.19
   10.    Full Copyright Statement...................................20

1.  Background and Intended Usage

   The inetOrgPerson object class is a general purpose object class that
   holds attributes about people.  The attributes it holds were chosen
   to accommodate information requirements found in typical Internet and
   Intranet directory service deployments.  The inetOrgPerson object
   class is designed to be used within directory services based on the
   LDAP [RFC2251] and the X.500 family of protocols, and it should be
   useful in other contexts as well.  There is no requirement for
   directory services implementors to use the inetOrgPerson object
   class; it is simply presented as well-documented class that
   implementors can choose to use if they find it useful.




Smith                        Informational                      [Page 2]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


   The attribute type and object class definitions in this document are
   written using the BNF form of AttributeTypeDescription and
   ObjectClassDescription given in [RFC2252].  In some cases lines have
   been folded for readability.

   Attributes that are referenced but not defined in this document are
   included in one of the following documents:

      The COSINE and Internet X.500 Schema [RFC1274]

      Definition of an X.500 Attribute Type and an Object Class to Hold
      Uniform Resource Identifiers (URIs) [RFC2079]

      A Summary of the X.500(96) User Schema for use with LDAPv3
      [RFC2256]

   See Appendix A for a summary of the attribute types, associated
   syntaxes, and matching rules used in this document.

2.  New Attribute Types Used in the inetOrgPerson Object Class

2.1.  Vehicle license or registration plate.

   This multivalued field is used to record the values of the license or
   registration plate associated with an individual.

    ( 2.16.840.1.113730.3.1.1 NAME 'carLicense'
      DESC 'vehicle license or registration plate'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

2.2.  Department number

   Code for department to which a person belongs.  This can also be
   strictly numeric (e.g., 1234) or alphanumeric (e.g., ABC/123).

    ( 2.16.840.1.113730.3.1.2
      NAME 'departmentNumber'
      DESC 'identifies a department within an organization'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )








Smith                        Informational                      [Page 3]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


2.3.  Display Name

   When displaying an entry, especially within a one-line summary list,
   it is useful to be able to identify a name to be used.  Since other
   attribute types such as 'cn' are multivalued, an additional attribute
   type is needed.  Display name is defined for this purpose.

  ( 2.16.840.1.113730.3.1.241
    NAME 'displayName'
    DESC 'preferred name of a person to be used when displaying entries'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    SINGLE-VALUE )

2.4.  Employee Number

   Numeric or alphanumeric identifier assigned to a person, typically
   based on order of hire or association with an organization.  Single
   valued.

    ( 2.16.840.1.113730.3.1.3
      NAME 'employeeNumber'
      DESC 'numerically identifies an employee within an organization'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      SINGLE-VALUE )

2.5.  Employee Type

   Used to identify the employer to employee relationship.  Typical
   values used will be "Contractor", "Employee", "Intern", "Temp",
   "External", and "Unknown" but any value may be used.

    ( 2.16.840.1.113730.3.1.4
      NAME 'employeeType'
      DESC 'type of employment for a person'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )










Smith                        Informational                      [Page 4]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


2.6.  JPEG Photograph

   Used to store one or more images of a person using the JPEG File
   Interchange Format [JFIF].

    ( 0.9.2342.19200300.100.1.60
      NAME 'jpegPhoto'
      DESC 'a JPEG image'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )

   Note that the jpegPhoto attribute type was defined for use in the
   Internet X.500 pilots but no referencable definition for it could be
   located.

2.7.  Preferred Language

   Used to indicate an individual's preferred written or spoken
   language.  This is useful for international correspondence or human-
   computer interaction.  Values for this attribute type MUST conform to
   the definition of the Accept-Language header field defined in
   [RFC2068] with one exception:  the sequence "Accept-Language" ":"
   should be omitted.  This is a single valued attribute type.

    ( 2.16.840.1.113730.3.1.39
      NAME 'preferredLanguage'
      DESC 'preferred written or spoken language for a person'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      SINGLE-VALUE )
   )

2.8.  User S/MIME Certificate

   A PKCS#7 [RFC2315] SignedData, where the content that is signed is
   ignored by consumers of userSMIMECertificate values.  It is
   recommended that values have a `contentType' of data with an absent
   `content' field.  Values of this attribute contain a person's entire
   certificate chain and an smimeCapabilities field [RFC2633] that at a
   minimum describes their SMIME algorithm capabilities.  Values for
   this attribute are to be stored and requested in binary form, as
   'userSMIMECertificate;binary'.  If available, this attribute is
   preferred over the userCertificate attribute for S/MIME applications.

    ( 2.16.840.1.113730.3.1.40
      NAME 'userSMIMECertificate'
      DESC 'PKCS#7 SignedData used to support S/MIME'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )



Smith                        Informational                      [Page 5]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


2.9.  User PKCS #12

   PKCS #12 [PKCS12] provides a format for exchange of personal identity
   information.  When such information is stored in a directory service,
   the userPKCS12 attribute should be used. This attribute is to be
   stored and requested in binary form, as 'userPKCS12;binary'.  The
   attribute values are PFX PDUs stored as binary data.

( 2.16.840.1.113730.3.1.216
  NAME 'userPKCS12'
  DESC 'PKCS #12 PFX PDU for exchange of personal identity information'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )

3.  Definition of the inetOrgPerson Object Class

   The inetOrgPerson represents people who are associated with an
   organization in some way.  It is a structural class and is derived
   from the organizationalPerson class which is defined in X.521 [X521].

( 2.16.840.1.113730.3.2.2
    NAME 'inetOrgPerson'
    SUP organizationalPerson
    STRUCTURAL
    MAY (
        audio $ businessCategory $ carLicense $ departmentNumber $
        displayName $ employeeNumber $ employeeType $ givenName $
        homePhone $ homePostalAddress $ initials $ jpegPhoto $
        labeledURI $ mail $ manager $ mobile $ o $ pager $
        photo $ roomNumber $ secretary $ uid $ userCertificate $
        x500uniqueIdentifier $ preferredLanguage $
        userSMIMECertificate $ userPKCS12
    )
)

   For reference, we list the following additional attribute types that
   are part of the inetOrgPerson object class.  These attribute types
   are inherited from organizationalPerson (which in turn is derived
   from the person object class):













Smith                        Informational                      [Page 6]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


    MUST (
        cn $ objectClass $ sn
    )
    MAY (
        description $ destinationIndicator $ facsimileTelephoneNumber $
        internationaliSDNNumber $ l $ ou $ physicalDeliveryOfficeName $
        postalAddress $ postalCode $ postOfficeBox $
        preferredDeliveryMethod $ registeredAddress $ seeAlso $
        st $ street $ telephoneNumber $ teletexTerminalIdentifier $
        telexNumber $ title $ userPassword $ x121Address
    )

4.  Example of an inetOrgPerson Entry

   The following example is expressed using the LDIF notation defined in
   [LDIF].

   version: 1
   dn: cn=Barbara Jensen,ou=Product Development,dc=siroe,dc=com
   objectClass: top
   objectClass: person
   objectClass: organizationalPerson
   objectClass: inetOrgPerson
   cn: Barbara Jensen
   cn: Babs Jensen
   displayName: Babs Jensen
   sn: Jensen
   givenName: Barbara
   initials: BJJ
   title: manager, product development
   uid: bjensen
   mail: bjensen@siroe.com
   telephoneNumber: +1 408 555 1862
   facsimileTelephoneNumber: +1 408 555 1992
   mobile: +1 408 555 1941
   roomNumber: 0209
   carLicense: 6ABC246
   o: Siroe
   ou: Product Development
   departmentNumber: 2604
   employeeNumber: 42
   employeeType: full time
   preferredLanguage: fr, en-gb;q=0.8, en;q=0.7
   labeledURI: http://www.siroe.com/users/bjensen My Home Page







Smith                        Informational                      [Page 7]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


5.  Security Considerations

   Attributes of directory entries are used to provide descriptive
   information about the real-world objects they represent, which can be
   people, organizations or devices.  Most countries have privacy laws
   regarding the publication of information about people.

   Transfer of cleartext passwords are strongly discouraged where the
   underlying transport service cannot guarantee confidentiality and may
   result in disclosure of the password to unauthorized parties.

6.  Acknowledgments

   The Netscape Directory Server team created the inetOrgPerson object
   class based on experience and customer requirements.  Anil Bhavnani
   and John Kristian in particular deserve credit for all of the early
   design work.

   Many members of the Internet community, in particular those in the
   IETF ASID and LDAPEXT groups, also contributed to the design of this
   object class.

7.  Bibliography

   [JFIF]    E. Hamilton, "JPEG File Interchange Format (Version 1.02)",
             C-Cube Microsystems, Milpitas, CA, September 1, 1992.

   [LDIF]    G. Good, "The LDAP Data Interchange Format (LDIF) -
             Technical Specification", Work in Progress.

   [PKCS12]  "PKCS #12: Personal Information Exchange Standard", Version
             1.0 Draft, 30 April 1997.

   [RFC1274] Barker, P. and S. Kille, "The COSINE and Internet X.500
             Schema", RFC 1274, November 1991.

   [RFC1847] Galvin, J., Murphy, S., Crocker, S. and N. Freed, "Security
             Multiparts for MIME:  Multipart/Signed and
             Multipart/Encrypted", RFC 1847, October 1995.

   [RFC2068] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T.
             Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC
             2068, January 1997.

   [RFC2079] Smith, M., "Definition of an X.500 Attribute Type and an
             Object Class to Hold Uniform Resource Identifiers (URIs)",
             RFC 2079, January 1997.




Smith                        Informational                      [Page 8]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


   [RFC2251] Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
             Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252] Wahl, M., Coulbeck, A., Howes, T., Kille, S., Yeong, W. and
             C. Robbins, "Lightweight Directory Access Protocol (v3):
             Attribute Syntax Definitions", RFC 2252, December 1997.

   [RFC2256] Wahl, M., "A Summary of the X.500(96) User Schema for use
             with LDAPv3", RFC 2256, December 1997.

   [RFC2315] Kaliski, B., "PKCS #7: Cryptographic Message Syntax Version
             1.5", RFC 2315, March 1998.

   [RFC2633] Ramsdell, B., "S/MIME Version 3 Message Specification", RFC
             2633, June 1999.

   [X520]    ITU-T Rec. X.520, "The Directory: Selected Attribute
             Types", 1996.

   [X521]    ITU-T Rec. X.521, "The Directory: Selected Object Classes",
             1996.

8.  Author's Address

   Mark Smith
   Netscape Communications Corp.
   501 E. Middlefield Rd., Mailstop MV068
   Mountain View, CA 94043, USA

   Phone:  +1 650 937-3477
   EMail:  mcs@netscape.com




















Smith                        Informational                      [Page 9]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


9.  Appendix A - inetOrgPerson Schema Summary

   This appendix provides definitions of all the attribute types
   included in the inetOrgPerson object class along with their
   associated syntaxes and matching rules.

9.1.  Attribute Types

9.1.1.  New attribute types that are defined in this document

  ( 2.16.840.1.113730.3.1.1 NAME 'carLicense'
    DESC 'vehicle license or registration plate'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

  ( 2.16.840.1.113730.3.1.2
    NAME 'departmentNumber'
    DESC 'identifies a department within an organization'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

  ( 2.16.840.1.113730.3.1.241
    NAME 'displayName'
    DESC 'preferred name of a person to be used when displaying entries'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    SINGLE-VALUE )

  ( 2.16.840.1.113730.3.1.3
    NAME 'employeeNumber'
    DESC 'numerically identifies an employee within an organization'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    SINGLE-VALUE )

  ( 2.16.840.1.113730.3.1.4
    NAME 'employeeType'
    DESC 'type of employment for a person'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )






Smith                        Informational                     [Page 10]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


  ( 0.9.2342.19200300.100.1.60
    NAME 'jpegPhoto'
    DESC 'a JPEG image'
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )
  Note: The jpegPhoto attribute type was defined for use in the
    Internet X.500 pilots but no referencable definition for it
    could be located.

  ( 2.16.840.1.113730.3.1.39
    NAME 'preferredLanguage'
    DESC 'preferred written or spoken language for a person'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    SINGLE-VALUE )

  ( 2.16.840.1.113730.3.1.40
    NAME 'userSMIMECertificate'
    DESC 'signed message used to support S/MIME'
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )

  ( 2.16.840.1.113730.3.1.216
    NAME 'userPKCS12'
    DESC 'PKCS #12 PFX PDU for exchange of personal identity information'
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 )

9.1.2.  Attribute types from RFC 2256

   Note that the original definitions of these types can be found in
   X.520.

    ( 2.5.4.15
      NAME 'businessCategory'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )

    ( 2.5.4.3
      NAME 'cn'
      SUP name )

    ( 2.5.4.13
      NAME 'description'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )





Smith                        Informational                     [Page 11]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


    ( 2.5.4.27
      NAME 'destinationIndicator'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )

    ( 2.5.4.23
      NAME 'facsimileTelephoneNumber'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )

    ( 2.5.4.42
      NAME 'givenName'
      SUP name )

    ( 2.5.4.43
      NAME 'initials'
      SUP name )

    ( 2.5.4.25
      NAME 'internationaliSDNNumber'
      EQUALITY numericStringMatch
      SUBSTR numericStringSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )

    ( 2.5.4.7
      NAME 'l'
      SUP name )

    ( 2.5.4.0
      NAME 'objectClass'
      EQUALITY objectIdentifierMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )

    ( 2.5.4.10
      NAME 'o'
      SUP name )

    ( 2.5.4.11
      NAME 'ou'
      SUP name )

    ( 2.5.4.19
      NAME 'physicalDeliveryOfficeName'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )





Smith                        Informational                     [Page 12]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


    ( 2.5.4.18
      NAME 'postOfficeBox'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )

    ( 2.5.4.16
      NAME 'postalAddress'
      EQUALITY caseIgnoreListMatch
      SUBSTR caseIgnoreListSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )

    ( 2.5.4.17
      NAME 'postalCode'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{40} )

    ( 2.5.4.28
      NAME 'preferredDeliveryMethod'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
      SINGLE-VALUE )

    ( 2.5.4.26
      NAME 'registeredAddress'
      SUP postalAddress
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )

    ( 2.5.4.34
      NAME 'seeAlso'
      SUP distinguishedName )

    ( 2.5.4.4
      NAME 'sn'
      SUP name )

    ( 2.5.4.8
      NAME 'st'
      SUP name )

    ( 2.5.4.9
      NAME 'street'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )






Smith                        Informational                     [Page 13]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


    ( 2.5.4.20
      NAME 'telephoneNumber'
      EQUALITY telephoneNumberMatch
      SUBSTR telephoneNumberSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )

    ( 2.5.4.22
      NAME 'teletexTerminalIdentifier'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )

    ( 2.5.4.21
      NAME 'telexNumber'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )

    ( 2.5.4.12
      NAME 'title'
      SUP name )

    ( 2.5.4.36
      NAME 'userCertificate'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )

    ( 2.5.4.35
      NAME 'userPassword'
      EQUALITY octetStringMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )

    ( 2.5.4.24
      NAME 'x121Address'
      EQUALITY numericStringMatch
      SUBSTR numericStringSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{15} )

    ( 2.5.4.45
      NAME 'x500UniqueIdentifier'
      EQUALITY bitStringMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )

   Some attribute types included in inetOrgPerson are derived from the
   'name' and 'distinguishedName' attribute supertypes:

    ( 2.5.4.41
      NAME 'name'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )





Smith                        Informational                     [Page 14]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


    ( 2.5.4.49
      NAME 'distinguishedName'
      EQUALITY distinguishedNameMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

9.1.3.  Attribute types from RFC 1274

    ( 0.9.2342.19200300.100.1.55
      NAME 'audio'
      EQUALITY octetStringMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{250000} )
    Note: The syntax used here for the audio attribute type is Octet
      String. RFC 1274 uses a syntax called audio which is not defined
      in RFC 1274.

    ( 0.9.2342.19200300.100.1.20
      NAME 'homePhone'
      EQUALITY telephoneNumberMatch
      SUBSTR telephoneNumberSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
    Note: RFC 1274 uses the longer name 'homeTelephoneNumber'.

    ( 0.9.2342.19200300.100.1.39
      NAME 'homePostalAddress'
      EQUALITY caseIgnoreListMatch
      SUBSTR caseIgnoreListSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )

    ( 0.9.2342.19200300.100.1.3
      NAME 'mail'
      EQUALITY caseIgnoreIA5Match
      SUBSTR caseIgnoreIA5SubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
    Note: RFC 1274 uses the longer name 'rfc822Mailbox' and syntax OID
      of 0.9.2342.19200300.100.3.5.  All recent LDAP documents and most
      deployed LDAP implementations refer to this attribute as 'mail'
      and define the IA5 String syntax using using the OID
      1.3.6.1.4.1.1466.115.121.1.26, as is done here.

    ( 0.9.2342.19200300.100.1.10
      NAME 'manager'
      EQUALITY distinguishedNameMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )








Smith                        Informational                     [Page 15]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


    ( 0.9.2342.19200300.100.1.41
      NAME 'mobile'
      EQUALITY telephoneNumberMatch
      SUBSTR telephoneNumberSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
    Note: RFC 1274 uses the longer name 'mobileTelephoneNumber'.

    ( 0.9.2342.19200300.100.1.42
      NAME 'pager'
      EQUALITY telephoneNumberMatch
      SUBSTR telephoneNumberSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )
    Note: RFC 1274 uses the longer name 'pagerTelephoneNumber'.

    ( 0.9.2342.19200300.100.1.7
      NAME 'photo' )
    Note: Photo attribute values are encoded in G3 fax format with an
      ASN.1 wrapper. Please refer to RFC 1274 section 9.3.7 for
      detailed syntax information for this attribute.

    ( 0.9.2342.19200300.100.1.6
      NAME 'roomNumber'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

    ( 0.9.2342.19200300.100.1.21
      NAME 'secretary'
      EQUALITY distinguishedNameMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

    ( 0.9.2342.19200300.100.1.1
      NAME 'uid'
      EQUALITY caseIgnoreMatch
      SUBSTR caseIgnoreSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
    Note: RFC 1274 uses the longer name 'userid'.

9.1.4.  Attribute type from RFC 2079

    ( 1.3.6.1.4.1.250.1.57
      NAME 'labeledURI'
      EQUALITY caseExactMatch
      SUBSTR caseExactSubstringsMatch
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )






Smith                        Informational                     [Page 16]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


9.2.  Syntaxes

9.2.1.  Syntaxes from RFC 2252

    ( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' )

    ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )

    ( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' )

    ( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'DN' )

    ( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )

    ( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )

    ( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )

    ( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' )

    ( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )

    ( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )

    ( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )

    ( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )

    ( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )

9.2.2.  Syntaxes from RFC 2256

    ( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )

    ( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )

    ( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )

    ( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )

9.3.  Matching Rules

9.3.1.  Matching rules from RFC 2252

   Note that the original definition of many of these matching rules can
   be found in X.520.





Smith                        Informational                     [Page 17]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


    ( 2.5.13.16 NAME 'bitStringMatch'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )

    ( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

    ( 2.5.13.11 NAME 'caseIgnoreListMatch'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )

    ( 2.5.13.2 NAME 'caseIgnoreMatch'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

    ( 2.5.13.1 NAME 'distinguishedNameMatch'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

    ( 2.5.13.8 NAME 'numericStringMatch'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )

    ( 2.5.13.0 NAME 'objectIdentifierMatch'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )

    ( 2.5.13.20 NAME 'telephoneNumberMatch'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

9.3.2.  Matching rule from RFC 2256

   Note that the original definition of this matching rule can be found
   in X.520.

    ( 2.5.13.17 NAME 'octetStringMatch'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

9.3.3.  Additional matching rules from X.520

   caseExactMatch

       ( 2.5.13.5 NAME 'caseExactMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   This rule determines whether a presented string exactly matches an
   attribute value of syntax DirectoryString.  It is identical to
   caseIgnoreMatch except that case is not ignored.  Multiple adjoining
   whitespace characters are treated the same as an individual space,
   and leading and trailing whitespace is ignored.







Smith                        Informational                     [Page 18]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


   caseExactSubstringsMatch

       ( 2.5.13.7 NAME 'caseExactSubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   This rules determines whether the initial, any and final substring
   elements in a presented value are present in an attribute value of
   syntax DirectoryString.  It is identical to caseIgnoreSubstringsMatch
   except that case is not ignored.

   caseIgnoreListSubstringsMatch

       ( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   This rule compares a presented substring with an attribute value
   which is a sequence of DirectoryStrings, but where the case of
   letters is not significant for comparison purposes.  A presented
   value matches a stored value if and only if the presented value
   matches the string formed by concatenating the strings of the stored
   value.  Matching is done according to the caseIgnoreSubstringsMatch
   rule except that none of the initial, final, or any values of the
   presented value match a substring of the concatenated string which
   spans more than one of the strings of the stored value.

9.3.4.  Matching rules not defined in any referenced document

   caseIgnoreIA5SubstringsMatch

       ( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   This rules determines whether the initial, any and final substring
   elements in a presented value are present in an attribute value of
   syntax IA5 String without regard to the case of the letters in the
   strings.  It is expected that this matching rule will be added to an
   update of RFC 2252.














Smith                        Informational                     [Page 19]

RFC 2798          The LDAP inetOrgPerson Object Class         April 2000


10.  Full Copyright Statement

   Copyright (C) The Internet Society (2000).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Smith                        Informational                     [Page 20]

alt-openldap11-devel/rfc/rfc4522.txt000064400000037624150410163170012777 0ustar00





Network Working Group                                            S. Legg
Request for Comments: 4522                                       eB2Bcom
Category: Standards Track                                      June 2006


             Lightweight Directory Access Protocol (LDAP):
                       The Binary Encoding Option

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   Each attribute stored in a Lightweight Directory Access Protocol
   (LDAP) directory has a defined syntax (i.e., data type).  A syntax
   definition specifies how attribute values conforming to the syntax
   are normally represented when transferred in LDAP operations.  This
   representation is referred to as the LDAP-specific encoding to
   distinguish it from other methods of encoding attribute values.  This
   document defines an attribute option, the binary option, that can be
   used to specify that the associated attribute values are instead
   encoded according to the Basic Encoding Rules (BER) used by X.500
   directories.

Table of Contents

   1. Introduction ....................................................2
   2. Conventions .....................................................2
   3. The Binary Option ...............................................2
   4. Syntaxes Requiring Binary Transfer ..............................3
   5. Attributes Returned in a Search .................................4
   6. All User Attributes .............................................4
   7. Conflicting Requests ............................................5
   8. Security Considerations .........................................5
   9. IANA Considerations .............................................5
   10. References .....................................................5
      10.1. Normative References ......................................5
      10.2. Informative References ....................................6




Legg                        Standards Track                     [Page 1]

RFC 4522            LDAP: The Binary Encoding Option           June 2006


1.  Introduction

   Each attribute stored in a Lightweight Directory Access Protocol
   (LDAP) directory [RFC4510] has a defined syntax (i.e., data type)
   which constrains the structure and format of its values.

   The description of each syntax [RFC4517] specifies how attribute or
   assertion values [RFC4512] conforming to the syntax are normally
   represented when transferred in LDAP operations [RFC4511].  This
   representation is referred to as the LDAP-specific encoding to
   distinguish it from other methods of encoding attribute values.

   This document defines an attribute option, the binary option, which
   can be used in an attribute description [RFC4512] in an LDAP
   operation to specify that the associated attribute values or
   assertion values are, or are requested to be, encoded according to
   the Basic Encoding Rules (BER) [BER] as used by X.500 [X.500]
   directories, instead of the usual LDAP-specific encoding.

   The binary option was originally defined in RFC 2251 [RFC2251].  The
   LDAP technical specification [RFC4510] has obsoleted the previously
   defined LDAP technical specification [RFC3377], which included RFC
   2251.  The binary option was not included in the revised LDAP
   technical specification for a variety of reasons including
   implementation inconsistencies.  No attempt is made here to resolve
   the known inconsistencies.

   This document reintroduces the binary option for use with certain
   attribute syntaxes, such as certificate syntax [RFC4523], that
   specifically require it.  No attempt has been made to address use of
   the binary option with attributes of syntaxes that do not require its
   use.  Unless addressed in a future specification, this use is to be
   avoided.

2.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14, RFC 2119
   [BCP14].

3.  The Binary Option

   The binary option is indicated with the attribute option string
   "binary" in an attribute description.  Note that, like all attribute
   options, the string representing the binary option is case
   insensitive.




Legg                        Standards Track                     [Page 2]

RFC 4522            LDAP: The Binary Encoding Option           June 2006


   Where the binary option is present in an attribute description, the
   associated attribute values or assertion values MUST be BER encoded
   (otherwise the values are encoded according to the LDAP-specific
   encoding [RFC4517] for the attribute's syntax).  Note that it is
   possible for a syntax to be defined such that its LDAP-specific
   encoding is exactly the same as its BER encoding.

   In terms of the protocol [RFC4511], the binary option specifies that
   the contents octets of the associated AttributeValue or
   AssertionValue OCTET STRING are a complete BER encoding of the
   relevant value.

   The binary option is not a tagging option [RFC4512], so the presence
   of the binary option does not specify an attribute subtype.  An
   attribute description containing the binary option references exactly
   the same attribute as the attribute description without the binary
   option.  The supertype/subtype relationships of attributes with
   tagging options are not altered in any way by the presence or absence
   of the binary option.

   An attribute description SHALL be treated as unrecognized if it
   contains the binary option and the syntax of the attribute does not
   have an associated ASN.1 type [RFC4517], or the BER encoding of
   values of that type is not supported.

   The presence or absence of the binary option only affects the
   transfer of attribute and assertion values in the protocol; servers
   store any particular attribute value in a format of their choosing.

4.  Syntaxes Requiring Binary Transfer

   The attribute values of certain attribute syntaxes are defined
   without an LDAP-specific encoding and are required to be transferred
   in the BER-encoded form.  For the purposes of this document, these
   syntaxes are said to have a binary transfer requirement.  The
   certificate, certificate list, certificate pair, and supported
   algorithm syntaxes [RFC4523] are examples of syntaxes with a binary
   transfer requirement.  These syntaxes also have an additional
   requirement that the exact BER encoding must be preserved.  Note that
   this is a property of the syntaxes themselves, and not a property of
   the binary option.  In the absence of this requirement, LDAP clients
   would need to re-encode values using the Distinguished Encoding Rules
   (DER).








Legg                        Standards Track                     [Page 3]

RFC 4522            LDAP: The Binary Encoding Option           June 2006


5.  Attributes Returned in a Search

   An LDAP search request [RFC4511] contains a list of the attributes
   (the requested attributes list) to be returned from each entry
   matching the search filter.  An attribute description in the
   requested attributes list also implicitly requests all subtypes of
   the attribute type in the attribute description, whether through
   attribute subtyping or attribute tagging option subtyping [RFC4512].

   The requested attributes list MAY contain attribute descriptions with
   the binary option, but MUST NOT contain two attribute descriptions
   with the same attribute type and the same tagging options (even if
   only one of them has the binary option).  The binary option in an
   attribute description in the requested attributes list implicitly
   applies to all the subtypes of the attribute type in the attribute
   description (however, see Section 7).

   Attributes of a syntax with the binary transfer requirement, if
   returned, SHALL be returned in the binary form (i.e., with the binary
   option in the attribute description and the associated attribute
   values BER encoded) regardless of whether the binary option was
   present in the request (for the attribute or for one of its
   supertypes).

   Attributes of a syntax without the binary transfer requirement, if
   returned, SHOULD be returned in the form explicitly requested.  That
   is, if the attribute description in the requested attributes list
   contains the binary option, then the corresponding attribute in the
   result SHOULD be in the binary form.  If the attribute description in
   the request does not contain the binary option, then the
   corresponding attribute in the result SHOULD NOT be in the binary
   form.  A server MAY omit an attribute from the result if it does not
   support the requested encoding.

   Regardless of the encoding chosen, a particular attribute value is
   returned at most once.

6.  All User Attributes

   If the list of attributes in a search request is empty or contains
   the special attribute description string "*", then all user
   attributes are requested to be returned.

   Attributes of a syntax with the binary transfer requirement, if
   returned, SHALL be returned in the binary form.






Legg                        Standards Track                     [Page 4]

RFC 4522            LDAP: The Binary Encoding Option           June 2006


   Attributes of a syntax without the binary transfer requirement and
   having a defined LDAP-specific encoding SHOULD NOT be returned in the
   binary form.

   Attributes of a syntax without the binary transfer requirement and
   without a defined LDAP-specific encoding may be returned in the
   binary form or omitted from the result.

7.  Conflicting Requests

   A particular attribute could be explicitly requested by an attribute
   description and/or implicitly requested by the attribute descriptions
   of one or more of its supertypes, or by the special attribute
   description string "*".  If the binary option is present in at least
   one, but not all, of these attribute descriptions then the effect of
   the request with respect to binary transfer is implementation
   defined.

8.  Security Considerations

   When interpreting security-sensitive fields, and in particular fields
   used to grant or deny access, implementations MUST ensure that any
   matching rule comparisons are done on the underlying abstract value,
   regardless of the particular encoding used.

9.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has updated the LDAP
   attribute description option registry [BCP64] as indicated by the
   following template:

      Subject:
        Request for LDAP Attribute Description Option Registration
      Option Name: binary
      Family of Options: NO
      Person & email address to contact for further information:
        Steven Legg <steven.legg@eb2bcom.com>
      Specification: RFC 4522
      Author/Change Controller: IESG

10.  References

10.1.  Normative References

   [BCP14]    Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.





Legg                        Standards Track                     [Page 5]

RFC 4522            LDAP: The Binary Encoding Option           June 2006


   [BCP64]    Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [RFC4510]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC RFC 4510,
              June 2006.

   [RFC4511]  Sermersheim, J., "Lightweight Directory Access Protocol
              (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512, June
              2006.

   [RFC4517]  Legg, S., Ed., "Lightweight Directory Access Protocol
              (LDAP):  Syntaxes and Matching Rules", RFC 4517, June
              2006.

   [RFC4523]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP) Schema Definitions for X.509 Certificates", RFC
              4523, June 2006.

   [BER]      ITU-T Recommendation X.690 (07/02) | ISO/IEC 8825-1,
              Information Technology - ASN.1 encoding rules:
              Specification of Basic Encoding Rules (BER), Canonical
              Encoding Rules (CER) and Distinguished Encoding Rules
              (DER).

10.2.  Informative References

   [RFC2251]  Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC3377]  Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

   [X.500]    ITU-T Recommendation X.500 (02/01) | ISO/IEC 9594-1:2001,
              Information technology - Open Systems Interconnection -
              The Directory:  Overview of concepts, models and services










Legg                        Standards Track                     [Page 6]

RFC 4522            LDAP: The Binary Encoding Option           June 2006


Author's Address

   Dr. Steven Legg
   eB2Bcom
   Suite 3, Woodhouse Corporate Centre
   935 Station Street
   Box Hill North, Victoria 3129
   AUSTRALIA

   Phone: +61 3 9896 7830
   Fax:   +61 3 9896 7801
   EMail: steven.legg@eb2bcom.com







































Legg                        Standards Track                     [Page 7]

RFC 4522            LDAP: The Binary Encoding Option           June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Legg                        Standards Track                     [Page 8]

alt-openldap11-devel/rfc/rfc4511.txt000064400000445144150410163170012775 0ustar00





Network Working Group                                J. Sermersheim, Ed.
Request for Comments: 4511                                  Novell, Inc.
Obsoletes: 2251, 2830, 3771                                    June 2006
Category: Standards Track


      Lightweight Directory Access Protocol (LDAP): The Protocol

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document describes the protocol elements, along with their
   semantics and encodings, of the Lightweight Directory Access Protocol
   (LDAP).  LDAP provides access to distributed directory services that
   act in accordance with X.500 data and service models.  These protocol
   elements are based on those described in the X.500 Directory Access
   Protocol (DAP).

Table of Contents

   1. Introduction ....................................................3
      1.1. Relationship to Other LDAP Specifications ..................3
   2. Conventions .....................................................3
   3. Protocol Model ..................................................4
      3.1. Operation and LDAP Message Layer Relationship ..............5
   4. Elements of Protocol ............................................5
      4.1. Common Elements ............................................5
           4.1.1. Message Envelope ....................................6
           4.1.2. String Types ........................................7
           4.1.3. Distinguished Name and Relative Distinguished Name ..8
           4.1.4. Attribute Descriptions ..............................8
           4.1.5. Attribute Value .....................................8
           4.1.6. Attribute Value Assertion ...........................9
           4.1.7. Attribute and PartialAttribute ......................9
           4.1.8. Matching Rule Identifier ...........................10
           4.1.9. Result Message .....................................10
           4.1.10. Referral ..........................................12



Sermersheim                 Standards Track                     [Page 1]

RFC 4511                         LDAPv3                        June 2006


           4.1.11. Controls ..........................................14
      4.2. Bind Operation ............................................16
           4.2.1. Processing of the Bind Request .....................17
           4.2.2. Bind Response ......................................18
      4.3. Unbind Operation ..........................................18
      4.4. Unsolicited Notification ..................................19
           4.4.1. Notice of Disconnection ............................19
      4.5. Search Operation ..........................................20
           4.5.1. Search Request .....................................20
           4.5.2. Search Result ......................................27
           4.5.3. Continuation References in the Search Result .......28
      4.6. Modify Operation ..........................................31
      4.7. Add Operation .............................................33
      4.8. Delete Operation ..........................................34
      4.9. Modify DN Operation .......................................34
      4.10. Compare Operation ........................................36
      4.11. Abandon Operation ........................................36
      4.12. Extended Operation .......................................37
      4.13. IntermediateResponse Message .............................39
           4.13.1. Usage with LDAP ExtendedRequest and
                   ExtendedResponse ..................................40
           4.13.2. Usage with LDAP Request Controls ..................40
      4.14. StartTLS Operation .......................................40
           4.14.1. StartTLS Request ..................................40
           4.14.2. StartTLS Response .................................41
           4.14.3. Removal of the TLS Layer ..........................41
   5. Protocol Encoding, Connection, and Transfer ....................42
      5.1. Protocol Encoding .........................................42
      5.2. Transmission Control Protocol (TCP) .......................43
      5.3. Termination of the LDAP session ...........................43
   6. Security Considerations ........................................43
   7. Acknowledgements ...............................................45
   8. Normative References ...........................................46
   9. Informative References .........................................48
   10. IANA Considerations ...........................................48
   Appendix A. LDAP Result Codes .....................................49
      A.1. Non-Error Result Codes ....................................49
      A.2. Result Codes ..............................................49
   Appendix B. Complete ASN.1 Definition .............................54
   Appendix C. Changes ...............................................60
      C.1. Changes Made to RFC 2251 ..................................60
      C.2. Changes Made to RFC 2830 ..................................66
      C.3. Changes Made to RFC 3771 ..................................66








Sermersheim                 Standards Track                     [Page 2]

RFC 4511                         LDAPv3                        June 2006


1.  Introduction

   The Directory is "a collection of open systems cooperating to provide
   directory services" [X.500].  A directory user, which may be a human
   or other entity, accesses the Directory through a client (or
   Directory User Agent (DUA)).  The client, on behalf of the directory
   user, interacts with one or more servers (or Directory System Agents
   (DSA)).  Clients interact with servers using a directory access
   protocol.

   This document details the protocol elements of the Lightweight
   Directory Access Protocol (LDAP), along with their semantics.
   Following the description of protocol elements, it describes the way
   in which the protocol elements are encoded and transferred.

1.1.  Relationship to Other LDAP Specifications

   This document is an integral part of the LDAP Technical Specification
   [RFC4510], which obsoletes the previously defined LDAP technical
   specification, RFC 3377, in its entirety.

   This document, together with [RFC4510], [RFC4513], and [RFC4512],
   obsoletes RFC 2251 in its entirety.  Section 3.3 is obsoleted by
   [RFC4510].  Sections 4.2.1 (portions) and 4.2.2 are obsoleted by
   [RFC4513].  Sections 3.2, 3.4, 4.1.3 (last paragraph), 4.1.4, 4.1.5,
   4.1.5.1, 4.1.9 (last paragraph), 5.1, 6.1, and 6.2 (last paragraph)
   are obsoleted by [RFC4512].  The remainder of RFC 2251 is obsoleted
   by this document.  Appendix C.1 summarizes substantive changes in the
   remainder.

   This document obsoletes RFC 2830, Sections 2 and 4.  The remainder of
   RFC 2830 is obsoleted by [RFC4513].  Appendix C.2 summarizes
   substantive changes to the remaining sections.

   This document also obsoletes RFC 3771 in entirety.

2.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", and "MAY" in this document are
   to be interpreted as described in [RFC2119].

   Character names in this document use the notation for code points and
   names from the Unicode Standard [Unicode].  For example, the letter
   "a" may be represented as either <U+0061> or <LATIN SMALL LETTER A>.






Sermersheim                 Standards Track                     [Page 3]

RFC 4511                         LDAPv3                        June 2006


   Note: a glossary of terms used in Unicode can be found in [Glossary].
   Information on the Unicode character encoding model can be found in
   [CharModel].

   The term "transport connection" refers to the underlying transport
   services used to carry the protocol exchange, as well as associations
   established by these services.

   The term "TLS layer" refers to Transport Layer Security (TLS)
   services used in providing security services, as well as associations
   established by these services.

   The term "SASL layer" refers to Simply Authentication and Security
   Layer (SASL) services used in providing security services, as well as
   associations established by these services.

   The term "LDAP message layer" refers to the LDAP Message Protocol
   Data Unit (PDU) services used in providing directory services, as
   well as associations established by these services.

   The term "LDAP session" refers to combined services (transport
   connection, TLS layer, SASL layer, LDAP message layer) and their
   associations.

   See the table in Section 5 for an illustration of these four terms.

3.  Protocol Model

   The general model adopted by this protocol is one of clients
   performing protocol operations against servers.  In this model, a
   client transmits a protocol request describing the operation to be
   performed to a server.  The server is then responsible for performing
   the necessary operation(s) in the Directory.  Upon completion of an
   operation, the server typically returns a response containing
   appropriate data to the requesting client.

   Protocol operations are generally independent of one another.  Each
   operation is processed as an atomic action, leaving the directory in
   a consistent state.

   Although servers are required to return responses whenever such
   responses are defined in the protocol, there is no requirement for
   synchronous behavior on the part of either clients or servers.
   Requests and responses for multiple operations generally may be
   exchanged between a client and server in any order.  If required,
   synchronous behavior may be controlled by client applications.





Sermersheim                 Standards Track                     [Page 4]

RFC 4511                         LDAPv3                        June 2006


   The core protocol operations defined in this document can be mapped
   to a subset of the X.500 (1993) Directory Abstract Service [X.511].
   However, there is not a one-to-one mapping between LDAP operations
   and X.500 Directory Access Protocol (DAP) operations.  Server
   implementations acting as a gateway to X.500 directories may need to
   make multiple DAP requests to service a single LDAP request.

3.1.  Operation and LDAP Message Layer Relationship

   Protocol operations are exchanged at the LDAP message layer.  When
   the transport connection is closed, any uncompleted operations at the
   LDAP message layer are abandoned (when possible) or are completed
   without transmission of the response (when abandoning them is not
   possible).  Also, when the transport connection is closed, the client
   MUST NOT assume that any uncompleted update operations have succeeded
   or failed.

4.  Elements of Protocol

   The protocol is described using Abstract Syntax Notation One
   ([ASN.1]) and is transferred using a subset of ASN.1 Basic Encoding
   Rules ([BER]).  Section 5 specifies how the protocol elements are
   encoded and transferred.

   In order to support future extensions to this protocol, extensibility
   is implied where it is allowed per ASN.1 (i.e., sequence, set,
   choice, and enumerated types are extensible).  In addition, ellipses
   (...) have been supplied in ASN.1 types that are explicitly
   extensible as discussed in [RFC4520].  Because of the implied
   extensibility, clients and servers MUST (unless otherwise specified)
   ignore trailing SEQUENCE components whose tags they do not recognize.

   Changes to the protocol other than through the extension mechanisms
   described here require a different version number.  A client
   indicates the version it is using as part of the BindRequest,
   described in Section 4.2.  If a client has not sent a Bind, the
   server MUST assume the client is using version 3 or later.

   Clients may attempt to determine the protocol versions a server
   supports by reading the 'supportedLDAPVersion' attribute from the
   root DSE (DSA-Specific Entry) [RFC4512].

4.1.  Common Elements

   This section describes the LDAPMessage envelope Protocol Data Unit
   (PDU) format, as well as data type definitions, which are used in the
   protocol operations.




Sermersheim                 Standards Track                     [Page 5]

RFC 4511                         LDAPv3                        June 2006


4.1.1.  Message Envelope

   For the purposes of protocol exchanges, all protocol operations are
   encapsulated in a common envelope, the LDAPMessage, which is defined
   as follows:

        LDAPMessage ::= SEQUENCE {
             messageID       MessageID,
             protocolOp      CHOICE {
                  bindRequest           BindRequest,
                  bindResponse          BindResponse,
                  unbindRequest         UnbindRequest,
                  searchRequest         SearchRequest,
                  searchResEntry        SearchResultEntry,
                  searchResDone         SearchResultDone,
                  searchResRef          SearchResultReference,
                  modifyRequest         ModifyRequest,
                  modifyResponse        ModifyResponse,
                  addRequest            AddRequest,
                  addResponse           AddResponse,
                  delRequest            DelRequest,
                  delResponse           DelResponse,
                  modDNRequest          ModifyDNRequest,
                  modDNResponse         ModifyDNResponse,
                  compareRequest        CompareRequest,
                  compareResponse       CompareResponse,
                  abandonRequest        AbandonRequest,
                  extendedReq           ExtendedRequest,
                  extendedResp          ExtendedResponse,
                  ...,
                  intermediateResponse  IntermediateResponse },
             controls       [0] Controls OPTIONAL }

        MessageID ::= INTEGER (0 ..  maxInt)

        maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --

   The ASN.1 type Controls is defined in Section 4.1.11.

   The function of the LDAPMessage is to provide an envelope containing
   common fields required in all protocol exchanges.  At this time, the
   only common fields are the messageID and the controls.

   If the server receives an LDAPMessage from the client in which the
   LDAPMessage SEQUENCE tag cannot be recognized, the messageID cannot
   be parsed, the tag of the protocolOp is not recognized as a request,
   or the encoding structures or lengths of data fields are found to be
   incorrect, then the server SHOULD return the Notice of Disconnection



Sermersheim                 Standards Track                     [Page 6]

RFC 4511                         LDAPv3                        June 2006


   described in Section 4.4.1, with the resultCode set to protocolError,
   and MUST immediately terminate the LDAP session as described in
   Section 5.3.

   In other cases where the client or server cannot parse an LDAP PDU,
   it SHOULD abruptly terminate the LDAP session (Section 5.3) where
   further communication (including providing notice) would be
   pernicious.  Otherwise, server implementations MUST return an
   appropriate response to the request, with the resultCode set to
   protocolError.

4.1.1.1.  MessageID

   All LDAPMessage envelopes encapsulating responses contain the
   messageID value of the corresponding request LDAPMessage.

   The messageID of a request MUST have a non-zero value different from
   the messageID of any other request in progress in the same LDAP
   session.  The zero value is reserved for the unsolicited notification
   message.

   Typical clients increment a counter for each request.

   A client MUST NOT send a request with the same messageID as an
   earlier request in the same LDAP session unless it can be determined
   that the server is no longer servicing the earlier request (e.g.,
   after the final response is received, or a subsequent Bind
   completes).  Otherwise, the behavior is undefined.  For this purpose,
   note that Abandon and successfully abandoned operations do not send
   responses.

4.1.2.  String Types

   The LDAPString is a notational convenience to indicate that, although
   strings of LDAPString type encode as ASN.1 OCTET STRING types, the
   [ISO10646] character set (a superset of [Unicode]) is used, encoded
   following the UTF-8 [RFC3629] algorithm.  Note that Unicode
   characters U+0000 through U+007F are the same as ASCII 0 through 127,
   respectively, and have the same single octet UTF-8 encoding.  Other
   Unicode characters have a multiple octet UTF-8 encoding.

        LDAPString ::= OCTET STRING -- UTF-8 encoded,
                                    -- [ISO10646] characters

   The LDAPOID is a notational convenience to indicate that the
   permitted value of this string is a (UTF-8 encoded) dotted-decimal
   representation of an OBJECT IDENTIFIER.  Although an LDAPOID is




Sermersheim                 Standards Track                     [Page 7]

RFC 4511                         LDAPv3                        June 2006


   encoded as an OCTET STRING, values are limited to the definition of
   <numericoid> given in Section 1.4 of [RFC4512].

        LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
                                 -- [RFC4512]

   For example,

        1.3.6.1.4.1.1466.1.2.3

4.1.3.  Distinguished Name and Relative Distinguished Name

   An LDAPDN is defined to be the representation of a Distinguished Name
   (DN) after encoding according to the specification in [RFC4514].

        LDAPDN ::= LDAPString
                   -- Constrained to <distinguishedName> [RFC4514]

   A RelativeLDAPDN is defined to be the representation of a Relative
   Distinguished Name (RDN) after encoding according to the
   specification in [RFC4514].

        RelativeLDAPDN ::= LDAPString
                           -- Constrained to <name-component> [RFC4514]

4.1.4.  Attribute Descriptions

   The definition and encoding rules for attribute descriptions are
   defined in Section 2.5 of [RFC4512].  Briefly, an attribute
   description is an attribute type and zero or more options.

        AttributeDescription ::= LDAPString
                                -- Constrained to <attributedescription>
                                -- [RFC4512]

4.1.5.  Attribute Value

   A field of type AttributeValue is an OCTET STRING containing an
   encoded attribute value.  The attribute value is encoded according to
   the LDAP-specific encoding definition of its corresponding syntax.
   The LDAP-specific encoding definitions for different syntaxes and
   attribute types may be found in other documents and in particular
   [RFC4517].

        AttributeValue ::= OCTET STRING






Sermersheim                 Standards Track                     [Page 8]

RFC 4511                         LDAPv3                        June 2006


   Note that there is no defined limit on the size of this encoding;
   thus, protocol values may include multi-megabyte attribute values
   (e.g., photographs).

   Attribute values may be defined that have arbitrary and non-printable
   syntax.  Implementations MUST NOT display or attempt to decode an
   attribute value if its syntax is not known.  The implementation may
   attempt to discover the subschema of the source entry and to retrieve
   the descriptions of 'attributeTypes' from it [RFC4512].

   Clients MUST only send attribute values in a request that are valid
   according to the syntax defined for the attributes.

4.1.6.  Attribute Value Assertion

   The AttributeValueAssertion (AVA) type definition is similar to the
   one in the X.500 Directory standards.  It contains an attribute
   description and a matching rule ([RFC4512], Section 4.1.3) assertion
   value suitable for that type.  Elements of this type are typically
   used to assert that the value in assertionValue matches a value of an
   attribute.

        AttributeValueAssertion ::= SEQUENCE {
             attributeDesc   AttributeDescription,
             assertionValue  AssertionValue }

        AssertionValue ::= OCTET STRING

   The syntax of the AssertionValue depends on the context of the LDAP
   operation being performed.  For example, the syntax of the EQUALITY
   matching rule for an attribute is used when performing a Compare
   operation.  Often this is the same syntax used for values of the
   attribute type, but in some cases the assertion syntax differs from
   the value syntax.  See objectIdentiferFirstComponentMatch in
   [RFC4517] for an example.

4.1.7.  Attribute and PartialAttribute

   Attributes and partial attributes consist of an attribute description
   and attribute values.  A PartialAttribute allows zero values, while
   Attribute requires at least one value.

        PartialAttribute ::= SEQUENCE {
             type       AttributeDescription,
             vals       SET OF value AttributeValue }






Sermersheim                 Standards Track                     [Page 9]

RFC 4511                         LDAPv3                        June 2006


        Attribute ::= PartialAttribute(WITH COMPONENTS {
             ...,
             vals (SIZE(1..MAX))})

   No two of the attribute values may be equivalent as described by
   Section 2.2 of [RFC4512].  The set of attribute values is unordered.
   Implementations MUST NOT rely upon the ordering being repeatable.

4.1.8.  Matching Rule Identifier

   Matching rules are defined in Section 4.1.3 of [RFC4512].  A matching
   rule is identified in the protocol by the printable representation of
   either its <numericoid> or one of its short name descriptors
   [RFC4512], e.g., 'caseIgnoreMatch' or '2.5.13.2'.

        MatchingRuleId ::= LDAPString

4.1.9.  Result Message

   The LDAPResult is the construct used in this protocol to return
   success or failure indications from servers to clients.  To various
   requests, servers will return responses containing the elements found
   in LDAPResult to indicate the final status of the protocol operation
   request.

        LDAPResult ::= SEQUENCE {
             resultCode         ENUMERATED {
                  success                      (0),
                  operationsError              (1),
                  protocolError                (2),
                  timeLimitExceeded            (3),
                  sizeLimitExceeded            (4),
                  compareFalse                 (5),
                  compareTrue                  (6),
                  authMethodNotSupported       (7),
                  strongerAuthRequired         (8),
                       -- 9 reserved --
                  referral                     (10),
                  adminLimitExceeded           (11),
                  unavailableCriticalExtension (12),
                  confidentialityRequired      (13),
                  saslBindInProgress           (14),
                  noSuchAttribute              (16),
                  undefinedAttributeType       (17),
                  inappropriateMatching        (18),
                  constraintViolation          (19),
                  attributeOrValueExists       (20),
                  invalidAttributeSyntax       (21),



Sermersheim                 Standards Track                    [Page 10]

RFC 4511                         LDAPv3                        June 2006


                       -- 22-31 unused --
                  noSuchObject                 (32),
                  aliasProblem                 (33),
                  invalidDNSyntax              (34),
                       -- 35 reserved for undefined isLeaf --
                  aliasDereferencingProblem    (36),
                       -- 37-47 unused --
                  inappropriateAuthentication  (48),
                  invalidCredentials           (49),
                  insufficientAccessRights     (50),
                  busy                         (51),
                  unavailable                  (52),
                  unwillingToPerform           (53),
                  loopDetect                   (54),
                       -- 55-63 unused --
                  namingViolation              (64),
                  objectClassViolation         (65),
                  notAllowedOnNonLeaf          (66),
                  notAllowedOnRDN              (67),
                  entryAlreadyExists           (68),
                  objectClassModsProhibited    (69),
                       -- 70 reserved for CLDAP --
                  affectsMultipleDSAs          (71),
                       -- 72-79 unused --
                  other                        (80),
                  ...  },
             matchedDN          LDAPDN,
             diagnosticMessage  LDAPString,
             referral           [3] Referral OPTIONAL }

   The resultCode enumeration is extensible as defined in Section 3.8 of
   [RFC4520].  The meanings of the listed result codes are given in
   Appendix A.  If a server detects multiple errors for an operation,
   only one result code is returned.  The server should return the
   result code that best indicates the nature of the error encountered.
   Servers may return substituted result codes to prevent unauthorized
   disclosures.

   The diagnosticMessage field of this construct may, at the server's
   option, be used to return a string containing a textual, human-
   readable diagnostic message (terminal control and page formatting
   characters should be avoided).  As this diagnostic message is not
   standardized, implementations MUST NOT rely on the values returned.
   Diagnostic messages typically supplement the resultCode with
   additional information.  If the server chooses not to return a
   textual diagnostic, the diagnosticMessage field MUST be empty.





Sermersheim                 Standards Track                    [Page 11]

RFC 4511                         LDAPv3                        June 2006


   For certain result codes (typically, but not restricted to
   noSuchObject, aliasProblem, invalidDNSyntax, and
   aliasDereferencingProblem), the matchedDN field is set (subject to
   access controls) to the name of the last entry (object or alias) used
   in finding the target (or base) object.  This will be a truncated
   form of the provided name or, if an alias was dereferenced while
   attempting to locate the entry, of the resulting name.  Otherwise,
   the matchedDN field is empty.

4.1.10.  Referral

   The referral result code indicates that the contacted server cannot
   or will not perform the operation and that one or more other servers
   may be able to.  Reasons for this include:

   - The target entry of the request is not held locally, but the server
     has knowledge of its possible existence elsewhere.

   - The operation is restricted on this server -- perhaps due to a
     read-only copy of an entry to be modified.

   The referral field is present in an LDAPResult if the resultCode is
   set to referral, and it is absent with all other result codes.  It
   contains one or more references to one or more servers or services
   that may be accessed via LDAP or other protocols.  Referrals can be
   returned in response to any operation request (except Unbind and
   Abandon, which do not have responses).  At least one URI MUST be
   present in the Referral.

   During a Search operation, after the baseObject is located, and
   entries are being evaluated, the referral is not returned.  Instead,
   continuation references, described in Section 4.5.3, are returned
   when other servers would need to be contacted to complete the
   operation.

        Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI

        URI ::= LDAPString     -- limited to characters permitted in
                               -- URIs

   If the client wishes to progress the operation, it contacts one of
   the supported services found in the referral.  If multiple URIs are
   present, the client assumes that any supported URI may be used to
   progress the operation.

   Clients that follow referrals MUST ensure that they do not loop
   between servers.  They MUST NOT repeatedly contact the same server
   for the same request with the same parameters.  Some clients use a



Sermersheim                 Standards Track                    [Page 12]

RFC 4511                         LDAPv3                        June 2006


   counter that is incremented each time referral handling occurs for an
   operation, and these kinds of clients MUST be able to handle at least
   ten nested referrals while progressing the operation.

   A URI for a server implementing LDAP and accessible via TCP/IP (v4 or
   v6) [RFC793][RFC791] is written as an LDAP URL according to
   [RFC4516].

   Referral values that are LDAP URLs follow these rules:

   - If an alias was dereferenced, the <dn> part of the LDAP URL MUST be
     present, with the new target object name.

   - It is RECOMMENDED that the <dn> part be present to avoid ambiguity.

   - If the <dn> part is present, the client uses this name in its next
     request to progress the operation, and if it is not present the
     client uses the same name as in the original request.

   - Some servers (e.g., participating in distributed indexing) may
     provide a different filter in a URL of a referral for a Search
     operation.

   - If the <filter> part of the LDAP URL is present, the client uses
     this filter in its next request to progress this Search, and if it
     is not present the client uses the same filter as it used for that
     Search.

   - For Search, it is RECOMMENDED that the <scope> part be present to
     avoid ambiguity.

   - If the <scope> part is missing, the scope of the original Search is
     used by the client to progress the operation.

   - Other aspects of the new request may be the same as or different
     from the request that generated the referral.

   Other kinds of URIs may be returned.  The syntax and semantics of
   such URIs is left to future specifications.  Clients may ignore URIs
   that they do not support.

   UTF-8 encoded characters appearing in the string representation of a
   DN, search filter, or other fields of the referral value may not be
   legal for URIs (e.g., spaces) and MUST be escaped using the % method
   in [RFC3986].






Sermersheim                 Standards Track                    [Page 13]

RFC 4511                         LDAPv3                        June 2006


4.1.11.  Controls

   Controls provide a mechanism whereby the semantics and arguments of
   existing LDAP operations may be extended.  One or more controls may
   be attached to a single LDAP message.  A control only affects the
   semantics of the message it is attached to.

   Controls sent by clients are termed 'request controls', and those
   sent by servers are termed 'response controls'.

        Controls ::= SEQUENCE OF control Control

        Control ::= SEQUENCE {
             controlType             LDAPOID,
             criticality             BOOLEAN DEFAULT FALSE,
             controlValue            OCTET STRING OPTIONAL }

   The controlType field is the dotted-decimal representation of an
   OBJECT IDENTIFIER that uniquely identifies the control.  This
   provides unambiguous naming of controls.  Often, response control(s)
   solicited by a request control share controlType values with the
   request control.

   The criticality field only has meaning in controls attached to
   request messages (except UnbindRequest).  For controls attached to
   response messages and the UnbindRequest, the criticality field SHOULD
   be FALSE, and MUST be ignored by the receiving protocol peer.  A
   value of TRUE indicates that it is unacceptable to perform the
   operation without applying the semantics of the control.
   Specifically, the criticality field is applied as follows:

   - If the server does not recognize the control type, determines that
     it is not appropriate for the operation, or is otherwise unwilling
     to perform the operation with the control, and if the criticality
     field is TRUE, the server MUST NOT perform the operation, and for
     operations that have a response message, it MUST return with the
     resultCode set to unavailableCriticalExtension.

   - If the server does not recognize the control type, determines that
     it is not appropriate for the operation, or is otherwise unwilling
     to perform the operation with the control, and if the criticality
     field is FALSE, the server MUST ignore the control.

   - Regardless of criticality, if a control is applied to an
     operation, it is applied consistently and impartially to the
     entire operation.





Sermersheim                 Standards Track                    [Page 14]

RFC 4511                         LDAPv3                        June 2006


   The controlValue may contain information associated with the
   controlType.  Its format is defined by the specification of the
   control.  Implementations MUST be prepared to handle arbitrary
   contents of the controlValue octet string, including zero bytes.  It
   is absent only if there is no value information that is associated
   with a control of its type.  When a controlValue is defined in terms
   of ASN.1, and BER-encoded according to Section 5.1, it also follows
   the extensibility rules in Section 4.

   Servers list the controlType of request controls they recognize in
   the 'supportedControl' attribute in the root DSE (Section 5.1 of
   [RFC4512]).

   Controls SHOULD NOT be combined unless the semantics of the
   combination has been specified.  The semantics of control
   combinations, if specified, are generally found in the control
   specification most recently published.  When a combination of
   controls is encountered whose semantics are invalid, not specified
   (or not known), the message is considered not well-formed; thus, the
   operation fails with protocolError.  Controls with a criticality of
   FALSE may be ignored in order to arrive at a valid combination.
   Additionally, unless order-dependent semantics are given in a
   specification, the order of a combination of controls in the SEQUENCE
   is ignored.  Where the order is to be ignored but cannot be ignored
   by the server, the message is considered not well-formed, and the
   operation fails with protocolError.  Again, controls with a
   criticality of FALSE may be ignored in order to arrive at a valid
   combination.

   This document does not specify any controls.  Controls may be
   specified in other documents.  Documents detailing control extensions
   are to provide for each control:

   - the OBJECT IDENTIFIER assigned to the control,

   - direction as to what value the sender should provide for the
     criticality field (note: the semantics of the criticality field are
     defined above should not be altered by the control's
     specification),

   - whether the controlValue field is present, and if so, the format of
     its contents,

   - the semantics of the control, and

   - optionally, semantics regarding the combination of the control with
     other controls.




Sermersheim                 Standards Track                    [Page 15]

RFC 4511                         LDAPv3                        June 2006


4.2.  Bind Operation

   The function of the Bind operation is to allow authentication
   information to be exchanged between the client and server.  The Bind
   operation should be thought of as the "authenticate" operation.
   Operational, authentication, and security-related semantics of this
   operation are given in [RFC4513].

   The Bind request is defined as follows:

        BindRequest ::= [APPLICATION 0] SEQUENCE {
             version                 INTEGER (1 ..  127),
             name                    LDAPDN,
             authentication          AuthenticationChoice }

        AuthenticationChoice ::= CHOICE {
             simple                  [0] OCTET STRING,
                                     -- 1 and 2 reserved
             sasl                    [3] SaslCredentials,
             ...  }

        SaslCredentials ::= SEQUENCE {
             mechanism               LDAPString,
             credentials             OCTET STRING OPTIONAL }

   Fields of the BindRequest are:

   - version: A version number indicating the version of the protocol to
     be used at the LDAP message layer.  This document describes version
     3 of the protocol.  There is no version negotiation.  The client
     sets this field to the version it desires.  If the server does not
     support the specified version, it MUST respond with a BindResponse
     where the resultCode is set to protocolError.

   - name: If not empty, the name of the Directory object that the
     client wishes to bind as.  This field may take on a null value (a
     zero-length string) for the purposes of anonymous binds ([RFC4513],
     Section 5.1) or when using SASL [RFC4422] authentication
     ([RFC4513], Section 5.2).  Where the server attempts to locate the
     named object, it SHALL NOT perform alias dereferencing.

   - authentication: Information used in authentication.  This type is
     extensible as defined in Section 3.7 of [RFC4520].  Servers that do
     not support a choice supplied by a client return a BindResponse
     with the resultCode set to authMethodNotSupported.






Sermersheim                 Standards Track                    [Page 16]

RFC 4511                         LDAPv3                        June 2006


     Textual passwords (consisting of a character sequence with a known
     character set and encoding) transferred to the server using the
     simple AuthenticationChoice SHALL be transferred as UTF-8 [RFC3629]
     encoded [Unicode].  Prior to transfer, clients SHOULD prepare text
     passwords as "query" strings by applying the SASLprep [RFC4013]
     profile of the stringprep [RFC3454] algorithm.  Passwords
     consisting of other data (such as random octets) MUST NOT be
     altered.  The determination of whether a password is textual is a
     local client matter.

4.2.1.  Processing of the Bind Request

   Before processing a BindRequest, all uncompleted operations MUST
   either complete or be abandoned.  The server may either wait for the
   uncompleted operations to complete, or abandon them.  The server then
   proceeds to authenticate the client in either a single-step or
   multi-step Bind process.  Each step requires the server to return a
   BindResponse to indicate the status of authentication.

   After sending a BindRequest, clients MUST NOT send further LDAP PDUs
   until receiving the BindResponse.  Similarly, servers SHOULD NOT
   process or respond to requests received while processing a
   BindRequest.

   If the client did not bind before sending a request and receives an
   operationsError to that request, it may then send a BindRequest.  If
   this also fails or the client chooses not to bind on the existing
   LDAP session, it may terminate the LDAP session, re-establish it, and
   begin again by first sending a BindRequest.  This will aid in
   interoperating with servers implementing other versions of LDAP.

   Clients may send multiple Bind requests to change the authentication
   and/or security associations or to complete a multi-stage Bind
   process.  Authentication from earlier binds is subsequently ignored.

   For some SASL authentication mechanisms, it may be necessary for the
   client to invoke the BindRequest multiple times ([RFC4513], Section
   5.2).  Clients MUST NOT invoke operations between two Bind requests
   made as part of a multi-stage Bind.

   A client may abort a SASL bind negotiation by sending a BindRequest
   with a different value in the mechanism field of SaslCredentials, or
   an AuthenticationChoice other than sasl.








Sermersheim                 Standards Track                    [Page 17]

RFC 4511                         LDAPv3                        June 2006


   If the client sends a BindRequest with the sasl mechanism field as an
   empty string, the server MUST return a BindResponse with the
   resultCode set to authMethodNotSupported.  This will allow the client
   to abort a negotiation if it wishes to try again with the same SASL
   mechanism.

4.2.2.  Bind Response

   The Bind response is defined as follows.

        BindResponse ::= [APPLICATION 1] SEQUENCE {
             COMPONENTS OF LDAPResult,
             serverSaslCreds    [7] OCTET STRING OPTIONAL }

   BindResponse consists simply of an indication from the server of the
   status of the client's request for authentication.

   A successful Bind operation is indicated by a BindResponse with a
   resultCode set to success.  Otherwise, an appropriate result code is
   set in the BindResponse.  For BindResponse, the protocolError result
   code may be used to indicate that the version number supplied by the
   client is unsupported.

   If the client receives a BindResponse where the resultCode is set to
   protocolError, it is to assume that the server does not support this
   version of LDAP.  While the client may be able proceed with another
   version of this protocol (which may or may not require closing and
   re-establishing the transport connection), how to proceed with
   another version of this protocol is beyond the scope of this
   document.  Clients that are unable or unwilling to proceed SHOULD
   terminate the LDAP session.

   The serverSaslCreds field is used as part of a SASL-defined bind
   mechanism to allow the client to authenticate the server to which it
   is communicating, or to perform "challenge-response" authentication.
   If the client bound with the simple choice, or the SASL mechanism
   does not require the server to return information to the client, then
   this field SHALL NOT be included in the BindResponse.

4.3.  Unbind Operation

   The function of the Unbind operation is to terminate an LDAP session.
   The Unbind operation is not the antithesis of the Bind operation as
   the name implies.  The naming of these operations are historical.
   The Unbind operation should be thought of as the "quit" operation.






Sermersheim                 Standards Track                    [Page 18]

RFC 4511                         LDAPv3                        June 2006


   The Unbind operation is defined as follows:

        UnbindRequest ::= [APPLICATION 2] NULL

   The client, upon transmission of the UnbindRequest, and the server,
   upon receipt of the UnbindRequest, are to gracefully terminate the
   LDAP session as described in Section 5.3.  Uncompleted operations are
   handled as specified in Section 3.1.

4.4.  Unsolicited Notification

   An unsolicited notification is an LDAPMessage sent from the server to
   the client that is not in response to any LDAPMessage received by the
   server.  It is used to signal an extraordinary condition in the
   server or in the LDAP session between the client and the server.  The
   notification is of an advisory nature, and the server will not expect
   any response to be returned from the client.

   The unsolicited notification is structured as an LDAPMessage in which
   the messageID is zero and protocolOp is set to the extendedResp
   choice using the ExtendedResponse type (See Section 4.12).  The
   responseName field of the ExtendedResponse always contains an LDAPOID
   that is unique for this notification.

   One unsolicited notification (Notice of Disconnection) is defined in
   this document.  The specification of an unsolicited notification
   consists of:

   - the OBJECT IDENTIFIER assigned to the notification (to be specified
     in the responseName,

   - the format of the contents of the responseValue (if any),

   - the circumstances which will cause the notification to be sent, and

   - the semantics of the message.

4.4.1.  Notice of Disconnection

   This notification may be used by the server to advise the client that
   the server is about to terminate the LDAP session on its own
   initiative.  This notification is intended to assist clients in
   distinguishing between an exceptional server condition and a
   transient network failure.  Note that this notification is not a
   response to an Unbind requested by the client.  Uncompleted
   operations are handled as specified in Section 3.1.





Sermersheim                 Standards Track                    [Page 19]

RFC 4511                         LDAPv3                        June 2006


   The responseName is 1.3.6.1.4.1.1466.20036, the responseValue field
   is absent, and the resultCode is used to indicate the reason for the
   disconnection.  When the strongerAuthRequired resultCode is returned
   with this message, it indicates that the server has detected that an
   established security association between the client and server has
   unexpectedly failed or been compromised.

   Upon transmission of the Notice of Disconnection, the server
   gracefully terminates the LDAP session as described in Section 5.3.

4.5.  Search Operation

   The Search operation is used to request a server to return, subject
   to access controls and other restrictions, a set of entries matching
   a complex search criterion.  This can be used to read attributes from
   a single entry, from entries immediately subordinate to a particular
   entry, or from a whole subtree of entries.

4.5.1.  Search Request

   The Search request is defined as follows:

        SearchRequest ::= [APPLICATION 3] SEQUENCE {
             baseObject      LDAPDN,
             scope           ENUMERATED {
                  baseObject              (0),
                  singleLevel             (1),
                  wholeSubtree            (2),
                  ...  },
             derefAliases    ENUMERATED {
                  neverDerefAliases       (0),
                  derefInSearching        (1),
                  derefFindingBaseObj     (2),
                  derefAlways             (3) },
             sizeLimit       INTEGER (0 ..  maxInt),
             timeLimit       INTEGER (0 ..  maxInt),
             typesOnly       BOOLEAN,
             filter          Filter,
             attributes      AttributeSelection }

        AttributeSelection ::= SEQUENCE OF selector LDAPString
                        -- The LDAPString is constrained to
                        -- <attributeSelector> in Section 4.5.1.8

        Filter ::= CHOICE {
             and             [0] SET SIZE (1..MAX) OF filter Filter,
             or              [1] SET SIZE (1..MAX) OF filter Filter,
             not             [2] Filter,



Sermersheim                 Standards Track                    [Page 20]

RFC 4511                         LDAPv3                        June 2006


             equalityMatch   [3] AttributeValueAssertion,
             substrings      [4] SubstringFilter,
             greaterOrEqual  [5] AttributeValueAssertion,
             lessOrEqual     [6] AttributeValueAssertion,
             present         [7] AttributeDescription,
             approxMatch     [8] AttributeValueAssertion,
             extensibleMatch [9] MatchingRuleAssertion,
             ...  }

        SubstringFilter ::= SEQUENCE {
             type           AttributeDescription,
             substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
                  initial [0] AssertionValue,  -- can occur at most once
                  any     [1] AssertionValue,
                  final   [2] AssertionValue } -- can occur at most once
             }

        MatchingRuleAssertion ::= SEQUENCE {
             matchingRule    [1] MatchingRuleId OPTIONAL,
             type            [2] AttributeDescription OPTIONAL,
             matchValue      [3] AssertionValue,
             dnAttributes    [4] BOOLEAN DEFAULT FALSE }

   Note that an X.500 "list"-like operation can be emulated by the
   client requesting a singleLevel Search operation with a filter
   checking for the presence of the 'objectClass' attribute, and that an
   X.500 "read"-like operation can be emulated by a baseObject Search
   operation with the same filter.  A server that provides a gateway to
   X.500 is not required to use the Read or List operations, although it
   may choose to do so, and if it does, it must provide the same
   semantics as the X.500 Search operation.

4.5.1.1.  SearchRequest.baseObject

   The name of the base object entry (or possibly the root) relative to
   which the Search is to be performed.

4.5.1.2.  SearchRequest.scope

   Specifies the scope of the Search to be performed.  The semantics (as
   described in [X.511]) of the defined values of this field are:

      baseObject: The scope is constrained to the entry named by
      baseObject.

      singleLevel: The scope is constrained to the immediate
      subordinates of the entry named by baseObject.




Sermersheim                 Standards Track                    [Page 21]

RFC 4511                         LDAPv3                        June 2006


      wholeSubtree: The scope is constrained to the entry named by
      baseObject and to all its subordinates.

4.5.1.3.  SearchRequest.derefAliases

   An indicator as to whether or not alias entries (as defined in
   [RFC4512]) are to be dereferenced during stages of the Search
   operation.

   The act of dereferencing an alias includes recursively dereferencing
   aliases that refer to aliases.

   Servers MUST detect looping while dereferencing aliases in order to
   prevent denial-of-service attacks of this nature.

   The semantics of the defined values of this field are:

      neverDerefAliases: Do not dereference aliases in searching or in
      locating the base object of the Search.

      derefInSearching: While searching subordinates of the base object,
      dereference any alias within the search scope.  Dereferenced
      objects become the vertices of further search scopes where the
      Search operation is also applied.  If the search scope is
      wholeSubtree, the Search continues in the subtree(s) of any
      dereferenced object.  If the search scope is singleLevel, the
      search is applied to any dereferenced objects and is not applied
      to their subordinates.  Servers SHOULD eliminate duplicate entries
      that arise due to alias dereferencing while searching.

      derefFindingBaseObj: Dereference aliases in locating the base
      object of the Search, but not when searching subordinates of the
      base object.

      derefAlways: Dereference aliases both in searching and in locating
      the base object of the Search.

4.5.1.4.  SearchRequest.sizeLimit

   A size limit that restricts the maximum number of entries to be
   returned as a result of the Search.  A value of zero in this field
   indicates that no client-requested size limit restrictions are in
   effect for the Search.  Servers may also enforce a maximum number of
   entries to return.







Sermersheim                 Standards Track                    [Page 22]

RFC 4511                         LDAPv3                        June 2006


4.5.1.5.  SearchRequest.timeLimit

   A time limit that restricts the maximum time (in seconds) allowed for
   a Search.  A value of zero in this field indicates that no client-
   requested time limit restrictions are in effect for the Search.
   Servers may also enforce a maximum time limit for the Search.

4.5.1.6.  SearchRequest.typesOnly

   An indicator as to whether Search results are to contain both
   attribute descriptions and values, or just attribute descriptions.
   Setting this field to TRUE causes only attribute descriptions (and
   not values) to be returned.  Setting this field to FALSE causes both
   attribute descriptions and values to be returned.

4.5.1.7.  SearchRequest.filter

   A filter that defines the conditions that must be fulfilled in order
   for the Search to match a given entry.

   The 'and', 'or', and 'not' choices can be used to form combinations
   of filters.  At least one filter element MUST be present in an 'and'
   or 'or' choice.  The others match against individual attribute values
   of entries in the scope of the Search.  (Implementor's note: the
   'not' filter is an example of a tagged choice in an implicitly-tagged
   module.  In BER this is treated as if the tag were explicit.)

   A server MUST evaluate filters according to the three-valued logic of
   [X.511] (1993), Clause 7.8.1.  In summary, a filter is evaluated to
   "TRUE", "FALSE", or "Undefined".  If the filter evaluates to TRUE for
   a particular entry, then the attributes of that entry are returned as
   part of the Search result (subject to any applicable access control
   restrictions).  If the filter evaluates to FALSE or Undefined, then
   the entry is ignored for the Search.

   A filter of the "and" choice is TRUE if all the filters in the SET OF
   evaluate to TRUE, FALSE if at least one filter is FALSE, and
   Undefined otherwise.  A filter of the "or" choice is FALSE if all the
   filters in the SET OF evaluate to FALSE, TRUE if at least one filter
   is TRUE, and Undefined otherwise.  A filter of the 'not' choice is
   TRUE if the filter being negated is FALSE, FALSE if it is TRUE, and
   Undefined if it is Undefined.

   A filter item evaluates to Undefined when the server would not be
   able to determine whether the assertion value matches an entry.
   Examples include:





Sermersheim                 Standards Track                    [Page 23]

RFC 4511                         LDAPv3                        June 2006


   - An attribute description in an equalityMatch, substrings,
     greaterOrEqual, lessOrEqual, approxMatch, or extensibleMatch filter
     is not recognized by the server.

   - The attribute type does not define the appropriate matching rule.

   - A MatchingRuleId in the extensibleMatch is not recognized by the
     server or is not valid for the attribute type.

   - The type of filtering requested is not implemented.

   - The assertion value is invalid.

   For example, if a server did not recognize the attribute type
   shoeSize, the filters (shoeSize=*), (shoeSize=12), (shoeSize>=12),
   and (shoeSize<=12) would each evaluate to Undefined.

   Servers MUST NOT return errors if attribute descriptions or matching
   rule ids are not recognized, assertion values are invalid, or the
   assertion syntax is not supported.  More details of filter processing
   are given in Clause 7.8 of [X.511].

4.5.1.7.1.  SearchRequest.filter.equalityMatch

   The matching rule for an equalityMatch filter is defined by the
   EQUALITY matching rule for the attribute type or subtype.  The filter
   is TRUE when the EQUALITY rule returns TRUE as applied to the
   attribute or subtype and the asserted value.

4.5.1.7.2.  SearchRequest.filter.substrings

   There SHALL be at most one 'initial' and at most one 'final' in the
   'substrings' of a SubstringFilter.  If 'initial' is present, it SHALL
   be the first element of 'substrings'.  If 'final' is present, it
   SHALL be the last element of 'substrings'.

   The matching rule for an AssertionValue in a substrings filter item
   is defined by the SUBSTR matching rule for the attribute type or
   subtype.  The filter is TRUE when the SUBSTR rule returns TRUE as
   applied to the attribute or subtype and the asserted value.

   Note that the AssertionValue in a substrings filter item conforms to
   the assertion syntax of the EQUALITY matching rule for the attribute
   type rather than to the assertion syntax of the SUBSTR matching rule
   for the attribute type.  Conceptually, the entire SubstringFilter is
   converted into an assertion value of the substrings matching rule
   prior to applying the rule.




Sermersheim                 Standards Track                    [Page 24]

RFC 4511                         LDAPv3                        June 2006


4.5.1.7.3.  SearchRequest.filter.greaterOrEqual

   The matching rule for a greaterOrEqual filter is defined by the
   ORDERING matching rule for the attribute type or subtype.  The filter
   is TRUE when the ORDERING rule returns FALSE as applied to the
   attribute or subtype and the asserted value.

4.5.1.7.4.  SearchRequest.filter.lessOrEqual

   The matching rules for a lessOrEqual filter are defined by the
   ORDERING and EQUALITY matching rules for the attribute type or
   subtype.  The filter is TRUE when either the ORDERING or EQUALITY
   rule returns TRUE as applied to the attribute or subtype and the
   asserted value.

4.5.1.7.5.  SearchRequest.filter.present

   A present filter is TRUE when there is an attribute or subtype of the
   specified attribute description present in an entry, FALSE when no
   attribute or subtype of the specified attribute description is
   present in an entry, and Undefined otherwise.

4.5.1.7.6.  SearchRequest.filter.approxMatch

   An approxMatch filter is TRUE when there is a value of the attribute
   type or subtype for which some locally-defined approximate matching
   algorithm (e.g., spelling variations, phonetic match, etc.) returns
   TRUE.  If a value matches for equality, it also satisfies an
   approximate match.  If approximate matching is not supported for the
   attribute, this filter item should be treated as an equalityMatch.

4.5.1.7.7.  SearchRequest.filter.extensibleMatch

   The fields of the extensibleMatch filter item are evaluated as
   follows:

   - If the matchingRule field is absent, the type field MUST be
     present, and an equality match is performed for that type.

   - If the type field is absent and the matchingRule is present, the
     matchValue is compared against all attributes in an entry that
     support that matchingRule.

   - If the type field is present and the matchingRule is present, the
     matchValue is compared against the specified attribute type and its
     subtypes.





Sermersheim                 Standards Track                    [Page 25]

RFC 4511                         LDAPv3                        June 2006


   - If the dnAttributes field is set to TRUE, the match is additionally
     applied against all the AttributeValueAssertions in an entry's
     distinguished name, and it evaluates to TRUE if there is at least
     one attribute or subtype in the distinguished name for which the
     filter item evaluates to TRUE.  The dnAttributes field is present
     to alleviate the need for multiple versions of generic matching
     rules (such as word matching), where one applies to entries and
     another applies to entries and DN attributes as well.

   The matchingRule used for evaluation determines the syntax for the
   assertion value.  Once the matchingRule and attribute(s) have been
   determined, the filter item evaluates to TRUE if it matches at least
   one attribute type or subtype in the entry, FALSE if it does not
   match any attribute type or subtype in the entry, and Undefined if
   the matchingRule is not recognized, the matchingRule is unsuitable
   for use with the specified type, or the assertionValue is invalid.

4.5.1.8.  SearchRequest.attributes

   A selection list of the attributes to be returned from each entry
   that matches the search filter.  Attributes that are subtypes of
   listed attributes are implicitly included.  LDAPString values of this
   field are constrained to the following Augmented Backus-Naur Form
   (ABNF) [RFC4234]:

      attributeSelector = attributedescription / selectorspecial

      selectorspecial = noattrs / alluserattrs

      noattrs = %x31.2E.31 ; "1.1"

      alluserattrs = %x2A ; asterisk ("*")

      The <attributedescription> production is defined in Section 2.5 of
      [RFC4512].

      There are three special cases that may appear in the attributes
      selection list:

      1. An empty list with no attributes requests the return of all
         user attributes.

      2. A list containing "*" (with zero or more attribute
         descriptions) requests the return of all user attributes in
         addition to other listed (operational) attributes.






Sermersheim                 Standards Track                    [Page 26]

RFC 4511                         LDAPv3                        June 2006


      3. A list containing only the OID "1.1" indicates that no
         attributes are to be returned.  If "1.1" is provided with other
         attributeSelector values, the "1.1" attributeSelector is
         ignored.  This OID was chosen because it does not (and can not)
         correspond to any attribute in use.

   Client implementors should note that even if all user attributes are
   requested, some attributes and/or attribute values of the entry may
   not be included in Search results due to access controls or other
   restrictions.  Furthermore, servers will not return operational
   attributes, such as objectClasses or attributeTypes, unless they are
   listed by name.  Operational attributes are described in [RFC4512].

   Attributes are returned at most once in an entry.  If an attribute
   description is named more than once in the list, the subsequent names
   are ignored.  If an attribute description in the list is not
   recognized, it is ignored by the server.

4.5.2.  Search Result

   The results of the Search operation are returned as zero or more
   SearchResultEntry and/or SearchResultReference messages, followed by
   a single SearchResultDone message.

        SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
             objectName      LDAPDN,
             attributes      PartialAttributeList }

        PartialAttributeList ::= SEQUENCE OF
                             partialAttribute PartialAttribute

        SearchResultReference ::= [APPLICATION 19] SEQUENCE
                                  SIZE (1..MAX) OF uri URI

        SearchResultDone ::= [APPLICATION 5] LDAPResult

   Each SearchResultEntry represents an entry found during the Search.
   Each SearchResultReference represents an area not yet explored during
   the Search.  The SearchResultEntry and SearchResultReference messages
   may come in any order.  Following all the SearchResultReference and
   SearchResultEntry responses, the server returns a SearchResultDone
   response, which contains an indication of success or details any
   errors that have occurred.

   Each entry returned in a SearchResultEntry will contain all
   appropriate attributes as specified in the attributes field of the
   Search Request, subject to access control and other administrative
   policy.  Note that the PartialAttributeList may hold zero elements.



Sermersheim                 Standards Track                    [Page 27]

RFC 4511                         LDAPv3                        June 2006


   This may happen when none of the attributes of an entry were
   requested or could be returned.  Note also that the partialAttribute
   vals set may hold zero elements.  This may happen when typesOnly is
   requested, access controls prevent the return of values, or other
   reasons.

   Some attributes may be constructed by the server and appear in a
   SearchResultEntry attribute list, although they are not stored
   attributes of an entry.  Clients SHOULD NOT assume that all
   attributes can be modified, even if this is permitted by access
   control.

   If the server's schema defines short names [RFC4512] for an attribute
   type, then the server SHOULD use one of those names in attribute
   descriptions for that attribute type (in preference to using the
   <numericoid> [RFC4512] format of the attribute type's object
   identifier).  The server SHOULD NOT use the short name if that name
   is known by the server to be ambiguous, or if it is otherwise likely
   to cause interoperability problems.

4.5.3.  Continuation References in the Search Result

   If the server was able to locate the entry referred to by the
   baseObject but was unable or unwilling to search one or more non-
   local entries, the server may return one or more
   SearchResultReference messages, each containing a reference to
   another set of servers for continuing the operation.  A server MUST
   NOT return any SearchResultReference messages if it has not located
   the baseObject and thus has not searched any entries.  In this case,
   it would return a SearchResultDone containing either a referral or
   noSuchObject result code (depending on the server's knowledge of the
   entry named in the baseObject).

   If a server holds a copy or partial copy of the subordinate naming
   context (Section 5 of [RFC4512]), it may use the search filter to
   determine whether or not to return a SearchResultReference response.
   Otherwise, SearchResultReference responses are always returned when
   in scope.

   The SearchResultReference is of the same data type as the Referral.

   If the client wishes to progress the Search, it issues a new Search
   operation for each SearchResultReference that is returned.  If
   multiple URIs are present, the client assumes that any supported URI
   may be used to progress the operation.






Sermersheim                 Standards Track                    [Page 28]

RFC 4511                         LDAPv3                        June 2006


   Clients that follow search continuation references MUST ensure that
   they do not loop between servers.  They MUST NOT repeatedly contact
   the same server for the same request with the same parameters.  Some
   clients use a counter that is incremented each time search result
   reference handling occurs for an operation, and these kinds of
   clients MUST be able to handle at least ten nested referrals while
   progressing the operation.

   Note that the Abandon operation described in Section 4.11 applies
   only to a particular operation sent at the LDAP message layer between
   a client and server.  The client must individually abandon subsequent
   Search operations it wishes to.

   A URI for a server implementing LDAP and accessible via TCP/IP (v4 or
   v6) [RFC793][RFC791] is written as an LDAP URL according to
   [RFC4516].

   SearchResultReference values that are LDAP URLs follow these rules:

   - The <dn> part of the LDAP URL MUST be present, with the new target
     object name.  The client uses this name when following the
     reference.

   - Some servers (e.g., participating in distributed indexing) may
     provide a different filter in the LDAP URL.

   - If the <filter> part of the LDAP URL is present, the client uses
     this filter in its next request to progress this Search, and if it
     is not present the client uses the same filter as it used for that
     Search.

   - If the originating search scope was singleLevel, the <scope> part
     of the LDAP URL will be "base".

   - It is RECOMMENDED that the <scope> part be present to avoid
     ambiguity.  In the absence of a <scope> part, the scope of the
     original Search request is assumed.

   - Other aspects of the new Search request may be the same as or
     different from the Search request that generated the
     SearchResultReference.

   - The name of an unexplored subtree in a SearchResultReference need
     not be subordinate to the base object.

   Other kinds of URIs may be returned.  The syntax and semantics of
   such URIs is left to future specifications.  Clients may ignore URIs
   that they do not support.



Sermersheim                 Standards Track                    [Page 29]

RFC 4511                         LDAPv3                        June 2006


   UTF-8-encoded characters appearing in the string representation of a
   DN, search filter, or other fields of the referral value may not be
   legal for URIs (e.g., spaces) and MUST be escaped using the % method
   in [RFC3986].

4.5.3.1.  Examples

   For example, suppose the contacted server (hosta) holds the entry
   <DC=Example,DC=NET> and the entry <CN=Manager,DC=Example,DC=NET>.  It
   knows that both LDAP servers (hostb) and (hostc) hold
   <OU=People,DC=Example,DC=NET> (one is the master and the other server
   a shadow), and that LDAP-capable server (hostd) holds the subtree
   <OU=Roles,DC=Example,DC=NET>.  If a wholeSubtree Search of
   <DC=Example,DC=NET> is requested to the contacted server, it may
   return the following:

     SearchResultEntry for DC=Example,DC=NET
     SearchResultEntry for CN=Manager,DC=Example,DC=NET
     SearchResultReference {
       ldap://hostb/OU=People,DC=Example,DC=NET??sub
       ldap://hostc/OU=People,DC=Example,DC=NET??sub }
     SearchResultReference {
       ldap://hostd/OU=Roles,DC=Example,DC=NET??sub }
     SearchResultDone (success)

   Client implementors should note that when following a
   SearchResultReference, additional SearchResultReference may be
   generated.  Continuing the example, if the client contacted the
   server (hostb) and issued the Search request for the subtree
   <OU=People,DC=Example,DC=NET>, the server might respond as follows:

     SearchResultEntry for OU=People,DC=Example,DC=NET
     SearchResultReference {
       ldap://hoste/OU=Managers,OU=People,DC=Example,DC=NET??sub }
     SearchResultReference {
       ldap://hostf/OU=Consultants,OU=People,DC=Example,DC=NET??sub }
     SearchResultDone (success)

   Similarly, if a singleLevel Search of <DC=Example,DC=NET> is
   requested to the contacted server, it may return the following:

     SearchResultEntry for CN=Manager,DC=Example,DC=NET
     SearchResultReference {
       ldap://hostb/OU=People,DC=Example,DC=NET??base
       ldap://hostc/OU=People,DC=Example,DC=NET??base }
     SearchResultReference {
       ldap://hostd/OU=Roles,DC=Example,DC=NET??base }
     SearchResultDone (success)



Sermersheim                 Standards Track                    [Page 30]

RFC 4511                         LDAPv3                        June 2006


   If the contacted server does not hold the base object for the Search,
   but has knowledge of its possible location, then it may return a
   referral to the client.  In this case, if the client requests a
   subtree Search of <DC=Example,DC=ORG> to hosta, the server returns a
   SearchResultDone containing a referral.

     SearchResultDone (referral) {
       ldap://hostg/DC=Example,DC=ORG??sub }

4.6.  Modify Operation

   The Modify operation allows a client to request that a modification
   of an entry be performed on its behalf by a server.  The Modify
   Request is defined as follows:

        ModifyRequest ::= [APPLICATION 6] SEQUENCE {
             object          LDAPDN,
             changes         SEQUENCE OF change SEQUENCE {
                  operation       ENUMERATED {
                       add     (0),
                       delete  (1),
                       replace (2),
                       ...  },
                  modification    PartialAttribute } }

   Fields of the Modify Request are:

   - object: The value of this field contains the name of the entry to
     be modified.  The server SHALL NOT perform any alias dereferencing
     in determining the object to be modified.

   - changes: A list of modifications to be performed on the entry.  The
     entire list of modifications MUST be performed in the order they
     are listed as a single atomic operation.  While individual
     modifications may violate certain aspects of the directory schema
     (such as the object class definition and Directory Information Tree
     (DIT) content rule), the resulting entry after the entire list of
     modifications is performed MUST conform to the requirements of the
     directory model and controlling schema [RFC4512].

     -  operation: Used to specify the type of modification being
        performed.  Each operation type acts on the following
        modification.  The values of this field have the following
        semantics, respectively:

           add: add values listed to the modification attribute,
           creating the attribute if necessary.




Sermersheim                 Standards Track                    [Page 31]

RFC 4511                         LDAPv3                        June 2006


           delete: delete values listed from the modification attribute.
           If no values are listed, or if all current values of the
           attribute are listed, the entire attribute is removed.

           replace: replace all existing values of the modification
           attribute with the new values listed, creating the attribute
           if it did not already exist.  A replace with no value will
           delete the entire attribute if it exists, and it is ignored
           if the attribute does not exist.

     -  modification: A PartialAttribute (which may have an empty SET
        of vals) used to hold the attribute type or attribute type and
        values being modified.

   Upon receipt of a Modify Request, the server attempts to perform the
   necessary modifications to the DIT and returns the result in a Modify
   Response, defined as follows:

        ModifyResponse ::= [APPLICATION 7] LDAPResult

   The server will return to the client a single Modify Response
   indicating either the successful completion of the DIT modification,
   or the reason that the modification failed.  Due to the requirement
   for atomicity in applying the list of modifications in the Modify
   Request, the client may expect that no modifications of the DIT have
   been performed if the Modify Response received indicates any sort of
   error, and that all requested modifications have been performed if
   the Modify Response indicates successful completion of the Modify
   operation.  Whether or not the modification was applied cannot be
   determined by the client if the Modify Response was not received
   (e.g., the LDAP session was terminated or the Modify operation was
   abandoned).

   Servers MUST ensure that entries conform to user and system schema
   rules or other data model constraints.  The Modify operation cannot
   be used to remove from an entry any of its distinguished values,
   i.e., those values which form the entry's relative distinguished
   name.  An attempt to do so will result in the server returning the
   notAllowedOnRDN result code.  The Modify DN operation described in
   Section 4.9 is used to rename an entry.

   For attribute types that specify no equality matching, the rules in
   Section 2.5.1 of [RFC4512] are followed.

   Note that due to the simplifications made in LDAP, there is not a
   direct mapping of the changes in an LDAP ModifyRequest onto the
   changes of a DAP ModifyEntry operation, and different implementations




Sermersheim                 Standards Track                    [Page 32]

RFC 4511                         LDAPv3                        June 2006


   of LDAP-DAP gateways may use different means of representing the
   change.  If successful, the final effect of the operations on the
   entry MUST be identical.

4.7.  Add Operation

   The Add operation allows a client to request the addition of an entry
   into the Directory.  The Add Request is defined as follows:

        AddRequest ::= [APPLICATION 8] SEQUENCE {
             entry           LDAPDN,
             attributes      AttributeList }

        AttributeList ::= SEQUENCE OF attribute Attribute

   Fields of the Add Request are:

   - entry: the name of the entry to be added.  The server SHALL NOT
     dereference any aliases in locating the entry to be added.

   - attributes: the list of attributes that, along with those from the
     RDN, make up the content of the entry being added.  Clients MAY or
     MAY NOT include the RDN attribute(s) in this list.  Clients MUST
     NOT supply NO-USER-MODIFICATION attributes such as the
     createTimestamp or creatorsName attributes, since the server
     maintains these automatically.

   Servers MUST ensure that entries conform to user and system schema
   rules or other data model constraints.  For attribute types that
   specify no equality matching, the rules in Section 2.5.1 of [RFC4512]
   are followed (this applies to the naming attribute in addition to any
   multi-valued attributes being added).

   The entry named in the entry field of the AddRequest MUST NOT exist
   for the AddRequest to succeed.  The immediate superior (parent) of an
   object or alias entry to be added MUST exist.  For example, if the
   client attempted to add <CN=JS,DC=Example,DC=NET>, the
   <DC=Example,DC=NET> entry did not exist, and the <DC=NET> entry did
   exist, then the server would return the noSuchObject result code with
   the matchedDN field containing <DC=NET>.

   Upon receipt of an Add Request, a server will attempt to add the
   requested entry.  The result of the Add attempt will be returned to
   the client in the Add Response, defined as follows:

        AddResponse ::= [APPLICATION 9] LDAPResult





Sermersheim                 Standards Track                    [Page 33]

RFC 4511                         LDAPv3                        June 2006


   A response of success indicates that the new entry has been added to
   the Directory.

4.8.  Delete Operation

   The Delete operation allows a client to request the removal of an
   entry from the Directory.  The Delete Request is defined as follows:

        DelRequest ::= [APPLICATION 10] LDAPDN

   The Delete Request consists of the name of the entry to be deleted.
   The server SHALL NOT dereference aliases while resolving the name of
   the target entry to be removed.

   Only leaf entries (those with no subordinate entries) can be deleted
   with this operation.

   Upon receipt of a Delete Request, a server will attempt to perform
   the entry removal requested and return the result in the Delete
   Response defined as follows:

        DelResponse ::= [APPLICATION 11] LDAPResult

4.9.  Modify DN Operation

   The Modify DN operation allows a client to change the Relative
   Distinguished Name (RDN) of an entry in the Directory and/or to move
   a subtree of entries to a new location in the Directory.  The Modify
   DN Request is defined as follows:

        ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
             entry           LDAPDN,
             newrdn          RelativeLDAPDN,
             deleteoldrdn    BOOLEAN,
             newSuperior     [0] LDAPDN OPTIONAL }

   Fields of the Modify DN Request are:

   - entry: the name of the entry to be changed.  This entry may or may
     not have subordinate entries.

   - newrdn: the new RDN of the entry.  The value of the old RDN is
     supplied when moving the entry to a new superior without changing
     its RDN.  Attribute values of the new RDN not matching any
     attribute value of the entry are added to the entry, and an
     appropriate error is returned if this fails.





Sermersheim                 Standards Track                    [Page 34]

RFC 4511                         LDAPv3                        June 2006


   - deleteoldrdn: a boolean field that controls whether the old RDN
     attribute values are to be retained as attributes of the entry or
     deleted from the entry.

   - newSuperior: if present, this is the name of an existing object
     entry that becomes the immediate superior (parent) of the
     existing entry.

   The server SHALL NOT dereference any aliases in locating the objects
   named in entry or newSuperior.

   Upon receipt of a ModifyDNRequest, a server will attempt to perform
   the name change and return the result in the Modify DN Response,
   defined as follows:

        ModifyDNResponse ::= [APPLICATION 13] LDAPResult

   For example, if the entry named in the entry field was <cn=John
   Smith,c=US>, the newrdn field was <cn=John Cougar Smith>, and the
   newSuperior field was absent, then this operation would attempt to
   rename the entry as <cn=John Cougar Smith,c=US>.  If there was
   already an entry with that name, the operation would fail with the
   entryAlreadyExists result code.

   Servers MUST ensure that entries conform to user and system schema
   rules or other data model constraints.  For attribute types that
   specify no equality matching, the rules in Section 2.5.1 of [RFC4512]
   are followed (this pertains to newrdn and deleteoldrdn).

   The object named in newSuperior MUST exist.  For example, if the
   client attempted to add <CN=JS,DC=Example,DC=NET>, the
   <DC=Example,DC=NET> entry did not exist, and the <DC=NET> entry did
   exist, then the server would return the noSuchObject result code with
   the matchedDN field containing <DC=NET>.

   If the deleteoldrdn field is TRUE, the attribute values forming the
   old RDN (but not the new RDN) are deleted from the entry.  If the
   deleteoldrdn field is FALSE, the attribute values forming the old RDN
   will be retained as non-distinguished attribute values of the entry.

   Note that X.500 restricts the ModifyDN operation to affect only
   entries that are contained within a single server.  If the LDAP
   server is mapped onto DAP, then this restriction will apply, and the
   affectsMultipleDSAs result code will be returned if this error
   occurred.  In general, clients MUST NOT expect to be able to perform
   arbitrary movements of entries and subtrees between servers or
   between naming contexts.




Sermersheim                 Standards Track                    [Page 35]

RFC 4511                         LDAPv3                        June 2006


4.10.  Compare Operation

   The Compare operation allows a client to compare an assertion value
   with the values of a particular attribute in a particular entry in
   the Directory.  The Compare Request is defined as follows:

        CompareRequest ::= [APPLICATION 14] SEQUENCE {
             entry           LDAPDN,
             ava             AttributeValueAssertion }

   Fields of the Compare Request are:

   - entry: the name of the entry to be compared.  The server SHALL NOT
     dereference any aliases in locating the entry to be compared.

   - ava: holds the attribute value assertion to be compared.

   Upon receipt of a Compare Request, a server will attempt to perform
   the requested comparison and return the result in the Compare
   Response, defined as follows:

        CompareResponse ::= [APPLICATION 15] LDAPResult

   The resultCode is set to compareTrue, compareFalse, or an appropriate
   error.  compareTrue indicates that the assertion value in the ava
   field matches a value of the attribute or subtype according to the
   attribute's EQUALITY matching rule.  compareFalse indicates that the
   assertion value in the ava field and the values of the attribute or
   subtype did not match.  Other result codes indicate either that the
   result of the comparison was Undefined (Section 4.5.1.7), or that
   some error occurred.

   Note that some directory systems may establish access controls that
   permit the values of certain attributes (such as userPassword) to be
   compared but not interrogated by other means.

4.11.  Abandon Operation

   The function of the Abandon operation is to allow a client to request
   that the server abandon an uncompleted operation.  The Abandon
   Request is defined as follows:

        AbandonRequest ::= [APPLICATION 16] MessageID

   The MessageID is that of an operation that was requested earlier at
   this LDAP message layer.  The Abandon request itself has its own
   MessageID.  This is distinct from the MessageID of the earlier
   operation being abandoned.



Sermersheim                 Standards Track                    [Page 36]

RFC 4511                         LDAPv3                        June 2006


   There is no response defined in the Abandon operation.  Upon receipt
   of an AbandonRequest, the server MAY abandon the operation identified
   by the MessageID.  Since the client cannot tell the difference
   between a successfully abandoned operation and an uncompleted
   operation, the application of the Abandon operation is limited to
   uses where the client does not require an indication of its outcome.

   Abandon, Bind, Unbind, and StartTLS operations cannot be abandoned.

   In the event that a server receives an Abandon Request on a Search
   operation in the midst of transmitting responses to the Search, that
   server MUST cease transmitting entry responses to the abandoned
   request immediately, and it MUST NOT send the SearchResultDone.  Of
   course, the server MUST ensure that only properly encoded LDAPMessage
   PDUs are transmitted.

   The ability to abandon other (particularly update) operations is at
   the discretion of the server.

   Clients should not send Abandon requests for the same operation
   multiple times, and they MUST also be prepared to receive results
   from operations they have abandoned (since these might have been in
   transit when the Abandon was requested or might not be able to be
   abandoned).

   Servers MUST discard Abandon requests for messageIDs they do not
   recognize, for operations that cannot be abandoned, and for
   operations that have already been abandoned.

4.12.  Extended Operation

   The Extended operation allows additional operations to be defined for
   services not already available in the protocol; for example, to Add
   operations to install transport layer security (see Section 4.14).

   The Extended operation allows clients to make requests and receive
   responses with predefined syntaxes and semantics.  These may be
   defined in RFCs or be private to particular implementations.

   Each Extended operation consists of an Extended request and an
   Extended response.

        ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
             requestName      [0] LDAPOID,
             requestValue     [1] OCTET STRING OPTIONAL }






Sermersheim                 Standards Track                    [Page 37]

RFC 4511                         LDAPv3                        June 2006


   The requestName is a dotted-decimal representation of the unique
   OBJECT IDENTIFIER corresponding to the request.  The requestValue is
   information in a form defined by that request, encapsulated inside an
   OCTET STRING.

   The server will respond to this with an LDAPMessage containing an
   ExtendedResponse.

        ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
             COMPONENTS OF LDAPResult,
             responseName     [10] LDAPOID OPTIONAL,
             responseValue    [11] OCTET STRING OPTIONAL }

   The responseName field, when present, contains an LDAPOID that is
   unique for this extended operation or response.  This field is
   optional (even when the extension specification defines an LDAPOID
   for use in this field).  The field will be absent whenever the server
   is unable or unwilling to determine the appropriate LDAPOID to
   return, for instance, when the requestName cannot be parsed or its
   value is not recognized.

   Where the requestName is not recognized, the server returns
   protocolError.  (The server may return protocolError in other cases.)

   The requestValue and responseValue fields contain information
   associated with the operation.  The format of these fields is defined
   by the specification of the Extended operation.  Implementations MUST
   be prepared to handle arbitrary contents of these fields, including
   zero bytes.  Values that are defined in terms of ASN.1 and BER-
   encoded according to Section 5.1 also follow the extensibility rules
   in Section 4.

   Servers list the requestName of Extended Requests they recognize in
   the 'supportedExtension' attribute in the root DSE (Section 5.1 of
   [RFC4512]).

   Extended operations may be specified in other documents.  The
   specification of an Extended operation consists of:

   - the OBJECT IDENTIFIER assigned to the requestName,

   - the OBJECT IDENTIFIER (if any) assigned to the responseName (note
     that the same OBJECT IDENTIFIER may be used for both the
     requestName and responseName),







Sermersheim                 Standards Track                    [Page 38]

RFC 4511                         LDAPv3                        June 2006


   - the format of the contents of the requestValue and responseValue
     (if any), and

   - the semantics of the operation.

4.13.  IntermediateResponse Message

   While the Search operation provides a mechanism to return multiple
   response messages for a single Search request, other operations, by
   nature, do not provide for multiple response messages.

   The IntermediateResponse message provides a general mechanism for
   defining single-request/multiple-response operations in LDAP.  This
   message is intended to be used in conjunction with the Extended
   operation to define new single-request/multiple-response operations
   or in conjunction with a control when extending existing LDAP
   operations in a way that requires them to return Intermediate
   response information.

   It is intended that the definitions and descriptions of Extended
   operations and controls that make use of the IntermediateResponse
   message will define the circumstances when an IntermediateResponse
   message can be sent by a server and the associated meaning of an
   IntermediateResponse message sent in a particular circumstance.

        IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
                responseName     [0] LDAPOID OPTIONAL,
                responseValue    [1] OCTET STRING OPTIONAL }

   IntermediateResponse messages SHALL NOT be returned to the client
   unless the client issues a request that specifically solicits their
   return.  This document defines two forms of solicitation: Extended
   operation and request control.  IntermediateResponse messages are
   specified in documents describing the manner in which they are
   solicited (i.e., in the Extended operation or request control
   specification that uses them).  These specifications include:

   - the OBJECT IDENTIFIER (if any) assigned to the responseName,

   - the format of the contents of the responseValue (if any), and

   - the semantics associated with the IntermediateResponse message.

   Extensions that allow the return of multiple types of
   IntermediateResponse messages SHALL identify those types using unique
   responseName values (note that one of these may specify no value).





Sermersheim                 Standards Track                    [Page 39]

RFC 4511                         LDAPv3                        June 2006


   Sections 4.13.1 and 4.13.2 describe additional requirements on the
   inclusion of responseName and responseValue in IntermediateResponse
   messages.

4.13.1.  Usage with LDAP ExtendedRequest and ExtendedResponse

   A single-request/multiple-response operation may be defined using a
   single ExtendedRequest message to solicit zero or more
   IntermediateResponse messages of one or more kinds, followed by an
   ExtendedResponse message.

4.13.2.  Usage with LDAP Request Controls

   A control's semantics may include the return of zero or more
   IntermediateResponse messages prior to returning the final result
   code for the operation.  One or more kinds of IntermediateResponse
   messages may be sent in response to a request control.

   All IntermediateResponse messages associated with request controls
   SHALL include a responseName.  This requirement ensures that the
   client can correctly identify the source of IntermediateResponse
   messages when:

   - two or more controls using IntermediateResponse messages are
     included in a request for any LDAP operation or

   - one or more controls using IntermediateResponse messages are
     included in a request with an LDAP Extended operation that uses
     IntermediateResponse messages.

4.14.  StartTLS Operation

   The Start Transport Layer Security (StartTLS) operation's purpose is
   to initiate installation of a TLS layer.  The StartTLS operation is
   defined using the Extended operation mechanism described in Section
   4.12.

4.14.1.  StartTLS Request

   A client requests TLS establishment by transmitting a StartTLS
   request message to the server.  The StartTLS request is defined in
   terms of an ExtendedRequest.  The requestName is
   "1.3.6.1.4.1.1466.20037", and the requestValue field is always
   absent.







Sermersheim                 Standards Track                    [Page 40]

RFC 4511                         LDAPv3                        June 2006


   The client MUST NOT send any LDAP PDUs at this LDAP message layer
   following this request until it receives a StartTLS Extended response
   and, in the case of a successful response, completes TLS
   negotiations.

   Detected sequencing problems (particularly those detailed in Section
   3.1.1 of [RFC4513]) result in the resultCode being set to
   operationsError.

   If the server does not support TLS (whether by design or by current
   configuration), it returns with the resultCode set to protocolError
   as described in Section 4.12.

4.14.2.  StartTLS Response

   When a StartTLS request is received, servers supporting the operation
   MUST return a StartTLS response message to the requestor.  The
   responseName is "1.3.6.1.4.1.1466.20037" when provided (see Section
   4.12).  The responseValue is always absent.

   If the server is willing and able to negotiate TLS, it returns the
   StartTLS response with the resultCode set to success.  Upon client
   receipt of a successful StartTLS response, protocol peers may
   commence with TLS negotiation as discussed in Section 3 of [RFC4513].

   If the server is otherwise unwilling or unable to perform this
   operation, the server is to return an appropriate result code
   indicating the nature of the problem.  For example, if the TLS
   subsystem is not presently available, the server may indicate this by
   returning with the resultCode set to unavailable.  In cases where a
   non-success result code is returned, the LDAP session is left without
   a TLS layer.

4.14.3.  Removal of the TLS Layer

   Either the client or server MAY remove the TLS layer and leave the
   LDAP message layer intact by sending and receiving a TLS closure
   alert.

   The initiating protocol peer sends the TLS closure alert and MUST
   wait until it receives a TLS closure alert from the other peer before
   sending further LDAP PDUs.

   When a protocol peer receives the initial TLS closure alert, it may
   choose to allow the LDAP message layer to remain intact.  In this
   case, it MUST immediately transmit a TLS closure alert.  Following
   this, it MAY send and receive LDAP PDUs.




Sermersheim                 Standards Track                    [Page 41]

RFC 4511                         LDAPv3                        June 2006


   Protocol peers MAY terminate the LDAP session after sending or
   receiving a TLS closure alert.

5.  Protocol Encoding, Connection, and Transfer

   This protocol is designed to run over connection-oriented, reliable
   transports, where the data stream is divided into octets (8-bit
   units), with each octet and each bit being significant.

   One underlying service, LDAP over TCP, is defined in Section 5.2.
   This service is generally applicable to applications providing or
   consuming X.500-based directory services on the Internet.  This
   specification was generally written with the TCP mapping in mind.
   Specifications detailing other mappings may encounter various
   obstacles.

   Implementations of LDAP over TCP MUST implement the mapping as
   described in Section 5.2.

   This table illustrates the relationship among the different layers
   involved in an exchange between two protocol peers:

               +----------------------+
               |  LDAP message layer  |
               +----------------------+ > LDAP PDUs
               +----------------------+ < data
               |      SASL layer      |
               +----------------------+ > SASL-protected data
               +----------------------+ < data
               |       TLS layer      |
   Application +----------------------+ > TLS-protected data
   ------------+----------------------+ < data
     Transport | transport connection |
               +----------------------+

5.1.  Protocol Encoding

   The protocol elements of LDAP SHALL be encoded for exchange using the
   Basic Encoding Rules [BER] of [ASN.1] with the following
   restrictions:

   - Only the definite form of length encoding is used.

   - OCTET STRING values are encoded in the primitive form only.

   - If the value of a BOOLEAN type is true, the encoding of the value
     octet is set to hex "FF".




Sermersheim                 Standards Track                    [Page 42]

RFC 4511                         LDAPv3                        June 2006


   - If a value of a type is its default value, it is absent.  Only some
     BOOLEAN and INTEGER types have default values in this protocol
     definition.

   These restrictions are meant to ease the overhead of encoding and
   decoding certain elements in BER.

   These restrictions do not apply to ASN.1 types encapsulated inside of
   OCTET STRING values, such as attribute values, unless otherwise
   stated.

5.2.  Transmission Control Protocol (TCP)

   The encoded LDAPMessage PDUs are mapped directly onto the TCP
   [RFC793] bytestream using the BER-based encoding described in Section
   5.1.  It is recommended that server implementations running over the
   TCP provide a protocol listener on the Internet Assigned Numbers
   Authority (IANA)-assigned LDAP port, 389 [PortReg].  Servers may
   instead provide a listener on a different port number.  Clients MUST
   support contacting servers on any valid TCP port.

5.3.  Termination of the LDAP session

   Termination of the LDAP session is typically initiated by the client
   sending an UnbindRequest (Section 4.3), or by the server sending a
   Notice of Disconnection (Section 4.4.1).  In these cases, each
   protocol peer gracefully terminates the LDAP session by ceasing
   exchanges at the LDAP message layer, tearing down any SASL layer,
   tearing down any TLS layer, and closing the transport connection.

   A protocol peer may determine that the continuation of any
   communication would be pernicious, and in this case, it may abruptly
   terminate the session by ceasing communication and closing the
   transport connection.

   In either case, when the LDAP session is terminated, uncompleted
   operations are handled as specified in Section 3.1.

6.  Security Considerations

   This version of the protocol provides facilities for simple
   authentication using a cleartext password, as well as any SASL
   [RFC4422] mechanism.  Installing SASL and/or TLS layers can provide
   integrity and other data security services.

   It is also permitted that the server can return its credentials to
   the client, if it chooses to do so.




Sermersheim                 Standards Track                    [Page 43]

RFC 4511                         LDAPv3                        June 2006


   Use of cleartext password is strongly discouraged where the
   underlying transport service cannot guarantee confidentiality and may
   result in disclosure of the password to unauthorized parties.

   Servers are encouraged to prevent directory modifications by clients
   that have authenticated anonymously [RFC4513].

   Security considerations for authentication methods, SASL mechanisms,
   and TLS are described in [RFC4513].

   Note that SASL authentication exchanges do not provide data
   confidentiality or integrity protection for the version or name
   fields of the BindRequest or the resultCode, diagnosticMessage, or
   referral fields of the BindResponse, nor for any information
   contained in controls attached to Bind requests or responses.  Thus,
   information contained in these fields SHOULD NOT be relied on unless
   it is otherwise protected (such as by establishing protections at the
   transport layer).

   Implementors should note that various security factors (including
   authentication and authorization information and data security
   services) may change during the course of the LDAP session or even
   during the performance of a particular operation.  For instance,
   credentials could expire, authorization identities or access controls
   could change, or the underlying security layer(s) could be replaced
   or terminated.  Implementations should be robust in the handling of
   changing security factors.

   In some cases, it may be appropriate to continue the operation even
   in light of security factor changes.  For instance, it may be
   appropriate to continue an Abandon operation regardless of the
   change, or to continue an operation when the change upgraded (or
   maintained) the security factor.  In other cases, it may be
   appropriate to fail or alter the processing of the operation.  For
   instance, if confidential protections were removed, it would be
   appropriate either to fail a request to return sensitive data or,
   minimally, to exclude the return of sensitive data.

   Implementations that cache attributes and entries obtained via LDAP
   MUST ensure that access controls are maintained if that information
   is to be provided to multiple clients, since servers may have access
   control policies that prevent the return of entries or attributes in
   Search results except to particular authenticated clients.  For
   example, caches could serve result information only to the client
   whose request caused it to be in the cache.






Sermersheim                 Standards Track                    [Page 44]

RFC 4511                         LDAPv3                        June 2006


   Servers may return referrals or Search result references that
   redirect clients to peer servers.  It is possible for a rogue
   application to inject such referrals into the data stream in an
   attempt to redirect a client to a rogue server.  Clients are advised
   to be aware of this and possibly reject referrals when
   confidentiality measures are not in place.  Clients are advised to
   reject referrals from the StartTLS operation.

   The matchedDN and diagnosticMessage fields, as well as some
   resultCode values (e.g., attributeOrValueExists and
   entryAlreadyExists), could disclose the presence or absence of
   specific data in the directory that is subject to access and other
   administrative controls.  Server implementations should restrict
   access to protected information equally under both normal and error
   conditions.

   Protocol peers MUST be prepared to handle invalid and arbitrary-
   length protocol encodings.  Invalid protocol encodings include: BER
   encoding exceptions, format string and UTF-8 encoding exceptions,
   overflow exceptions, integer value exceptions, and binary mode on/off
   flag exceptions.  The LDAPv3 PROTOS [PROTOS-LDAP] test suite provides
   excellent examples of these exceptions and test cases used to
   discover flaws.

   In the event that a protocol peer senses an attack that in its nature
   could cause damage due to further communication at any layer in the
   LDAP session, the protocol peer should abruptly terminate the LDAP
   session as described in Section 5.3.

7.  Acknowledgements

   This document is based on RFC 2251 by Mark Wahl, Tim Howes, and Steve
   Kille.  RFC 2251 was a product of the IETF ASID Working Group.

   It is also based on RFC 2830 by Jeff Hodges, RL "Bob" Morgan, and
   Mark Wahl.  RFC 2830 was a product of the IETF LDAPEXT Working Group.

   It is also based on RFC 3771 by Roger Harrison and Kurt Zeilenga.
   RFC 3771 was an individual submission to the IETF.

   This document is a product of the IETF LDAPBIS Working Group.
   Significant contributors of technical review and content include Kurt
   Zeilenga, Steven Legg, and Hallvard Furuseth.








Sermersheim                 Standards Track                    [Page 45]

RFC 4511                         LDAPv3                        June 2006


8.  Normative References

   [ASN.1]       ITU-T Recommendation X.680 (07/2002) | ISO/IEC 8824-
                 1:2002 "Information Technology - Abstract Syntax
                 Notation One (ASN.1): Specification of basic notation".

   [BER]         ITU-T Rec. X.690 (07/2002) | ISO/IEC 8825-1:2002,
                 "Information technology - ASN.1 encoding rules:
                 Specification of Basic Encoding Rules (BER), Canonical
                 Encoding Rules (CER) and Distinguished Encoding Rules
                 (DER)", 2002.

   [ISO10646]    Universal Multiple-Octet Coded Character Set (UCS) -
                 Architecture and Basic Multilingual Plane, ISO/IEC
                 10646-1 : 1993.

   [RFC791]      Postel, J., "Internet Protocol", STD 5, RFC 791,
                 September 1981.

   [RFC793]      Postel, J., "Transmission Control Protocol", STD 7, RFC
                 793, September 1981.

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3454]     Hoffman P. and M. Blanchet, "Preparation of
                 Internationalized Strings ('stringprep')", RFC 3454,
                 December 2002.

   [RFC3629]     Yergeau, F., "UTF-8, a transformation format of ISO
                 10646", STD 63, RFC 3629, November 2003.

   [RFC3986]     Berners-Lee, T., Fielding, R., and L. Masinter,
                 "Uniform Resource Identifier (URI): Generic Syntax",
                 STD 66, RFC 3986, January 2005.

   [RFC4013]     Zeilenga, K., "SASLprep: Stringprep Profile for User
                 Names and Passwords", RFC 4013, February 2005.

   [RFC4234]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
                 Specifications: ABNF", RFC 4234, October 2005.

   [RFC4346]     Dierks, T. and E. Rescorla, "The TLS Protocol Version
                 1.1", RFC 4346, March 2006.

   [RFC4422]     Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
                 Authentication and Security Layer (SASL)", RFC 4422,
                 June 2006.



Sermersheim                 Standards Track                    [Page 46]

RFC 4511                         LDAPv3                        June 2006


   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4512]     Zeilenga, K., Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [RFC4513]     Harrison, R., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Authentication Methods and Security
                 Mechanisms", RFC 4513, June 2006.

   [RFC4514]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): String Representation of Distinguished
                 Names", RFC 4514, June 2006.

   [RFC4516]     Smith, M., Ed. and T. Howes, "Lightweight Directory
                 Access Protocol (LDAP): Uniform Resource Locator", RFC
                 4516, June 2006.

   [RFC4517]     Legg, S., Ed., "Lightweight Directory Access Protocol
                 (LDAP): Syntaxes and Matching Rules", RFC 4517, June
                 2006.

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
                 3.2.0" is defined by "The Unicode Standard, Version
                 3.0" (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-
                 61633-5), as amended by the "Unicode Standard Annex
                 #27: Unicode 3.1"
                 (http://www.unicode.org/reports/tr27/) and by the
                 "Unicode Standard Annex #28: Unicode 3.2"
                 (http://www.unicode.org/reports/tr28/).

   [X.500]       ITU-T Rec. X.500, "The Directory: Overview of Concepts,
                 Models and Service", 1993.

   [X.511]       ITU-T Rec. X.511, "The Directory: Abstract Service
                 Definition", 1993.









Sermersheim                 Standards Track                    [Page 47]

RFC 4511                         LDAPv3                        June 2006


9.  Informative References

   [CharModel]   Whistler, K. and M. Davis, "Unicode Technical Report
                 #17, Character Encoding Model", UTR17,
                 <http://www.unicode.org/unicode/reports/tr17/>, August
                 2000.

   [Glossary]    The Unicode Consortium, "Unicode Glossary",
                 <http://www.unicode.org/glossary/>.

   [PortReg]     IANA, "Port Numbers",
                 <http://www.iana.org/assignments/port-numbers>.

   [PROTOS-LDAP] University of Oulu, "PROTOS Test-Suite: c06-ldapv3"
                 <http://www.ee.oulu.fi/research/ouspg/protos/testing/
                 c06/ldapv3/>.

10.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has updated the LDAP
   result code registry to indicate that this document provides the
   definitive technical specification for result codes 0-36, 48-54, 64-
   70, 80-90.  It is also noted that one resultCode value
   (strongAuthRequired) has been renamed (to strongerAuthRequired).

   The IANA has also updated the LDAP Protocol Mechanism registry to
   indicate that this document and [RFC4513] provides the definitive
   technical specification for the StartTLS (1.3.6.1.4.1.1466.20037)
   Extended operation.

   IANA has assigned LDAP Object Identifier 18 [RFC4520] to identify the
   ASN.1 module defined in this document.

        Subject: Request for LDAP Object Identifier Registration
        Person & email address to contact for further information:
             Jim Sermersheim <jimse@novell.com>
        Specification: RFC 4511
        Author/Change Controller: IESG
        Comments:
             Identifies the LDAP ASN.1 module











Sermersheim                 Standards Track                    [Page 48]

RFC 4511                         LDAPv3                        June 2006


Appendix A.  LDAP Result Codes

   This normative appendix details additional considerations regarding
   LDAP result codes and provides a brief, general description of each
   LDAP result code enumerated in Section 4.1.9.

   Additional result codes MAY be defined for use with extensions
   [RFC4520].  Client implementations SHALL treat any result code that
   they do not recognize as an unknown error condition.

   The descriptions provided here do not fully account for result code
   substitutions used to prevent unauthorized disclosures (such as
   substitution of noSuchObject for insufficientAccessRights, or
   invalidCredentials for insufficientAccessRights).

A.1.  Non-Error Result Codes

   These result codes (called "non-error" result codes) do not indicate
   an error condition:

        success (0),
        compareFalse (5),
        compareTrue (6),
        referral (10), and
        saslBindInProgress (14).

   The success, compareTrue, and compareFalse result codes indicate
   successful completion (and, hence, are referred to as "successful"
   result codes).

   The referral and saslBindInProgress result codes indicate the client
   needs to take additional action to complete the operation.

A.2.  Result Codes

   Existing LDAP result codes are described as follows:

      success (0)
         Indicates the successful completion of an operation.  Note:
         this code is not used with the Compare operation.  See
         compareFalse (5) and compareTrue (6).










Sermersheim                 Standards Track                    [Page 49]

RFC 4511                         LDAPv3                        June 2006


      operationsError (1)
         Indicates that the operation is not properly sequenced with
         relation to other operations (of same or different type).

         For example, this code is returned if the client attempts to
         StartTLS [RFC4346] while there are other uncompleted operations
         or if a TLS layer was already installed.

      protocolError (2)
         Indicates the server received data that is not well-formed.

         For Bind operation only, this code is also used to indicate
         that the server does not support the requested protocol
         version.

         For Extended operations only, this code is also used to
         indicate that the server does not support (by design or
         configuration) the Extended operation associated with the
         requestName.

         For request operations specifying multiple controls, this may
         be used to indicate that the server cannot ignore the order
         of the controls as specified, or that the combination of the
         specified controls is invalid or unspecified.

      timeLimitExceeded (3)
         Indicates that the time limit specified by the client was
         exceeded before the operation could be completed.

      sizeLimitExceeded (4)
         Indicates that the size limit specified by the client was
         exceeded before the operation could be completed.

      compareFalse (5)
         Indicates that the Compare operation has successfully
         completed and the assertion has evaluated to FALSE or
         Undefined.

      compareTrue (6)
         Indicates that the Compare operation has successfully
         completed and the assertion has evaluated to TRUE.

      authMethodNotSupported (7)
         Indicates that the authentication method or mechanism is not
         supported.






Sermersheim                 Standards Track                    [Page 50]

RFC 4511                         LDAPv3                        June 2006


      strongerAuthRequired (8)
         Indicates the server requires strong(er) authentication in
         order to complete the operation.

         When used with the Notice of Disconnection operation, this
         code indicates that the server has detected that an
         established security association between the client and
         server has unexpectedly failed or been compromised.

      referral (10)
         Indicates that a referral needs to be chased to complete the
         operation (see Section 4.1.10).

      adminLimitExceeded (11)
         Indicates that an administrative limit has been exceeded.

      unavailableCriticalExtension (12)
         Indicates a critical control is unrecognized (see Section
         4.1.11).

      confidentialityRequired (13)
         Indicates that data confidentiality protections are required.

      saslBindInProgress (14)
         Indicates the server requires the client to send a new bind
         request, with the same SASL mechanism, to continue the
         authentication process (see Section 4.2).

      noSuchAttribute (16)
         Indicates that the named entry does not contain the specified
         attribute or attribute value.

      undefinedAttributeType (17)
         Indicates that a request field contains an unrecognized
         attribute description.

      inappropriateMatching (18)
         Indicates that an attempt was made (e.g., in an assertion) to
         use a matching rule not defined for the attribute type
         concerned.

      constraintViolation (19)
         Indicates that the client supplied an attribute value that
         does not conform to the constraints placed upon it by the
         data model.

         For example, this code is returned when multiple values are
         supplied to an attribute that has a SINGLE-VALUE constraint.



Sermersheim                 Standards Track                    [Page 51]

RFC 4511                         LDAPv3                        June 2006


      attributeOrValueExists (20)
         Indicates that the client supplied an attribute or value to
         be added to an entry, but the attribute or value already
         exists.

      invalidAttributeSyntax (21)
         Indicates that a purported attribute value does not conform
         to the syntax of the attribute.

      noSuchObject (32)
         Indicates that the object does not exist in the DIT.

      aliasProblem (33)
         Indicates that an alias problem has occurred.  For example,
         the code may used to indicate an alias has been dereferenced
         that names no object.

      invalidDNSyntax (34)
         Indicates that an LDAPDN or RelativeLDAPDN field (e.g., search
         base, target entry, ModifyDN newrdn, etc.) of a request does
         not conform to the required syntax or contains attribute
         values that do not conform to the syntax of the attribute's
         type.

      aliasDereferencingProblem (36)
         Indicates that a problem occurred while dereferencing an
         alias.  Typically, an alias was encountered in a situation
         where it was not allowed or where access was denied.

      inappropriateAuthentication (48)
         Indicates the server requires the client that had attempted
         to bind anonymously or without supplying credentials to
         provide some form of credentials.

      invalidCredentials (49)
         Indicates that the provided credentials (e.g., the user's name
         and password) are invalid.

      insufficientAccessRights (50)
         Indicates that the client does not have sufficient access
         rights to perform the operation.

      busy (51)
         Indicates that the server is too busy to service the
         operation.






Sermersheim                 Standards Track                    [Page 52]

RFC 4511                         LDAPv3                        June 2006


      unavailable (52)
         Indicates that the server is shutting down or a subsystem
         necessary to complete the operation is offline.

      unwillingToPerform (53)
         Indicates that the server is unwilling to perform the
         operation.

      loopDetect (54)
         Indicates that the server has detected an internal loop (e.g.,
         while dereferencing aliases or chaining an operation).

      namingViolation (64)
         Indicates that the entry's name violates naming restrictions.

      objectClassViolation (65)
         Indicates that the entry violates object class restrictions.

      notAllowedOnNonLeaf (66)
         Indicates that the operation is inappropriately acting upon a
         non-leaf entry.

      notAllowedOnRDN (67)
         Indicates that the operation is inappropriately attempting to
         remove a value that forms the entry's relative distinguished
         name.

      entryAlreadyExists (68)
         Indicates that the request cannot be fulfilled (added, moved,
         or renamed) as the target entry already exists.

      objectClassModsProhibited (69)
         Indicates that an attempt to modify the object class(es) of
         an entry's 'objectClass' attribute is prohibited.

         For example, this code is returned when a client attempts to
         modify the structural object class of an entry.

      affectsMultipleDSAs (71)
         Indicates that the operation cannot be performed as it would
         affect multiple servers (DSAs).

      other (80)
         Indicates the server has encountered an internal error.







Sermersheim                 Standards Track                    [Page 53]

RFC 4511                         LDAPv3                        June 2006


Appendix B.  Complete ASN.1 Definition

   This appendix is normative.

        Lightweight-Directory-Access-Protocol-V3 {1 3 6 1 1 18}
        -- Copyright (C) The Internet Society (2006).  This version of
        -- this ASN.1 module is part of RFC 4511; see the RFC itself
        -- for full legal notices.
        DEFINITIONS
        IMPLICIT TAGS
        EXTENSIBILITY IMPLIED ::=

        BEGIN

        LDAPMessage ::= SEQUENCE {
             messageID       MessageID,
             protocolOp      CHOICE {
                  bindRequest           BindRequest,
                  bindResponse          BindResponse,
                  unbindRequest         UnbindRequest,
                  searchRequest         SearchRequest,
                  searchResEntry        SearchResultEntry,
                  searchResDone         SearchResultDone,
                  searchResRef          SearchResultReference,
                  modifyRequest         ModifyRequest,
                  modifyResponse        ModifyResponse,
                  addRequest            AddRequest,
                  addResponse           AddResponse,
                  delRequest            DelRequest,
                  delResponse           DelResponse,
                  modDNRequest          ModifyDNRequest,
                  modDNResponse         ModifyDNResponse,
                  compareRequest        CompareRequest,
                  compareResponse       CompareResponse,
                  abandonRequest        AbandonRequest,
                  extendedReq           ExtendedRequest,
                  extendedResp          ExtendedResponse,
                  ...,
                  intermediateResponse  IntermediateResponse },
             controls       [0] Controls OPTIONAL }

        MessageID ::= INTEGER (0 ..  maxInt)

        maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --

        LDAPString ::= OCTET STRING -- UTF-8 encoded,
                                    -- [ISO10646] characters




Sermersheim                 Standards Track                    [Page 54]

RFC 4511                         LDAPv3                        June 2006


        LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
                                 -- [RFC4512]

        LDAPDN ::= LDAPString -- Constrained to <distinguishedName>
                              -- [RFC4514]

        RelativeLDAPDN ::= LDAPString -- Constrained to <name-component>
                                      -- [RFC4514]

        AttributeDescription ::= LDAPString
                                -- Constrained to <attributedescription>
                                -- [RFC4512]

        AttributeValue ::= OCTET STRING

        AttributeValueAssertion ::= SEQUENCE {
             attributeDesc   AttributeDescription,
             assertionValue  AssertionValue }

        AssertionValue ::= OCTET STRING

        PartialAttribute ::= SEQUENCE {
             type       AttributeDescription,
             vals       SET OF value AttributeValue }

        Attribute ::= PartialAttribute(WITH COMPONENTS {
             ...,
             vals (SIZE(1..MAX))})

        MatchingRuleId ::= LDAPString

        LDAPResult ::= SEQUENCE {
             resultCode         ENUMERATED {
                  success                      (0),
                  operationsError              (1),
                  protocolError                (2),
                  timeLimitExceeded            (3),
                  sizeLimitExceeded            (4),
                  compareFalse                 (5),
                  compareTrue                  (6),
                  authMethodNotSupported       (7),
                  strongerAuthRequired         (8),
                       -- 9 reserved --
                  referral                     (10),
                  adminLimitExceeded           (11),
                  unavailableCriticalExtension (12),
                  confidentialityRequired      (13),
                  saslBindInProgress           (14),



Sermersheim                 Standards Track                    [Page 55]

RFC 4511                         LDAPv3                        June 2006


                  noSuchAttribute              (16),
                  undefinedAttributeType       (17),
                  inappropriateMatching        (18),
                  constraintViolation          (19),
                  attributeOrValueExists       (20),
                  invalidAttributeSyntax       (21),
                       -- 22-31 unused --
                  noSuchObject                 (32),
                  aliasProblem                 (33),
                  invalidDNSyntax              (34),
                       -- 35 reserved for undefined isLeaf --
                  aliasDereferencingProblem    (36),
                       -- 37-47 unused --
                  inappropriateAuthentication  (48),
                  invalidCredentials           (49),
                  insufficientAccessRights     (50),
                  busy                         (51),
                  unavailable                  (52),
                  unwillingToPerform           (53),
                  loopDetect                   (54),
                       -- 55-63 unused --
                  namingViolation              (64),
                  objectClassViolation         (65),
                  notAllowedOnNonLeaf          (66),
                  notAllowedOnRDN              (67),
                  entryAlreadyExists           (68),
                  objectClassModsProhibited    (69),
                       -- 70 reserved for CLDAP --
                  affectsMultipleDSAs          (71),
                       -- 72-79 unused --
                  other                        (80),
                  ...  },
             matchedDN          LDAPDN,
             diagnosticMessage  LDAPString,
             referral           [3] Referral OPTIONAL }

        Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI

        URI ::= LDAPString     -- limited to characters permitted in
                               -- URIs

        Controls ::= SEQUENCE OF control Control

        Control ::= SEQUENCE {
             controlType             LDAPOID,
             criticality             BOOLEAN DEFAULT FALSE,
             controlValue            OCTET STRING OPTIONAL }




Sermersheim                 Standards Track                    [Page 56]

RFC 4511                         LDAPv3                        June 2006


        BindRequest ::= [APPLICATION 0] SEQUENCE {
             version                 INTEGER (1 ..  127),
             name                    LDAPDN,
             authentication          AuthenticationChoice }

        AuthenticationChoice ::= CHOICE {
             simple                  [0] OCTET STRING,
                                     -- 1 and 2 reserved
             sasl                    [3] SaslCredentials,
             ...  }

        SaslCredentials ::= SEQUENCE {
             mechanism               LDAPString,
             credentials             OCTET STRING OPTIONAL }

        BindResponse ::= [APPLICATION 1] SEQUENCE {
             COMPONENTS OF LDAPResult,
             serverSaslCreds    [7] OCTET STRING OPTIONAL }

        UnbindRequest ::= [APPLICATION 2] NULL

        SearchRequest ::= [APPLICATION 3] SEQUENCE {
             baseObject      LDAPDN,
             scope           ENUMERATED {
                  baseObject              (0),
                  singleLevel             (1),
                  wholeSubtree            (2),
                  ...  },
             derefAliases    ENUMERATED {
                  neverDerefAliases       (0),
                  derefInSearching        (1),
                  derefFindingBaseObj     (2),
                  derefAlways             (3) },
             sizeLimit       INTEGER (0 ..  maxInt),
             timeLimit       INTEGER (0 ..  maxInt),
             typesOnly       BOOLEAN,
             filter          Filter,
             attributes      AttributeSelection }

        AttributeSelection ::= SEQUENCE OF selector LDAPString
                       -- The LDAPString is constrained to
                       -- <attributeSelector> in Section 4.5.1.8

        Filter ::= CHOICE {
             and             [0] SET SIZE (1..MAX) OF filter Filter,
             or              [1] SET SIZE (1..MAX) OF filter Filter,
             not             [2] Filter,
             equalityMatch   [3] AttributeValueAssertion,



Sermersheim                 Standards Track                    [Page 57]

RFC 4511                         LDAPv3                        June 2006


             substrings      [4] SubstringFilter,
             greaterOrEqual  [5] AttributeValueAssertion,
             lessOrEqual     [6] AttributeValueAssertion,
             present         [7] AttributeDescription,
             approxMatch     [8] AttributeValueAssertion,
             extensibleMatch [9] MatchingRuleAssertion,
             ...  }

        SubstringFilter ::= SEQUENCE {
             type           AttributeDescription,
             substrings     SEQUENCE SIZE (1..MAX) OF substring CHOICE {
                  initial [0] AssertionValue,  -- can occur at most once
                  any     [1] AssertionValue,
                  final   [2] AssertionValue } -- can occur at most once
             }

        MatchingRuleAssertion ::= SEQUENCE {
             matchingRule    [1] MatchingRuleId OPTIONAL,
             type            [2] AttributeDescription OPTIONAL,
             matchValue      [3] AssertionValue,
             dnAttributes    [4] BOOLEAN DEFAULT FALSE }

        SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
             objectName      LDAPDN,
             attributes      PartialAttributeList }

        PartialAttributeList ::= SEQUENCE OF
                             partialAttribute PartialAttribute

        SearchResultReference ::= [APPLICATION 19] SEQUENCE
                                  SIZE (1..MAX) OF uri URI

        SearchResultDone ::= [APPLICATION 5] LDAPResult

        ModifyRequest ::= [APPLICATION 6] SEQUENCE {
             object          LDAPDN,
             changes         SEQUENCE OF change SEQUENCE {
                  operation       ENUMERATED {
                       add     (0),
                       delete  (1),
                       replace (2),
                       ...  },
                  modification    PartialAttribute } }

        ModifyResponse ::= [APPLICATION 7] LDAPResult






Sermersheim                 Standards Track                    [Page 58]

RFC 4511                         LDAPv3                        June 2006


        AddRequest ::= [APPLICATION 8] SEQUENCE {
             entry           LDAPDN,
             attributes      AttributeList }

        AttributeList ::= SEQUENCE OF attribute Attribute

        AddResponse ::= [APPLICATION 9] LDAPResult

        DelRequest ::= [APPLICATION 10] LDAPDN

        DelResponse ::= [APPLICATION 11] LDAPResult

        ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
             entry           LDAPDN,
             newrdn          RelativeLDAPDN,
             deleteoldrdn    BOOLEAN,
             newSuperior     [0] LDAPDN OPTIONAL }

        ModifyDNResponse ::= [APPLICATION 13] LDAPResult

        CompareRequest ::= [APPLICATION 14] SEQUENCE {
             entry           LDAPDN,
             ava             AttributeValueAssertion }

        CompareResponse ::= [APPLICATION 15] LDAPResult

        AbandonRequest ::= [APPLICATION 16] MessageID

        ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
             requestName      [0] LDAPOID,
             requestValue     [1] OCTET STRING OPTIONAL }

        ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
             COMPONENTS OF LDAPResult,
             responseName     [10] LDAPOID OPTIONAL,
             responseValue    [11] OCTET STRING OPTIONAL }

        IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
             responseName     [0] LDAPOID OPTIONAL,
             responseValue    [1] OCTET STRING OPTIONAL }

        END









Sermersheim                 Standards Track                    [Page 59]

RFC 4511                         LDAPv3                        June 2006


Appendix C.  Changes

   This appendix is non-normative.

   This appendix summarizes substantive changes made to RFC 2251, RFC
   2830, and RFC 3771.

C.1.  Changes Made to RFC 2251

   This section summarizes the substantive changes made to Sections 1,
   2, 3.1, and 4, and the remainder of RFC 2251.  Readers should
   consult [RFC4512] and [RFC4513] for summaries of changes to other
   sections.

C.1.1.  Section 1 (Status of this Memo)

   - Removed IESG note.  Post publication of RFC 2251, mandatory LDAP
     authentication mechanisms have been standardized which are
     sufficient to remove this note.  See [RFC4513] for authentication
     mechanisms.

C.1.2.  Section 3.1 (Protocol Model) and others

   - Removed notes giving history between LDAP v1, v2, and v3.  Instead,
     added sufficient language so that this document can stand on its
     own.

C.1.3.  Section 4 (Elements of Protocol)

   - Clarified where the extensibility features of ASN.1 apply to the
     protocol.  This change affected various ASN.1 types by the
     inclusion of ellipses (...) to certain elements.
   - Removed the requirement that servers that implement version 3 or
     later MUST provide the 'supportedLDAPVersion' attribute.  This
     statement provided no interoperability advantages.

C.1.4.  Section 4.1.1 (Message Envelope)

   - There was a mandatory requirement for the server to return a
     Notice of Disconnection and drop the transport connection when a
     PDU is malformed in a certain way.  This has been updated such that
     the server SHOULD return the Notice of Disconnection, and it MUST
     terminate the LDAP Session.

C.1.5.  Section 4.1.1.1 (Message ID)

   - Required that the messageID of requests MUST be non-zero as the
     zero is reserved for Notice of Disconnection.



Sermersheim                 Standards Track                    [Page 60]

RFC 4511                         LDAPv3                        June 2006


   - Specified when it is and isn't appropriate to return an already
     used messageID.  RFC 2251 accidentally imposed synchronous server
     behavior in its wording of this.

C.1.6.  Section 4.1.2 (String Types)

   - Stated that LDAPOID is constrained to <numericoid> from [RFC4512].

C.1.7.  Section 4.1.5.1 (Binary Option) and others

   - Removed the Binary Option from the specification.  There are
     numerous interoperability problems associated with this method of
     alternate attribute type encoding.  Work to specify a suitable
     replacement is ongoing.

C.1.8.  Section 4.1.8 (Attribute)

   - Combined the definitions of PartialAttribute and Attribute here,
     and defined Attribute in terms of PartialAttribute.

C.1.9.  Section 4.1.10 (Result Message)

   - Renamed "errorMessage" to "diagnosticMessage" as it is allowed to
     be sent for non-error results.
   - Moved some language into Appendix A, and referred the reader there.
   - Allowed matchedDN to be present for other result codes than those
     listed in RFC 2251.
   - Renamed the code "strongAuthRequired" to "strongerAuthRequired" to
     clarify that this code may often be returned to indicate that a
     stronger authentication is needed to perform a given operation.

C.1.10.  Section 4.1.11 (Referral)

   - Defined referrals in terms of URIs rather than URLs.
   - Removed the requirement that all referral URIs MUST be equally
     capable of progressing the operation.  The statement was ambiguous
     and provided no instructions on how to carry it out.
   - Added the requirement that clients MUST NOT loop between servers.
   - Clarified the instructions for using LDAPURLs in referrals, and in
     doing so added a recommendation that the scope part be present.
   - Removed imperatives which required clients to use URLs in specific
     ways to progress an operation.  These did nothing for
     interoperability.








Sermersheim                 Standards Track                    [Page 61]

RFC 4511                         LDAPv3                        June 2006


C.1.11.  Section 4.1.12 (Controls)

   - Specified how control values defined in terms of ASN.1 are to be
     encoded.
   - Noted that the criticality field is only applied to request
     messages (except UnbindRequest), and must be ignored when present
     on response messages and UnbindRequest.
   - Specified that non-critical controls may be ignored at the
     server's discretion.  There was confusion in the original wording
     which led some to believe that recognized controls may not be
     ignored as long as they were associated with a proper request.
   - Added language regarding combinations of controls and the ordering
     of controls on a message.
   - Specified that when the semantics of the combination of controls
     is undefined or unknown, it results in a protocolError.
   - Changed "The server MUST be prepared" to "Implementations MUST be
     prepared" in paragraph 8 to reflect that both client and server
     implementations must be able to handle this (as both parse
     controls).

C.1.12.  Section 4.2 (Bind Operation)

   - Mandated that servers return protocolError when the version is not
     supported.
   - Disambiguated behavior when the simple authentication is used, the
     name is empty, and the password is non-empty.
   - Required servers to not dereference aliases for Bind.  This was
     added for consistency with other operations and to help ensure
     data consistency.
   - Required that textual passwords be transferred as UTF-8 encoded
     Unicode, and added recommendations on string preparation.  This was
     to help ensure interoperability of passwords being sent from
     different clients.

C.1.13.  Section 4.2.1 (Sequencing of the Bind Request)

   - This section was largely reorganized for readability, and language
     was added to clarify the authentication state of failed and
     abandoned Bind operations.
   - Removed: "If a SASL transfer encryption or integrity mechanism has
     been negotiated, that mechanism does not support the changing of
     credentials from one identity to another, then the client MUST
     instead establish a new connection."
     If there are dependencies between multiple negotiations of a
     particular SASL mechanism, the technical specification for that
     SASL mechanism details how applications are to deal with them.
     LDAP should not require any special handling.
   - Dropped MUST imperative in paragraph 3 to align with [RFC2119].



Sermersheim                 Standards Track                    [Page 62]

RFC 4511                         LDAPv3                        June 2006


   - Mandated that clients not send non-Bind operations while a Bind is
     in progress, and suggested that servers not process them if they
     are received.  This is needed to ensure proper sequencing of the
     Bind in relationship to other operations.

C.1.14.  Section 4.2.3 (Bind Response)

   - Moved most error-related text to Appendix A, and added text
     regarding certain errors used in conjunction with the Bind
     operation.
   - Prohibited the server from specifying serverSaslCreds when not
     appropriate.

C.1.15.  Section 4.3 (Unbind Operation)

   - Specified that both peers are to cease transmission and terminate
     the LDAP session for the Unbind operation.

C.1.16.  Section 4.4 (Unsolicited Notification)

   - Added instructions for future specifications of Unsolicited
     Notifications.

C.1.17.  Section 4.5.1 (Search Request)

   - SearchRequest attributes is now defined as an AttributeSelection
     type rather than AttributeDescriptionList, and an ABNF is
     provided.
   - SearchRequest attributes may contain duplicate attribute
     descriptions.  This was previously prohibited.  Now servers are
     instructed to ignore subsequent names when they are duplicated.
     This was relaxed in order to allow different short names and also
     OIDs to be requested for an attribute.
   - The present search filter now evaluates to Undefined when the
     specified attribute is not known to the server.  It used to
     evaluate to FALSE, which caused behavior inconsistent with what
     most would expect, especially when the 'not' operator was used.
   - The Filter choice SubstringFilter substrings type is now defined
     with a lower bound of 1.
   - The SubstringFilter substrings 'initial, 'any', and 'final' types
     are now AssertionValue rather than LDAPString.  Also, added
     imperatives stating that 'initial' (if present) must be listed
     first, and 'final' (if present) must be listed last.
   - Disambiguated the semantics of the derefAliases choices.  There was
     question as to whether derefInSearching applied to the base object
     in a wholeSubtree Search.
   - Added instructions for equalityMatch, substrings, greaterOrEqual,
     lessOrEqual, and approxMatch.



Sermersheim                 Standards Track                    [Page 63]

RFC 4511                         LDAPv3                        June 2006



C.1.18.  Section 4.5.2 (Search Result)

   - Recommended that servers not use attribute short names when it
     knows they are ambiguous or may cause interoperability problems.
   - Removed all mention of ExtendedResponse due to lack of
     implementation.

C.1.19.  Section 4.5.3 (Continuation References in the Search Result)

   - Made changes similar to those made to Section 4.1.11.

C.1.20.  Section 4.5.3.1 (Example)

   - Fixed examples to adhere to changes made to Section 4.5.3.

C.1.21.  Section 4.6 (Modify Operation)

   - Replaced AttributeTypeAndValues with Attribute as they are
     equivalent.
   - Specified the types of modification changes that might
     temporarily violate schema.  Some readers were under the impression
     that any temporary schema violation was allowed.

C.1.22.  Section 4.7 (Add Operation)

   - Aligned Add operation with X.511 in that the attributes of the RDN
     are used in conjunction with the listed attributes to create the
     entry.  Previously, Add required that the distinguished values be
     present in the listed attributes.
   - Removed requirement that the objectClass attribute MUST be
     specified as some DSE types do not require this attribute.
     Instead, generic wording was added, requiring the added entry to
     adhere to the data model.
   - Removed recommendation regarding placement of objects.  This is
     covered in the data model document.

C.1.23.  Section 4.9 (Modify DN Operation)

   - Required servers to not dereference aliases for Modify DN.  This
     was added for consistency with other operations and to help ensure
     data consistency.
   - Allow Modify DN to fail when moving between naming contexts.
   - Specified what happens when the attributes of the newrdn are not
     present on the entry.






Sermersheim                 Standards Track                    [Page 64]

RFC 4511                         LDAPv3                        June 2006


C.1.24.  Section 4.10 (Compare Operation)

   - Specified that compareFalse means that the Compare took place and
     the result is false.  There was confusion that led people to
     believe that an Undefined match resulted in compareFalse.
   - Required servers to not dereference aliases for Compare.  This was
     added for consistency with other operations and to help ensure
     data consistency.

C.1.25.  Section 4.11 (Abandon Operation)

   - Explained that since Abandon returns no response, clients should
     not use it if they need to know the outcome.
   - Specified that Abandon and Unbind cannot be abandoned.

C.1.26.  Section 4.12 (Extended Operation)

   - Specified how values of Extended operations defined in terms of
     ASN.1 are to be encoded.
   - Added instructions on what Extended operation specifications
     consist of.
   - Added a recommendation that servers advertise supported Extended
     operations.

C.1.27.  Section 5.2 (Transfer Protocols)

   - Moved referral-specific instructions into referral-related
     sections.

C.1.28.  Section 7 (Security Considerations)

   - Reworded notes regarding SASL not protecting certain aspects of
     the LDAP Bind messages.
   - Noted that Servers are encouraged to prevent directory
     modifications by clients that have authenticated anonymously
     [RFC4513].
   - Added a note regarding the possibility of changes to security
     factors (authentication, authorization, and data confidentiality).
   - Warned against following referrals that may have been injected in
     the data stream.
   - Noted that servers should protect information equally, whether in
     an error condition or not, and mentioned matchedDN,
     diagnosticMessage, and resultCodes specifically.
   - Added a note regarding malformed and long encodings.







Sermersheim                 Standards Track                    [Page 65]

RFC 4511                         LDAPv3                        June 2006


C.1.29.  Appendix A (Complete ASN.1 Definition)

   - Added "EXTENSIBILITY IMPLIED" to ASN.1 definition.
   - Removed AttributeType.  It is not used.

C.2.  Changes Made to RFC 2830

   This section summarizes the substantive changes made to Sections of
   RFC 2830.  Readers should consult [RFC4513] for summaries of changes
   to other sections.

C.2.1.  Section 2.3 (Response other than "success")

   - Removed wording indicating that referrals can be returned from
     StartTLS.
   - Removed requirement that only a narrow set of result codes can be
     returned.  Some result codes are required in certain scenarios, but
     any other may be returned if appropriate.
   - Removed requirement that the ExtendedResponse.responseName MUST be
     present.  There are circumstances where this is impossible, and
     requiring this is at odds with language in Section 4.12.

C.2.1.  Section 4 (Closing a TLS Connection)

   - Reworded most of this section to align with definitions of the
     LDAP protocol layers.
   - Removed instructions on abrupt closure as this is covered in other
     areas of the document (specifically, Section 5.3)

C.3.  Changes Made to RFC 3771

   - Rewrote to fit into this document.  In general, semantics were
     preserved.  Supporting and background language seen as redundant
     due to its presence in this document was omitted.

   - Specified that Intermediate responses to a request may be of
     different types, and one of the response types may be specified to
     have no response value.













Sermersheim                 Standards Track                    [Page 66]

RFC 4511                         LDAPv3                        June 2006


Editor's Address

   Jim Sermersheim
   Novell, Inc.
   1800 South Novell Place
   Provo, Utah 84606, USA

   Phone: +1 801 861-3088
   EMail: jimse@novell.com










































Sermersheim                 Standards Track                    [Page 67]

RFC 4511                         LDAPv3                        June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Sermersheim                 Standards Track                    [Page 68]

alt-openldap11-devel/rfc/rfc3829.txt000064400000027322150410163200012774 0ustar00





Network Working Group                                         R. Weltman
Request for Comments: 3829                                America Online
Category: Informational                                         M. Smith
                                                     Pearl Crescent, LLC
                                                                 M. Wahl
                                                               July 2004

             Lightweight Directory Access Protocol (LDAP)
         Authorization Identity Request and Response Controls

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).

Abstract

   This document extends the Lightweight Directory Access Protocol
   (LDAP) bind operation with a mechanism for requesting and returning
   the authorization identity it establishes.  Specifically, this
   document defines the Authorization Identity Request and Response
   controls for use with the Bind operation.

1.  Introduction

   This document defines support for the Authorization Identity Request
   Control and the Authorization Identity Response Control for
   requesting and returning the authorization established in a bind
   operation.  The Authorization Identity Request Control may be
   submitted by a client in a bind request if authenticating with
   version 3 of the Lightweight Directory Access Protocol (LDAP)
   protocol [LDAPv3].  In the LDAP server's bind response, it may then
   include an Authorization Identity Response Control.  The response
   control contains the identity assumed by the client.  This is useful
   when there is a mapping step or other indirection during the bind, so
   that the client can be told what LDAP identity was granted.  Client
   authentication with certificates is the primary situation where this
   applies.  Also, some Simple Authentication and Security Layer [SASL]
   authentication mechanisms may not involve the client explicitly
   providing a DN, or may result in an authorization identity which is
   different from the authentication identity provided by the client
   [AUTH].




Weltman, et al.              Informational                      [Page 1]

RFC 3829          Authorization Identity Bind Control          July 2004


   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
   used in this document are to be interpreted as described in
   [RFCKeyWords].

2.  Publishing support for the Authorization Identity Request Control
    and the Authorization Identity Response Control

   Support for the Authorization Identity Request Control and the
   Authorization Identity Response Control is indicated by the presence
   of the Object Identifiers (OIDs) 2.16.840.1.113730.3.4.16 and
   2.16.840.1.113730.3.4.15, respectively, in the supportedControl
   attribute [LDAPATTRS] of a server's root DSA-specific Entry (DSE).

3.  Authorization Identity Request Control

   This control MAY be included in any bind request which specifies
   protocol version 3, as part of the controls field of the LDAPMessage
   as defined in [LDAPPROT].  In a multi-step bind operation, the client
   MUST provide the control with each bind request.

   The controlType is "2.16.840.1.113730.3.4.16" and the controlValue is
   absent.

4.  Authorization Identity Response Control

   This control MAY be included in any final bind response where the
   first bind request of the bind operation included an Authorization
   Identity Request Control as part of the controls field of the
   LDAPMessage as defined in [LDAPPROT].

   The controlType is "2.16.840.1.113730.3.4.15".  If the bind request
   succeeded and resulted in an identity (not anonymous), the
   controlValue contains the authorization identity (authzId), as
   defined in [AUTH] section 9, granted to the requestor.  If the bind
   request resulted in an anonymous association, the controlValue field
   is a string of zero length.  If the bind request resulted in more
   than one authzId, the primary authzId is returned in the controlValue
   field.

   The control is only included in a bind response if the resultCode for
   the bind operation is success.

   If the server requires confidentiality protections to be in place
   prior to use of this control (see Security Considerations), the
   server reports failure to have adequate confidentiality protections
   in place by returning the confidentialityRequired result code.





Weltman, et al.              Informational                      [Page 2]

RFC 3829          Authorization Identity Bind Control          July 2004


   If the client has insufficient access rights to the requested
   authorization information, the server reports this by returning the
   insufficientAccessRights result code.

   Identities presented by a client as part of the authentication
   process may be mapped by the server to one or more authorization
   identities.  The bind response control can be used to retrieve the
   primary authzId.

   For example, during client authentication with certificates [AUTH], a
   client may possess more than one certificate and may not be able to
   determine which one was ultimately selected for authentication to the
   server.  The subject DN field in the selected certificate may not
   correspond exactly to a DN in the directory, but rather have gone
   through a mapping process controlled by the server.  Upon completing
   the certificate-based authentication, the client may issue a SASL
   [SASL] bind request, specifying the EXTERNAL mechanism and including
   an Authorization Identity Request Control.  The bind response MAY
   include an Authorization Identity Response Control indicating the DN
   in the server's Directory Information Tree (DIT) which the
   certificate was mapped to.

5.  Alternative Approach with Extended Operation

   The LDAP "Who am I?" [AUTHZID] extended operation provides a
   mechanism to query the authorization identity associated with a bound
   connection.  Using an extended operation, as opposed to a bind
   response control, allows a client to learn the authorization identity
   after the bind has established integrity and data confidentiality
   protections.  The disadvantages of the extended operation approach
   are coordination issues between "Who am I?" requests, bind requests,
   and other requests, and that an extra operation is required to learn
   the authorization identity.  For multithreaded or high bandwidth
   server application environments, the bind response approach may be
   preferable.

6.  Security Considerations

   The Authorization Identity Request and Response Controls are subject
   to standard LDAP security considerations.  The controls may be passed
   over a secure as well as over an insecure channel.  They are not
   protected by security layers negotiated by the bind operation.

   The response control allows for an additional authorization identity
   to be passed.  In some deployments, these identities may contain
   confidential information which require privacy protection.  In such
   deployments, a security layer should be established prior to issuing
   a bind request with an Authorization Identity Request Control.



Weltman, et al.              Informational                      [Page 3]

RFC 3829          Authorization Identity Bind Control          July 2004


7.  IANA Considerations

   The OIDs 2.16.840.1.113730.3.4.16 and 2.16.840.1.113730.3.4.15 are
   reserved for the Authorization Identity Request and Response
   Controls, respectively.  The Authorization Identity Request Control
   has been registered as an LDAP Protocol Mechanism [IANALDAP].

8.  References

8.1.  Normative References

   [LDAPv3]      Hodges, J. and R. Morgan, "Lightweight Directory Access
                 Protocol (v3): Technical Specification", RFC 3377,
                 September 2002.

   [LDAPPROT]    Wahl, M., Howes, T. and S. Kille, "Lightweight
                 Directory Access Protocol (v3)", RFC 2251, December
                 1997.

   [RFCKeyWords] Bradner, S., "Key Words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [AUTH]        Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
                 "Authentication Methods for LDAP", RFC 2829, May 2000.

   [SASL]        Myers, J., "Simple Authentication and Security Layer
                 (SASL)", RFC 2222, October 1997.

   [LDAPATTRS]   Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
                 "Lightweight Directory Access Protocol (v3): Attribute
                 Syntax Definitions", RFC 2252, December 1997.

   [IANALDAP]    Hodges, J. and R. Morgan, "Lightweight Directory Access
                 Protocol (v3): Technical Specification", RFC 3377,
                 September 2002.

8.2.  Informative References

   [AUTHZID]     Zeilenga, K., "LDAP 'Who am I?' Operation", Work in
                 Progress, April 2002.











Weltman, et al.              Informational                      [Page 4]

RFC 3829          Authorization Identity Bind Control          July 2004


9.  Author's Addresses

   Rob Weltman
   America Online
   360 W. Caribbean Drive
   Sunnyvale, CA 94089
   USA

   Phone: +1 650 937-3194
   EMail: robw@worldspot.com


   Mark Smith
   Pearl Crescent, LLC
   447 Marlpool Drive
   Saline, MI 48176
   USA

   Phone: +1 734 944-2856
   EMail: mcs@pearlcrescent.com


   Mark Wahl
   PO Box 90626
   Austin, TX 78709-0626
   USA

























Weltman, et al.              Informational                      [Page 5]

RFC 3829          Authorization Identity Bind Control          July 2004


10.  Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at ietf-
   ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.









Weltman, et al.              Informational                      [Page 6]

alt-openldap11-devel/rfc/rfc4530.txt000064400000035527150410163200012770 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4530                           OpenLDAP Foundation
Category: Standards Track                                      June 2006


              Lightweight Directory Access Protocol (LDAP)
                    entryUUID Operational Attribute


Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document describes the LDAP/X.500 'entryUUID' operational
   attribute and associated matching rules and syntax.  The attribute
   holds a server-assigned Universally Unique Identifier (UUID) for the
   object.  Directory clients may use this attribute to distinguish
   objects identified by a distinguished name or to locate an object
   after renaming.






















Zeilenga                    Standards Track                     [Page 1]

RFC 4530                     LDAP entryUUID                    June 2006


Table of Contents

   1. Background and Intended Use .....................................2
   2. UUID Schema Elements ............................................3
      2.1. UUID Syntax ................................................3
      2.2. 'uuidMatch' Matching Rule ..................................3
      2.3. 'uuidOrderingMatch' Matching Rule ..........................3
      2.4. 'entryUUID' Attribute ......................................4
   3. Security Considerations .........................................4
   4. IANA Considerations .............................................5
      4.1. Object Identifier Registration .............................5
      4.2. UUID Syntax Registration ...................................5
      4.3. 'uuidMatch' Descriptor Registration ........................5
      4.4. 'uuidOrderingMatch' Descriptor Registration ................5
      4.5. 'entryUUID' Descriptor Registration ........................6
   5. Acknowledgements ................................................6
   6. References ......................................................6
      6.1. Normative References .......................................6
      6.2. Informative References .....................................7

1.  Background and Intended Use

   In X.500 Directory Services [X.501], such as those accessible using
   the Lightweight Directory Access Protocol (LDAP) [RFC4510], an object
   is identified by its distinguished name (DN).  However, DNs are not
   stable identifiers.  That is, a new object may be identified by a DN
   that previously identified another (now renamed or deleted) object.

   A Universally Unique Identifier (UUID) is "an identifier unique
   across both space and time, with respect to the space of all UUIDs"
   [RFC4122].  UUIDs are used in a wide range of systems.

   This document describes the 'entryUUID' operational attribute, which
   holds the UUID assigned to the object by the server.  Clients may use
   this attribute to distinguish objects identified by a particular
   distinguished name or to locate a particular object after renaming.

   This document defines the UUID syntax, the 'uuidMatch' and
   'uuidOrderingMatch' matching rules, and the 'entryUUID' attribute
   type.

   Schema definitions are provided using LDAP description formats
   [RFC4512].  Definitions provided here are formatted (line wrapped)
   for readability.







Zeilenga                    Standards Track                     [Page 2]

RFC 4530                     LDAP entryUUID                    June 2006


   In this document, the key words "MUST", "MUST NOT", "REQUIRED",
   "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
   and "OPTIONAL" are to be interpreted as described in BCP 14
   [RFC2119].

2.  UUID Schema Elements

2.1.  UUID Syntax

   A Universally Unique Identifier (UUID) [RFC4122] is a 16-octet (128-
   bit) value that identifies an object.  The ASN.1 [X.680] type UUID is
   defined to represent UUIDs as follows:

       UUID ::= OCTET STRING (SIZE(16))
             -- constrained to an UUID [RFC4122]

   In LDAP, UUID values are encoded using the [ASCII] character string
   representation described in [RFC4122].  For example,
   "597ae2f6-16a6-1027-98f4-d28b5365dc14".

   The following is an LDAP syntax description suitable for publication
   in subschema subentries.

       ( 1.3.6.1.1.16.1 DESC 'UUID' )

2.2.  'uuidMatch' Matching Rule

   The 'uuidMatch' matching rule compares an asserted UUID with a stored
   UUID for equality.  Its semantics are the same as the
   'octetStringMatch' [X.520][RFC4517] matching rule.  The rule differs
   from 'octetStringMatch' in that the assertion value is encoded using
   the UUID string representation instead of the normal OCTET STRING
   string representation.

   The following is an LDAP matching rule description suitable for
   publication in subschema subentries.

       ( 1.3.6.1.1.16.2 NAME 'uuidMatch'
           SYNTAX 1.3.6.1.1.16.1 )

2.3.  'uuidOrderingMatch' Matching Rule

   The 'uuidOrderingMatch' matching rule compares an asserted UUID with
   a stored UUID for ordering.  Its semantics are the same as the
   'octetStringOrderingMatch' [X.520][RFC4517] matching rule.  The rule
   differs from 'octetStringOrderingMatch' in that the assertion value
   is encoded using the UUID string representation instead of the normal
   OCTET STRING string representation.



Zeilenga                    Standards Track                     [Page 3]

RFC 4530                     LDAP entryUUID                    June 2006


   The following is an LDAP matching rule description suitable for
   publication in subschema subentries.

       ( 1.3.6.1.1.16.3 NAME 'uuidOrderingMatch'
           SYNTAX 1.3.6.1.1.16.1 )

   Note that not all UUID variants have a defined ordering; and even
   where it does, servers are not obligated to assign UUIDs in any
   particular order.  This matching rule is provided for completeness.

2.4.  'entryUUID' Attribute

   The 'entryUUID' operational attribute provides the Universally Unique
   Identifier (UUID) assigned to the entry.

   The following is an LDAP attribute type description suitable for
   publication in subschema subentries.

       ( 1.3.6.1.1.16.4 NAME 'entryUUID'
           DESC 'UUID of the entry'
           EQUALITY uuidMatch
           ORDERING uuidOrderingMatch
           SYNTAX 1.3.6.1.1.16.1
           SINGLE-VALUE
           NO-USER-MODIFICATION
           USAGE directoryOperation )

   Servers SHALL generate and assign a new UUID to each entry upon its
   addition to the directory and provide that UUID as the value of the
   'entryUUID' operational attribute.  An entry's UUID is immutable.

   UUID are to be generated in accordance with Section 4 of [RFC4122].
   In particular, servers MUST ensure that each generated UUID is unique
   in space and time.

3.  Security Considerations

   An entry's relative distinguish name (RDN) is composed from attribute
   values of the entry, which are commonly descriptive of the object the
   entry represents.  Although deployers are encouraged to use naming
   attributes whose values are widely disclosable [RFC4514], entries are
   often named using information that cannot be disclosed to all
   parties.  As UUIDs do not contain any descriptive information of the
   object they identify, UUIDs may be used to identify a particular
   entry without disclosure of its contents.

   General UUID security considerations [RFC4122] apply.




Zeilenga                    Standards Track                     [Page 4]

RFC 4530                     LDAP entryUUID                    June 2006


   General LDAP security considerations [RFC4510] apply.

4.  IANA Considerations

   The IANA has registered the LDAP values [RFC4520] specified in this
   document.

4.1.  Object Identifier Registration

       Subject: Request for LDAP OID Registration
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Specification: RFC 4530
       Author/Change Controller: IESG
       Comments:
           Identifies the UUID schema elements

4.2.  UUID Syntax Registration

       Subject: Request for LDAP Syntax Registration
       Object Identifier: 1.3.6.1.1.16.1
       Description: UUID
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Specification: RFC 4530
       Author/Change Controller: IESG
       Comments:
            Identifies the UUID syntax

4.3.  'uuidMatch' Descriptor Registration

       Subject: Request for LDAP Descriptor Registration
       Descriptor (short name): uuidMatch
       Object Identifier: 1.3.6.1.1.16.2
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Usage: Matching Rule
       Specification: RFC 4530
       Author/Change Controller: IESG

4.4.  'uuidOrderingMatch' Descriptor Registration

       Subject: Request for LDAP Descriptor Registration
       Descriptor (short name): uuidOrderingMatch
       Object Identifier: 1.3.6.1.1.16.3
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Usage: Matching Rule



Zeilenga                    Standards Track                     [Page 5]

RFC 4530                     LDAP entryUUID                    June 2006


       Specification: RFC 4530
       Author/Change Controller: IESG

4.5.  'entryUUID' Descriptor Registration

   The IANA has registered the LDAP 'entryUUID' descriptor.

       Subject: Request for LDAP Descriptor Registration
       Descriptor (short name): entryUUID
       Object Identifier: 1.3.6.1.1.16.4
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Usage: Attribute Type
       Specification: RFC 4530
       Author/Change Controller: IESG

5.  Acknowledgements

   This document is based upon discussions in the LDAP Update and
   Duplication Protocols (LDUP) WG.  Members of the LDAP Directorate
   provided review.

6.  References

6.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4122]     Leach, P., Mealling, M., and R. Salz, "A Universally
                 Unique IDentifier (UUID) URN Namespace", RFC 4122, July
                 2005.

   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [RFC4517]     Legg, S., Ed., "Lightweight Directory Access Protocol
                 (LDAP): Syntaxes and Matching Rules", RFC 4517, June
                 2006.

   [ASCII]       Coded Character Set--7-bit American Standard Code for
                 Information Interchange, ANSI X3.4-1986.




Zeilenga                    Standards Track                     [Page 6]

RFC 4530                     LDAP entryUUID                    June 2006


   [X.501]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Models," X.501(1993) (also ISO/IEC 9594-
                 2:1994).

   [X.520]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory: Selected Attribute Types", X.520(1993) (also
                 ISO/IEC 9594-6:1994).

   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(2002) (also ISO/IEC 8824-1:2002).

6.2.  Informative References

   [RFC4514]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): String Representation of Distinguished
                 Names", RFC 4514, June 2006.

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org




















Zeilenga                    Standards Track                     [Page 7]

RFC 4530                     LDAP entryUUID                    June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                     [Page 8]

alt-openldap11-devel/rfc/INDEX000064400000006334150410163200011725 0ustar00This is an index of RFC contained in this directory:

rfc2079.txt X.500 Attribute Type and an Object Class to Hold URIs (PS)
rfc2247.txt Using Domains in LDAP DNs (PS)
rfc2293.txt Tables and Subtrees in the X.500 Directory (PS)
rfc2294.txt O/R Address hierarchy in the X.500 DIT (PS)
rfc2307.txt LDAP Network Information Services Schema (E)
rfc2377.txt LDAP Naming Plan (I)
rfc2589.txt LDAPv3: Dynamic Directory Services Extensions (PS)
rfc2649.txt LDAPv3 Operational Signatures (E)
rfc2696.txt LDAP Simple Paged Result Control (I)
rfc2713.txt LDAP Java schema (I)
rfc2714.txt LDAP CORBA schema (I)
rfc2798.txt LDAP inetOrgPerson schema (I)
rfc2849.txt LDIFv1 (PS)
rfc2891.txt LDAPv3: Server Side Sorting of Search Results (PS)
rfc2926.txt LDAP: Conversion of LDAP Schemas to and from SLP Templates (I)
rfc3045.txt Storing Vendor Information in the LDAP root DSE (I)
rfc3062.txt LDAP Password Modify Extended Operation (PS)
rfc3088.txt OpenLDAP Root Service (E)
rfc3112.txt LDAP Authentication Password Schema (I)
rfc3296.txt Named Subordinate References in LDAP (PS)
rfc3663.txt Domain Administrative Data in LDAP (E)
rfc3671.txt Collective Attributes in LDAP (PS)
rfc3672.txt Subentries in LDAP (PS)
rfc3673.txt LDAPv3: All Operational Attributes (PS)
rfc3687.txt LDAP Component Matching Rules (PS)
rfc3698.txt LDAP: Additional Matching Rules (PS)
rfc3703.txt LDAP: Schema for Policy Core (PS)
rfc3712.txt LDAP: Schema for Printer Services (I)
rfc3727.txt ASN.1 Module for LDAP Component Matching Rules (PS)
rfc3829.txt LDAP Authorization Identity Controls (I)
rfc3866.txt Language Tag and Ranges in LDAP (PS)
rfc3876.txt Returning Matched Values with LDAP (PS)
rfc3909.txt LDAP Cancel Operation (PS)
rfc3928.txt LDAP Client Update Protocol (PS)
rfc4013.txt SASLprep (PS)
rfc4370.txt LDAP Proxied Authorization Control (PS)
rfc4373.txt LBURP (I)
rfc4403.txt LDAP Schema for UDDI (I)
rfc4510.txt LDAP Technical Specification Roadmap (PS)
rfc4511.txt LDAP: The Protocol (PS)
rfc4512.txt LDAP: Directory Information Models (PS)
rfc4513.txt LDAP: Authentication Methods and Security Mechanisms (PS)
rfc4514.txt LDAP: DN (PS)
rfc4515.txt LDAP: Search Filters (PS)
rfc4516.txt LDAP: URL (PS)
rfc4517.txt LDAP: Syntaxes and Matching Rules (PS)
rfc4518.txt LDAP: Internationalized String Preparation (PS)
rfc4519.txt LDAP: User Applications Schema (PS)
rfc4520.txt IANA Considerations for LDAP (BCP)
rfc4521.txt Considerations for LDAP Extensions (BCP)
rfc4522.txt LDAP: Binary Encoding Option (PS)
rfc4523.txt LDAP: X.509 Certificate Schema (PS)
rfc4524.txt LDAP: COSINE Schema (PS)
rfc4525.txt LDAP: Modify-Increment Extension (I)
rfc4526.txt LDAP: Absolute True and False Filters (PS)
rfc4527.txt LDAP: Read Entry Controls (PS)
rfc4528.txt LDAP: Assertion Control (PS)
rfc4529.txt LDAP: Requesting Attributes by Object Class
rfc4530.txt LDAP: entryUUID (PS)
rfc4531.txt LDAP Turn Operation (E)
rfc4532.txt LDAP Who am I? Operation (PS)
rfc4533.txt LDAP Content Sync Operation (E)
rfc5020.txt LDAP 'entryDN' operational attribute (PS)
rfc5805.txt LDAP Transactions (E)

Legend:
STD	Standard
DS	Draft Standard
PS	Proposed Standard
I	Information
E	Experimental
FYI	For Your Information 
BCP	Best Common Practice

Please see http://www.rfc-editor.org/ for up-to-date status information.

$OpenLDAP$
alt-openldap11-devel/rfc/rfc2926.txt000064400000154105150410163200012771 0ustar00





Network Working Group                                           J. Kempf
Request for Comments: 2926                        Sun Microsystems, Inc.
Category: Informational                                         R. Moats
                                                            Coreon, Inc.
                                                           P. St. Pierre
                                                  Sun Microsystems, Inc.
                                                          September 2000


          Conversion of LDAP Schemas to and from SLP Templates

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2000).  All Rights Reserved.

Abstract

   This document describes a procedure for mapping between Service
   Location Protocol (SLP) service advertisements and lightweight
   directory access protocol (LDAP) descriptions of services.  The
   document covers two aspects of the mapping.  One aspect is mapping
   between SLP service type templates and LDAP directory schema.
   Because the SLP service type template grammar is relatively simple,
   mapping from service type templates to LDAP types is straightforward.
   Mapping in the other direction is straightforward if the attributes
   are restricted to use just a few of the syntaxes defined in RFC 2252.
   If arbitrary ASN.1 types occur in the schema, then the mapping is
   more complex and may even be impossible.  The second aspect is
   representation of service information in an LDAP directory.  The
   recommended representation simplifies interoperability with SLP by
   allowing SLP directory agents to backend into LDAP directory servers.
   The resulting system allows service advertisements to propagate
   easily between SLP and LDAP.












Kempf, et al.                Informational                      [Page 1]

RFC 2926               Conversion of LDAP Schemas         September 2000


Table of Contents

   1.0 Introduction ................................................  2
   2.0 Mapping SLP Templates to LDAP Schema ........................  3
     2.1 Mapping from SLP Attribute Types to LDAP Attribute Types ..  8
       2.1.1 Integer ...............................................  8
       2.1.2 String ................................................  8
       2.1.3 Boolean ...............................................  9
       2.1.4 Opaque ................................................  9
     2.2 Keyword Attributes ........................................  9
     2.3 Template Flags ............................................  9
       2.3.1 Multi-valued ..........................................  9
       2.3.2 Optional .............................................. 10
       2.3.3 Literal ............................................... 10
       2.3.4 Explicit Matching ..................................... 10
     2.4 Default and Allowed Value Lists ........................... 10
     2.5 Descriptive Text .......................................... 11
     2.6 Generating LDAP Attribute OIDs ............................ 11
     2.7 Example ................................................... 11
   3.0 Attribute Name Conflicts .................................... 15
   4.0 Mapping from Schema to Templates ............................ 15
     4.1 Mapping LDAP Attribute Types to SLP Attribute Types ....... 16
     4.2 Mapping ASN.1 Types to SLP Types .......................... 17
       4.2.1 Integer ............................................... 18
       4.2.2 Boolean ............................................... 18
       4.2.3 Enumerated ............................................ 18
       4.2.4 Object Identifier ..................................... 19
       4.2.5 Octet String .......................................... 19
       4.2.6 Real .................................................. 19
     4.3 Example ASN.1 Schema ...................................... 19
   5.0 Representing SLP Service Advertisements in an LDAP DIT ...... 22
   6.0 Internationalization Considerations ......................... 24
   7.0 Security Considerations ..................................... 24
   8.0 References .................................................. 25
   9.0 Authors' Addresses .......................................... 26
   10.0 Full Copyright Statement ................................... 27

1.0 Introduction

   SLP templates [1] are intended to create a simple encoding of the
   syntactic and semantic conventions for individual service types,
   their attributes, and conventions.  They can easily be generated,
   transmitted, read by humans and parsed by programs, as it is a string
   based syntax with required comments.  Directory schemas serve to
   formalize directory entry structures for use with LDAP [2] These
   directories serve to store information about many types of entities.
   Network services are an example of one such entity.




Kempf, et al.                Informational                      [Page 2]

RFC 2926               Conversion of LDAP Schemas         September 2000


   Interoperability between SLP and LDAP is important so clients using
   one protocol derive benefit from services registered through the
   other. In addition, LDAP directory servers can serve as the backend
   for SLP directory agents (DAs) if interoperability is possible In
   order to facilitate interoperability, this document creates mappings
   between the SLP template grammar and LDAP directory schema, and
   establishes some conventions for representing service advertisements
   in LDAP directories. The goal of the translation is to allow SLPv2
   queries (which are syntactically and semantically equivalent to
   LDAPv3 string queries [7]) to be submitted to an LDAP directory
   server by an SLP DA backended into LDAP without extensive processing
   by the DA.

   The simple notation and syntactic/semantic attribute capabilities of
   SLP templates map easily into directory schemas, and are easily
   converted into directory schemas, even by automated means.  The
   reverse may not be true. If the LDAP schema contains attributes with
   unrecognized or complex syntaxes, the translation may be difficult or
   impossible.  If, however, the LDAP schema only uses a few of the
   common syntaxes defined in RFC 2252 [8], then the translation is more
   straightforward. In addition, to foster complete bidirectionality,
   the mapping must follow a very specific representation in its DESC
   attributes.

   This document outlines the correct mappings for SLP templates into
   the syntactic representation specified for LDAP directory schema by
   RFC 2252 [8]. This syntax is a subset of the ASN.1/BER described in
   the X.209 specification [9], and is used by the LDAPv3 [2] directory
   schema.  Likewise, rules and guidelines are proposed to facilitate
   consistent mapping of ASN.1 based schemas to be translated in the SLP
   template grammar. Finally, a proposal for a representation of service
   advertisements in LDAP directory services is made that facilitates
   SLP interoperability.

   Except when used as elements in the definition of LDAP schemas, the
   key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in RFC 2119 [16].

2.0 Mapping SLP Templates to LDAP Schema

   We define the following abstract object class as the parent class for
   all services.  Any specific service type is a subclass of this, with
   its own attributes:







Kempf, et al.                Informational                      [Page 3]

RFC 2926               Conversion of LDAP Schemas         September 2000


      ( 1.3.6.1.4.1.6252.2.27.6.2.1
        NAME 'slpService'
        DESC 'parent superclass for SLP services'
        ABSTRACT
        SUP top
        MUST  ( template-major-version-number $
                template-minor-version-number $
                description $
                template-url-syntax $
                service-advert-service-type $
                service-advert-scopes )
        MAY   ( service-advert-url-authenticator $
                service-advert-attribute-authenticator ) )

   The attributes correspond to various parts of the SLP service
   template and SLP service advertisement.

   SLP service type templates begin with four definitions that set the
   context of the template:

      template-type - This defines the service type of the template. The
      service type can be a simple service type, like "service:ftp", an
      abstract service type, like "service:printer" or a concrete
      service type, like "service:printer:lpr". The type name can
      additionally include a naming authority, for example
      "service:printer.sun:local".  The name that appears in this field
      omits the "service:" prefix.

      template-version - A string containing a major and minor version
      number, separated by a period.

      template-description - A block of human readable text describing
      what the service type does.

      template-url-syntax - An ABNF [6] grammar describing the service
      type specific part of the service URL.

   The SLP template-type definition is used as the name of the LDAP
   object class for the template, a subclass of the "slpService" class,
   together with the "service" prefix to indicate that the name is for a
   service. In the translating service type name, colons and the period
   separating the naming authority are converted into hyphens. If the
   template defines an SLP concrete type, the concrete type name is
   used; the abstract type name is never used.  For example, the
   template for "service:printer:lpr" is translated into an LDAP object
   class called "service-printer-lpr". Furthermore, if the type name
   contains a naming authority, the naming authority name must be




Kempf, et al.                Informational                      [Page 4]

RFC 2926               Conversion of LDAP Schemas         September 2000


   included. For example, the service type name
   "service:printer.sun:local" becomes "service-printer-sun-local".  The
   LDAP object class is always "STRUCTURAL".

   The template-version definition is partitioned into two attributes,
   template-major-version-number and template-minor-version-number. The
   LDAP definition for these attributes is:

      ( 1.3.6.1.4.1.6252.2.27.6.1.1
        NAME 'template-major-version-number'
        DESC 'The major version number of the service type template'
        EQUALITY integerMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
        SINGLE-VALUE
      )

      ( 1.3.6.1.4.1.6252.2.27.6.1.2
        NAME 'template-minor-version-number'
        DESC 'The minor version number of the service type template'
        EQUALITY integerMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
        SINGLE-VALUE
      )

   The template-url-syntax definition in the SLP template is described
   by the following attribute:

      ( 1.3.6.1.4.1.6252.2.27.6.1.3
        NAME 'template-url-syntax'
        DESC 'An ABNF grammar describing the service type
              specific part of the service URL'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
        SINGLE-VALUE
      )

   The template-description attribute is translated into the X.520
   standard attribute "description" [3].

   We further establish the convention that SLP template characteristics
   that can't be translated into LDAP are inserted into the DESC field
   of the object class definition. The items are separated by empty
   lines (consisting of two "LINE FEED" characters), are preceded by a
   LINE FEED character, and are tagged at the  beginning of the line to
   indicate what they represent.   This allows the template to be
   reconstructed from the schema by properly parsing the comments.





Kempf, et al.                Informational                      [Page 5]

RFC 2926               Conversion of LDAP Schemas         September 2000


   The bulk of an SLP template consists of attribute definitions.  There
   are four items in an SLP template attribute definition that need to
   be mapped into LDAP:

      Attribute Name - Since SLPv2 attribute names are defined to be
      compatible with LDAPv3, SLP attributes map directly into LDAP
      attributes with no change. Similarly, LDAP attributes map directly
      to SLP attributes.

      Attribute Type - The SLP attribute type is mapped into the LDAP
      attribute type.

      Attribute Flags - The SLP attribute flags are mapped into
      characteristics of the LDAP attribute definition, or into the DESC
      field if no equivalent LDAP attribute definition characteristic
      occurs.

      Default and Allowed Values - These must be handled by the client
      or a DA enabled to handle templates, as in SLP. For reference,
      however, they should be included in the DESC field of the LDAP
      attribute definition.

      Descriptive Text - The SLP template descriptive text should be
      mapped into the DESC field.

   We discuss mapping of types, flags, default and allowed values, and
   descriptive text in the subsections below.

   OIDs for SLP template conversion schema elements are standardized
   under the enterprise number of SrvLoc.Org (6252) [18].

   For purposes of representing an SLP entry, we also define two
   standardized LDAP syntaxes and attributes with standardized OIDs.

      ( 1.3.6.1.4.1.6252.2.27.6.2.2
        DESC 'SLP Service Type'
      )

   Defines the syntax for the service type name. The syntax is defined
   in the BNF for the service URL in RFC 2609 Section 2.1 [1].

      ( 1.3.6.1.4.1.6252.2.27.6.2.3
        DESC 'SLP Scope'
      )

   Defines the syntax for the scope name. The syntax is defined in the
   BNF for scope names in RFC 2608 Section 6.4.1 [5].




Kempf, et al.                Informational                      [Page 6]

RFC 2926               Conversion of LDAP Schemas         September 2000


      ( 1.3.6.1.4.1.6252.2.27.6.1.4
        NAME 'service-advert-service-type'
        DESC 'The service type of the service advertisement, including
              the "service:" prefix.'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.6252.2.27.6.2.2
        SINGLE-VALUE
      )

   Defines an attribute for the service type name.

      ( 1.3.6.1.4.1.6252.2.27.6.1.5
        NAME 'service-advert-scopes'
        DESC 'A list of scopes for a service advertisement.'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.6252.2.27.6.2.3
      )

   Defines a multivalued attribute for the scopes.

   Searches for abstract types can be made with an LDAP query that
   wildcards the concrete type. For example, a search for all service
   advertisements of the printer abstract type can be made with the
   following query:

         (service-advert-service-type=service:printer:*)

   SLP specifies that service URLs and attribute lists can be
   accompanied by a structured authenticator consisting of a digital
   signature and information necessary to verify the signature.  A
   syntax and two standardized SLP attributes are defined for this
   purpose:

      ( 1.3.6.1.4.1.6252.2.27.6.2.3 DESC 'SLP Authenticator')

      The syntax of an SLP authenticator is the bytes of the
      authenticator in network byte order, see RFC 2608, Section 9.2
      [5].

      ( 1.3.6.1.4.1.6252.2.27.6.1.6
        NAME 'service-advert-url-authenticator'
        DESC 'The authenticator for the URL, null if none.'
        SYNTAX 1.3.6.1.4.1.6252.2.27.6.2.3
        SINGLE-VALUE
      )

      This attribute contains the SLP URL authenticator, as defined in
      RFC 2608, Section 9.2 [5].



Kempf, et al.                Informational                      [Page 7]

RFC 2926               Conversion of LDAP Schemas         September 2000


      ( 1.3.6.1.4.1.6252.2.27.6.1.7
        NAME 'service-advert-attribute-authenticator'
        DESC 'The authenticator for the attribute list, null if none.'
        SYNTAX 1.3.6.1.4.1.6252.2.27.6.2.3
        SINGLE_VALUE
      )

      This attribute contains the SLP attribute authenticator, as
      defined in RFC 2608, Section 9.2 [5].

2.1 Mapping from SLP Attribute Types to LDAP Attribute Types

   We define the mapping from SLP attribute types to LDAP as follows:

      SLP Type    ASN.1 Type               LDAP Type
      ---------------------------------------------------
       Integer     INTEGER              INTEGER
       String      DirectoryString      Directory String
       Boolean     BOOLEAN              Boolean
       Opaque      OCTET STRING         Octet String
       Keyword     (N/A)                IA5 String

   The following subsections discuss further details of the mapping.

2.1.1 Integer

   SLP integers compare as integers when performing a query.  LDAP
   integers behave similarly.  Consequently, the mapping from the SLP
   integer type to LDAP is INTEGER, with the integerMatch matching rule.

2.1.2 String

   SLP strings are encoded as described in the SLP protocol
   specification [5].  All value strings are considered case insensitive
   for matching operations.  SLP strings are not null terminated and are
   encoded in UTF-8.

   SLP strings are mapped to the LDAP Directory String type. The
   Directory String type exactly matches the SLP string type, i.e. it is
   a non-null terminated UTF-8 string. The caseIgnoreMatch equality
   rule, caseIgnoreOrderingMatch ordering rule, and
   caseIgnoreSubstringsMatch substring rule are used for comparing
   string attribute values.








Kempf, et al.                Informational                      [Page 8]

RFC 2926               Conversion of LDAP Schemas         September 2000


2.1.3 Boolean

   Boolean attributes may have one of two possible values.  In SLP,
   these values are represented as strings, TRUE and FALSE.  In SLP's
   string encoding of a boolean value, case does not matter.

   The SLP Boolean type maps directly into an LDAP BOOLEAN. The
   caseIgnoreMatch rule is used for equality matching.

2.1.4 Opaque

   SLP attribute values of type Opaque are represented as OCTET STRING
   in LDAP, and the octetStringMatch matching rule is used to compare
   them.

2.2 Keyword Attributes

   SLP service type templates allow the definition of keyword
   attributes.  Keyword attributes are attributes whose only
   characteristic is their presence. Keyword attributes have no flag
   information, nor any default or allowed values (since, by definition,
   they have no values).

   ASN.1 has no concept of keyword attributes. Keyword attributes are
   translated into a "May" clause in the ASN.1 class definition for the
   service type. If the keyword attribute is present, then its value is
   of no consequence, but for consistency we make it simply the NUL
   character, "\00".

2.3 Template Flags

   SLP template flags can be handled as described in the following
   subsections.

2.3.1 Multi-valued

   Multi-valued attributes are defined in an SLP template using the one
   value.  All values for a given attribute must be of the same type.

   LDAP attribute definitions require that a single valued attribute
   include the SINGLE-VALUE tag if the attribute is single valued.
   Otherwise, the attribute is assumed to be multivalued by default.









Kempf, et al.                Informational                      [Page 9]

RFC 2926               Conversion of LDAP Schemas         September 2000


2.3.2 Optional

   SLP uses the 'O' flag to indicate an attribute may or may not be
   present.  These optional attributes are defined using the "May"
   clause in the ASN.1 definition class definition for the service type.
   All other attributes must be defined as a "Must".

2.3.3 Literal

   ASN.1 does not have a mechanism to indicate that the values of an
   attribute may not be translated from one language to another, since
   ASN.1 schema are not typically translated. This flag is dropped when
   translating a template, but presence of the flag should be noted in
   the DESC field. It should be placed on a separate line and tagged
   with "Literal:" so the template can be reconstructed from the schema.

2.3.4 Explicit Matching

   The SLP template syntax uses a flag of 'X' to indicate that an
   attribute must be present in order for the query to be properly
   satisfied.  There is no provision for requiring that particular
   attributes be in a query. Consequently, this flag is dropped when
   translating a template, but presence of the flag should be noted in
   the DESC field. It should be placed on a separate line and tagged
   with "Explicit:" so the template can be reconstructed from the
   schema.

2.4 Default and Allowed Value Lists

   The SLP template grammar provides the capability to define default
   and allowed values for an attribute. The SLP protocol does not
   enforce these restrictions on registered attributes, however.  The
   default and allowed values may be used by client side applications,
   or alternatively it may also be used by DAs to initialize
   registrations having no attributes and to limit attribute values to
   the template allowed values.

   LDAP servers also do not support default and allowed values on
   attributes. Therefore, enforcement of default and allowed values in
   SLP templates is left up to the clients or a DA, if the DA is
   backending into LDAP. The default and allowed values should be
   included in the DESC field. The comments should be placed on separate
   lines and labeled with the "Default:" and "Allowed:" tags to allow
   reconstruction of the template.







Kempf, et al.                Informational                     [Page 10]

RFC 2926               Conversion of LDAP Schemas         September 2000


2.5 Descriptive Text

   The descriptive text associated with an attribute definition should
   be included in the DESC field. It should start on a separate line and
   begin with the "Description:" tag.

2.6 Generating LDAP Attribute OIDs

   LDAP attributes require an OID. In general, there is no a priori way
   that an algorithm can be defined for generating OIDs, because it will
   depend on the conventions used by the organization developing the
   template. In some cases, an organization's procedure for generating
   OIDs may be regular enough that a template developer can
   algorithmically generate OIDs off of an assigned root. Whatever means
   is used, the template developer should assure that unique OIDs are
   assigned to each SLP attribute that is translated into an LDAP
   attribute.

2.7 Example

   The template included below is a hypothetical abstract printer
   service template, similar to that described in [10].

      template-type = printer

      template-version = 0.0

      template-description =
      The printer service template describes the attributes supported by
      network printing devices.  Devices may be either directly
      connected to a network, or connected to a printer spooler that
      understands the a network queuing protocol such as IPP, lpr or the
      Salutation  Architecture.

      template-url-syntax =
      ;The URL syntax is specific to the printing protocol being
      ;employed

      description = STRING
      # This attribute is a free form string that can contain any
      # site-specific descriptive information about this printer.

      printer-security-mechanisms-supported = STRING L M
      none
      # This attribute indicates the security mechanisms supported
      tls, ssl, http-basic, http-digest, none





Kempf, et al.                Informational                     [Page 11]

RFC 2926               Conversion of LDAP Schemas         September 2000


      printer-operator = STRING O L M
      # A person, or persons responsible for maintaining a
      # printer on a day-to-day basis, including such tasks
      # as filling empty media trays, emptying full output
      # trays, replacing toner cartridges, clearing simple
      # paper jams, etc.

      printer-location-address = STRING O
      # Physical/Postal address for this device.  Useful for
      # nailing down a group of printers in a very large corporate
      # network.  For example: 960 Main Street, San Jose, CA 95130

      printer-priority-queue = BOOLEAN O
      FALSE
      # TRUE indicates this printer or print queue is a priority
      # queuing device.

      printer-number-up = INTEGER O
      1
      # This job attribute specifies the number of source
      # page-images to impose upon a single side of an instance
      # of a selected medium.
      1, 2, 4

      printer-paper-output = STRING M L O
      standard
      # This attribute describes the mode in which pages output
      # are arranged.

      standard, noncollated sort, collated sort, stack, unknown

   We assume that the concrete type "service:printer:lpr" for printers
   that speak the LPR protocol [4] has the following template
   definition:

      template-type = printer:lpr

      template-version = 0.0

      template-description =
      The printer:lpr service template describes the attributes
      supported by network printing devices that speak the
      LPR protocol. No new attributes are included.

      template-url-syntax = queue
      queue = ;The queue name, see RFC 1179.





Kempf, et al.                Informational                     [Page 12]

RFC 2926               Conversion of LDAP Schemas         September 2000


   The LDAP class definition for the "service:printer:lpr" concrete
   service type is translated as follows:

   ( ---place the assigned OID here---
     NAME  'service-printer-lpr'
     DESC  'Description: The printer:lpr service template
                 describes the attributes supported by network printing
                 devices that speak the LPR protocol. No new attributes
                 are included.

            URL Syntax: queue
                 queue = ;The queue name, see RFC 1179.'
     SUP   slpService
     MUST  ( description $ security-mechanisms-supported $
     labeledURI)
     MAY   ( operator $ location-address $ priority-queue $
             number-up $ paper-output)
   )

   The attribute definitions are translated as follows:

   ( ---place the assigned OID here---
     NAME 'printer-security-mechanisms-supported'
     DESC 'Description: This attribute indicates the security mechanisms
           supported.

           Default: value

           Allowed: tls, ssl, http-basic, http-digest, none

           Literal:'
     EQUALITY caseIgnoreMatch
     ORDERING caseIgnoreOrderingMatch
     SUBSTR caseIgnoreSubstringsMatch
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   )

   ( ---place the assigned OID here---
     NAME 'printer-operator'
     DESC 'Description: A person, or persons responsible for
           maintaining a printer on a day-to-day basis, including
           such tasks as filling empty media trays, emptying full
           output trays, replacing toner cartridges, clearing simple
           paper jams, etc.







Kempf, et al.                Informational                     [Page 13]

RFC 2926               Conversion of LDAP Schemas         September 2000


           Literal:'
     EQUALITY caseIgnoreMatch
     ORDERING caseIgnoreOrderingMatch
     SUBSTR caseIgnoreSubstringsMatch
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   )

   ( --place the assigned OID here---
     NAME 'printer-location-address'
     DESC 'Description Physical/Postal address for this device.
           Useful for nailing down a group of printers in a very
           large corporate network.  For example: 960 Main Street,
           San Jose, CA 95130.'
     EQUALITY caseIgnoreMatch
     ORDERING caseIgnoreOrderingMatch
     SUBSTR caseIgnoreSubstringsMatch
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
     SINGLE-VALUE
   )

   ( ---place the assigned OID here---
     NAME 'printer-priority-queue'
     DESC 'Description: TRUE indicates this printer or print
          queue is a priority queuing device.'
     EQUALITY booleanMatch
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
     SINGLE-VALUE
   )

   ( ---place the assigned OID here---
     NAME 'printer-number-up'
     DESC 'Description: This job attribute specifies the number
           of source page-images to impose upon a single side of
           an instance of a selected medium. This attribute is
           INTEGER.

           Default: 1

           Allowed: 1, 2, 3, 4'
     EQUALITY integerMatch
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
     SINGLE-VALUE
   )








Kempf, et al.                Informational                     [Page 14]

RFC 2926               Conversion of LDAP Schemas         September 2000


   ( ---place the assigned OID here---
     NAME 'printer-paper-output'
     DESC 'Description: This attribute describes the mode in
           which pages output are arranged. Default value is
           standard.

           Default: standard

           Allowed: standard, noncollated sort, collated sort,
             stack, unknown.
           Literal:'
     EQUALITY caseIgnoreMatch
     ORDERING caseIgnoreOrderingMatch
     SUBSTR caseIgnoreSubstringsMatch
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   )

3.0 Attribute Name Conflicts

   LDAP has a flat name space, and attribute names and OIDs must be
   unique in a directory server. In order to avoid name conflicts in the
   translation of SLP templates to LDAP schemas, template developers may
   want to consider prepending the name of the service type to the
   attribute. Postprocessing attribute names to make them unique when
   translated is not possible, because it would require the DA to
   rewrite queries before submitting them to the directory server. In
   addition, developers should use standard LDAP attributes when such
   attributes are available.

   In the above example template, the abstract type name "printer" is
   prepended to attributes to avoid conflicts. The standard
   "description" attribute defined by X.520 [3] is used to translate the
   template description attribute.

4.0 Mapping from Schema to Templates

   The reverse mapping from LDAP schema to SLP service type templates
   requires dealing with both LDAP and ASN.1 data types.  RFC 2252
   defines 33 attribute syntaxes that should be supported by LDAP
   directory servers.  These syntaxes are defined using BNF for strings
   or using ASN.1 for binary  valued attributes defined by X.520.

   Mapping of the LDAP data types into SLP template types is fairly
   straightforward, but mapping arbitrary ASN.1 data types is somewhat
   more complicated and requires encoding the ASN.1 data type into a
   string. To a certain extent, this masks the ASN.1 data type because
   it becomes impossible to distinguish between a native string having




Kempf, et al.                Informational                     [Page 15]

RFC 2926               Conversion of LDAP Schemas         September 2000


   content equivalent to an encoded ASN.1 string. However, inclusion of
   the ASN.1 data type in the comment provides additional information
   should a reverse transformation from SLP to ASN.1 be required.

   The following subsections deal with both LDAP and ASN.1 attribute
   data type mappings.

4.1 Mapping LDAP Attribute Syntaxes to SLP Attribute Types

   The following table contains the mappings for LDAP syntaxes to SLP
   data types:

         LDAP Type                              SLP Type
      --------------------------------------------------------
         ACI Item                                 NA
         Access Point                             NA
         Attribute Type Description               NA
         Audio                                    Opaque
         Binary                                   ASN.1 escape
         Bit String                               String
         Boolean                                  Boolean
         Certificate                              Opaque
         Certificate List                         Opaque
         Certificate Pair                         Opaque
         Country String                           String
         DN                                       String
         Data Quality Syntax                      NA
         Delivery Method                          NA
         Directory String                         String
         DIT Content Rule Description             NA
         DIT Structure Rule Description           NA
         DL Submit Permission                     NA
         DSA Quality Syntax                       NA
         Enhanced Guide                           NA
         Facsimile Telephone Number               String
         Fax                                      Opaque
         Generalized Time                         String
         Guide                                    NA
         IA5 String                               String
         INTEGER                                  Integer
         JPEG                                     Opaque
         LDAP Syntax Description                  NA
         LDAP Schema Definition                   NA
         LDAP Schema Description                  NA
         Master and Shadow Access Points          NA
         Matching Rule Description                NA
         Matching Rule Use Description            NA
         Mail Preference                          NA



Kempf, et al.                Informational                     [Page 16]

RFC 2926               Conversion of LDAP Schemas         September 2000


         MHS OR Address                           String
         Modify Rights                            NA
         Name and Optional UID                    NA
         Name Form Description                    NA
         Numeric String                           String
         Object Class Description                 NA
         Octet String                             Opaque
         OID                                      String
         Other Mailbox                            String
         Postal Address                           String
         Protocol Information                     NA
         Presentation Address                     String
         Printable String                         String
         Substring Assertion                      NA
         Subtree Specification                    NA
         Supplier Information                     NA
         Supplier or Consumer                     NA
         Supplier And Consumer                    NA
         Supported Algorithm                      NA
         DSE Type                                 NA
         Telephone Number                         String
         Teletex Terminal Identifier              String
         Telex Number                             String
         UTC Time                                 String

4.2 Mapping ASN.1 Types to SLP Types

   ASN.1 employs a much richer set of data types than provided by SLP.
   The table below show the mapping of selected ASN.1 data type to their
   nearest SLP equivalent.  Because of the complexity and flexibility of
   ASN.1, a complete list cannot be provided.

   As sample of some ASN.1 encodings and their mappings to SLP:

      ASN.1 type               SLP type
      -----------------------------------------
      INTEGER                  Integer
      BOOLEAN                  Boolean
      ENUMERATED               String
      OBJECT IDENTIFIER        String
      OCTET STRING             Opaque
      REAL                     String

   Data types that do not map directly to SLP data types should be
   defined as either a String, or as Opaque.  ASN.1 types that may only
   contain valid characters for Strings, as defined in X.680 [9] should
   be encoded as strings.  ASN.1 types such as GraphicString that change
   their character set encoding in part way through a value should not



Kempf, et al.                Informational                     [Page 17]

RFC 2926               Conversion of LDAP Schemas         September 2000


   be encoded as strings, however, If such types are required, the SLP
   Opaque type should be used. In either case, the first line of the
   help text is used to indicate the original ASN.1 data type.

   The following subsections describe how to convert from the ASN.1 BER
   [9] to the SLP template for the different types in the table above.

4.2.1 Integer

   Both SLP templates and ASN.1 support Integers, so there is a one to
   one mapping between an SLP Integer attribute and an ASN.1 Integer
   attribute.  Details on the encoding of integers is summarized in the
   SLP template to ASN.1 section above.

4.2.2 Boolean

   Boolean values are supported by both SLP and ASN.1, though on wire
   encodings differ.  X.680 [9] specifies zero and non-zero encoding for
   booleans, where SLP encodes booleans using the strings TRUE and
   FALSE.  In general, most LDAP servers will use the LDAP Boolean type
   (which is a string), so again the ASN.1 type should be recorded in
   the comment or it will be lost.

4.2.3 Enumerated

   SLP templates support the concept of enumerations through the listing
   of allowed values in the attribute definition.  These enumerations
   are not strictly binding on clients or DAs, but they are similar to
   the ASN.1 definition of enumerations. BER encodes the ASN.1
   enumeration by passing the number of the element's position in the
   enumeration.  This requires both sides to have knowledge of the
   specific enumeration prior to decoding an enumeration's value. SLP
   provides no specific support for transmitting enumerations. They are
   simply String types. Information on the ASN.1 type and ASN.1 encoding
   of the enumeration values is recorded in the comment.

   Example:

   color-supported = STRING   M
   none
   # ASN.1: Enumeration.
   # ASN.1 Mapping: none = 0, highlight = 1, three color = 2,
   #   four color = 4, monochromatic = 5
   #This attribute specifies whether the Printer supports
   # color and, if so, what type.
   none,highlight,three color,four color,monochromatic





Kempf, et al.                Informational                     [Page 18]

RFC 2926               Conversion of LDAP Schemas         September 2000


4.2.4 Object Identifier

   Object identifiers(OIDs) are commonly used in the ASN.1 world to
   identify object and attributes.  OIDs are a numerical representation
   of an element's place in the naming hierarchy. Each element at a
   particular level of a hierarchy has a unique number assigned within
   that level of the hierarchy. A sample OID would be the naming tree
   for SNMP MIBs:  iso(1) org(3) dod(6) internet(1) mgmt(2) mib(1) would
   be written as the string "1.3.6.1.2.1".

   Because this representation reduces down to a string of dot separated
   numbers, this maps easily to the SLP String type.  The help text for
   this element should indicate it is an ASN.1 OID

      identifier = STRING
      # ASN.1: OID
      # The object identifier for this SNMP agent.

4.2.5 Octet String

   An ASN.1 octet string should be mapped to an Opaque in an SLP
   template.  An octet string is a sequence of bytes, whereas an Opaque
   is a a string that encodes a sequence of bytes. Again, the ASN.1 type
   is lost unless recorded in the comment.

4.2.6 Real

   There is no direct mapping between floating point numbers and any SLP
   data types.  Attributes having the ASN.1 type of Real are mapped to
   SLP type String.  Comments are added to the attribute help text
   indicating the value was originally an ASN.1 real.  For example:

      weight = STRING
      # ASN.1: Real
      # The objects weight in pounds.

4.3 Example ASN.1 Schema

   The following is an example schema for an exported filesystem.  The
   section presents it as in ASN.1 and the following section shows the
   SLP template translation. The template translation does not capture
   the actual attribute format for the Set type, that would be done in
   the LDAP client software making the translation. Note that even
   though the class definition does not conform with the previously
   defined conventions for SLP classes, the schema can still be
   translated into an SLP template.  The syntax used in this example
   follows




Kempf, et al.                Informational                     [Page 19]

RFC 2926               Conversion of LDAP Schemas         September 2000


         -- Abstraction of a fstab entry (a "mount").
         -- These lookups would likely be performed by an
         -- an automounter type application.
         mount   OBJECT-CLASS ::= {
                 SUBCLASS OF { top }
                 MUST CONTAIN { mountHost |
                                mountDirectory |
                                mountType
                              }
                 MAY CONTAIN { mountOption |
                               mountDumpFrequency |
                               mountPassNo
                             }
                 ID { <oid1> }
         }


         - The mount host.
         mountHost       ATTRIBUTE ::= {
                         WITH SYNTAX caseIgnoreString
                         EQUALITY MATCHING RULE caseIgnoreMatch
                         SINGLE VALUE
                         ID { <oid2> }
         }


         - The file system to mount.
         mountDirectory  ATTRIBUTE ::= {
                         WITH SYNTAX caseIgnoreString
                         EQUALITY MATCHING RULE caseIgnoreMatch
                         SINGLE VALUE
                         ID { <oid3> }
         }

         - The type of file system being mounted.
         mountType       ATTRIBUTE ::= {
                         WITH SYNTAX INTEGER { ufs(1),
                                               hsfs(2),
                                               nfs(3),
                                               rfs(4)
                                             }
                         EQUALITY MATCHING RULE integerMatch
                         SINGLE VALUE
                         ID { <oid4> }
         }






Kempf, et al.                Informational                     [Page 20]

RFC 2926               Conversion of LDAP Schemas         September 2000


         - Options for the mount operation.
         mountOption     ATTRIBUTE ::= {
                         WITH SYNTAX caseIgnoreString
                         EQUALITY MATCHING RULE caseIgnoreString
                         ID { <oid5> }
         }


         - How often to dump the file system.
         mountDumpFrequency      ATTRIBUTE :: = {
                                 WITH SYNTAX  INTEGER (0..9)
                                 EQUALITY MATCHING RULE integerMatch
                                 SINGLE VALUE
                                 ID { <oid6> }
         }

         - Boot time mount pass number.
         mountPassNo     ATTRIBUTE ::= {
                         WITH SYNTAX INTEGER
                         EQUALITY MATCHING RULE integerMatch
                         SINGLE VALUE
                         ID { <oid7> }
         }

   The translated SLP template is:

      template-type = mount

      template-version = 1.0

      template-description = "Describes a remote filesystem access
      protocol"

      template-url-syntax =
                   filesystem   = 1*[ DIGIT / ALPHA ]
                   urlpath = "/" filesystem

      mountHost = STRING L
      # ASN.1: Case Ignore String, Single Value
      # The mount host

      mountDirectory = STRING L
      # ASN.1: Case Ignore String, Single Value
      # The filesystem to mount







Kempf, et al.                Informational                     [Page 21]

RFC 2926               Conversion of LDAP Schemas         September 2000


      mountType = STRING L
      ufs
      # ASN.1: Enumeration, Single Value
      # ASN.1 Mapping: ufs = 1, hsfs = 2, nfs = 3, rfs = 4
      # The type of the filesystem being mounted
      ufs, hsfs, nfs, rfs

      mountOption = STRING M O L
      # ASN.1: Case Ignore String
      # mount options for this filesystem

      mountDumpFrequency = INTEGER O
      0
      # ASN.1: Integer Range, Single Value
      # How often to dump this filesystem
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9

      mountPassNo = INTEGER O
      # ASN.1: Integer, Single Value
      # Boot time mount pass number

5.0 Representing SLP Service Advertisements in an LDAP DIT

   In addition to translating between SLP templates and LDAP schema,
   another area requiring compatibility is the representation of SLP
   service advertisements in an LDAP DIT. A standardized representation
   for service information allows SLP DAs to store service
   advertisements in LDAP, and for LDAP clients to query the DIT for
   those services.  Similarly, if LDAP clients represent service
   information in the same form, SLP clients can benefit from
   interoperability.

   A service advertisement contains the service URL in a 'labeledURI'
   attribute [11]. The labeledURI attribute in a service advertisement
   should only contain the service URL for the service, with no
   additional label. It is recommended that the labeledURI be used as
   the RDN for the service object in the DIT.

   Although service advertisements can appear anywhere within the DIT,
   it is recommended that all services be stored under a single common
   point, or root node, to facilitate searching in a domain. This allows
   a  client to search for all of advertisements of a particular service
   type, say, for all printers.  The recommended parent entry is one
   named "ou=service" below the entry which is the representation of the
   domain, as described in RFC 2247.






Kempf, et al.                Informational                     [Page 22]

RFC 2926               Conversion of LDAP Schemas         September 2000


   For example, a printer service with labeledURI of
   "service:lpr://printsrv/queue1" in the domain foobar.com advertised
   in the LDAP server that holds the entry "dc=foobar,dc=com" tree has
   the following DN:

   "labeledURI=service:lpr://printsrv/queue1, ou=service, dc=foobar,
   dc=com"

   While this leads to a flat space of service storage, since SLP uses
   search filters from LDAP for searches, these filters can be used for
   one-level searches from the root node.

   The following example illustrates how an advertisement having a
   simple service type is represented. The advertisement (in conceptual
   form) for a printer is:

      Service Type: service:lpr://printsrv/queue1
      Scopes: eng,corp
      Attributes:
        description = A general printer for all to use.
        security-mechanisms-supported = none
      Authentication: none

   The RDN of the object is labeledURI=service:lpr://printsrv/queue1,
   and the following LDAP search filter will return this object, along
   with any others of the service type "service:lpr" that match the
   other attributes:

      (&(service-advert-service-type=service:lpr)
        (service-advert-scopes=eng)
        (service-advert-scopes=corp)
        (description=A general printer for all to use.)
        (security-mechanisms-supported=none))

   Service advertisements in SLP also have a lease time associated with
   them. In LDAP servers that support the extensions for dynamic
   directory services [12], the service advertisement entry objectClass
   should be extended with the dynamicObject class. This allows the
   service advertisement to time out within the LDAP directory server.
   If the LDAP directory server does not support the dynamic directory
   services extension, then advertisement lease timeouts must be handled
   by the SLP agent.

   While the service advertisement schema outlined in this section is
   primarily for SLP DAs that use LDAP as a backing store, if LDAP
   agents register services using the same format, complete
   interoperability with SLP is achieved.




Kempf, et al.                Informational                     [Page 23]

RFC 2926               Conversion of LDAP Schemas         September 2000


6.0 Internationalization Considerations

   SLP specifies that an RFC 1766 [13] language code accompanies every
   service advertisement. Language codes for service advertisements in
   LDAP must be represented according to RFC 2596 [14].

   RFC 2596 prohibits language codes in DNs, and specifies that a
   directory server which does not support language codes must treat an
   attribute with a language code as an unrecognized attributes.
   According to RFC 2596, language codes are appended to attribute names
   with a semicolon (";"). For example, the following attribute/value
   pair is in the German locale:

      (address;lang-de=44 Bahnhofstrasse, 2365 Weibstadt, Deutschland)

   An attribute with a language tag in a specific locale is considered a
   separate attribute from attributes in other locales.

   If the service advertisement is in the default SLP locale ("en", no
   dialect), then the language code need not be appended to the
   attribute name.

   SLP queries in locales other than the default need not be rewritten
   to include language tags before being submitted to the directory
   server.  RFC 2596 specifies that all entries that match are returned,
   including those with language tags, without requiring the language
   tags to be explicitly present in the query. The SLP DA can then
   postprocess the result to select the entries from the required
   locale.

7.0 Security Considerations

   SLP authenticators are stored with the service advertisement in the
   DIT, as discussed in Section~7ef{slpdit}. LDAP clients need to use
   LDAP authentication [15] to assure that they are connecting with a
   secure server. In particular, SLP DAs that use LDAP as a back end
   store and that implement SLP authentication MUST use LDAP
   authentication to assure that the LDAP entries for their service
   registrations are secure.

Acknowledgements

   Many thanks are due to Mark Wahl whose detailed and insightful
   comments were instrumental in helping improve the technical accuracy
   of this document with respect to LDAP.






Kempf, et al.                Informational                     [Page 24]

RFC 2926               Conversion of LDAP Schemas         September 2000


8.0 References

   [1]  Guttman, E., Perkins, C. and J. Kempf, "Service Templates and
        service: Schemes", RFC 2609, April 1999.

   [2]  Wahl, W., Howes, T. and S. Kille, "Lightweight Directory Access
        Protocol (v3)", RFC 2251, December 1997.

   [3]  International Telecommunications Union. The Directory:Selected
        Attribute Types.  ITU Recommendation X.520. August, 1997.

   [4]  McLaughlin, L., "Line Printer Daemon Protocol, RFC 1179, August
        1990.

   [5]  Guttman, E., Perkins, C., Veizades, J. and M. Day, "Service
        Location Protocol Version 2", RFC 2608, April 1999.

   [6]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
        Specifications: ABNF", RFC 2234, November 1997.

   [7]  Howes, T., "The String Representation of LDAP Search Filters",
        RFC 2254, December 1997.

   [8]  Wahl, W., Coulbeck, A., Howe, T. and S. Kille, "Lightweight
        Directory Access Protocol (v3): Attribute Syntax Definition",
        RFC 2252, December 1997.

   [9]  ITU-T Rec. X.680. Abstract Syntax Notation One (ASN.1) -
        Specification of Basic Notation. 1994.

   [10] Fleming, P., Jones, K., Lewis, H., and McDonald, I., "Internet
        Printing Protocol (IPP): LDAP Schema for Printer Services", Work
        in Progress.

   [11] Smith, M., "Definition of an X.500 Attribute Type and an Object
        Class to Hold Uniform Resource Identifiers (URIs)", RFC 2079,
        January 1997.

   [12] Yaacovi, Y., Wahl, M. and T. Genovese, "Lightweight Directory
        Access Protocol (v3): Extensions for Dynamic Directory
        Services", RFC 2589, May 1999.

   [13] Alvestrand, H., "Tags for the Identification of Languages", RFC
        1766, December 1997.

   [14] Wahl, M. and T. Howes, "Use of Language Codes in LDAP", RFC
        2596, May 1999.




Kempf, et al.                Informational                     [Page 25]

RFC 2926               Conversion of LDAP Schemas         September 2000


   [15] Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
        "Authentication Methods for LDAP", RFC 2829, May 2000.

   [16] Bradner, S., "Key Words for Use in RFCs to Indicate Requirement
        Levels", BCP 14, RFC 2119, March 1997.

   [17] Dubuisson, O. ASN.1: Communication between Heterogeneous
        Systems. OSS Nokalva, 2000.

   [18] http://www.srvloc.org

9.0 Authors' Addresses

   James Kempf
   Sun Microsystems
   901 San Antonio Avenue
   Palo Alto, CA 94303
   USA

   Phone: +1 650 786-5890
   EMail: james.kempf@sun.com


   Ryan Moats
   Coreon, Inc.
   15621 Drexel Circle
   Omaha, NE, 68135
   USA

   EMail: rmoats@coreon.net


   Pete St. Pierre
   Sun Microsystems
   901 San Antonio Avenue
   Palo Alto, CA 94303
   USA

   Phone: +1 415 786-5790
   EMail: Pete.StPierre@Eng.Sun.COM











Kempf, et al.                Informational                     [Page 26]

RFC 2926               Conversion of LDAP Schemas         September 2000


10.  Full Copyright Statement

   Copyright (C) The Internet Society (2000).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Kempf, et al.                Informational                     [Page 27]

alt-openldap11-devel/rfc/rfc5020.txt000064400000020637150410163200012757 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 5020                                 Isode Limited
Category: Standards Track                                    August 2007


       The Lightweight Directory Access Protocol (LDAP) entryDN
                         Operational Attribute

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The IETF Trust (2007).

Abstract

   This document describes the Lightweight Directory Access Protocol
   (LDAP) / X.500 'entryDN' operational attribute.  The attribute
   provides a copy of the entry's distinguished name for use in
   attribute value assertions.

























Zeilenga                    Standards Track                     [Page 1]

RFC 5020                      LDAP entryDN                   August 2007


1.  Background and Intended Use

   In X.500 Directory Services [X.501], such as those accessible using
   the Lightweight Directory Access Protocol (LDAP) [RFC4510], an entry
   is identified by its distinguished name (DN) [RFC4512].  However, as
   an entry's DN is not an attribute of the entry, it is not possible to
   perform attribute value assertions [RFC4511] against it.

   This document describes the 'entryDN' operational attribute which
   holds a copy of the entry's distinguished name.  This attribute may
   be used in search filters.  For instance, searching the subtree
   <dc=example,dc=com> with the filter:

      (entryDN:componentFilterMatch:=or:{
          item:{ component "3", rule rdnMatch, value "ou=A" },
          item:{ component "3", rule rdnMatch, value "ou=B" } })

   would return entries in the subtree <ou=A,dc=example,dc=com> and
   entries in subtree <ou=B,dc=example,dc=com>, but would not return any
   other entries in the subtree <dc=example,dc=com>.

   In the above paragraph, DNs are presented using the string
   representation defined in [RFC4514], and the example search filter is
   presented using the string representation defined in [RFC4515] with
   whitespace (line breaks and indentation) added to improve
   readability.  The 'componentFilterMatch' and 'rdnMatch' rules are
   specified in [RFC3687].

   Schema definitions are provided using LDAP description formats
   [RFC4512].  Definitions provided here are formatted (line wrapped)
   for readability.

2.  'entryDN' Operational Attribute

   The 'entryDN' operational attribute provides a copy of the entry's
   current DN.

   The following is an LDAP attribute type description suitable for
   publication in subschema subentries.

      ( 1.3.6.1.1.20 NAME 'entryDN'
          DESC 'DN of the entry'
          EQUALITY distinguishedNameMatch
          SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
          SINGLE-VALUE
          NO-USER-MODIFICATION
          USAGE directoryOperation )




Zeilenga                    Standards Track                     [Page 2]

RFC 5020                      LDAP entryDN                   August 2007


   Note that the DN of the entry cannot be modified through this
   attribute.

3.  Security Considerations

   As this attribute only provides an additional mechanism to access an
   entry's DN, the introduction of this attribute is not believed to
   introduce new security considerations.

4.  IANA Considerations

4.1.  Object Identifier Registration

   IANA has registered (upon Standards Action) an LDAP Object Identifier
   [RFC4520] for use in this document.

      Subject: Request for LDAP OID Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Specification: RFC 5020
      Author/Change Controller: IESG
      Comments:
          Identifies the 'entryDN' attribute type

4.2.  'entryDN' Descriptor Registration

   IANA has registered (upon Standards Action) the LDAP 'entryDN'
   descriptor [RFC4520].

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): entryDN
      Object Identifier: 1.3.6.1.1.20
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Usage: Attribute Type
      Specification: RFC 5020
      Author/Change Controller: IESG














Zeilenga                    Standards Track                     [Page 3]

RFC 5020                      LDAP entryDN                   August 2007


5.  References

5.1.  Normative References

   [RFC4510]   Zeilenga, K., Ed., "Lightweight Directory Access Protocol
               (LDAP): Technical Specification Road Map", RFC 4510, June
               2006.

   [RFC4512]   Zeilenga, K., Ed., "Lightweight Directory Access Protocol
               (LDAP): Directory Information Models", RFC 4512, June
               2006.

   [X.501]     International Telecommunication Union - Telecommunication
               Standardization Sector, "The Directory -- Models,"
               X.501(1993) (also ISO/IEC 9594-2:1994).

5.2.  Informative References

   [RFC3687]   Legg, S., "Lightweight Directory Access Protocol (LDAP)
               and X.500 Component Matching Rules", RFC 3687, February
               2004.

   [RFC4511]   Sermersheim, J., Ed., "Lightweight Directory Access
               Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4514]   Zeilenga, K., Ed., "Lightweight Directory Access Protocol
               (LDAP): String Representation of Distinguished Names",
               RFC 4514, June 2006.

   [RFC4515]   Smith, M., Ed., and T. Howes, "Lightweight Directory
               Access Protocol (LDAP): String Representation of Search
               Filters", RFC 4515, June 2006.

   [RFC4520]   Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
               Considerations for the Lightweight Directory Access
               Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

Author's Address

   Kurt D. Zeilenga
   Isode Limited

   EMail: Kurt.Zeilenga@Isode.COM








Zeilenga                    Standards Track                     [Page 4]

RFC 5020                      LDAP entryDN                   August 2007


Full Copyright Statement

   Copyright (C) The IETF Trust (2007).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.







Zeilenga                    Standards Track                     [Page 5]

alt-openldap11-devel/rfc/rfc3866.txt000064400000075415150410163200013003 0ustar00





Network Working Group                                   K. Zeilenga, Ed.
Request for Comments: 3866                           OpenLDAP Foundation
Obsoletes: 2596                                                July 2004
Category: Standards Track


                    Language Tags and Ranges in the
              Lightweight Directory Access Protocol (LDAP)

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).

Abstract

   It is often desirable to be able to indicate the natural language
   associated with values held in a directory and to be able to query
   the directory for values which fulfill the user's language needs.
   This document details the use of Language Tags and Ranges in the
   Lightweight Directory Access Protocol (LDAP).

1.  Background and Intended Use

   The Lightweight Directory Access Protocol (LDAP) [RFC3377] provides a
   means for clients to interrogate and modify information stored in a
   distributed directory system.  The information in the directory is
   maintained as attributes of entries.  Most of these attributes have
   syntaxes which are human-readable strings, and it is desirable to be
   able to indicate the natural language associated with attribute
   values.

   This document describes how language tags and ranges [RFC3066] are
   carried in LDAP and are to be interpreted by LDAP implementations.
   All LDAP implementations MUST be prepared to accept language tags and
   ranges.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].




Zeilenga                    Standards Track                     [Page 1]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   This document replaces RFC 2596.  Appendix A summaries changes made
   since RFC 2596.

   Appendix B discusses differences from X.500(1997) "contexts"
   mechanism.

   Appendix A and B are provided for informational purposes only.

   The remainder of this section provides a summary of Language Tags,
   Language Ranges, and Attribute Descriptions.

1.1.  Language Tags

   Section 2 of BCP 47 [RFC3066] describes the language tag format which
   is used in LDAP.  Briefly, it is a string of [ASCII] letters and
   hyphens.  Examples include "fr", "en-US" and "ja-JP".  Language tags
   are case insensitive.  That is, the language tag "en-us" is the same
   as "EN-US".

   Section 2 of this document details use of language tags in LDAP.

1.2.  Language Ranges

   Section 2.5 of BCP 47 [RFC3066] describes the language ranges.
   Language ranges are used to specify sets of language tags.

   A language range matches a language tag if it is exactly equal to the
   tag, or if it is exactly equal to a prefix of the tag such that the
   first character following the prefix is "-".  That is, the language
   range "de" matches the language tags "de" and "de-CH" but not "den".
   The special language range "*" matches all language tags.

   Due to attribute description option naming restrictions in LDAP, this
   document defines a different language range syntax.  However, the
   semantics of language ranges in LDAP are consistent with BCP 47.

   Section 3 of this document details use of language ranges in LDAP.

1.3.  Attribute Descriptions

   This section provides an overview of attribute descriptions in LDAP.
   LDAP attributes and attribute descriptions are defined in [RFC2251].

   An attribute consists of a type, a set of zero or more associated
   tagging options, and a set of one or more values.  The type and the
   options are combined into the AttributeDescription.





Zeilenga                    Standards Track                     [Page 2]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   AttributeDescriptions can also contain options which are not part of
   the attribute, but indicate some other function (such as range
   assertion or transfer encoding).

   An AttributeDescription with one or more tagging options is a direct
   subtype of each AttributeDescription of the same type with all but
   one of the tagging options.  If the AttributeDescription's type is a
   direct subtype of some other type, then the AttributeDescription is
   also a direct subtype of the AttributeDescription which consists of
   the supertype and all of the tagging options.  That is,
   "CN;x-bar;x-foo" is a direct subtype of "CN;x-bar", "CN;x-foo", and
   "name;x-bar;x-foo".  Note that "CN" is a subtype of "name".

2.  Use of Language Tags in LDAP

   This section describes how LDAP implementations MUST interpret
   language tags in performing operations.

   Servers which support storing attributes with language tag options in
   the Directory Information Tree (DIT) SHOULD allow any attribute type
   it recognizes that has the Directory String, IA5 String, or other
   textual string syntaxes to have language tag options associated with
   it.  Servers MAY allow language options to be associated with other
   attributes types.

   Clients SHOULD NOT assume servers are capable of storing attributes
   with language tags in the directory.

   Implementations MUST NOT otherwise interpret the structure of the tag
   when comparing two tags, and MUST treat them simply as strings of
   characters.  Implementations MUST allow any arbitrary string which
   conforms to the syntax defined in BCP 47 [RFC3066] to be used as a
   language tag.

2.1.  Language Tag Options

   A language tag option associates a natural language with values of an
   attribute.  An attribute description may contain multiple language
   tag options.  An entry may contain multiple attributes with same
   attribute type but different combinations of language tag (and other)
   options.

   A language tag option conforms to the following ABNF [RFC2234]:

      language-tag-option = "lang-" Language-Tag






Zeilenga                    Standards Track                     [Page 3]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   where the Language-Tag production is as defined in BCP 47 [RFC3066].
   This production and those it imports from [RFC2234] are provided here
   for convenience:

      Language-Tag = Primary-subtag *( "-" Subtag )

      Primary-subtag = 1*8ALPHA

      Subtag = 1*8(ALPHA / DIGIT)

      ALPHA = %x41-5A / %x61-7A   ; A-Z / a-z

      DIGIT = %x30-39             ; 0-9

   A language tag option is a tagging option.  A language tag option has
   no effect on the syntax of the attribute's values nor their transfer
   encoding.

   Examples of valid AttributeDescription:

      givenName;lang-en-US
      CN;lang-ja
      SN;lang-de;lang-gem-PFL
      O;lang-i-klingon;x-foobar
      description;x-foobar
      CN

   Notes: The last two have no language tag options.  The x-foobar
          option is fictious and used for example purposes.

2.2.  Search Filter

   If language tag options are present in an AttributeDescription in an
   assertion, then for each entry within scope, the values of each
   attribute whose AttributeDescription consists of the same attribute
   type or its subtypes and contains each of the presented (and possibly
   other) options is to be matched.

   Thus, for example, a filter of an equality match of type
   "name;lang-en-US" and assertion value "Billy Ray", against the
   following directory entry:

   dn: SN=Ray,DC=example,DC=com
   objectClass: person                 DOES NOT MATCH (wrong type)
   objectClass: extensibleObject       DOES NOT MATCH (wrong type)
   name;lang-en-US: Billy Ray          MATCHES
   name;lang-en-US: Billy Bob          DOES NOT MATCH (wrong value)
   CN;lang-en-US: Billy Ray            MATCHES



Zeilenga                    Standards Track                     [Page 4]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   CN;lang-en-US;x-foobar: Billy Ray   MATCHES
   CN;lang-en;x-foobar: Billy Ray      DOES NOT MATCH (differing lang-)
   CN;x-foobar: Billy Ray              DOES NOT MATCH (no lang-)
   name: Billy Ray                     DOES NOT MATCH (no lang-)
   SN;lang-en-GB;lang-en-US: Billy Ray MATCHES
   SN: Ray                             DOES NOT MATCH (no lang-,
                                           wrong value)

   Note that "CN" and "SN" are subtypes of "name".

   It is noted that providing a language tag option in a search filter
   AttributeDescription will filter out desirable values where the tag
   does not match exactly.  For example, the filter (name;lang-en=Billy
   Ray) does NOT match the attribute "name;lang-en-US:  Billy Ray".

   If the server does not support storing attributes with language tag
   options in the DIT, then any assertion which includes a language tag
   option will not match as such it is an unrecognized attribute type.
   No error would be returned because of this; a presence assertion
   would evaluate to FALSE and all other assertions to Undefined.

   If no options are specified in the assertion, then only the base
   attribute type and the assertion value need match the value in the
   directory.

   Thus, for example, a filter of an equality match of type "name" and
   assertion value "Billy Ray", against the following directory entry:

      dn: SN=Ray,DC=example,DC=com
      objectClass: person                 DOES NOT MATCH (wrong type)
      objectClass: extensibleObject       DOES NOT MATCH (wrong type)
      name;lang-en-US: Billy Ray          MATCHES
      name;lang-en-US: Billy Bob          DOES NOT MATCH (wrong value)
      CN;lang-en-US;x-foobar: Billy Ray   MATCHES
      CN;lang-en;x-foobar: Billy Ray      MATCHES
      CN;x-foobar: Billy Ray              MATCHES
      name: Billy Ray                     MATCHES
      SN;lang-en-GB;lang-en-US: Billy Ray MATCHES
      SN: Ray                             DOES NOT MATCH (wrong value)

2.3.  Requested Attributes in Search

   Clients can provide language tag options in each AttributeDescription
   in the requested attribute list in a search request.

   If language tag options are provided in an attribute description,
   then only attributes in a directory entry whose attribute
   descriptions have the same attribute type or its subtype and contains



Zeilenga                    Standards Track                     [Page 5]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   each of the presented (and possibly other) language tag options are
   to be returned.  Thus if a client requests just the attribute
   "name;lang-en", the server would return "name;lang-en" and
   "CN;lang-en;lang-ja" but not "SN" nor "name;lang-fr".

   Clients can provide in the attribute list multiple
   AttributeDescriptions which have the same base attribute type but
   different options.  For example, a client could provide both
   "name;lang-en" and "name;lang-fr", and this would permit an attribute
   with either language tag option to be returned.  Note there would be
   no need to provide both "name" and "name;lang-en" since all subtypes
   of name would match "name".

   If a server does not support storing attributes with language tag
   options in the DIT, then any attribute descriptions in the list which
   include language tag options are to be ignored, just as if they were
   unknown attribute types.

   If a request is made specifying all attributes or an attribute is
   requested without providing a language tag option, then all attribute
   values regardless of their language tag option are returned.

   For example, if the client requests a "description" attribute, and a
   matching entry contains the following attributes:

      objectClass: top
      objectClass: organization
      O: Software GmbH
      description: software products
      description;lang-en: software products
      description;lang-de: Softwareprodukte

   The server would return:

      description: software products
      description;lang-en: software products
      description;lang-de: Softwareprodukte

2.4.  Compare

   Language tag options can be present in an AttributeDescription used
   in a compare request AttributeValueAssertion.  This is to be treated
   by servers the same as the use of language tag options in a search
   filter with an equality match, as described in Section 2.2.  If there
   is no attribute in the entry with the same attribute type or its
   subtype and contains each of the presented (or possibly other)
   language tag options, the noSuchAttributeType error will be returned.




Zeilenga                    Standards Track                     [Page 6]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   Thus, for example, a compare request of type "name" and assertion
   value "Johann", against an entry containing the following attributes:

      objectClass: top
      objectClass: person
      givenName;lang-de-DE: Johann
      CN: Johann Sibelius
      SN: Sibelius

   would cause the server to return compareTrue.

   However, if the client issued a compare request of type
   "name;lang-de" and assertion value "Johann" against the above entry,
   the request would fail with the noSuchAttributeType error.

   If the server does not support storing attributes with language tag
   options in the DIT, then any comparison which includes a language tag
   option will always fail to locate an attribute, and
   noSuchAttributeType will be returned.

2.5.  Add Operation

   Clients can provide language options in AttributeDescription in
   attributes of a new entry to be created.

   A client can provide multiple attributes with the same attribute type
   and value, so long as each attribute has a different set of language
   tag options.

   For example, the following is a valid request:

      dn: CN=John Smith,DC=example,DC=com
      objectClass: residentialPerson
      CN: John Smith
      CN;lang-en: John Smith
      SN: Smith
      SN;lang-en: Smith
      streetAddress: 1 University Street
      streetAddress;lang-en-US: 1 University Street
      streetAddress;lang-fr: 1 rue Universite
      houseIdentifier;lang-fr: 9e etage

   If a server does not support storing language tag options with
   attribute values in the DIT, then it MUST treat an
   AttributeDescription with a language tag option as an unrecognized
   attribute.  If the server forbids the addition of unrecognized
   attributes then it MUST fail the add request with an appropriate
   result code.



Zeilenga                    Standards Track                     [Page 7]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


2.6.  Modify Operation

   A client can provide language tag options in an AttributeDescription
   as part of a modification element in the modify operation.

   Attribute types and language tag options MUST match exactly against
   values stored in the directory.  For example, if the modification is
   a "delete", then if the stored values to be deleted have language tag
   options, then those language tag options MUST be provided in the
   modify operation, and if the stored values to be deleted do not have
   any language tag option, then no language tag option is to be
   provided.

   If the server does not support storing language tag options with
   attribute values in the DIT, then it MUST treat an
   AttributeDescription with a language tag option as an unrecognized
   attribute, and MUST fail the request with an appropriate result code.

3.  Use of Language Ranges in LDAP

   Since the publication of RFC 2596, it has become apparent that there
   is a need to provide a mechanism for a client to request attributes
   based upon set of language tag options whose tags all begin with the
   same sequence of language sub-tags.

   AttributeDescriptions containing language range options are intended
   to be used in attribute value assertions, search attribute lists, and
   other places where the client desires to provide an attribute
   description matching of a range of language tags associated with
   attributes.

   A language range option conforms to the following ABNF [RFC2234]:

      language-range-option = "lang-" [ Language-Tag "-" ]

   where the Language-Tag production is as defined in BCP 47 [RFC3066].
   This production and those it imports from [RFC2234] are provided in
   Section 2.1 for convenience.

   A language range option matches a language tag option if the language
   range option less the trailing "-" matches exactly the language tag
   or if the language range option (including the trailing "-") matches
   a prefix of the language tag option.  Note that the language range
   option "lang-" matches all language tag options.







Zeilenga                    Standards Track                     [Page 8]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   Examples of valid AttributeDescription containing language range
   options:

      givenName;lang-en-
      CN;lang-
      SN;lang-de-;lang-gem-
      O;lang-x-;x-foobar

   A language range option is not a tagging option.  Attributes cannot
   be stored with language range options.  Any attempt to add or update
   an attribute description with a language range option SHALL be
   treated as an undefined attribute type and result in an error.

   A language range option has no effect on the transfer encoding nor on
   the syntax of the attribute values.

   Servers SHOULD support assertion of language ranges for any attribute
   type which they allow to be stored with language tags.

3.1.  Search Filter

   If a language range option is present in an AttributeDescription in
   an assertion, then for each entry within scope, the values of each
   attribute whose AttributeDescription consists of the same attribute
   type or its subtypes and contains a language tag option matching the
   language range option are to be returned.

   Thus, for example, a filter of an equality match of type
   "name;lang-en-" and assertion value "Billy Ray", against the
   following directory entry:

      dn: SN=Ray,DC=example,DC=com
      objectClass: person                 DOES NOT MATCH (wrong type)
      objectClass: extensibleObject       DOES NOT MATCH (wrong type)
      name;lang-en-US: Billy Ray          MATCHES
      name;lang-en-US: Billy Bob          DOES NOT MATCH (wrong value)
      CN;lang-en-US: Billy Ray            MATCHES
      CN;lang-en-US;x-foobar: Billy Ray   MATCHES
      CN;lang-en;x-foobar: Billy Ray      MATCHES
      CN;x-foobar: Billy Ray              DOES NOT MATCH (no lang-)
      name: Billy Ray                     DOES NOT MATCH (no lang-)
      SN;lang-en-GB;lang-en-US: Billy Ray MATCHES
      SN: Ray                             DOES NOT MATCH (no lang-,
                                            wrong value)

   Note that "CN" and "SN" are subtypes of "name".





Zeilenga                    Standards Track                     [Page 9]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   If the server does not support storing attributes with language tag
   options in the DIT, then any assertion which includes a language
   range option will not match as it is an unrecognized attribute type.
   No error would be returned because of this; a presence filter would
   evaluate to FALSE and all other assertions to Undefined.

3.2.  Requested Attributes in Search

   Clients can provide language range options in each
   AttributeDescription in the requested attribute list in a search
   request.

   If a language range option is provided in an attribute description,
   then only attributes in a directory entry whose attribute
   descriptions have the same attribute type or its subtype and a
   language tag option matching the provided language range option are
   to be returned.  Thus if a client requests just the attribute
   "name;lang-en-", the server would return "name;lang-en-US" and
   "CN;lang-en;lang-ja" but not "SN" nor "name;lang-fr".

   Clients can provide in the attribute list multiple
   AttributeDescriptions which have the same base attribute type but
   different options.  For example a client could provide both
   "name;lang-en-" and "name;lang-fr-", and this would permit an
   attribute whose type was name or subtype of name and with a language
   tag option matching either language range option to be returned.

   If a server does not support storing attributes with language tag
   options in the DIT, then any attribute descriptions in the list which
   include language range options are to be ignored, just as if they
   were unknown attribute types.

3.3.  Compare

   Language range options can be present in an AttributeDescription used
   in a compare request AttributeValueAssertion.  This is to be treated
   by servers the same as the use of language range options in a search
   filter with an equality match, as described in Section 3.1.  If there
   is no attribute in the entry with the same subtype and a matching
   language tag option, the noSuchAttributeType error will be returned.

   Thus, for example, a compare request of type "name;lang-" and
   assertion value "Johann", against the entry with the following
   attributes:







Zeilenga                    Standards Track                    [Page 10]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


      objectClass: top
      objectClass: person
      givenName;lang-de-DE: Johann
      CN: Johann Sibelius
      SN: Sibelius

   will cause the server to return compareTrue.  (Note that the language
   range option "lang-" matches any language tag option.)

   However, if the client issued a compare request of type
   "name;lang-de" and assertion value "Sibelius" against the above
   entry, the request would fail with the noSuchAttributeType error.

   If the server does not support storing attributes with language tag
   options in the DIT, then any comparison which includes a language
   range option will always fail to locate an attribute, and
   noSuchAttributeType will be returned.

4.  Discovering Language Option Support

   A server SHOULD indicate that it supports storing attributes with
   language tag options in the DIT by publishing 1.3.6.1.4.1.4203.1.5.4
   as a value of the root DSE.

   A server SHOULD indicate that it supports language range matching of
   attributes with language tag options stored in the DIT by publishing
   1.3.6.1.4.1.4203.1.5.5 as a value of the "supportedFeatures"
   [RFC3674] attribute in the root DSE.

   A server MAY restrict use of language tag options to a subset of the
   attribute types it recognizes.  This document does not define a
   mechanism for determining which subset of attribute types can be used
   with language tag options.

5.  Interoperability with Non-supporting Implementations

   Implementators of this specification should take care that their use
   of language tag options does not impede proper function of
   implementations which do not support language tags.

   Per RFC 2251, "an AttributeDescription with one or more options is
   treated as a subtype of the attribute type without any options."  A
   non-supporting server will treat an AttributeDescription with any
   language tag options as an unrecognized attribute type.  A non-
   supporting client will either do the same, or will treat the
   AttributeDescription as it would any other unknown subtype.
   Typically, non-supporting clients simply ignore unrecognized subtypes
   (and unrecognized attribute types) of attributes they request.



Zeilenga                    Standards Track                    [Page 11]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


   To ensure proper function of non-supporting clients, supporting
   clients SHOULD ensure that entries they populate with tagged values
   are also populated with non-tagged values.

   Additionally, supporting clients SHOULD be prepared to handle entries
   which are not populated with tagged values.

6.  Security Considerations

   Language tags and range options are used solely to indicate the
   native language of values and in querying the directory for values
   which fulfill the user's language needed.  These options are not
   known to raise specific security considerations.  However, the reader
   should consider general directory security issues detailed in the
   LDAP technical specification [RFC3377].

7.  IANA Considerations

   Registration of these protocol mechanisms [RFC3383] has been
   completed by the IANA.

   Subject: Request for LDAP Protocol Mechanism Registration
   Object Identifier: 1.3.6.1.4.1.4203.1.5.4
   Description: Language Tag Options
   Object Identifier: 1.3.6.1.4.1.4203.1.5.5
   Description: Language Range Options
   Person & email address to contact for further information:
        Kurt Zeilenga <kurt@openldap.org>
   Usage: Feature
   Specification: RFC 3866
   Author/Change Controller: IESG
   Comments: none

   These OIDs were assigned [ASSIGN] by OpenLDAP Foundation, under its
   IANA-assigned private enterprise allocation [PRIVATE], for use in
   this specification.

8.  Acknowledgments

   This document is a revision of RFC 2596 by Mark Wahl and Tim Howes.
   RFC 2596 was a product of the IETF ASID and LDAPEXT working groups.
   This document also borrows from a number of IETF documents including
   BCP 47 by H. Alvestrand.








Zeilenga                    Standards Track                    [Page 12]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


9.  References

9.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2234]     Crocker, D., Ed. and P. Overell, "Augmented BNF for
                 Syntax Specifications: ABNF", RFC 2234, November 1997.

   [RFC2251]     Wahl, M., Howes, T. and S. Kille, "Lightweight
                 Directory Access Protocol (v3)", RFC 2251, December
                 1997.

   [RFC3066]     Alvestrand, H., "Tags for the Identification of
                 Languages", BCP 47, RFC 3066, January 2001.

   [RFC3377]     Hodges, J. and R. Morgan, "Lightweight Directory Access
                 Protocol (v3): Technical Specification", RFC 3377,
                 September 2002.

   [RFC3674]     Zeilenga, K., "Feature Discovery in Lightweight
                 Directory Access Protocol (LDAP)", RFC 3674, December
                 2003.

   [ASCII]       Coded Character Set--7-bit American Standard Code for
                 Information Interchange, ANSI X3.4-1986.

9.2.  Informative References

   [X.501]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Models," X.501(1997).

   [RFC3383]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for Lightweight Directory Access
                 Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [ASSIGN]      OpenLDAP Foundation, "OpenLDAP OID Delegations",
                 http://www.openldap.org/foundation/oid-delegate.txt.

   [PRIVATE]     IANA, "Private Enterprise Numbers",
                 http://www.iana.org/assignments/enterprise-numbers.








Zeilenga                    Standards Track                    [Page 13]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


Appendix A. Differences from RFC 2596

   This document adds support for language ranges, provides a mechanism
   that a client can use to discover whether a server supports language
   tags and ranges, and clarifies how attributes with multiple language
   tags are to be treated.  This document is a significant rewrite of
   RFC 2596.

Appendix B. Differences from X.500(1997)

   X.500(1997) [X.501] defines a different mechanism, contexts, as the
   means of representing language tags (codes).  This section summarizes
   the major differences in approach.

   a) An X.500 operation which has specified a language code on a value
      matches a value in the directory without a language code.

   b) LDAP references BCP 47 [RFC3066], which allows for IANA
      registration of new tags as well as unregistered tags.

   c) LDAP supports language ranges (new in this revision).

   d) LDAP does not allow language tags (and ranges) in distinguished
      names.

   e) X.500 describes subschema administration procedures to allow
      language codes to be associated with particular attributes types.

Editor's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org

















Zeilenga                    Standards Track                    [Page 14]

RFC 3866            Language Tags and Ranges in LDAP           July 2004


Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at ietf-
   ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.









Zeilenga                    Standards Track                    [Page 15]

alt-openldap11-devel/rfc/rfc4510.txt000064400000030102150410163210012747 0ustar00





Network Working Group                                   K. Zeilenga, Ed.
Request for Comments: 4510                           OpenLDAP Foundation
Obsoletes: 2251, 2252, 2253, 2254, 2255,                       June 2006
           2256, 2829, 2830, 3377, 3771
Category: Standards Track


             Lightweight Directory Access Protocol (LDAP):
                    Technical Specification Road Map

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   The Lightweight Directory Access Protocol (LDAP) is an Internet
   protocol for accessing distributed directory services that act in
   accordance with X.500 data and service models.  This document
   provides a road map of the LDAP Technical Specification.

1.  The LDAP Technical Specification

   The technical specification detailing version 3 of the Lightweight
   Directory Access Protocol (LDAP), an Internet Protocol, consists of
   this document and the following documents:

      LDAP: The Protocol [RFC4511]
      LDAP: Directory Information Models [RFC4512]
      LDAP: Authentication Methods and Security Mechanisms [RFC4513]
      LDAP: String Representation of Distinguished Names [RFC4514]
      LDAP: String Representation of Search Filters [RFC4515]
      LDAP: Uniform Resource Locator [RFC4516]
      LDAP: Syntaxes and Matching Rules [RFC4517]
      LDAP: Internationalized String Preparation [RFC4518]
      LDAP: Schema for User Applications [RFC4519]







Zeilenga                    Standards Track                     [Page 1]

RFC 4510                   LDAP: TS Road Map                   June 2006


   The terms "LDAP" and "LDAPv3" are commonly used to refer informally
   to the protocol specified by this technical specification.  The LDAP
   suite, as defined here, should be formally identified in other
   documents by a normative reference to this document.

   LDAP is an extensible protocol.  Extensions to LDAP may be specified
   in other documents.  Nomenclature denoting such combinations of
   LDAP-plus-extensions is not defined by this document but may be
   defined in some future document(s).  Extensions are expected to be
   truly optional.  Considerations for the LDAP extensions described in
   BCP 118, RFC 4521 [RFC4521] fully apply to this revision of the LDAP
   Technical Specification.

   IANA (Internet Assigned Numbers Authority) considerations for LDAP
   described in BCP 64, RFC 4520 [RFC4520] apply fully to this revision
   of the LDAP technical specification.

1.1.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

2.  Relationship to X.500

   This technical specification defines LDAP in terms of [X.500] as an
   X.500 access mechanism.  An LDAP server MUST act in accordance with
   the X.500 (1993) series of International Telecommunication Union -
   Telecommunication Standardization (ITU-T) Recommendations when
   providing the service.  However, it is not required that an LDAP
   server make use of any X.500 protocols in providing this service.
   For example, LDAP can be mapped onto any other directory system so
   long as the X.500 data and service models [X.501][X.511], as used in
   LDAP, are not violated in the LDAP interface.

   This technical specification explicitly incorporates portions of
   X.500(93).  Later revisions of X.500 do not automatically apply to
   this technical specification.

3.  Relationship to Obsolete Specifications

   This technical specification, as defined in Section 1, obsoletes
   entirely the previously defined LDAP technical specification defined
   in RFC 3377 (and consisting of RFCs 2251-2256, 2829, 2830, 3771, and
   3377 itself).  The technical specification was significantly
   reorganized.





Zeilenga                    Standards Track                     [Page 2]

RFC 4510                   LDAP: TS Road Map                   June 2006


   This document replaces RFC 3377 as well as Section 3.3 of RFC 2251.
   [RFC4512] replaces portions of RFC 2251, RFC 2252, and RFC 2256.
   [RFC4511] replaces the majority RFC 2251, portions of RFC 2252, and
   all of RFC 3771.  [RFC4513] replaces RFC 2829, RFC 2830, and portions
   of RFC 2251.  [RFC4517] replaces the majority of RFC 2252 and
   portions of RFC 2256.  [RFC4519] replaces the majority of RFC 2256.
   [RFC4514] replaces RFC 2253.  [RFC4515] replaces RFC 2254.  [RFC4516]
   replaces RFC 2255.

   [RFC4518] is new to this revision of the LDAP technical
   specification.

   Each document of this specification contains appendices summarizing
   changes to all sections of the specifications they replace.  Appendix
   A.1 of this document details changes made to RFC 3377.  Appendix A.2
   of this document details changes made to Section 3.3 of RFC 2251.

   Additionally, portions of this technical specification update and/or
   replace a number of other documents not listed above.  These
   relationships are discussed in the documents detailing these portions
   of this technical specification.

4.  Security Considerations

   LDAP security considerations are discussed in each document
   comprising the technical specification.

5.  Acknowledgements

   This document is based largely on RFC 3377 by J. Hodges and R.
   Morgan, a product of the LDAPBIS and LDAPEXT Working Groups.  The
   document also borrows from RFC 2251 by M. Wahl, T. Howes, and S.
   Kille, a product of the ASID Working Group.

   This document is a product of the IETF LDAPBIS Working Group.
















Zeilenga                    Standards Track                     [Page 3]

RFC 4510                   LDAP: TS Road Map                   June 2006


6.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [RFC4513]     Harrison, R., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Authentication Methods and Security
                 Mechanisms", RFC 4513, June 2006.

   [RFC4514]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): String Representation of Distinguished
                 Names", RFC 4514, June 2006.

   [RFC4515]     Smith, M., Ed. and T. Howes, "Lightweight Directory
                 Access Protocol (LDAP): String Representation of Search
                 Filters", RFC 4515, June 2006.

   [RFC4516]     Smith, M., Ed. and T. Howes, "Lightweight Directory
                 Access Protocol (LDAP): Uniform Resource Locator", RFC
                 4516, June 2006.

   [RFC4517]     Legg, S., Ed., "Lightweight Directory Access Protocol
                 (LDAP): Syntaxes and Matching Rules", RFC 4517, June
                 2006.

   [RFC4518]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Internationalized String Preparation", RFC
                 4518, June 2006.

   [RFC4519]     Sciberras, A., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Schema for User Applications", RFC
                 4519, June 2006.

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [RFC4521]     Zeilenga, K., "Considerations for LDAP Extensions", BCP
                 118, RFC 4521, June 2006.





Zeilenga                    Standards Track                     [Page 4]

RFC 4510                   LDAP: TS Road Map                   June 2006


   [X.500]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Overview of concepts, models and
                 services", X.500(1993) (also ISO/IEC 9594-1:1994).

   [X.501]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Models", X.501(1993) (also ISO/IEC 9594-
                 2:1994).

   [X.511]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory: Abstract Service Definition", X.511(1993)
                 (also ISO/IEC 9594-3:1993).





































Zeilenga                    Standards Track                     [Page 5]

RFC 4510                   LDAP: TS Road Map                   June 2006


Appendix A.  Changes to Previous Documents

   This appendix outlines changes this document makes relative to the
   documents it replaces (in whole or in part).

A.1. Changes to RFC 3377

   This document is nearly a complete rewrite of RFC 3377 as much of the
   material of RFC 3377 is no longer applicable.  The changes include
   redefining the terms "LDAP" and "LDAPv3" to refer to this revision of
   the technical specification.

A.2. Changes to Section 3.3 of RFC 2251

   The section was modified slightly (the word "document" was replaced
   with "technical specification") to clarify that it applies to the
   entire LDAP technical specification.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org



























Zeilenga                    Standards Track                     [Page 6]

RFC 4510                   LDAP: TS Road Map                   June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                     [Page 7]

alt-openldap11-devel/rfc/rfc4513.txt000064400000235242150410163210012766 0ustar00





Network Working Group                                   R. Harrison, Ed.
Request for Comments: 4513                                  Novell, Inc.
Obsoletes: 2251, 2829, 2830                                    June 2006
Category: Standards Track


             Lightweight Directory Access Protocol (LDAP):
             Authentication Methods and Security Mechanisms

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document describes authentication methods and security
   mechanisms of the Lightweight Directory Access Protocol (LDAP).  This
   document details establishment of Transport Layer Security (TLS)
   using the StartTLS operation.

   This document details the simple Bind authentication method including
   anonymous, unauthenticated, and name/password mechanisms and the
   Simple Authentication and Security Layer (SASL) Bind authentication
   method including the EXTERNAL mechanism.

   This document discusses various authentication and authorization
   states through which a session to an LDAP server may pass and the
   actions that trigger these state changes.

   This document, together with other documents in the LDAP Technical
   Specification (see Section 1 of the specification's road map),
   obsoletes RFC 2251, RFC 2829, and RFC 2830.











Harrison                    Standards Track                     [Page 1]

RFC 4513              LDAP Authentication Methods              June 2006


Table of Contents

   1. Introduction ....................................................4
      1.1. Relationship to Other Documents ............................6
      1.2. Conventions ................................................6
   2. Implementation Requirements .....................................7
   3. StartTLS Operation ..............................................8
      3.1.  TLS Establishment Procedures ..............................8
           3.1.1. StartTLS Request Sequencing .........................8
           3.1.2. Client Certificate ..................................9
           3.1.3. Server Identity Check ...............................9
                  3.1.3.1. Comparison of DNS Names ...................10
                  3.1.3.2. Comparison of IP Addresses ................11
                  3.1.3.3. Comparison of Other subjectName Types .....11
           3.1.4. Discovery of Resultant Security Level ..............11
           3.1.5. Refresh of Server Capabilities Information .........11
      3.2.  Effect of TLS on Authorization State .....................12
      3.3. TLS Ciphersuites ..........................................12
   4. Authorization State ............................................13
   5. Bind Operation .................................................14
      5.1. Simple Authentication Method ..............................14
           5.1.1. Anonymous Authentication Mechanism of Simple Bind ..14
           5.1.2. Unauthenticated Authentication Mechanism of
                  Simple Bind ........................................14
           5.1.3. Name/Password Authentication Mechanism of
                  Simple Bind ........................................15
      5.2. SASL Authentication Method ................................16
           5.2.1. SASL Protocol Profile ..............................16
                  5.2.1.1. SASL Service Name for LDAP ................16
                  5.2.1.2. SASL Authentication Initiation and
                           Protocol Exchange .........................16
                  5.2.1.3. Optional Fields ...........................17
                  5.2.1.4. Octet Where Negotiated Security
                           Layers Take Effect ........................18
                  5.2.1.5. Determination of Supported SASL
                           Mechanisms ................................18
                  5.2.1.6. Rules for Using SASL Layers ...............19
                  5.2.1.7. Support for Multiple Authentications ......19
                  5.2.1.8. SASL Authorization Identities .............19
           5.2.2. SASL Semantics within LDAP .........................20
           5.2.3. SASL EXTERNAL Authentication Mechanism .............20
                  5.2.3.1. Implicit Assertion ........................21
                  5.2.3.2. Explicit Assertion ........................21
   6. Security Considerations ........................................21
      6.1. General LDAP Security Considerations ......................21
      6.2. StartTLS Security Considerations ..........................22
      6.3. Bind Operation Security Considerations ....................23
           6.3.1. Unauthenticated Mechanism Security Considerations ..23



Harrison                    Standards Track                     [Page 2]

RFC 4513              LDAP Authentication Methods              June 2006


           6.3.2. Name/Password Mechanism Security Considerations ....23
           6.3.3. Password-Related Security Considerations ...........23
           6.3.4. Hashed Password Security Considerations ............24
      6.4. SASL Security Considerations ..............................24
      6.5. Related Security Considerations ...........................25
   7. IANA Considerations ............................................25
   8. Acknowledgements ...............................................25
   9. Normative References ...........................................26
   10. Informative References ........................................27
   Appendix A. Authentication and Authorization Concepts .............28
      A.1. Access Control Policy .....................................28
      A.2. Access Control Factors ....................................28
      A.3. Authentication, Credentials, Identity .....................28
      A.4. Authorization Identity ....................................29
   Appendix B. Summary of Changes ....................................29
      B.1. Changes Made to RFC 2251 ..................................30
           B.1.1. Section 4.2.1 ("Sequencing of the Bind Request") ...30
           B.1.2. Section 4.2.2 ("Authentication and Other Security
                  Services") .........................................30
      B.2. Changes Made to RFC 2829 ..................................30
           B.2.1. Section 4 ("Required security mechanisms") .........30
           B.2.2. Section 5.1 ("Anonymous authentication
                  procedure") ........................................31
           B.2.3. Section 6 ("Password-based authentication") ........31
           B.2.4. Section 6.1 ("Digest authentication") ..............31
           B.2.5. Section 6.2 ("'simple' authentication choice under
                  TLS encryption") ...................................31
           B.2.6. Section 6.3 ("Other authentication choices with
                  TLS") ..............................................31
           B.2.7. Section 7.1 ("Certificate-based authentication
                  with TLS") .........................................31
           B.2.8. Section 8 ("Other mechanisms") .....................32
           B.2.9. Section 9 ("Authorization Identity") ...............32
           B.2.10. Section 10 ("TLS Ciphersuites") ...................32
      B.3. Changes Made to RFC 2830 ..................................32
           B.3.1. Section 3.6 ("Server Identity Check") ..............32
           B.3.2. Section 3.7 ("Refresh of Server Capabilities
                  Information") ......................................33
           B.3.3. Section 5 ("Effects of TLS on a Client's
                  Authorization Identity") ...........................33
           B.3.4. Section 5.2 ("TLS Connection Closure Effects") .....33










Harrison                    Standards Track                     [Page 3]

RFC 4513              LDAP Authentication Methods              June 2006


1.  Introduction

   The Lightweight Directory Access Protocol (LDAP) [RFC4510] is a
   powerful protocol for accessing directories.  It offers means of
   searching, retrieving, and manipulating directory content and ways to
   access a rich set of security functions.

   It is vital that these security functions be interoperable among all
   LDAP clients and servers on the Internet; therefore there has to be a
   minimum subset of security functions that is common to all
   implementations that claim LDAP conformance.

   Basic threats to an LDAP directory service include (but are not
   limited to):

   (1) Unauthorized access to directory data via data-retrieval
       operations.

   (2) Unauthorized access to directory data by monitoring access of
       others.

   (3) Unauthorized access to reusable client authentication information
       by monitoring access of others.

   (4) Unauthorized modification of directory data.

   (5) Unauthorized modification of configuration information.

   (6) Denial of Service: Use of resources (commonly in excess) in a
       manner intended to deny service to others.

   (7) Spoofing: Tricking a user or client into believing that
       information came from the directory when in fact it did not,
       either by modifying data in transit or misdirecting the client's
       transport connection.  Tricking a user or client into sending
       privileged information to a hostile entity that appears to be the
       directory server but is not.  Tricking a directory server into
       believing that information came from a particular client when in
       fact it came from a hostile entity.

   (8) Hijacking: An attacker seizes control of an established protocol
       session.

   Threats (1), (4), (5), (6), (7), and (8) are active attacks.  Threats
   (2) and (3) are passive attacks.






Harrison                    Standards Track                     [Page 4]

RFC 4513              LDAP Authentication Methods              June 2006


   Threats (1), (4), (5), and (6) are due to hostile clients.  Threats
   (2), (3), (7), and (8) are due to hostile agents on the path between
   client and server or hostile agents posing as a server, e.g., IP
   spoofing.

   LDAP offers the following security mechanisms:

   (1) Authentication by means of the Bind operation.  The Bind
       operation provides a simple method that supports anonymous,
       unauthenticated, and name/password mechanisms, and the Simple
       Authentication and Security Layer (SASL) method, which supports a
       wide variety of authentication mechanisms.

   (2) Mechanisms to support vendor-specific access control facilities
       (LDAP does not offer a standard access control facility).

   (3) Data integrity service by means of security layers in Transport
       Layer Security (TLS) or SASL mechanisms.

   (4) Data confidentiality service by means of security layers in TLS
       or SASL mechanisms.

   (5) Server resource usage limitation by means of administrative
       limits configured on the server.

   (6) Server authentication by means of the TLS protocol or SASL
       mechanisms.

   LDAP may also be protected by means outside the LDAP protocol, e.g.,
   with IP layer security [RFC4301].

   Experience has shown that simply allowing implementations to pick and
   choose the security mechanisms that will be implemented is not a
   strategy that leads to interoperability.  In the absence of mandates,
   clients will continue to be written that do not support any security
   function supported by the server, or worse, they will only support
   mechanisms that provide inadequate security for most circumstances.

   It is desirable to allow clients to authenticate using a variety of
   mechanisms including mechanisms where identities are represented as
   distinguished names [X.501][RFC4512], in string form [RFC4514], or as
   used in different systems (e.g., simple user names [RFC4013]).
   Because some authentication mechanisms transmit credentials in plain
   text form, and/or do not provide data security services and/or are
   subject to passive attacks, it is necessary to ensure secure
   interoperability by identifying a mandatory-to-implement mechanism
   for establishing transport-layer security services.




Harrison                    Standards Track                     [Page 5]

RFC 4513              LDAP Authentication Methods              June 2006


   The set of security mechanisms provided in LDAP and described in this
   document is intended to meet the security needs for a wide range of
   deployment scenarios and still provide a high degree of
   interoperability among various LDAP implementations and deployments.

1.1.  Relationship to Other Documents

   This document is an integral part of the LDAP Technical Specification
   [RFC4510].

   This document, together with [RFC4510], [RFC4511], and [RFC4512],
   obsoletes RFC 2251 in its entirety.  Sections 4.2.1 (portions) and
   4.2.2 of RFC 2251 are obsoleted by this document.  Appendix B.1
   summarizes the substantive changes made to RFC 2251 by this document.

   This document obsoletes RFC 2829 in its entirety.  Appendix B.2
   summarizes the substantive changes made to RFC 2829 by this document.

   Sections 2 and 4 of RFC 2830 are obsoleted by [RFC4511].  The
   remainder of RFC 2830 is obsoleted by this document.  Appendix B.3
   summarizes the substantive changes made to RFC 2830 by this document.

1.2.  Conventions

   The key words "MUST", "MUST NOT", "SHALL", "SHOULD", "SHOULD NOT",
   "MAY", and "OPTIONAL" in this document are to be interpreted as
   described in RFC 2119 [RFC2119].

   The term "user" represents any human or application entity that is
   accessing the directory using a directory client.  A directory client
   (or client) is also known as a directory user agent (DUA).

   The term "transport connection" refers to the underlying transport
   services used to carry the protocol exchange, as well as associations
   established by these services.

   The term "TLS layer" refers to TLS services used in providing
   security services, as well as associations established by these
   services.

   The term "SASL layer" refers to SASL services used in providing
   security services, as well as associations established by these
   services.

   The term "LDAP message layer" refers to the LDAP Message (PDU)
   services used in providing directory services, as well as
   associations established by these services.




Harrison                    Standards Track                     [Page 6]

RFC 4513              LDAP Authentication Methods              June 2006


   The term "LDAP session" refers to combined services (transport
   connection, TLS layer, SASL layer, LDAP message layer) and their
   associations.

   In general, security terms in this document are used consistently
   with the definitions provided in [RFC2828].  In addition, several
   terms and concepts relating to security, authentication, and
   authorization are presented in Appendix A of this document.  While
   the formal definition of these terms and concepts is outside the
   scope of this document, an understanding of them is prerequisite to
   understanding much of the material in this document.  Readers who are
   unfamiliar with security-related concepts are encouraged to review
   Appendix A before reading the remainder of this document.

2.  Implementation Requirements

   LDAP server implementations MUST support the anonymous authentication
   mechanism of the simple Bind method (Section 5.1.1).

   LDAP implementations that support any authentication mechanism other
   than the anonymous authentication mechanism of the simple Bind method
   MUST support the name/password authentication mechanism of the simple
   Bind method (Section 5.1.3) and MUST be capable of protecting this
   name/password authentication using TLS as established by the StartTLS
   operation (Section 3).

   Implementations SHOULD disallow the use of the name/password
   authentication mechanism by default when suitable data security
   services are not in place, and they MAY provide other suitable data
   security services for use with this authentication mechanism.

   Implementations MAY support additional authentication mechanisms.
   Some of these mechanisms are discussed below.

   LDAP server implementations SHOULD support client assertion of
   authorization identity via the SASL EXTERNAL mechanism (Section
   5.2.3).

   LDAP server implementations that support no authentication mechanism
   other than the anonymous mechanism of the simple bind method SHOULD
   support use of TLS as established by the StartTLS operation (Section
   3).  (Other servers MUST support TLS per the second paragraph of this
   section.)








Harrison                    Standards Track                     [Page 7]

RFC 4513              LDAP Authentication Methods              June 2006


   Implementations supporting TLS MUST support the
   TLS_RSA_WITH_3DES_EDE_CBC_SHA ciphersuite and SHOULD support the
   TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA ciphersuite.  Support for the
   latter ciphersuite is recommended to encourage interoperability with
   implementations conforming to earlier LDAP StartTLS specifications.

3.  StartTLS Operation

   The Start Transport Layer Security (StartTLS) operation defined in
   Section 4.14 of [RFC4511] provides the ability to establish TLS
   [RFC4346] in an LDAP session.

   The goals of using the TLS protocol with LDAP are to ensure data
   confidentiality and integrity, and to optionally provide for
   authentication.  TLS expressly provides these capabilities, although
   the authentication services of TLS are available to LDAP only in
   combination with the SASL EXTERNAL authentication method (see Section
   5.2.3), and then only if the SASL EXTERNAL implementation chooses to
   make use of the TLS credentials.

3.1.  TLS Establishment Procedures

   This section describes the overall procedures clients and servers
   must follow for TLS establishment.  These procedures take into
   consideration various aspects of the TLS layer including discovery of
   resultant security level and assertion of the client's authorization
   identity.

3.1.1.  StartTLS Request Sequencing

   A client may send the StartTLS extended request at any time after
   establishing an LDAP session, except:

      - when TLS is currently established on the session,
      - when a multi-stage SASL negotiation is in progress on the
        session, or
      - when there are outstanding responses for operation requests
        previously issued on the session.

   As described in [RFC4511], Section 4.14.1, a (detected) violation of
   any of these requirements results in a return of the operationsError
   resultCode.

   Client implementers should ensure that they strictly follow these
   operation sequencing requirements to prevent interoperability issues.
   Operational experience has shown that violating these requirements





Harrison                    Standards Track                     [Page 8]

RFC 4513              LDAP Authentication Methods              June 2006


   causes interoperability issues because there are race conditions that
   prevent servers from detecting some violations of these requirements
   due to factors such as server hardware speed and network latencies.

   There is no general requirement that the client have or have not
   already performed a Bind operation (Section 5) before sending a
   StartTLS operation request; however, where a client intends to
   perform both a Bind operation and a StartTLS operation, it SHOULD
   first perform the StartTLS operation so that the Bind request and
   response messages are protected by the data security services
   established by the StartTLS operation.

3.1.2.  Client Certificate

   If an LDAP server requests or demands that a client provide a user
   certificate during TLS negotiation and the client does not present a
   suitable user certificate (e.g., one that can be validated), the
   server may use a local security policy to determine whether to
   successfully complete TLS negotiation.

   If a client that has provided a suitable certificate subsequently
   performs a Bind operation using the SASL EXTERNAL authentication
   mechanism (Section 5.2.3), information in the certificate may be used
   by the server to identify and authenticate the client.

3.1.3.  Server Identity Check

   In order to prevent man-in-the-middle attacks, the client MUST verify
   the server's identity (as presented in the server's Certificate
   message).  In this section, the client's understanding of the
   server's identity (typically the identity used to establish the
   transport connection) is called the "reference identity".

   The client determines the type (e.g., DNS name or IP address) of the
   reference identity and performs a comparison between the reference
   identity and each subjectAltName value of the corresponding type
   until a match is produced.  Once a match is produced, the server's
   identity has been verified, and the server identity check is
   complete.  Different subjectAltName types are matched in different
   ways.  Sections 3.1.3.1 - 3.1.3.3 explain how to compare values of
   various subjectAltName types.

   The client may map the reference identity to a different type prior
   to performing a comparison.  Mappings may be performed for all
   available subjectAltName types to which the reference identity can be
   mapped; however, the reference identity should only be mapped to
   types for which the mapping is either inherently secure (e.g.,
   extracting the DNS name from a URI to compare with a subjectAltName



Harrison                    Standards Track                     [Page 9]

RFC 4513              LDAP Authentication Methods              June 2006


   of type dNSName) or for which the mapping is performed in a secure
   manner (e.g., using DNSSEC, or using user- or admin-configured host-
   to-address/address-to-host lookup tables).

   The server's identity may also be verified by comparing the reference
   identity to the Common Name (CN) [RFC4519] value in the leaf Relative
   Distinguished Name (RDN) of the subjectName field of the server's
   certificate.  This comparison is performed using the rules for
   comparison of DNS names in Section 3.1.3.1, below, with the exception
   that no wildcard matching is allowed.  Although the use of the Common
   Name value is existing practice, it is deprecated, and Certification
   Authorities are encouraged to provide subjectAltName values instead.
   Note that the TLS implementation may represent DNs in certificates
   according to X.500 or other conventions.  For example, some X.500
   implementations order the RDNs in a DN using a left-to-right (most
   significant to least significant) convention instead of LDAP's
   right-to-left convention.

   If the server identity check fails, user-oriented clients SHOULD
   either notify the user (clients may give the user the opportunity to
   continue with the LDAP session in this case) or close the transport
   connection and indicate that the server's identity is suspect.
   Automated clients SHOULD close the transport connection and then
   return or log an error indicating that the server's identity is
   suspect or both.

   Beyond the server identity check described in this section, clients
   should be prepared to do further checking to ensure that the server
   is authorized to provide the service it is requested to provide.  The
   client may need to make use of local policy information in making
   this determination.

3.1.3.1.  Comparison of DNS Names

   If the reference identity is an internationalized domain name,
   conforming implementations MUST convert it to the ASCII Compatible
   Encoding (ACE) format as specified in Section 4 of RFC 3490 [RFC3490]
   before comparison with subjectAltName values of type dNSName.
   Specifically, conforming implementations MUST perform the conversion
   operation specified in Section 4 of RFC 3490 as follows:

      * in step 1, the domain name SHALL be considered a "stored
        string";
      * in step 3, set the flag called "UseSTD3ASCIIRules";
      * in step 4, process each label with the "ToASCII" operation; and
      * in step 5, change all label separators to U+002E (full stop).





Harrison                    Standards Track                    [Page 10]

RFC 4513              LDAP Authentication Methods              June 2006


   After performing the "to-ASCII" conversion, the DNS labels and names
   MUST be compared for equality according to the rules specified in
   Section 3 of RFC3490.

   The '*' (ASCII 42) wildcard character is allowed in subjectAltName
   values of type dNSName, and then only as the left-most (least
   significant) DNS label in that value.  This wildcard matches any
   left-most DNS label in the server name.  That is, the subject
   *.example.com matches the server names a.example.com and
   b.example.com, but does not match example.com or a.b.example.com.

3.1.3.2.  Comparison of IP Addresses

   When the reference identity is an IP address, the identity MUST be
   converted to the "network byte order" octet string representation
   [RFC791][RFC2460].  For IP Version 4, as specified in RFC 791, the
   octet string will contain exactly four octets.  For IP Version 6, as
   specified in RFC 2460, the octet string will contain exactly sixteen
   octets.  This octet string is then compared against subjectAltName
   values of type iPAddress.  A match occurs if the reference identity
   octet string and value octet strings are identical.

3.1.3.3.  Comparison of Other subjectName Types

   Client implementations MAY support matching against subjectAltName
   values of other types as described in other documents.

3.1.4.  Discovery of Resultant Security Level

   After a TLS layer is established in an LDAP session, both parties are
   to each independently decide whether or not to continue based on
   local policy and the security level achieved.  If either party
   decides that the security level is inadequate for it to continue, it
   SHOULD remove the TLS layer immediately after the TLS (re)negotiation
   has completed (see [RFC4511], Section 4.14.3, and Section 3.2 below).
   Implementations may reevaluate the security level at any time and,
   upon finding it inadequate, should remove the TLS layer.

3.1.5.  Refresh of Server Capabilities Information

   After a TLS layer is established in an LDAP session, the client
   SHOULD discard or refresh all information about the server that it
   obtained prior to the initiation of the TLS negotiation and that it
   did not obtain through secure mechanisms.  This protects against
   man-in-the-middle attacks that may have altered any server
   capabilities information retrieved prior to TLS layer installation.





Harrison                    Standards Track                    [Page 11]

RFC 4513              LDAP Authentication Methods              June 2006


   The server may advertise different capabilities after installing a
   TLS layer.  In particular, the value of 'supportedSASLMechanisms' may
   be different after a TLS layer has been installed (specifically, the
   EXTERNAL and PLAIN [PLAIN] mechanisms are likely to be listed only
   after a TLS layer has been installed).

3.2.  Effect of TLS on Authorization State

   The establishment, change, and/or closure of TLS may cause the
   authorization state to move to a new state.  This is discussed
   further in Section 4.

3.3.  TLS Ciphersuites

   Several issues should be considered when selecting TLS ciphersuites
   that are appropriate for use in a given circumstance.  These issues
   include the following:

      - The ciphersuite's ability to provide adequate confidentiality
        protection for passwords and other data sent over the transport
        connection.  Client and server implementers should recognize
        that some TLS ciphersuites provide no confidentiality
        protection, while other ciphersuites that do provide
        confidentiality protection may be vulnerable to being cracked
        using brute force methods, especially in light of ever-
        increasing CPU speeds that reduce the time needed to
        successfully mount such attacks.

      - Client and server implementers should carefully consider the
        value of the password or data being protected versus the level
        of confidentiality protection provided by the ciphersuite to
        ensure that the level of protection afforded by the ciphersuite
        is appropriate.

      - The ciphersuite's vulnerability (or lack thereof) to man-in-the-
        middle attacks.  Ciphersuites vulnerable to man-in-the-middle
        attacks SHOULD NOT be used to protect passwords or sensitive
        data, unless the network configuration is such that the danger
        of a man-in-the-middle attack is negligible.

      - After a TLS negotiation (either initial or subsequent) is
        completed, both protocol peers should independently verify that
        the security services provided by the negotiated ciphersuite are
        adequate for the intended use of the LDAP session.  If they are
        not, the TLS layer should be closed.






Harrison                    Standards Track                    [Page 12]

RFC 4513              LDAP Authentication Methods              June 2006


4.  Authorization State

   Every LDAP session has an associated authorization state.  This state
   is comprised of numerous factors such as what (if any) authentication
   state has been established, how it was established, and what security
   services are in place.  Some factors may be determined and/or
   affected by protocol events (e.g., Bind, StartTLS, or TLS closure),
   and some factors may be determined by external events (e.g., time of
   day or server load).

   While it is often convenient to view authorization state in
   simplistic terms (as we often do in this technical specification)
   such as "an anonymous state", it is noted that authorization systems
   in LDAP implementations commonly involve many factors that
   interrelate in complex manners.

   Authorization in LDAP is a local matter.  One of the key factors in
   making authorization decisions is authorization identity.  The Bind
   operation (defined in Section 4.2 of [RFC4511] and discussed further
   in Section 5 below) allows information to be exchanged between the
   client and server to establish an authorization identity for the LDAP
   session.  The Bind operation may also be used to move the LDAP
   session to an anonymous authorization state (see Section 5.1.1).

   Upon initial establishment of the LDAP session, the session has an
   anonymous authorization identity.  Among other things this implies
   that the client need not send a BindRequest in the first PDU of the
   LDAP message layer.  The client may send any operation request prior
   to performing a Bind operation, and the server MUST treat it as if it
   had been performed after an anonymous Bind operation (Section 5.1.1).

   Upon receipt of a Bind request, the server immediately moves the
   session to an anonymous authorization state.  If the Bind request is
   successful, the session is moved to the requested authentication
   state with its associated authorization state.  Otherwise, the
   session remains in an anonymous state.

   It is noted that other events both internal and external to LDAP may
   result in the authentication and authorization states being moved to
   an anonymous one.  For instance, the establishment, change, or
   closure of data security services may result in a move to an
   anonymous state, or the user's credential information (e.g.,
   certificate) may have expired.  The former is an example of an event
   internal to LDAP, whereas the latter is an example of an event
   external to LDAP.






Harrison                    Standards Track                    [Page 13]

RFC 4513              LDAP Authentication Methods              June 2006


5.  Bind Operation

   The Bind operation ([RFC4511], Section 4.2) allows authentication
   information to be exchanged between the client and server to
   establish a new authorization state.

   The Bind request typically specifies the desired authentication
   identity.  Some Bind mechanisms also allow the client to specify the
   authorization identity.  If the authorization identity is not
   specified, the server derives it from the authentication identity in
   an implementation-specific manner.

   If the authorization identity is specified, the server MUST verify
   that the client's authentication identity is permitted to assume
   (e.g., proxy for) the asserted authorization identity.  The server
   MUST reject the Bind operation with an invalidCredentials resultCode
   in the Bind response if the client is not so authorized.

5.1.  Simple Authentication Method

   The simple authentication method of the Bind Operation provides three
   authentication mechanisms:

      - An anonymous authentication mechanism (Section 5.1.1).

      - An unauthenticated authentication mechanism (Section 5.1.2).

      - A name/password authentication mechanism using credentials
        consisting of a name (in the form of an LDAP distinguished name
        [RFC4514]) and a password (Section 5.1.3).

5.1.1.  Anonymous Authentication Mechanism of Simple Bind

   An LDAP client may use the anonymous authentication mechanism of the
   simple Bind method to explicitly establish an anonymous authorization
   state by sending a Bind request with a name value of zero length and
   specifying the simple authentication choice containing a password
   value of zero length.

5.1.2.  Unauthenticated Authentication Mechanism of Simple Bind

   An LDAP client may use the unauthenticated authentication mechanism
   of the simple Bind method to establish an anonymous authorization
   state by sending a Bind request with a name value (a distinguished
   name in LDAP string form [RFC4514] of non-zero length) and specifying
   the simple authentication choice containing a password value of zero
   length.




Harrison                    Standards Track                    [Page 14]

RFC 4513              LDAP Authentication Methods              June 2006


   The distinguished name value provided by the client is intended to be
   used for trace (e.g., logging) purposes only.  The value is not to be
   authenticated or otherwise validated (including verification that the
   DN refers to an existing directory object).  The value is not to be
   used (directly or indirectly) for authorization purposes.

   Unauthenticated Bind operations can have significant security issues
   (see Section 6.3.1).  In particular, users intending to perform
   Name/Password Authentication may inadvertently provide an empty
   password and thus cause poorly implemented clients to request
   Unauthenticated access.  Clients SHOULD be implemented to require
   user selection of the Unauthenticated Authentication Mechanism by
   means other than user input of an empty password.  Clients SHOULD
   disallow an empty password input to a Name/Password Authentication
   user interface.  Additionally, Servers SHOULD by default fail
   Unauthenticated Bind requests with a resultCode of
   unwillingToPerform.

5.1.3.  Name/Password Authentication Mechanism of Simple Bind

   An LDAP client may use the name/password authentication mechanism of
   the simple Bind method to establish an authenticated authorization
   state by sending a Bind request with a name value (a distinguished
   name in LDAP string form [RFC4514] of non-zero length) and specifying
   the simple authentication choice containing an OCTET STRING password
   value of non-zero length.

   Servers that map the DN sent in the Bind request to a directory entry
   with an associated set of one or more passwords used with this
   mechanism will compare the presented password to that set of
   passwords.  The presented password is considered valid if it matches
   any member of this set.

   A resultCode of invalidDNSyntax indicates that the DN sent in the
   name value is syntactically invalid.  A resultCode of
   invalidCredentials indicates that the DN is syntactically correct but
   not valid for purposes of authentication, that the password is not
   valid for the DN, or that the server otherwise considers the
   credentials invalid.  A resultCode of success indicates that the
   credentials are valid and that the server is willing to provide
   service to the entity these credentials identify.

   Server behavior is undefined for Bind requests specifying the
   name/password authentication mechanism with a zero-length name value
   and a password value of non-zero length.






Harrison                    Standards Track                    [Page 15]

RFC 4513              LDAP Authentication Methods              June 2006


   The name/password authentication mechanism of the simple Bind method
   is not suitable for authentication in environments without
   confidentiality protection.

5.2.  SASL Authentication Method

   The sasl authentication method of the Bind Operation provides
   facilities for using any SASL mechanism including authentication
   mechanisms and other services (e.g., data security services).

5.2.1.  SASL Protocol Profile

   LDAP allows authentication via any SASL mechanism [RFC4422].  As LDAP
   includes native anonymous and name/password (plain text)
   authentication methods, the ANONYMOUS [RFC4505] and PLAIN [PLAIN]
   SASL mechanisms are typically not used with LDAP.

   Each protocol that utilizes SASL services is required to supply
   certain information profiling the way they are exposed through the
   protocol ([RFC4422], Section 4).  This section explains how each of
   these profiling requirements is met by LDAP.

5.2.1.1.  SASL Service Name for LDAP

   The SASL service name for LDAP is "ldap", which has been registered
   with the IANA as a SASL service name.

5.2.1.2.  SASL Authentication Initiation and Protocol Exchange

   SASL authentication is initiated via a BindRequest message
   ([RFC4511], Section 4.2) with the following parameters:

      - The version is 3.
      - The AuthenticationChoice is sasl.
      - The mechanism element of the SaslCredentials sequence contains
        the value of the desired SASL mechanism.
      - The optional credentials field of the SaslCredentials sequence
        MAY be used to provide an initial client response for mechanisms
        that are defined to have the client send data first (see
        [RFC4422], Sections 3 and 5).

   In general, a SASL authentication protocol exchange consists of a
   series of server challenges and client responses, the contents of
   which are specific to and defined by the SASL mechanism.  Thus, for
   some SASL authentication mechanisms, it may be necessary for the
   client to respond to one or more server challenges by sending
   BindRequest messages multiple times.  A challenge is indicated by the
   server sending a BindResponse message with the resultCode set to



Harrison                    Standards Track                    [Page 16]

RFC 4513              LDAP Authentication Methods              June 2006


   saslBindInProgress.  This indicates that the server requires the
   client to send a new BindRequest message with the same SASL mechanism
   to continue the authentication process.

   To the LDAP message layer, these challenges and responses are opaque
   binary tokens of arbitrary length.  LDAP servers use the
   serverSaslCreds field (an OCTET STRING) in a BindResponse message to
   transmit each challenge.  LDAP clients use the credentials field (an
   OCTET STRING) in the SaslCredentials sequence of a BindRequest
   message to transmit each response.  Note that unlike some Internet
   protocols where SASL is used, LDAP is not text based and does not
   Base64-transform these challenge and response values.

   Clients sending a BindRequest message with the sasl choice selected
   SHOULD send a zero-length value in the name field.  Servers receiving
   a BindRequest message with the sasl choice selected SHALL ignore any
   value in the name field.

   A client may abort a SASL Bind negotiation by sending a BindRequest
   message with a different value in the mechanism field of
   SaslCredentials or with an AuthenticationChoice other than sasl.

   If the client sends a BindRequest with the sasl mechanism field as an
   empty string, the server MUST return a BindResponse with a resultCode
   of authMethodNotSupported.  This will allow the client to abort a
   negotiation if it wishes to try again with the same SASL mechanism.

   The server indicates completion of the SASL challenge-response
   exchange by responding with a BindResponse in which the resultCode
   value is not saslBindInProgress.

   The serverSaslCreds field in the BindResponse can be used to include
   an optional challenge with a success notification for mechanisms that
   are defined to have the server send additional data along with the
   indication of successful completion.

5.2.1.3.  Optional Fields

   As discussed above, LDAP provides an optional field for carrying an
   initial response in the message initiating the SASL exchange and
   provides an optional field for carrying additional data in the
   message indicating the outcome of the authentication exchange.  As
   the mechanism-specific content in these fields may be zero length,
   SASL requires protocol specifications to detail how an empty field is
   distinguished from an absent field.






Harrison                    Standards Track                    [Page 17]

RFC 4513              LDAP Authentication Methods              June 2006


   Zero-length initial response data is distinguished from no initial
   response data in the initiating message, a BindRequest PDU, by the
   presence of the SaslCredentials.credentials OCTET STRING (of length
   zero) in that PDU.  If the client does not intend to send an initial
   response with the BindRequest initiating the SASL exchange, it MUST
   omit the SaslCredentials.credentials OCTET STRING (rather than
   include an zero-length OCTET STRING).

   Zero-length additional data is distinguished from no additional
   response data in the outcome message, a BindResponse PDU, by the
   presence of the serverSaslCreds OCTET STRING (of length zero) in that
   PDU.  If a server does not intend to send additional data in the
   BindResponse message indicating outcome of the exchange, the server
   SHALL omit the serverSaslCreds OCTET STRING (rather than including a
   zero-length OCTET STRING).

5.2.1.4.  Octet Where Negotiated Security Layers Take Effect

   SASL layers take effect following the transmission by the server and
   reception by the client of the final BindResponse in the SASL
   exchange with a resultCode of success.

   Once a SASL layer providing data integrity or confidentiality
   services takes effect, the layer remains in effect until a new layer
   is installed (i.e., at the first octet following the final
   BindResponse of the Bind operation that caused the new layer to take
   effect).  Thus, an established SASL layer is not affected by a failed
   or non-SASL Bind.

5.2.1.5.  Determination of Supported SASL Mechanisms

   Clients may determine the SASL mechanisms a server supports by
   reading the 'supportedSASLMechanisms' attribute from the root DSE
   (DSA-Specific Entry) ([RFC4512], Section 5.1).  The values of this
   attribute, if any, list the mechanisms the server supports in the
   current LDAP session state.  LDAP servers SHOULD allow all clients --
   even those with an anonymous authorization -- to retrieve the
   'supportedSASLMechanisms' attribute of the root DSE both before and
   after the SASL authentication exchange.  The purpose of the latter is
   to allow the client to detect possible downgrade attacks (see Section
   6.4 and [RFC4422], Section 6.1.2).

   Because SASL mechanisms provide critical security functions, clients
   and servers should be configurable to specify what mechanisms are
   acceptable and allow only those mechanisms to be used.  Both clients
   and servers must confirm that the negotiated security level meets
   their requirements before proceeding to use the session.




Harrison                    Standards Track                    [Page 18]

RFC 4513              LDAP Authentication Methods              June 2006


5.2.1.6.  Rules for Using SASL Layers

   Upon installing a SASL layer, the client SHOULD discard or refresh
   all information about the server that it obtained prior to the
   initiation of the SASL negotiation and that it did not obtain through
   secure mechanisms.

   If a lower-level security layer (such as TLS) is installed, any SASL
   layer SHALL be layered on top of such security layers regardless of
   the order of their negotiation.  In all other respects, the SASL
   layer and other security layers act independently, e.g., if both a
   TLS layer and a SASL layer are in effect, then removing the TLS layer
   does not affect the continuing service of the SASL layer.

5.2.1.7.  Support for Multiple Authentications

   LDAP supports multiple SASL authentications as defined in [RFC4422],
   Section 4.

5.2.1.8.  SASL Authorization Identities

   Some SASL mechanisms allow clients to request a desired authorization
   identity for the LDAP session ([RFC4422], Section 3.4).  The decision
   to allow or disallow the current authentication identity to have
   access to the requested authorization identity is a matter of local
   policy.  The authorization identity is a string of UTF-8 [RFC3629]
   encoded [Unicode] characters corresponding to the following Augmented
   Backus-Naur Form (ABNF) [RFC4234] grammar:

      authzId = dnAuthzId / uAuthzId

      ; distinguished-name-based authz id
      dnAuthzId =  "dn:" distinguishedName

      ; unspecified authorization id, UTF-8 encoded
      uAuthzId = "u:" userid
      userid = *UTF8 ; syntax unspecified

   where the distinguishedName rule is defined in Section 3 of [RFC4514]
   and the UTF8 rule is defined in Section 1.4 of [RFC4512].

   The dnAuthzId choice is used to assert authorization identities in
   the form of a distinguished name to be matched in accordance with the
   distinguishedNameMatch matching rule ([RFC4517], Section 4.2.15).
   There is no requirement that the asserted distinguishedName value be
   that of an entry in the directory.





Harrison                    Standards Track                    [Page 19]

RFC 4513              LDAP Authentication Methods              June 2006


   The uAuthzId choice allows clients to assert an authorization
   identity that is not in distinguished name form.  The format of
   userid is defined only as a sequence of UTF-8 [RFC3629] encoded
   [Unicode] characters, and any further interpretation is a local
   matter.  For example, the userid could identify a user of a specific
   directory service, be a login name, or be an email address.  A
   uAuthzId SHOULD NOT be assumed to be globally unique.  To compare
   uAuthzId values, each uAuthzId value MUST be prepared as a "query"
   string ([RFC3454], Section 7) using the SASLprep [RFC4013] algorithm,
   and then the two values are compared octet-wise.

   The above grammar is extensible.  The authzId production may be
   extended to support additional forms of identities.  Each form is
   distinguished by its unique prefix (see Section 3.12 of [RFC4520] for
   registration requirements).

5.2.2.  SASL Semantics within LDAP

   Implementers must take care to maintain the semantics of SASL
   specifications when handling data that has different semantics in the
   LDAP protocol.

   For example, the SASL DIGEST-MD5 authentication mechanism
   [DIGEST-MD5] utilizes an authentication identity and a realm that are
   syntactically simple strings and semantically simple username
   [RFC4013] and realm values.  These values are not LDAP DNs, and there
   is no requirement that they be represented or treated as such.

5.2.3.  SASL EXTERNAL Authentication Mechanism

   A client can use the SASL EXTERNAL ([RFC4422], Appendix A) mechanism
   to request the LDAP server to authenticate and establish a resulting
   authorization identity using security credentials exchanged by a
   lower security layer (such as by TLS authentication).  If the
   client's authentication credentials have not been established at a
   lower security layer, the SASL EXTERNAL Bind MUST fail with a
   resultCode of inappropriateAuthentication.  Although this situation
   has the effect of leaving the LDAP session in an anonymous state
   (Section 4), the state of any installed security layer is unaffected.

   A client may either request that its authorization identity be
   automatically derived from its authentication credentials exchanged
   at a lower security layer, or it may explicitly provide a desired
   authorization identity.  The former is known as an implicit
   assertion, and the latter as an explicit assertion.






Harrison                    Standards Track                    [Page 20]

RFC 4513              LDAP Authentication Methods              June 2006


5.2.3.1.  Implicit Assertion

   An implicit authorization identity assertion is performed by invoking
   a Bind request of the SASL form using the EXTERNAL mechanism name
   that does not include the optional credentials field (found within
   the SaslCredentials sequence in the BindRequest).  The server will
   derive the client's authorization identity from the authentication
   identity supplied by a security layer (e.g., a public key certificate
   used during TLS layer installation) according to local policy.  The
   underlying mechanics of how this is accomplished are implementation
   specific.

5.2.3.2.  Explicit Assertion

   An explicit authorization identity assertion is performed by invoking
   a Bind request of the SASL form using the EXTERNAL mechanism name
   that includes the credentials field (found within the SaslCredentials
   sequence in the BindRequest).  The value of the credentials field (an
   OCTET STRING) is the asserted authorization identity and MUST be
   constructed as documented in Section 5.2.1.8.

6.  Security Considerations

   Security issues are discussed throughout this document.  The
   unsurprising conclusion is that security is an integral and necessary
   part of LDAP.  This section discusses a number of LDAP-related
   security considerations.

6.1.  General LDAP Security Considerations

   LDAP itself provides no security or protection from accessing or
   updating the directory by means other than through the LDAP protocol,
   e.g., from inspection of server database files by database
   administrators.

   Sensitive data may be carried in almost any LDAP message, and its
   disclosure may be subject to privacy laws or other legal regulation
   in many countries.  Implementers should take appropriate measures to
   protect sensitive data from disclosure to unauthorized entities.

   A session on which the client has not established data integrity and
   privacy services (e.g., via StartTLS, IPsec, or a suitable SASL
   mechanism) is subject to man-in-the-middle attacks to view and modify
   information in transit.  Client and server implementers SHOULD take
   measures to protect sensitive data in the LDAP session from these
   attacks by using data protection services as discussed in this
   document.  Clients and servers should provide the ability to be
   configured to require these protections.  A resultCode of



Harrison                    Standards Track                    [Page 21]

RFC 4513              LDAP Authentication Methods              June 2006


   confidentialityRequired indicates that the server requires
   establishment of (stronger) data confidentiality protection in order
   to perform the requested operation.

   Access control should always be applied when reading sensitive
   information or updating directory information.

   Various security factors, including authentication and authorization
   information and data security services may change during the course
   of the LDAP session, or even during the performance of a particular
   operation.  Implementations should be robust in the handling of
   changing security factors.

6.2.  StartTLS Security Considerations

   All security gained via use of the StartTLS operation is gained by
   the use of TLS itself.  The StartTLS operation, on its own, does not
   provide any additional security.

   The level of security provided through the use of TLS depends
   directly on both the quality of the TLS implementation used and the
   style of usage of that implementation.  Additionally, a man-in-the-
   middle attacker can remove the StartTLS extended operation from the
   'supportedExtension' attribute of the root DSE.  Both parties SHOULD
   independently ascertain and consent to the security level achieved
   once TLS is established and before beginning use of the TLS-
   protected session.  For example, the security level of the TLS layer
   might have been negotiated down to plaintext.

   Clients MUST either warn the user when the security level achieved
   does not provide an acceptable level of data confidentiality and/or
   data integrity protection, or be configurable to refuse to proceed
   without an acceptable level of security.

   As stated in Section 3.1.2, a server may use a local security policy
   to determine whether to successfully complete TLS negotiation.
   Information in the user's certificate that is originated or verified
   by the certification authority should be used by the policy
   administrator when configuring the identification and authorization
   policy.

   Server implementers SHOULD allow server administrators to elect
   whether and when data confidentiality and integrity are required, as
   well as elect whether authentication of the client during the TLS
   handshake is required.

   Implementers should be aware of and understand TLS security
   considerations as discussed in the TLS specification [RFC4346].



Harrison                    Standards Track                    [Page 22]

RFC 4513              LDAP Authentication Methods              June 2006


6.3.  Bind Operation Security Considerations

   This section discusses several security considerations relevant to
   LDAP authentication via the Bind operation.

6.3.1.  Unauthenticated Mechanism Security Considerations

   Operational experience shows that clients can (and frequently do)
   misuse the unauthenticated authentication mechanism of the simple
   Bind method (see Section 5.1.2).  For example, a client program might
   make a decision to grant access to non-directory information on the
   basis of successfully completing a Bind operation.  LDAP server
   implementations may return a success response to an unauthenticated
   Bind request.  This may erroneously leave the client with the
   impression that the server has successfully authenticated the
   identity represented by the distinguished name when in reality, an
   anonymous authorization state has been established.  Clients that use
   the results from a simple Bind operation to make authorization
   decisions should actively detect unauthenticated Bind requests (by
   verifying that the supplied password is not empty) and react
   appropriately.

6.3.2.  Name/Password Mechanism Security Considerations

   The name/password authentication mechanism of the simple Bind method
   discloses the password to the server, which is an inherent security
   risk.  There are other mechanisms, such as SASL DIGEST-MD5
   [DIGEST-MD5], that do not disclose the password to the server.

6.3.3.  Password-Related Security Considerations

   LDAP allows multi-valued password attributes.  In systems where
   entries are expected to have one and only one password,
   administrative controls should be provided to enforce this behavior.

   The use of clear text passwords and other unprotected authentication
   credentials is strongly discouraged over open networks when the
   underlying transport service cannot guarantee confidentiality.  LDAP
   implementations SHOULD NOT by default support authentication methods
   using clear text passwords and other unprotected authentication
   credentials unless the data on the session is protected using TLS or
   other data confidentiality and data integrity protection.

   The transmission of passwords in the clear -- typically for
   authentication or modification -- poses a significant security risk.
   This risk can be avoided by using SASL authentication [RFC4422]





Harrison                    Standards Track                    [Page 23]

RFC 4513              LDAP Authentication Methods              June 2006


   mechanisms that do not transmit passwords in the clear or by
   negotiating transport or session layer data confidentiality services
   before transmitting password values.

   To mitigate the security risks associated with the transfer of
   passwords, a server implementation that supports any password-based
   authentication mechanism that transmits passwords in the clear MUST
   support a policy mechanism that at the time of authentication or
   password modification, requires that:

         A TLS layer has been successfully installed.

         OR

         Some other data confidentiality mechanism that protects the
         password value from eavesdropping has been provided.

         OR

         The server returns a resultCode of confidentialityRequired for
         the operation (i.e., name/password Bind with password value,
         SASL Bind transmitting a password value in the clear, add or
         modify including a userPassword value, etc.), even if the
         password value is correct.

   Server implementations may also want to provide policy mechanisms to
   invalidate or otherwise protect accounts in situations where a server
   detects that a password for an account has been transmitted in the
   clear.

6.3.4.  Hashed Password Security Considerations

   Some authentication mechanisms (e.g., DIGEST-MD5) transmit a hash of
   the password value that may be vulnerable to offline dictionary
   attacks.  Implementers should take care to protect such hashed
   password values during transmission using TLS or other
   confidentiality mechanisms.

6.4.  SASL Security Considerations

   Until data integrity service is installed on an LDAP session, an
   attacker can modify the transmitted values of the
   'supportedSASLMechanisms' attribute response and thus downgrade the
   list of available SASL mechanisms to include only the least secure
   mechanism.  To detect this type of attack, the client may retrieve
   the SASL mechanisms the server makes available both before and after
   data integrity service is installed on an LDAP session.  If the
   client finds that the integrity-protected list (the list obtained



Harrison                    Standards Track                    [Page 24]

RFC 4513              LDAP Authentication Methods              June 2006


   after data integrity service was installed) contains a stronger
   mechanism than those in the previously obtained list, the client
   should assume the previously obtained list was modified by an
   attacker.  In this circumstance it is recommended that the client
   close the underlying transport connection and then reconnect to
   reestablish the session.

6.5.  Related Security Considerations

   Additional security considerations relating to the various
   authentication methods and mechanisms discussed in this document
   apply and can be found in [RFC4422], [RFC4013], [RFC3454], and
   [RFC3629].

7.  IANA Considerations

   The IANA has updated the LDAP Protocol Mechanism registry to indicate
   that this document and [RFC4511] provide the definitive technical
   specification for the StartTLS (1.3.6.1.4.1.1466.20037) extended
   operation.

   The IANA has updated the LDAP LDAPMessage types registry to indicate
   that this document and [RFC4511] provide the definitive technical
   specification for the bindRequest (0) and bindResponse (1) message
   types.

   The IANA has updated the LDAP Bind Authentication Method registry to
   indicate that this document and [RFC4511] provide the definitive
   technical specification for the simple (0) and sasl (3) bind
   authentication methods.

   The IANA has updated the LDAP authzid prefixes registry to indicate
   that this document provides the definitive technical specification
   for the dnAuthzId (dn:) and uAuthzId (u:) authzid prefixes.

8.  Acknowledgements

   This document combines information originally contained in RFC 2251,
   RFC 2829, and RFC 2830.  RFC 2251 was a product of the Access,
   Searching, and Indexing of Directories (ASID) Working Group.  RFC
   2829 and RFC 2830 were products of the LDAP Extensions (LDAPEXT)
   Working Group.

   This document is a product of the IETF LDAP Revision (LDAPBIS)
   working group.






Harrison                    Standards Track                    [Page 25]

RFC 4513              LDAP Authentication Methods              June 2006


9.  Normative References

   [RFC791]     Postel, J., "Internet Protocol", STD 5, RFC 791,
                September 1981.

   [RFC2119]    Bradner, S., "Key words for use in RFCs to Indicate
                Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2460]    Deering, S. and R. Hinden, "Internet Protocol, Version 6
                (IPv6) Specification", RFC 2460, December 1998.

   [RFC3454]    Hoffman, P. and M. Blanchet, "Preparation of
                Internationalized Strings ("stringprep")", RFC 3454,
                December 2002.

   [RFC3490]    Faltstrom, P., Hoffman, P., and A. Costello,
                "Internationalizing Domain Names in Applications
                (IDNA)", RFC 3490, March 2003.

   [RFC3629]    Yergeau, F., "UTF-8, a transformation format of ISO
                10646", STD 63, RFC 3629, November 2003.

   [RFC4013]    Zeilenga, K., "SASLprep: Stringprep Profile for User
                Names and Passwords", RFC 4013, February 2005.

   [RFC4234]    Crocker, D. and P. Overell, "Augmented BNF for Syntax
                Specifications: ABNF", RFC 4234, October 2005.

   [RFC4346]    Dierks, T. and E. Rescorla, "The TLS Protocol Version
                1.1", RFC 4346, March 2006.

   [RFC4422]    Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
                Authentication and Security Layer (SASL)", RFC 4422,
                June 2006.

   [RFC4510]    Zeilenga, K., Ed., "Lightweight Directory Access
                Protocol (LDAP): Technical Specification Road Map", RFC
                4510, June 2006.

   [RFC4511]    Sermersheim, J., Ed., "Lightweight Directory Access
                Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]    Zeilenga, K., "Lightweight Directory Access Protocol
                (LDAP): Directory Information Models", RFC 4512, June
                2006.






Harrison                    Standards Track                    [Page 26]

RFC 4513              LDAP Authentication Methods              June 2006


   [RFC4514]    Zeilenga, K., Ed., "Lightweight Directory Access
                Protocol (LDAP): String Representation of Distinguished
                Names", RFC 4514, June 2006.

   [RFC4517]    Legg, S., Ed., "Lightweight Directory Access Protocol
                (LDAP): Syntaxes and Matching Rules", RFC 4517, June
                2006.

   [RFC4519]    Sciberras, A., Ed., "Lightweight Directory Access
                Protocol (LDAP): Schema for User Applications", RFC
                4519, June 2006.

   [RFC4520]    Zeilenga, K., "Internet Assigned Numbers Authority
                (IANA) Considerations for the Lightweight Directory
                Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [Unicode]    The Unicode Consortium, "The Unicode Standard, Version
                3.2.0" is defined by "The Unicode Standard, Version 3.0"
                (Reading, MA, Addison-Wesley, 2000.  ISBN 0-201-61633-
                5), as amended by the "Unicode Standard Annex #27:
                Unicode 3.1" (http://www.unicode.org/reports/tr27/) and
                by the "Unicode Standard Annex #28: Unicode 3.2"
                (http://www.unicode.org/reports/tr28/).

   [X.501]      ITU-T Rec. X.501, "The Directory: Models", 1993.

10.  Informative References

   [DIGEST-MD5] Leach, P., Newman, C., and A. Melnikov, "Using Digest
                Authentication as a SASL Mechanism", Work in Progress,
                March 2006.

   [PLAIN]      Zeilenga, K., "The Plain SASL Mechanism", Work in
                Progress, March 2005.

   [RFC2828]    Shirey, R., "Internet Security Glossary", FYI 36, RFC
                2828, May 2000.

   [RFC4301]    Kent, S. and K. Seo, "Security Architecture for the
                Internet Protocol", RFC 4301, December 2005.

   [RFC4505]    Zeilenga, K., "The Anonymous SASL Mechanism", RFC 4505,
                June 2006.








Harrison                    Standards Track                    [Page 27]

RFC 4513              LDAP Authentication Methods              June 2006


Appendix A.  Authentication and Authorization Concepts

   This appendix is non-normative.

   This appendix defines basic terms, concepts, and interrelationships
   regarding authentication, authorization, credentials, and identity.
   These concepts are used in describing how various security approaches
   are utilized in client authentication and authorization.

A.1.  Access Control Policy

   An access control policy is a set of rules defining the protection of
   resources, generally in terms of the capabilities of persons or other
   entities accessing those resources.  Security objects and mechanisms,
   such as those described here, enable the expression of access control
   policies and their enforcement.

A.2.  Access Control Factors

   A request, when it is being processed by a server, may be associated
   with a wide variety of security-related factors.  The server uses
   these factors to determine whether and how to process the request.
   These are called access control factors (ACFs).  They might include
   source IP address, encryption strength, the type of operation being
   requested, time of day, etc..  Some factors may be specific to the
   request itself; others may be associated with the transport
   connection via which the request is transmitted; and others (e.g.,
   time of day) may be "environmental".

   Access control policies are expressed in terms of access control
   factors; for example, "a request having ACFs i,j,k can perform
   operation Y on resource Z".  The set of ACFs that a server makes
   available for such expressions is implementation specific.

A.3.  Authentication, Credentials, Identity

   Authentication credentials are the evidence supplied by one party to
   another, asserting the identity of the supplying party (e.g., a user)
   who is attempting to establish a new authorization state with the
   other party (typically a server).  Authentication is the process of
   generating, transmitting, and verifying these credentials and thus
   the identity they assert.  An authentication identity is the name
   presented in a credential.

   There are many forms of authentication credentials.  The form used
   depends upon the particular authentication mechanism negotiated by
   the parties.  X.509 certificates, Kerberos tickets, and simple
   identity and password pairs are all examples of authentication



Harrison                    Standards Track                    [Page 28]

RFC 4513              LDAP Authentication Methods              June 2006


   credential forms.  Note that an authentication mechanism may
   constrain the form of authentication identities used with it.

A.4.  Authorization Identity

   An authorization identity is one kind of access control factor.  It
   is the name of the user or other entity that requests that operations
   be performed.  Access control policies are often expressed in terms
   of authorization identities; for example, "entity X can perform
   operation Y on resource Z".

   The authorization identity of an LDAP session is often semantically
   the same as the authentication identity presented by the client, but
   it may be different.  SASL allows clients to specify an authorization
   identity distinct from the authentication identity asserted by the
   client's credentials.  This permits agents such as proxy servers to
   authenticate using their own credentials, yet request the access
   privileges of the identity for which they are proxying [RFC4422].
   Also, the form of authentication identity supplied by a service like
   TLS may not correspond to the authorization identities used to
   express a server's access control policy, thus requiring a server-
   specific mapping to be done.  The method by which a server composes
   and validates an authorization identity from the authentication
   credentials supplied by a client is implementation specific.

Appendix B.  Summary of Changes

   This appendix is non-normative.

   This appendix summarizes substantive changes made to RFC 2251, RFC
   2829 and RFC 2830.  In addition to the specific changes detailed
   below, the reader of this document should be aware that numerous
   general editorial changes have been made to the original content from
   the source documents.  These changes include the following:

   - The material originally found in RFC 2251 Sections 4.2.1 and 4.2.2,
     RFC 2829 (all sections except Sections 2 and 4), and RFC 2830 was
     combined into a single document.

   - The combined material was substantially reorganized and edited to
     group related subjects, improve the document flow, and clarify
     intent.

   - Changes were made throughout the text to align with definitions of
     LDAP protocol layers and IETF security terminology.






Harrison                    Standards Track                    [Page 29]

RFC 4513              LDAP Authentication Methods              June 2006


   - Substantial updates and additions were made to security
     considerations from both documents based on current operational
     experience.

B.1.  Changes Made to RFC 2251

   This section summarizes the substantive changes made to Sections
   4.2.1 and 4.2.2 of RFC 2251 by this document.  Additional substantive
   changes to Section 4.2.1 of RFC 2251 are also documented in
   [RFC4511].

B.1.1.  Section 4.2.1 ("Sequencing of the Bind Request")

   - Paragraph 1: Removed the sentence, "If at any stage the client
     wishes to abort the bind process it MAY unbind and then drop the
     underlying connection".  The Unbind operation still permits this
     behavior, but it is not documented explicitly.

   - Clarified that the session is moved to an anonymous state upon
     receipt of the BindRequest PDU and that it is only moved to a non-
     anonymous state if and when the Bind request is successful.

B.1.2.  Section 4.2.2 ("Authentication and Other Security Services")

   - RFC 2251 states that anonymous authentication MUST be performed
     using the simple bind method.  This specification defines the
     anonymous authentication mechanism of the simple bind method and
     requires all conforming implementations to support it.  Other
     authentication mechanisms producing anonymous authentication and
     authorization state may also be implemented and used by conforming
     implementations.

B.2.  Changes Made to RFC 2829

   This section summarizes the substantive changes made to RFC 2829.

B.2.1.  Section 4 ("Required security mechanisms")

   - The name/password authentication mechanism (see Section B.2.5
     below) protected by TLS replaces the SASL DIGEST-MD5 mechanism as
     LDAP's mandatory-to-implement password-based authentication
     mechanism.  Implementations are encouraged to continue supporting
     SASL DIGEST-MD5 [DIGEST-MD5].








Harrison                    Standards Track                    [Page 30]

RFC 4513              LDAP Authentication Methods              June 2006


B.2.2.  Section 5.1 ("Anonymous authentication procedure")

   - Clarified that anonymous authentication involves a name value of
     zero length and a password value of zero length.  The
     unauthenticated authentication mechanism was added to handle simple
     Bind requests involving a name value with a non-zero length and a
     password value of zero length.

B.2.3.  Section 6 ("Password-based authentication")

   - See Section B.2.1.

B.2.4.  Section 6.1 ("Digest authentication")

   - As the SASL-DIGEST-MD5 mechanism is no longer mandatory to
     implement, this section is now historical and was not included in
     this document.  RFC 2829, Section 6.1, continues to document the
     SASL DIGEST-MD5 authentication mechanism.

B.2.5.  Section 6.2 ("'simple' authentication choice under TLS
        encryption")

   - Renamed the "simple" authentication mechanism to the name/password
     authentication mechanism to better describe it.

   - The use of TLS was generalized to align with definitions of LDAP
     protocol layers.  TLS establishment is now discussed as an
     independent subject and is generalized for use with all
     authentication mechanisms and other security layers.

   - Removed the implication that the userPassword attribute is the sole
     location for storage of password values to be used in
     authentication.  There is no longer any implied requirement for how
     or where passwords are stored at the server for use in
     authentication.

B.2.6.  Section 6.3 ("Other authentication choices with TLS")

   - See Section B.2.5.

B.2.7.  Section 7.1 ("Certificate-based authentication with TLS")

   - See Section B.2.5.








Harrison                    Standards Track                    [Page 31]

RFC 4513              LDAP Authentication Methods              June 2006


B.2.8.  Section 8 ("Other mechanisms")

   - All SASL authentication mechanisms are explicitly allowed within
     LDAP.  Specifically, this means the SASL ANONYMOUS and SASL PLAIN
     mechanisms are no longer precluded from use within LDAP.

B.2.9.  Section 9 ("Authorization Identity")

   - Specified matching rules for dnAuthzId and uAuthzId values.  In
     particular, the DN value in the dnAuthzId form must be matched
     using DN matching rules, and the uAuthzId value MUST be prepared
     using SASLprep rules before being compared octet-wise.

   - Clarified that uAuthzId values should not be assumed to be globally
     unique.

B.2.10.  Section 10 ("TLS Ciphersuites")

   - TLS ciphersuite recommendations are no longer included in this
     specification.  Implementations must now support the
     TLS_RSA_WITH_3DES_EDE_CBC_SHA ciphersuite and should continue to
     support the TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA ciphersuite.

   - Clarified that anonymous authentication involves a name value of
     zero length and a password value of zero length.  The
     unauthenticated authentication mechanism was added to handle simple
     Bind requests involving a name value with a non-zero length and a
     password value of zero length.

B.3.  Changes Made to RFC 2830

   This section summarizes the substantive changes made to Sections 3
   and 5 of RFC 2830.  Readers should consult [RFC4511] for summaries of
   changes to other sections.

B.3.1.  Section 3.6 ("Server Identity Check")

   - Substantially updated the server identity check algorithm to ensure
     that it is complete and robust.  In particular, the use of all
     relevant values in the subjectAltName and the subjectName fields
     are covered by the algorithm and matching rules are specified for
     each type of value.  Mapped (derived) forms of the server identity
     may now be used when the mapping is performed in a secure fashion.








Harrison                    Standards Track                    [Page 32]

RFC 4513              LDAP Authentication Methods              June 2006


B.3.2.  Section 3.7 ("Refresh of Server Capabilities Information")

   - Clients are no longer required to always refresh information about
     server capabilities following TLS establishment.  This is to allow
     for situations where this information was obtained through a secure
     mechanism.

B.3.3.  Section 5 ("Effects of TLS on a Client's Authorization
        Identity")

   - Establishing a TLS layer on an LDAP session may now cause the
     authorization state of the LDAP session to change.

B.3.4.  Section 5.2 ("TLS Connection Closure Effects")

   - Closing a TLS layer on an LDAP session changes the authentication
     and authorization state of the LDAP session based on local policy.
     Specifically, this means that implementations are not required to
     change the authentication and authorization states to anonymous
     upon TLS closure.

   - Replaced references to RFC 2401 with RFC 4301.

Author's Address

   Roger Harrison
   Novell, Inc.
   1800 S.  Novell Place
   Provo, UT 84606
   USA

   Phone: +1 801 861 2642
   EMail: roger_harrison@novell.com


















Harrison                    Standards Track                    [Page 33]

RFC 4513              LDAP Authentication Methods              June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Harrison                    Standards Track                    [Page 34]

alt-openldap11-devel/rfc/rfc4517.txt000064400000337155150410163210013000 0ustar00





Network Working Group                                       S. Legg, Ed.
Request for Comments: 4517                                       eB2Bcom
Obsoletes: 2252, 2256                                          June 2006
Updates: 3698
Category: Standards Track


             Lightweight Directory Access Protocol (LDAP):
                      Syntaxes and Matching Rules


Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   Each attribute stored in a Lightweight Directory Access Protocol
   (LDAP) directory, whose values may be transferred in the LDAP
   protocol, has a defined syntax that constrains the structure and
   format of its values.  The comparison semantics for values of a
   syntax are not part of the syntax definition but are instead provided
   through separately defined matching rules.  Matching rules specify an
   argument, an assertion value, which also has a defined syntax.  This
   document defines a base set of syntaxes and matching rules for use in
   defining attributes for LDAP directories.

Table of Contents

   1. Introduction ....................................................3
   2. Conventions .....................................................4
   3. Syntaxes ........................................................4
      3.1. General Considerations .....................................5
      3.2. Common Definitions .........................................5
      3.3. Syntax Definitions .........................................6
           3.3.1. Attribute Type Description ..........................6
           3.3.2. Bit String ..........................................6
           3.3.3. Boolean .............................................7
           3.3.4. Country String ......................................7
           3.3.5. Delivery Method .....................................8



Legg                        Standards Track                     [Page 1]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


           3.3.6. Directory String ....................................8
           3.3.7. DIT Content Rule Description ........................9
           3.3.8. DIT Structure Rule Description .....................10
           3.3.9. DN .................................................10
           3.3.10. Enhanced Guide ....................................11
           3.3.11. Facsimile Telephone Number ........................12
           3.3.12. Fax ...............................................12
           3.3.13. Generalized Time ..................................13
           3.3.14. Guide .............................................14
           3.3.15. IA5 String ........................................15
           3.3.16. Integer ...........................................15
           3.3.17. JPEG ..............................................15
           3.3.18. LDAP Syntax Description ...........................16
           3.3.19. Matching Rule Description .........................16
           3.3.20. Matching Rule Use Description .....................17
           3.3.21. Name and Optional UID .............................17
           3.3.22. Name Form Description .............................18
           3.3.23. Numeric String ....................................18
           3.3.24. Object Class Description ..........................18
           3.3.25. Octet String ......................................19
           3.3.26. OID ...............................................19
           3.3.27. Other Mailbox .....................................20
           3.3.28. Postal Address ....................................20
           3.3.29. Printable String ..................................21
           3.3.30. Substring Assertion ...............................22
           3.3.31. Telephone Number ..................................23
           3.3.32. Teletex Terminal Identifier .......................23
           3.3.33. Telex Number ......................................24
           3.3.34. UTC Time ..........................................24
   4. Matching Rules .................................................25
      4.1. General Considerations ....................................25
      4.2. Matching Rule Definitions .................................27
           4.2.1. bitStringMatch .....................................27
           4.2.2. booleanMatch .......................................28
           4.2.3. caseExactIA5Match ..................................28
           4.2.4. caseExactMatch .....................................29
           4.2.5. caseExactOrderingMatch .............................29
           4.2.6. caseExactSubstringsMatch ...........................30
           4.2.7. caseIgnoreIA5Match .................................30
           4.2.8. caseIgnoreIA5SubstringsMatch .......................31
           4.2.9. caseIgnoreListMatch ................................31
           4.2.10. caseIgnoreListSubstringsMatch .....................32
           4.2.11. caseIgnoreMatch ...................................33
           4.2.12. caseIgnoreOrderingMatch ...........................33
           4.2.13. caseIgnoreSubstringsMatch .........................34
           4.2.14. directoryStringFirstComponentMatch ................34
           4.2.15. distinguishedNameMatch ............................35
           4.2.16. generalizedTimeMatch ..............................36



Legg                        Standards Track                     [Page 2]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


           4.2.17. generalizedTimeOrderingMatch ......................36
           4.2.18. integerFirstComponentMatch ........................36
           4.2.19. integerMatch ......................................37
           4.2.20. integerOrderingMatch ..............................37
           4.2.21. keywordMatch ......................................38
           4.2.22. numericStringMatch ................................38
           4.2.23. numericStringOrderingMatch ........................39
           4.2.24. numericStringSubstringsMatch ......................39
           4.2.25. objectIdentifierFirstComponentMatch ...............40
           4.2.26. objectIdentifierMatch .............................40
           4.2.27. octetStringMatch ..................................41
           4.2.28. octetStringOrderingMatch ..........................41
           4.2.29. telephoneNumberMatch ..............................42
           4.2.30. telephoneNumberSubstringsMatch ....................42
           4.2.31. uniqueMemberMatch .................................43
           4.2.32. wordMatch .........................................44
   5. Security Considerations ........................................44
   6. Acknowledgements ...............................................44
   7. IANA Considerations ............................................45
   8. References .....................................................46
      8.1. Normative References ......................................46
      8.2. Informative References ....................................48
   Appendix A. Summary of Syntax Object Identifiers ..................49
   Appendix B. Changes from RFC 2252 .................................49

1.  Introduction

   Each attribute stored in a Lightweight Directory Access Protocol
   (LDAP) directory [RFC4510], whose values may be transferred in the
   LDAP protocol [RFC4511], has a defined syntax (i.e., data type) that
   constrains the structure and format of its values.  The comparison
   semantics for values of a syntax are not part of the syntax
   definition but are instead provided through separately defined
   matching rules.  Matching rules specify an argument, an assertion
   value, which also has a defined syntax.  This document defines a base
   set of syntaxes and matching rules for use in defining attributes for
   LDAP directories.

   Readers are advised to familiarize themselves with the Directory
   Information Models [RFC4512] before reading the rest of this
   document.  Section 3 provides definitions for the base set of LDAP
   syntaxes.  Section 4 provides definitions for the base set of
   matching rules for LDAP.

   This document is an integral part of the LDAP technical specification
   [RFC4510], which obsoletes the previously defined LDAP technical
   specification, RFC 3377, in its entirety.




Legg                        Standards Track                     [Page 3]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   Sections 4, 5, and 7 of RFC 2252 are obsoleted by [RFC4512].  The
   remainder of RFC 2252 is obsoleted by this document.  Sections 6 and
   8 of RFC 2256 are obsoleted by this document.  The remainder of RFC
   2256 is obsoleted by [RFC4519] and [RFC4512].  All but Section 2.11
   of RFC 3698 is obsoleted by this document.

   A number of schema elements that were included in the previous
   revision of the LDAP technical specification are not included in this
   revision of LDAP.  Public Key Infrastructure schema elements are now
   specified in [RFC4523].  Unless reintroduced in future technical
   specifications, the remainder are to be considered Historic.

   The changes with respect to RFC 2252 are described in Appendix B of
   this document.

2.  Conventions

   In this document, the key words "MUST", "MUST NOT", "REQUIRED",
   "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
   and "OPTIONAL" are to be interpreted as described in BCP 14, RFC 2119
   [RFC2119].

   Syntax definitions are written according to the <SyntaxDescription>
   ABNF [RFC4234] rule specified in [RFC4512], and matching rule
   definitions are written according to the <MatchingRuleDescription>
   ABNF rule specified in [RFC4512], except that the syntax and matching
   rule definitions provided in this document are line-wrapped for
   readability.  When such definitions are transferred as attribute
   values in the LDAP protocol (e.g., as values of the ldapSyntaxes and
   matchingRules attributes [RFC4512], respectively), then those values
   would not contain line breaks.

3.  Syntaxes

   Syntax definitions constrain the structure of attribute values stored
   in an LDAP directory, and determine the representation of attribute
   and assertion values transferred in the LDAP protocol.

   Syntaxes that are required for directory operation, or that are in
   common use, are specified in this section.  Servers SHOULD recognize
   all the syntaxes listed in this document, but are not required to
   otherwise support them, and MAY recognise or support other syntaxes.
   However, the definition of additional arbitrary syntaxes is
   discouraged since it will hinder interoperability.  Client and server
   implementations typically do not have the ability to dynamically
   recognize new syntaxes.





Legg                        Standards Track                     [Page 4]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


3.1.  General Considerations

   The description of each syntax specifies how attribute or assertion
   values conforming to the syntax are to be represented when
   transferred in the LDAP protocol [RFC4511].  This representation is
   referred to as the LDAP-specific encoding to distinguish it from
   other methods of encoding attribute values (e.g., the Basic Encoding
   Rules (BER) encoding [BER] used by X.500 [X.500] directories).

   The LDAP-specific encoding of a given attribute syntax always
   produces octet-aligned values.  To the greatest extent possible,
   encoding rules for LDAP syntaxes should produce character strings
   that can be displayed with little or no translation by clients
   implementing LDAP.  However, clients MUST NOT assume that the LDAP-
   specific encoding of a value of an unrecognized syntax is a human-
   readable character string.  There are a few cases (e.g., the JPEG
   syntax) when it is not reasonable to produce a human-readable
   representation.

   Each LDAP syntax is uniquely identified with an object identifier
   [ASN.1] represented in the dotted-decimal format (short descriptive
   names are not defined for syntaxes).  These object identifiers are
   not intended to be displayed to users.  The object identifiers for
   the syntaxes defined in this document are summarized in Appendix A.

   A suggested minimum upper bound on the number of characters in an
   attribute value with a string-based syntax, or the number of octets
   in a value for all other syntaxes, MAY be indicated by appending the
   bound inside of curly braces following the syntax's OBJECT IDENTIFIER
   in an attribute type definition (see the <noidlen> rule in
   [RFC4512]).  Such a bound is not considered part of the syntax
   identifier.

   For example, "1.3.6.1.4.1.1466.115.121.1.15{64}" in an attribute
   definition suggests that the directory server will allow a value of
   the attribute to be up to 64 characters long, although it may allow
   longer character strings.  Note that a single character of the
   Directory String syntax can be encoded in more than one octet, since
   UTF-8 [RFC3629] is a variable-length encoding.  Therefore, a 64-
   character string may be more than 64 octets in length.

3.2.  Common Definitions

   The following ABNF rules are used in a number of the syntax
   definitions in Section 3.3.

      PrintableCharacter = ALPHA / DIGIT / SQUOTE / LPAREN / RPAREN /
                           PLUS / COMMA / HYPHEN / DOT / EQUALS /



Legg                        Standards Track                     [Page 5]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


                           SLASH / COLON / QUESTION / SPACE
      PrintableString    = 1*PrintableCharacter
      IA5String          = *(%x00-7F)
      SLASH              = %x2F  ; forward slash ("/")
      COLON              = %x3A  ; colon (":")
      QUESTION           = %x3F  ; question mark ("?")

   The <ALPHA>, <DIGIT>, <SQUOTE>, <LPAREN>, <RPAREN>, <PLUS>, <COMMA>,
   <HYPHEN>, <DOT>, <EQUALS>, and <SPACE> rules are defined in
   [RFC4512].

3.3.  Syntax Definitions

3.3.1.  Attribute Type Description

   A value of the Attribute Type Description syntax is the definition of
   an attribute type.  The LDAP-specific encoding of a value of this
   syntax is defined by the <AttributeTypeDescription> rule in
   [RFC4512].

      For example, the following definition of the createTimestamp
      attribute type from [RFC4512] is also a value of the Attribute
      Type Description syntax.  (Note: Line breaks have been added for
      readability; they are not part of the value when transferred in
      protocol.)

         ( 2.5.18.1 NAME 'createTimestamp'
            EQUALITY generalizedTimeMatch
            ORDERING generalizedTimeOrderingMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
            SINGLE-VALUE NO-USER-MODIFICATION
            USAGE directoryOperation )

   The LDAP definition for the Attribute Type Description syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )

   This syntax corresponds to the AttributeTypeDescription ASN.1 type
   from [X.501].

3.3.2.  Bit String

   A value of the Bit String syntax is a sequence of binary digits.  The
   LDAP-specific encoding of a value of this syntax is defined by the
   following ABNF:

      BitString    = SQUOTE *binary-digit SQUOTE "B"
      binary-digit = "0" / "1"



Legg                        Standards Track                     [Page 6]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   The <SQUOTE> rule is defined in [RFC4512].

      Example:
         '0101111101'B

   The LDAP definition for the Bit String syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )

   This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].

3.3.3.  Boolean

   A value of the Boolean syntax is one of the Boolean values, true or
   false.  The LDAP-specific encoding of a value of this syntax is
   defined by the following ABNF:

      Boolean = "TRUE" / "FALSE"

   The LDAP definition for the Boolean syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )

   This syntax corresponds to the BOOLEAN ASN.1 type from [ASN.1].

3.3.4.  Country String

   A value of the Country String syntax is one of the two-character
   codes from ISO 3166 [ISO3166] for representing a country.  The LDAP-
   specific encoding of a value of this syntax is defined by the
   following ABNF:

      CountryString  = 2(PrintableCharacter)

   The <PrintableCharacter> rule is defined in Section 3.2.

      Examples:

         US
         AU

   The LDAP definition for the Country String syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )

   This syntax corresponds to the following ASN.1 type from [X.520]:

      PrintableString (SIZE (2)) -- ISO 3166 codes only



Legg                        Standards Track                     [Page 7]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


3.3.5.  Delivery Method

   A value of the Delivery Method syntax is a sequence of items that
   indicate, in preference order, the service(s) by which an entity is
   willing and/or capable of receiving messages.  The LDAP-specific
   encoding of a value of this syntax is defined by the following ABNF:

      DeliveryMethod = pdm *( WSP DOLLAR WSP pdm )

      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
            "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"

   The <WSP> and <DOLLAR> rules are defined in [RFC4512].

      Example:
         telephone $ videotex

   The LDAP definition for the Delivery Method syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )

   This syntax corresponds to the following ASN.1 type from [X.520]:

      SEQUENCE OF INTEGER {
          any-delivery-method     (0),
          mhs-delivery            (1),
          physical-delivery       (2),
          telex-delivery          (3),
          teletex-delivery        (4),
          g3-facsimile-delivery   (5),
          g4-facsimile-delivery   (6),
          ia5-terminal-delivery   (7),
          videotex-delivery       (8),
          telephone-delivery      (9) }

3.3.6.  Directory String

   A value of the Directory String syntax is a string of one or more
   arbitrary characters from the Universal Character Set (UCS) [UCS].  A
   zero-length character string is not permitted.  The LDAP-specific
   encoding of a value of this syntax is the UTF-8 encoding [RFC3629] of
   the character string.  Such encodings conform to the following ABNF:

      DirectoryString = 1*UTF8

   The <UTF8> rule is defined in [RFC4512].





Legg                        Standards Track                     [Page 8]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      Example:
         This is a value of Directory String containing #!%#@.

   Servers and clients MUST be prepared to receive arbitrary UCS code
   points, including code points outside the range of printable ASCII
   and code points not presently assigned to any character.

   Attribute type definitions using the Directory String syntax should
   not restrict the format of Directory String values, e.g., by
   requiring that the character string conforms to specific patterns
   described by ABNF.  A new syntax should be defined in such cases.

   The LDAP definition for the Directory String syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )

   This syntax corresponds to the DirectoryString parameterized ASN.1
   type from [X.520].

   The DirectoryString ASN.1 type allows a choice between the
   TeletexString, PrintableString, or UniversalString ASN.1 types from
   [ASN.1].  However, note that the chosen alternative is not indicated
   in the LDAP-specific encoding of a Directory String value.

   Implementations that convert Directory String values from the LDAP-
   specific encoding to the BER encoding used by X.500 must choose an
   alternative that permits the particular characters in the string and
   must convert the characters from the UTF-8 encoding into the
   character encoding of the chosen alternative.  When converting
   Directory String values from the BER encoding to the LDAP-specific
   encoding, the characters must be converted from the character
   encoding of the chosen alternative into the UTF-8 encoding.  These
   conversions SHOULD be done in a manner consistent with the Transcode
   step of the string preparation algorithms [RFC4518] for LDAP.

3.3.7.  DIT Content Rule Description

   A value of the DIT Content Rule Description syntax is the definition
   of a DIT (Directory Information Tree) content rule.  The LDAP-
   specific encoding of a value of this syntax is defined by the
   <DITContentRuleDescription> rule in [RFC4512].

      Example:
         ( 2.5.6.4 DESC 'content rule for organization'
            NOT ( x121Address $ telexNumber ) )

      Note: A line break has been added for readability; it is not part
      of the value.



Legg                        Standards Track                     [Page 9]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   The LDAP definition for the DIT Content Rule Description syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.16
         DESC 'DIT Content Rule Description' )

   This syntax corresponds to the DITContentRuleDescription ASN.1 type
   from [X.501].

3.3.8.  DIT Structure Rule Description

   A value of the DIT Structure Rule Description syntax is the
   definition of a DIT structure rule.  The LDAP-specific encoding of a
   value of this syntax is defined by the <DITStructureRuleDescription>
   rule in [RFC4512].

      Example:
         ( 2 DESC 'organization structure rule' FORM 2.5.15.3 )

   The LDAP definition for the DIT Structure Rule Description syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.17
         DESC 'DIT Structure Rule Description' )

   This syntax corresponds to the DITStructureRuleDescription ASN.1 type
   from [X.501].

3.3.9.  DN

   A value of the DN syntax is the (purported) distinguished name (DN)
   of an entry [RFC4512].  The LDAP-specific encoding of a value of this
   syntax is defined by the <distinguishedName> rule from the string
   representation of distinguished names [RFC4514].

      Examples (from [RFC4514]):
         UID=jsmith,DC=example,DC=net
         OU=Sales+CN=J. Smith,DC=example,DC=net
         CN=John Smith\, III,DC=example,DC=net
         CN=Before\0dAfter,DC=example,DC=net
         1.3.6.1.4.1.1466.0=#04024869,DC=example,DC=com
         CN=Lu\C4\8Di\C4\87

   The LDAP definition for the DN syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'DN' )

   The DN syntax corresponds to the DistinguishedName ASN.1 type from
   [X.501].  Note that a BER encoded distinguished name (as used by
   X.500) re-encoded into the LDAP-specific encoding is not necessarily



Legg                        Standards Track                    [Page 10]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   reversible to the original BER encoding since the chosen string type
   in any DirectoryString components of the distinguished name is not
   indicated in the LDAP-specific encoding of the distinguished name
   (see Section 3.3.6).

3.3.10.  Enhanced Guide

   A value of the Enhanced Guide syntax suggests criteria, which consist
   of combinations of attribute types and filter operators, to be used
   in constructing filters to search for entries of particular object
   classes.  The Enhanced Guide syntax improves upon the Guide syntax by
   allowing the recommended depth of the search to be specified.

   The LDAP-specific encoding of a value of this syntax is defined by
   the following ABNF:

      EnhancedGuide = object-class SHARP WSP criteria WSP
                         SHARP WSP subset
      object-class  = WSP oid WSP
      subset        = "baseobject" / "oneLevel" / "wholeSubtree"

      criteria   = and-term *( BAR and-term )
      and-term   = term *( AMPERSAND term )
      term       = EXCLAIM term /
                   attributetype DOLLAR match-type /
                   LPAREN criteria RPAREN /
                   true /
                   false
      match-type = "EQ" / "SUBSTR" / "GE" / "LE" / "APPROX"
      true       = "?true"
      false      = "?false"
      BAR        = %x7C  ; vertical bar ("|")
      AMPERSAND  = %x26  ; ampersand ("&")
      EXCLAIM    = %x21  ; exclamation mark ("!")

   The <SHARP>, <WSP>, <oid>, <LPAREN>, <RPAREN>, <attributetype>, and
   <DOLLAR> rules are defined in [RFC4512].

   The LDAP definition for the Enhanced Guide syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )

      Example:
         person#(sn$EQ)#oneLevel

   The Enhanced Guide syntax corresponds to the EnhancedGuide ASN.1 type
   from [X.520].  The EnhancedGuide type references the Criteria ASN.1
   type, also from [X.520].  The <true> rule, above, represents an empty



Legg                        Standards Track                    [Page 11]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   "and" expression in a value of the Criteria type.  The <false> rule,
   above, represents an empty "or" expression in a value of the Criteria
   type.

3.3.11.  Facsimile Telephone Number

   A value of the Facsimile Telephone Number syntax is a subscriber
   number of a facsimile device on the public switched telephone
   network.  The LDAP-specific encoding of a value of this syntax is
   defined by the following ABNF:

      fax-number       = telephone-number *( DOLLAR fax-parameter )
      telephone-number = PrintableString
      fax-parameter    = "twoDimensional" /
                         "fineResolution" /
                         "unlimitedLength" /
                         "b4Length" /
                         "a3Width" /
                         "b4Width" /
                         "uncompressed"

   The <telephone-number> is a string of printable characters that
   complies with the internationally agreed format for representing
   international telephone numbers [E.123].  The <PrintableString> rule
   is defined in Section 3.2.  The <DOLLAR> rule is defined in
   [RFC4512].

   The LDAP definition for the Facsimile Telephone Number syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number')

   The Facsimile Telephone Number syntax corresponds to the
   FacsimileTelephoneNumber ASN.1 type from [X.520].

3.3.12.  Fax

   A value of the Fax syntax is an image that is produced using the
   Group 3 facsimile process [FAX] to duplicate an object, such as a
   memo.  The LDAP-specific encoding of a value of this syntax is the
   string of octets for a Group 3 Fax image as defined in [FAX].

   The LDAP definition for the Fax syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' )

   The ASN.1 type corresponding to the Fax syntax is defined as follows,
   assuming EXPLICIT TAGS:




Legg                        Standards Track                    [Page 12]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      Fax ::= CHOICE {
        g3-facsimile  [3] G3FacsimileBodyPart
      }

   The G3FacsimileBodyPart ASN.1 type is defined in [X.420].

3.3.13.  Generalized Time

   A value of the Generalized Time syntax is a character string
   representing a date and time.  The LDAP-specific encoding of a value
   of this syntax is a restriction of the format defined in [ISO8601],
   and is described by the following ABNF:

      GeneralizedTime = century year month day hour
                           [ minute [ second / leap-second ] ]
                           [ fraction ]
                           g-time-zone

      century = 2(%x30-39) ; "00" to "99"
      year    = 2(%x30-39) ; "00" to "99"
      month   =   ( %x30 %x31-39 ) ; "01" (January) to "09"
                / ( %x31 %x30-32 ) ; "10" to "12"
      day     =   ( %x30 %x31-39 )    ; "01" to "09"
                / ( %x31-32 %x30-39 ) ; "10" to "29"
                / ( %x33 %x30-31 )    ; "30" to "31"
      hour    = ( %x30-31 %x30-39 ) / ( %x32 %x30-33 ) ; "00" to "23"
      minute  = %x30-35 %x30-39                        ; "00" to "59"

      second      = ( %x30-35 %x30-39 ) ; "00" to "59"
      leap-second = ( %x36 %x30 )       ; "60"

      fraction        = ( DOT / COMMA ) 1*(%x30-39)
      g-time-zone     = %x5A  ; "Z"
                        / g-differential
      g-differential  = ( MINUS / PLUS ) hour [ minute ]
      MINUS           = %x2D  ; minus sign ("-")

   The <DOT>, <COMMA>, and <PLUS> rules are defined in [RFC4512].

   The above ABNF allows character strings that do not represent valid
   dates (in the Gregorian calendar) and/or valid times (e.g., February
   31, 1994).  Such character strings SHOULD be considered invalid for
   this syntax.

   The time value represents coordinated universal time (equivalent to
   Greenwich Mean Time) if the "Z" form of <g-time-zone> is used;
   otherwise, the value represents a local time in the time zone
   indicated by <g-differential>.  In the latter case, coordinated



Legg                        Standards Track                    [Page 13]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   universal time can be calculated by subtracting the differential from
   the local time.  The "Z" form of <g-time-zone> SHOULD be used in
   preference to <g-differential>.

   If <minute> is omitted, then <fraction> represents a fraction of an
   hour; otherwise, if <second> and <leap-second> are omitted, then
   <fraction> represents a fraction of a minute; otherwise, <fraction>
   represents a fraction of a second.

      Examples:
         199412161032Z
         199412160532-0500

   Both example values represent the same coordinated universal time:
   10:32 AM, December 16, 1994.

   The LDAP definition for the Generalized Time syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )

   This syntax corresponds to the GeneralizedTime ASN.1 type from
   [ASN.1], with the constraint that local time without a differential
   SHALL NOT be used.

3.3.14.  Guide

   A value of the Guide syntax suggests criteria, which consist of
   combinations of attribute types and filter operators, to be used in
   constructing filters to search for entries of particular object
   classes.  The Guide syntax is obsolete and should not be used for
   defining new attribute types.

   The LDAP-specific encoding of a value of this syntax is defined by
   the following ABNF:

      Guide = [ object-class SHARP ] criteria

   The <object-class> and <criteria> rules are defined in Section
   3.3.10.  The <SHARP> rule is defined in [RFC4512].

   The LDAP definition for the Guide syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )

   The Guide syntax corresponds to the Guide ASN.1 type from [X.520].






Legg                        Standards Track                    [Page 14]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


3.3.15.  IA5 String

   A value of the IA5 String syntax is a string of zero, one, or more
   characters from International Alphabet 5 (IA5) [T.50], the
   international version of the ASCII character set.  The LDAP-specific
   encoding of a value of this syntax is the unconverted string of
   characters, which conforms to the <IA5String> rule in Section 3.2.

   The LDAP definition for the IA5 String syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )

   This syntax corresponds to the IA5String ASN.1 type from [ASN.1].

3.3.16.  Integer

   A value of the Integer syntax is a whole number of unlimited
   magnitude.  The LDAP-specific encoding of a value of this syntax is
   the optionally signed decimal digit character string representation
   of the number (for example, the number 1321 is represented by the
   character string "1321").  The encoding is defined by the following
   ABNF:

      Integer = ( HYPHEN LDIGIT *DIGIT ) / number

   The <HYPHEN>, <LDIGIT>, <DIGIT>, and <number> rules are defined in
   [RFC4512].

   The LDAP definition for the Integer syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'INTEGER' )

   This syntax corresponds to the INTEGER ASN.1 type from [ASN.1].

3.3.17.  JPEG

   A value of the JPEG syntax is an image in the JPEG File Interchange
   Format (JFIF), as described in [JPEG].  The LDAP-specific encoding of
   a value of this syntax is the sequence of octets of the JFIF encoding
   of the image.

   The LDAP definition for the JPEG syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' )

   The JPEG syntax corresponds to the following ASN.1 type:





Legg                        Standards Track                    [Page 15]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      JPEG ::= OCTET STRING (CONSTRAINED BY
                   { -- contents octets are an image in the --
                     -- JPEG File Interchange Format -- })

3.3.18.  LDAP Syntax Description

   A value of the LDAP Syntax Description syntax is the description of
   an LDAP syntax.  The LDAP-specific encoding of a value of this syntax
   is defined by the <SyntaxDescription> rule in [RFC4512].

   The LDAP definition for the LDAP Syntax Description syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )

   The above LDAP definition for the LDAP Syntax Description syntax is
   itself a legal value of the LDAP Syntax Description syntax.

   The ASN.1 type corresponding to the LDAP Syntax Description syntax is
   defined as follows, assuming EXPLICIT TAGS:

      LDAPSyntaxDescription ::= SEQUENCE {
          identifier      OBJECT IDENTIFIER,
          description     DirectoryString { ub-schema } OPTIONAL }

   The DirectoryString parameterized ASN.1 type is defined in [X.520].

   The value of ub-schema (an integer) is implementation defined.  A
   non-normative definition appears in [X.520].

3.3.19.  Matching Rule Description

   A value of the Matching Rule Description syntax is the definition of
   a matching rule.  The LDAP-specific encoding of a value of this
   syntax is defined by the <MatchingRuleDescription> rule in [RFC4512].

      Example:
         ( 2.5.13.2 NAME 'caseIgnoreMatch'
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   Note: A line break has been added for readability; it is not part of
   the syntax.

   The LDAP definition for the Matching Rule Description syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )

   This syntax corresponds to the MatchingRuleDescription ASN.1 type
   from [X.501].



Legg                        Standards Track                    [Page 16]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


3.3.20.  Matching Rule Use Description

   A value of the Matching Rule Use Description syntax indicates the
   attribute types to which a matching rule may be applied in an
   extensibleMatch search filter [RFC4511].  The LDAP-specific encoding
   of a value of this syntax is defined by the
   <MatchingRuleUseDescription> rule in [RFC4512].

      Example:
         ( 2.5.13.16 APPLIES ( givenName $ surname ) )

   The LDAP definition for the Matching Rule Use Description syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.31
         DESC 'Matching Rule Use Description' )

   This syntax corresponds to the MatchingRuleUseDescription ASN.1 type
   from [X.501].

3.3.21.  Name and Optional UID

   A value of the Name and Optional UID syntax is the distinguished name
   [RFC4512] of an entity optionally accompanied by a unique identifier
   that serves to differentiate the entity from others with an identical
   distinguished name.

   The LDAP-specific encoding of a value of this syntax is defined by
   the following ABNF:

      NameAndOptionalUID = distinguishedName [ SHARP BitString ]

   The <BitString> rule is defined in Section 3.3.2.  The
   <distinguishedName> rule is defined in [RFC4514].  The <SHARP> rule
   is defined in [RFC4512].

   Note that although the '#' character may occur in the string
   representation of a distinguished name, no additional escaping of
   this character is performed when a <distinguishedName> is encoded in
   a <NameAndOptionalUID>.

      Example:
         1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B

   The LDAP definition for the Name and Optional UID syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )





Legg                        Standards Track                    [Page 17]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   This syntax corresponds to the NameAndOptionalUID ASN.1 type from
   [X.520].

3.3.22.  Name Form Description

   A value of the Name Form Description syntax is the definition of a
   name form, which regulates how entries may be named.  The LDAP-
   specific encoding of a value of this syntax is defined by the
   <NameFormDescription> rule in [RFC4512].

      Example:
         ( 2.5.15.3 NAME 'orgNameForm' OC organization MUST o )

   The LDAP definition for the Name Form Description syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )

   This syntax corresponds to the NameFormDescription ASN.1 type from
   [X.501].

3.3.23.  Numeric String

   A value of the Numeric String syntax is a sequence of one or more
   numerals and spaces.  The LDAP-specific encoding of a value of this
   syntax is the unconverted string of characters, which conforms to the
   following ABNF:

      NumericString = 1*(DIGIT / SPACE)

   The <DIGIT> and <SPACE> rules are defined in [RFC4512].

      Example:
         15 079 672 281

   The LDAP definition for the Numeric String syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )

   This syntax corresponds to the NumericString ASN.1 type from [ASN.1].

3.3.24.  Object Class Description

   A value of the Object Class Description syntax is the definition of
   an object class.  The LDAP-specific encoding of a value of this
   syntax is defined by the <ObjectClassDescription> rule in [RFC4512].






Legg                        Standards Track                    [Page 18]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      Example:
         ( 2.5.6.2 NAME 'country' SUP top STRUCTURAL MUST c
            MAY ( searchGuide $ description ) )

   Note: A line break has been added for readability; it is not part of
   the syntax.

   The LDAP definition for the Object Class Description syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )

   This syntax corresponds to the ObjectClassDescription ASN.1 type from
   [X.501].

3.3.25.  Octet String

   A value of the Octet String syntax is a sequence of zero, one, or
   more arbitrary octets.  The LDAP-specific encoding of a value of this
   syntax is the unconverted sequence of octets, which conforms to the
   following ABNF:

      OctetString = *OCTET

   The <OCTET> rule is defined in [RFC4512].  Values of this syntax are
   not generally human-readable.

   The LDAP definition for the Octet String syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )

   This syntax corresponds to the OCTET STRING ASN.1 type from [ASN.1].

3.3.26.  OID

   A value of the OID syntax is an object identifier: a sequence of two
   or more non-negative integers that uniquely identify some object or
   item of specification.  Many of the object identifiers used in LDAP
   also have IANA registered names [RFC4520].

   The LDAP-specific encoding of a value of this syntax is defined by
   the <oid> rule in [RFC4512].

      Examples:
         1.2.3.4
         cn

   The LDAP definition for the OID syntax is:




Legg                        Standards Track                    [Page 19]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      ( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )

   This syntax corresponds to the OBJECT IDENTIFIER ASN.1 type from
   [ASN.1].

3.3.27.  Other Mailbox

   A value of the Other Mailbox syntax identifies an electronic mailbox,
   in a particular named mail system.  The LDAP-specific encoding of a
   value of this syntax is defined by the following ABNF:

      OtherMailbox = mailbox-type DOLLAR mailbox
      mailbox-type = PrintableString
      mailbox      = IA5String

   The <mailbox-type> rule represents the type of mail system in which
   the mailbox resides (for example, "MCIMail"), and <mailbox> is the
   actual mailbox in the mail system described by <mailbox-type>.  The
   <PrintableString> and <IA5String> rules are defined in Section 3.2.
   The <DOLLAR> rule is defined in [RFC4512].

   The LDAP definition for the Other Mailbox syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )

   The ASN.1 type corresponding to the Other Mailbox syntax is defined
   as follows, assuming EXPLICIT TAGS:

      OtherMailbox ::= SEQUENCE {
          mailboxType  PrintableString,
          mailbox      IA5String
      }

3.3.28.  Postal Address

   A value of the Postal Address syntax is a sequence of strings of one
   or more arbitrary UCS characters, which form an address in a physical
   mail system.

   The LDAP-specific encoding of a value of this syntax is defined by
   the following ABNF:










Legg                        Standards Track                    [Page 20]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      PostalAddress = line *( DOLLAR line )
      line          = 1*line-char
      line-char     = %x00-23
                      / (%x5C "24")  ; escaped "$"
                      / %x25-5B
                      / (%x5C "5C")  ; escaped "\"
                      / %x5D-7F
                      / UTFMB

   Each character string (i.e., <line>) of a postal address value is
   encoded as a UTF-8 [RFC3629] string, except that "\" and "$"
   characters, if they occur in the string, are escaped by a "\"
   character followed by the two hexadecimal digit code for the
   character.  The <DOLLAR> and <UTFMB> rules are defined in [RFC4512].

   Many servers limit the postal address to no more than six lines of no
   more than thirty characters each.

      Example:
         1234 Main St.$Anytown, CA 12345$USA
         \241,000,000 Sweepstakes$PO Box 1000000$Anytown, CA 12345$USA

   The LDAP definition for the Postal Address syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )

   This syntax corresponds to the PostalAddress ASN.1 type from [X.520];
   that is

      PostalAddress ::= SEQUENCE SIZE(1..ub-postal-line) OF
          DirectoryString { ub-postal-string }

   The values of ub-postal-line and ub-postal-string (both integers) are
   implementation defined.  Non-normative definitions appear in [X.520].

3.3.29.  Printable String

   A value of the Printable String syntax is a string of one or more
   latin alphabetic, numeric, and selected punctuation characters as
   specified by the <PrintableCharacter> rule in Section 3.2.

   The LDAP-specific encoding of a value of this syntax is the
   unconverted string of characters, which conforms to the
   <PrintableString> rule in Section 3.2.

      Example:
         This is a PrintableString.




Legg                        Standards Track                    [Page 21]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   The LDAP definition for the PrintableString syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )

   This syntax corresponds to the PrintableString ASN.1 type from
   [ASN.1].

3.3.30.  Substring Assertion

   A value of the Substring Assertion syntax is a sequence of zero, one,
   or more character substrings used as an argument for substring
   extensible matching of character string attribute values; i.e., as
   the matchValue of a MatchingRuleAssertion [RFC4511].  Each substring
   is a string of one or more arbitrary characters from the Universal
   Character Set (UCS) [UCS].  A zero-length substring is not permitted.

   The LDAP-specific encoding of a value of this syntax is defined by
   the following ABNF:

      SubstringAssertion = [ initial ] any [ final ]

      initial  = substring
      any      = ASTERISK *(substring ASTERISK)
      final    = substring
      ASTERISK = %x2A  ; asterisk ("*")

      substring           = 1*substring-character
      substring-character = %x00-29
                            / (%x5C "2A")  ; escaped "*"
                            / %x2B-5B
                            / (%x5C "5C")  ; escaped "\"
                            / %x5D-7F
                            / UTFMB

   Each <substring> of a Substring Assertion value is encoded as a UTF-8
   [RFC3629] string, except that "\" and "*" characters, if they occur
   in the substring, are escaped by a "\" character followed by the two
   hexadecimal digit code for the character.

   The Substring Assertion syntax is used only as the syntax of
   assertion values in the extensible match.  It is not used as an
   attribute syntax, or in the SubstringFilter [RFC4511].

   The LDAP definition for the Substring Assertion syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )





Legg                        Standards Track                    [Page 22]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   This syntax corresponds to the SubstringAssertion ASN.1 type from
   [X.520].

3.3.31.  Telephone Number

   A value of the Telephone Number syntax is a string of printable
   characters that complies with the internationally agreed format for
   representing international telephone numbers [E.123].

   The LDAP-specific encoding of a value of this syntax is the
   unconverted string of characters, which conforms to the
   <PrintableString> rule in Section 3.2.

      Examples:
         +1 512 315 0280
         +1-512-315-0280
         +61 3 9896 7830

   The LDAP definition for the Telephone Number syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )

   The Telephone Number syntax corresponds to the following ASN.1 type
   from [X.520]:

      PrintableString (SIZE(1..ub-telephone-number))

   The value of ub-telephone-number (an integer) is implementation
   defined.  A non-normative definition appears in [X.520].

3.3.32.  Teletex Terminal Identifier

   A value of this syntax specifies the identifier and (optionally)
   parameters of a teletex terminal.

   The LDAP-specific encoding of a value of this syntax is defined by
   the following ABNF:

      teletex-id = ttx-term *(DOLLAR ttx-param)
      ttx-term   = PrintableString          ; terminal identifier
      ttx-param  = ttx-key COLON ttx-value  ; parameter
      ttx-key    = "graphic" / "control" / "misc" / "page" / "private"
      ttx-value  = *ttx-value-octet

      ttx-value-octet = %x00-23
                        / (%x5C "24")  ; escaped "$"
                        / %x25-5B
                        / (%x5C "5C")  ; escaped "\"



Legg                        Standards Track                    [Page 23]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


                        / %x5D-FF

   The <PrintableString> and <COLON> rules are defined in Section 3.2.
   The <DOLLAR> rule is defined in [RFC4512].

   The LDAP definition for the Teletex Terminal Identifier syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.51
         DESC 'Teletex Terminal Identifier' )

   This syntax corresponds to the TeletexTerminalIdentifier ASN.1 type
   from [X.520].

3.3.33.  Telex Number

   A value of the Telex Number syntax specifies the telex number,
   country code, and answerback code of a telex terminal.

   The LDAP-specific encoding of a value of this syntax is defined by
   the following ABNF:

      telex-number  = actual-number DOLLAR country-code
                         DOLLAR answerback
      actual-number = PrintableString
      country-code  = PrintableString
      answerback    = PrintableString

   The <PrintableString> rule is defined in Section 3.2.  The <DOLLAR>
   rule is defined in [RFC4512].

   The LDAP definition for the Telex Number syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )

   This syntax corresponds to the TelexNumber ASN.1 type from [X.520].

3.3.34.  UTC Time

   A value of the UTC Time syntax is a character string representing a
   date and time to a precision of one minute or one second.  The year
   is given as a two-digit number.  The LDAP-specific encoding of a
   value of this syntax follows the format defined in [ASN.1] for the
   UTCTime type and is described by the following ABNF:

      UTCTime         = year month day hour minute [ second ]
                           [ u-time-zone ]
      u-time-zone     = %x5A  ; "Z"
                        / u-differential



Legg                        Standards Track                    [Page 24]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      u-differential  = ( MINUS / PLUS ) hour minute

   The <year>, <month>, <day>, <hour>, <minute>, <second>, and <MINUS>
   rules are defined in Section 3.3.13.  The <PLUS> rule is defined in
   [RFC4512].

   The above ABNF allows character strings that do not represent valid
   dates (in the Gregorian calendar) and/or valid times.  Such character
   strings SHOULD be considered invalid for this syntax.

   The time value represents coordinated universal time if the "Z" form
   of <u-time-zone> is used; otherwise, the value represents a local
   time.  In the latter case, if <u-differential> is provided, then
   coordinated universal time can be calculated by subtracting the
   differential from the local time.  The <u-time-zone> SHOULD be
   present in time values, and the "Z" form of <u-time-zone> SHOULD be
   used in preference to <u-differential>.

   The LDAP definition for the UTC Time syntax is:

      ( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )

   Note: This syntax is deprecated in favor of the Generalized Time
   syntax.

   The UTC Time syntax corresponds to the UTCTime ASN.1 type from
   [ASN.1].

4.  Matching Rules

   Matching rules are used by directory implementations to compare
   attribute values against assertion values when performing Search and
   Compare operations [RFC4511].  They are also used when comparing a
   purported distinguished name [RFC4512] with the name of an entry.
   When modifying entries, matching rules are used to identify values to
   be deleted and to prevent an attribute from containing two equal
   values.

   Matching rules that are required for directory operation, or that are
   in common use, are specified in this section.

4.1.  General Considerations

   A matching rule is applied to attribute values through an
   AttributeValueAssertion or MatchingRuleAssertion [RFC4511].  The
   conditions under which an AttributeValueAssertion or
   MatchingRuleAssertion evaluates to Undefined are specified elsewhere
   [RFC4511].  If an assertion is not Undefined, then the result of the



Legg                        Standards Track                    [Page 25]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   assertion is the result of applying the selected matching rule.  A
   matching rule evaluates to TRUE, and in some cases Undefined, as
   specified in the description of the matching rule; otherwise, it
   evaluates to FALSE.

   Each assertion contains an assertion value.  The definition of each
   matching rule specifies the syntax for the assertion value.  The
   syntax of the assertion value is typically, but not necessarily, the
   same as the syntax of the attribute values to which the matching rule
   may be applied.  Note that an AssertionValue in a SubstringFilter
   [RFC4511] conforms to the assertion syntax of the equality matching
   rule for the attribute type rather than to the assertion syntax of
   the substrings matching rule for the attribute type.  Conceptually,
   the entire SubstringFilter is converted into an assertion value of
   the substrings matching rule prior to applying the rule.

   The definition of each matching rule indicates the attribute syntaxes
   to which the rule may be applied, by specifying conditions the
   corresponding ASN.1 type of a candidate attribute syntax must
   satisfy.  These conditions are also satisfied if the corresponding
   ASN.1 type is a tagged or constrained derivative of the ASN.1 type
   explicitly mentioned in the rule description (i.e., ASN.1 tags and
   constraints are ignored in checking applicability), or is an
   alternative reference notation for the explicitly mentioned type.
   Each rule description lists, as examples of applicable attribute
   syntaxes, the complete list of the syntaxes defined in this document
   to which the matching rule applies.  A matching rule may be
   applicable to additional syntaxes defined in other documents if those
   syntaxes satisfy the conditions on the corresponding ASN.1 type.

   The description of each matching rule indicates whether the rule is
   suitable for use as the equality matching rule (EQUALITY), ordering
   matching rule (ORDERING), or substrings matching rule (SUBSTR) in an
   attribute type definition [RFC4512].

   Each matching rule is uniquely identified with an object identifier.
   The definition of a matching rule should not subsequently be changed.
   If a change is desirable, then a new matching rule with a different
   object identifier should be defined instead.

   Servers MAY implement the wordMatch and keywordMatch matching rules,
   but they SHOULD implement the other matching rules in Section 4.2.
   Servers MAY implement additional matching rules.

   Servers that implement the extensibleMatch filter SHOULD allow the
   matching rules listed in Section 4.2 to be used in the
   extensibleMatch filter and SHOULD allow matching rules to be used
   with all attribute types known to the server, where the assertion



Legg                        Standards Track                    [Page 26]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   syntax of the matching rule is the same as the value syntax of the
   attribute.

   Servers MUST publish, in the matchingRules attribute, the definitions
   of matching rules referenced by values of the attributeTypes and
   matchingRuleUse attributes in the same subschema entry.  Other
   unreferenced matching rules MAY be published in the matchingRules
   attribute.

   If the server supports the extensibleMatch filter, then the server
   MAY use the matchingRuleUse attribute to indicate the applicability
   (in an extensibleMatch filter) of selected matching rules to
   nominated attribute types.

4.2.  Matching Rule Definitions

   Nominated character strings in assertion and attribute values are
   prepared according to the string preparation algorithms [RFC4518] for
   LDAP when evaluating the following matching rules:

      numericStringMatch,
      numericStringSubstringsMatch,
      caseExactMatch,
      caseExactOrderingMatch,
      caseExactSubstringsMatch,
      caseExactIA5Match,
      caseIgnoreIA5Match,
      caseIgnoreIA5SubstringsMatch,
      caseIgnoreListMatch,
      caseIgnoreListSubstringsMatch,
      caseIgnoreMatch,
      caseIgnoreOrderingMatch,
      caseIgnoreSubstringsMatch,
      directoryStringFirstComponentMatch,
      telephoneNumberMatch,
      telephoneNumberSubstringsMatch and
      wordMatch.

   The Transcode, Normalize, Prohibit, and Check bidi steps are the same
   for each of the matching rules.  However, the Map and Insignificant
   Character Handling steps depend on the specific rule, as detailed in
   the description of these matching rules in the sections that follow.

4.2.1.  bitStringMatch

   The bitStringMatch rule compares an assertion value of the Bit String
   syntax to an attribute value of a syntax (e.g., the Bit String
   syntax) whose corresponding ASN.1 type is BIT STRING.



Legg                        Standards Track                    [Page 27]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   If the corresponding ASN.1 type of the attribute syntax does not have
   a named bit list [ASN.1] (which is the case for the Bit String
   syntax), then the rule evaluates to TRUE if and only if the attribute
   value has the same number of bits as the assertion value and the bits
   match on a bitwise basis.

   If the corresponding ASN.1 type does have a named bit list, then
   bitStringMatch operates as above, except that trailing zero bits in
   the attribute and assertion values are treated as absent.

   The LDAP definition for the bitStringMatch rule is:

      ( 2.5.13.16 NAME 'bitStringMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )

   The bitStringMatch rule is an equality matching rule.

4.2.2.  booleanMatch

   The booleanMatch rule compares an assertion value of the Boolean
   syntax to an attribute value of a syntax (e.g., the Boolean syntax)
   whose corresponding ASN.1 type is BOOLEAN.

   The rule evaluates to TRUE if and only if the attribute value and the
   assertion value are both TRUE or both FALSE.

   The LDAP definition for the booleanMatch rule is:

      ( 2.5.13.13 NAME 'booleanMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )

   The booleanMatch rule is an equality matching rule.

4.2.3.  caseExactIA5Match

   The caseExactIA5Match rule compares an assertion value of the IA5
   String syntax to an attribute value of a syntax (e.g., the IA5 String
   syntax) whose corresponding ASN.1 type is IA5String.

   The rule evaluates to TRUE if and only if the prepared attribute
   value character string and the prepared assertion value character
   string have the same number of characters and corresponding
   characters have the same code point.

   In preparing the attribute value and assertion value for comparison,
   characters are not case folded in the Map preparation step, and only
   Insignificant Space Handling is applied in the Insignificant
   Character Handling step.



Legg                        Standards Track                    [Page 28]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   The LDAP definition for the caseExactIA5Match rule is:

      ( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

   The caseExactIA5Match rule is an equality matching rule.

4.2.4.  caseExactMatch

   The caseExactMatch rule compares an assertion value of the Directory
   String syntax to an attribute value of a syntax (e.g., the Directory
   String, Printable String, Country String, or Telephone Number syntax)
   whose corresponding ASN.1 type is DirectoryString or one of the
   alternative string types of DirectoryString, such as PrintableString
   (the other alternatives do not correspond to any syntax defined in
   this document).

   The rule evaluates to TRUE if and only if the prepared attribute
   value character string and the prepared assertion value character
   string have the same number of characters and corresponding
   characters have the same code point.

   In preparing the attribute value and assertion value for comparison,
   characters are not case folded in the Map preparation step, and only
   Insignificant Space Handling is applied in the Insignificant
   Character Handling step.

   The LDAP definition for the caseExactMatch rule is:

      ( 2.5.13.5 NAME 'caseExactMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The caseExactMatch rule is an equality matching rule.

4.2.5.  caseExactOrderingMatch

   The caseExactOrderingMatch rule compares an assertion value of the
   Directory String syntax to an attribute value of a syntax (e.g., the
   Directory String, Printable String, Country String, or Telephone
   Number syntax) whose corresponding ASN.1 type is DirectoryString or
   one of its alternative string types.

   The rule evaluates to TRUE if and only if, in the code point
   collation order, the prepared attribute value character string
   appears earlier than the prepared assertion value character string;
   i.e., the attribute value is "less than" the assertion value.





Legg                        Standards Track                    [Page 29]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   In preparing the attribute value and assertion value for comparison,
   characters are not case folded in the Map preparation step, and only
   Insignificant Space Handling is applied in the Insignificant
   Character Handling step.

   The LDAP definition for the caseExactOrderingMatch rule is:

      ( 2.5.13.6 NAME 'caseExactOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The caseExactOrderingMatch rule is an ordering matching rule.

4.2.6.  caseExactSubstringsMatch

   The caseExactSubstringsMatch rule compares an assertion value of the
   Substring Assertion syntax to an attribute value of a syntax (e.g.,
   the Directory String, Printable String, Country String, or Telephone
   Number syntax) whose corresponding ASN.1 type is DirectoryString or
   one of its alternative string types.

   The rule evaluates to TRUE if and only if (1) the prepared substrings
   of the assertion value match disjoint portions of the prepared
   attribute value character string in the order of the substrings in
   the assertion value, (2) an <initial> substring, if present, matches
   the beginning of the prepared attribute value character string, and
   (3) a <final> substring, if present, matches the end of the prepared
   attribute value character string.  A prepared substring matches a
   portion of the prepared attribute value character string if
   corresponding characters have the same code point.

   In preparing the attribute value and assertion value substrings for
   comparison, characters are not case folded in the Map preparation
   step, and only Insignificant Space Handling is applied in the
   Insignificant Character Handling step.

   The LDAP definition for the caseExactSubstringsMatch rule is:

      ( 2.5.13.7 NAME 'caseExactSubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   The caseExactSubstringsMatch rule is a substrings matching rule.

4.2.7.  caseIgnoreIA5Match

   The caseIgnoreIA5Match rule compares an assertion value of the IA5
   String syntax to an attribute value of a syntax (e.g., the IA5 String
   syntax) whose corresponding ASN.1 type is IA5String.




Legg                        Standards Track                    [Page 30]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   The rule evaluates to TRUE if and only if the prepared attribute
   value character string and the prepared assertion value character
   string have the same number of characters and corresponding
   characters have the same code point.

   In preparing the attribute value and assertion value for comparison,
   characters are case folded in the Map preparation step, and only
   Insignificant Space Handling is applied in the Insignificant
   Character Handling step.

   The LDAP definition for the caseIgnoreIA5Match rule is:

      ( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

   The caseIgnoreIA5Match rule is an equality matching rule.

4.2.8.  caseIgnoreIA5SubstringsMatch

   The caseIgnoreIA5SubstringsMatch rule compares an assertion value of
   the Substring Assertion syntax to an attribute value of a syntax
   (e.g., the IA5 String syntax) whose corresponding ASN.1 type is
   IA5String.

   The rule evaluates to TRUE if and only if (1) the prepared substrings
   of the assertion value match disjoint portions of the prepared
   attribute value character string in the order of the substrings in
   the assertion value, (2) an <initial> substring, if present, matches
   the beginning of the prepared attribute value character string, and
   (3) a <final> substring, if present, matches the end of the prepared
   attribute value character string.  A prepared substring matches a
   portion of the prepared attribute value character string if
   corresponding characters have the same code point.

   In preparing the attribute value and assertion value substrings for
   comparison, characters are case folded in the Map preparation step,
   and only Insignificant Space Handling is applied in the Insignificant
   Character Handling step.

      ( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   The caseIgnoreIA5SubstringsMatch rule is a substrings matching rule.

4.2.9.  caseIgnoreListMatch

   The caseIgnoreListMatch rule compares an assertion value that is a
   sequence of strings to an attribute value of a syntax (e.g., the



Legg                        Standards Track                    [Page 31]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   Postal Address syntax) whose corresponding ASN.1 type is a SEQUENCE
   OF the DirectoryString ASN.1 type.

   The rule evaluates to TRUE if and only if the attribute value and the
   assertion value have the same number of strings and corresponding
   strings (by position) match according to the caseIgnoreMatch matching
   rule.

   In [X.520], the assertion syntax for this matching rule is defined to
   be:

      SEQUENCE OF DirectoryString {ub-match}

   That is, it is different from the corresponding type for the Postal
   Address syntax.  The choice of the Postal Address syntax for the
   assertion syntax of the caseIgnoreListMatch in LDAP should not be
   seen as limiting the matching rule to apply only to attributes with
   the Postal Address syntax.

   The LDAP definition for the caseIgnoreListMatch rule is:

      ( 2.5.13.11 NAME 'caseIgnoreListMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )

   The caseIgnoreListMatch rule is an equality matching rule.

4.2.10.  caseIgnoreListSubstringsMatch

   The caseIgnoreListSubstringsMatch rule compares an assertion value of
   the Substring Assertion syntax to an attribute value of a syntax
   (e.g., the Postal Address syntax) whose corresponding ASN.1 type is a
   SEQUENCE OF the DirectoryString ASN.1 type.

   The rule evaluates to TRUE if and only if the assertion value
   matches, per the caseIgnoreSubstringsMatch rule, the character string
   formed by concatenating the strings of the attribute value, except
   that none of the <initial>, <any>, or <final> substrings of the
   assertion value are considered to match a substring of the
   concatenated string which spans more than one of the original strings
   of the attribute value.

   Note that, in terms of the LDAP-specific encoding of the Postal
   Address syntax, the concatenated string omits the <DOLLAR> line
   separator and the escaping of "\" and "$" characters.

   The LDAP definition for the caseIgnoreListSubstringsMatch rule is:

      ( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch'



Legg                        Standards Track                    [Page 32]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   The caseIgnoreListSubstringsMatch rule is a substrings matching rule.

4.2.11.  caseIgnoreMatch

   The caseIgnoreMatch rule compares an assertion value of the Directory
   String syntax to an attribute value of a syntax (e.g., the Directory
   String, Printable String, Country String, or Telephone Number syntax)
   whose corresponding ASN.1 type is DirectoryString or one of its
   alternative string types.

   The rule evaluates to TRUE if and only if the prepared attribute
   value character string and the prepared assertion value character
   string have the same number of characters and corresponding
   characters have the same code point.

   In preparing the attribute value and assertion value for comparison,
   characters are case folded in the Map preparation step, and only
   Insignificant Space Handling is applied in the Insignificant
   Character Handling step.

   The LDAP definition for the caseIgnoreMatch rule is:

      ( 2.5.13.2 NAME 'caseIgnoreMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The caseIgnoreMatch rule is an equality matching rule.

4.2.12.  caseIgnoreOrderingMatch

   The caseIgnoreOrderingMatch rule compares an assertion value of the
   Directory String syntax to an attribute value of a syntax (e.g., the
   Directory String, Printable String, Country String, or Telephone
   Number syntax) whose corresponding ASN.1 type is DirectoryString or
   one of its alternative string types.

   The rule evaluates to TRUE if and only if, in the code point
   collation order, the prepared attribute value character string
   appears earlier than the prepared assertion value character string;
   i.e., the attribute value is "less than" the assertion value.

   In preparing the attribute value and assertion value for comparison,
   characters are case folded in the Map preparation step, and only
   Insignificant Space Handling is applied in the Insignificant
   Character Handling step.

   The LDAP definition for the caseIgnoreOrderingMatch rule is:



Legg                        Standards Track                    [Page 33]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      ( 2.5.13.3 NAME 'caseIgnoreOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The caseIgnoreOrderingMatch rule is an ordering matching rule.

4.2.13.  caseIgnoreSubstringsMatch

   The caseIgnoreSubstringsMatch rule compares an assertion value of the
   Substring Assertion syntax to an attribute value of a syntax (e.g.,
   the Directory String, Printable String, Country String, or Telephone
   Number syntax) whose corresponding ASN.1 type is DirectoryString or
   one of its alternative string types.

   The rule evaluates to TRUE if and only if (1) the prepared substrings
   of the assertion value match disjoint portions of the prepared
   attribute value character string in the order of the substrings in
   the assertion value, (2) an <initial> substring, if present, matches
   the beginning of the prepared attribute value character string, and
   (3) a <final> substring, if present, matches the end of the prepared
   attribute value character string.  A prepared substring matches a
   portion of the prepared attribute value character string if
   corresponding characters have the same code point.

   In preparing the attribute value and assertion value substrings for
   comparison, characters are case folded in the Map preparation step,
   and only Insignificant Space Handling is applied in the Insignificant
   Character Handling step.

   The LDAP definition for the caseIgnoreSubstringsMatch rule is:

      ( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   The caseIgnoreSubstringsMatch rule is a substrings matching rule.

4.2.14.  directoryStringFirstComponentMatch

   The directoryStringFirstComponentMatch rule compares an assertion
   value of the Directory String syntax to an attribute value of a
   syntax whose corresponding ASN.1 type is a SEQUENCE with a mandatory
   first component of the DirectoryString ASN.1 type.

   Note that the assertion syntax of this matching rule differs from the
   attribute syntax of attributes for which this is the equality
   matching rule.






Legg                        Standards Track                    [Page 34]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   The rule evaluates to TRUE if and only if the assertion value matches
   the first component of the attribute value using the rules of
   caseIgnoreMatch.

   The LDAP definition for the directoryStringFirstComponentMatch
   matching rule is:

      ( 2.5.13.31 NAME 'directoryStringFirstComponentMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The directoryStringFirstComponentMatch rule is an equality matching
   rule.  When using directoryStringFirstComponentMatch to compare two
   attribute values (of an applicable syntax), an assertion value must
   first be derived from one of the attribute values.  An assertion
   value can be derived from an attribute value by taking the first
   component of that attribute value.

4.2.15.  distinguishedNameMatch

   The distinguishedNameMatch rule compares an assertion value of the DN
   syntax to an attribute value of a syntax (e.g., the DN syntax) whose
   corresponding ASN.1 type is DistinguishedName.

   The rule evaluates to TRUE if and only if the attribute value and the
   assertion value have the same number of relative distinguished names
   and corresponding relative distinguished names (by position) are the
   same.  A relative distinguished name (RDN) of the assertion value is
   the same as an RDN of the attribute value if and only if they have
   the same number of attribute value assertions and each attribute
   value assertion (AVA) of the first RDN is the same as the AVA of the
   second RDN with the same attribute type.  The order of the AVAs is
   not significant.  Also note that a particular attribute type may
   appear in at most one AVA in an RDN.  Two AVAs with the same
   attribute type are the same if their values are equal according to
   the equality matching rule of the attribute type.  If one or more of
   the AVA comparisons evaluate to Undefined and the remaining AVA
   comparisons return TRUE then the distinguishedNameMatch rule
   evaluates to Undefined.

   The LDAP definition for the distinguishedNameMatch rule is:

      ( 2.5.13.1 NAME 'distinguishedNameMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

   The distinguishedNameMatch rule is an equality matching rule.






Legg                        Standards Track                    [Page 35]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


4.2.16.  generalizedTimeMatch

   The generalizedTimeMatch rule compares an assertion value of the
   Generalized Time syntax to an attribute value of a syntax (e.g., the
   Generalized Time syntax) whose corresponding ASN.1 type is
   GeneralizedTime.

   The rule evaluates to TRUE if and only if the attribute value
   represents the same universal coordinated time as the assertion
   value.  If a time is specified with the minutes or seconds absent,
   then the number of minutes or seconds (respectively) is assumed to be
   zero.

   The LDAP definition for the generalizedTimeMatch rule is:

      ( 2.5.13.27 NAME 'generalizedTimeMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )

   The generalizedTimeMatch rule is an equality matching rule.

4.2.17.  generalizedTimeOrderingMatch

   The generalizedTimeOrderingMatch rule compares the time ordering of
   an assertion value of the Generalized Time syntax to an attribute
   value of a syntax (e.g., the Generalized Time syntax) whose
   corresponding ASN.1 type is GeneralizedTime.

   The rule evaluates to TRUE if and only if the attribute value
   represents a universal coordinated time that is earlier than the
   universal coordinated time represented by the assertion value.

   The LDAP definition for the generalizedTimeOrderingMatch rule is:

      ( 2.5.13.28 NAME 'generalizedTimeOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )

   The generalizedTimeOrderingMatch rule is an ordering matching rule.

4.2.18.  integerFirstComponentMatch

   The integerFirstComponentMatch rule compares an assertion value of
   the Integer syntax to an attribute value of a syntax (e.g., the DIT
   Structure Rule Description syntax) whose corresponding ASN.1 type is
   a SEQUENCE with a mandatory first component of the INTEGER ASN.1
   type.






Legg                        Standards Track                    [Page 36]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   Note that the assertion syntax of this matching rule differs from the
   attribute syntax of attributes for which this is the equality
   matching rule.

   The rule evaluates to TRUE if and only if the assertion value and the
   first component of the attribute value are the same integer value.

   The LDAP definition for the integerFirstComponentMatch matching rule
   is:

      ( 2.5.13.29 NAME 'integerFirstComponentMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )

   The integerFirstComponentMatch rule is an equality matching rule.
   When using integerFirstComponentMatch to compare two attribute values
   (of an applicable syntax), an assertion value must first be derived
   from one of the attribute values.  An assertion value can be derived
   from an attribute value by taking the first component of that
   attribute value.

4.2.19.  integerMatch

   The integerMatch rule compares an assertion value of the Integer
   syntax to an attribute value of a syntax (e.g., the Integer syntax)
   whose corresponding ASN.1 type is INTEGER.

   The rule evaluates to TRUE if and only if the attribute value and the
   assertion value are the same integer value.

   The LDAP definition for the integerMatch matching rule is:

      ( 2.5.13.14 NAME 'integerMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )

   The integerMatch rule is an equality matching rule.

4.2.20.  integerOrderingMatch

   The integerOrderingMatch rule compares an assertion value of the
   Integer syntax to an attribute value of a syntax (e.g., the Integer
   syntax) whose corresponding ASN.1 type is INTEGER.

   The rule evaluates to TRUE if and only if the integer value of the
   attribute value is less than the integer value of the assertion
   value.

   The LDAP definition for the integerOrderingMatch matching rule is:




Legg                        Standards Track                    [Page 37]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      ( 2.5.13.15 NAME 'integerOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )

   The integerOrderingMatch rule is an ordering matching rule.

4.2.21.  keywordMatch

   The keywordMatch rule compares an assertion value of the Directory
   String syntax to an attribute value of a syntax (e.g., the Directory
   String syntax) whose corresponding ASN.1 type is DirectoryString.

   The rule evaluates to TRUE if and only if the assertion value
   character string matches any keyword in the attribute value.  The
   identification of keywords in the attribute value and the exactness
   of the match are both implementation specific.

   The LDAP definition for the keywordMatch rule is:

      ( 2.5.13.33 NAME 'keywordMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

4.2.22.  numericStringMatch

   The numericStringMatch rule compares an assertion value of the
   Numeric String syntax to an attribute value of a syntax (e.g., the
   Numeric String syntax) whose corresponding ASN.1 type is
   NumericString.

   The rule evaluates to TRUE if and only if the prepared attribute
   value character string and the prepared assertion value character
   string have the same number of characters and corresponding
   characters have the same code point.

   In preparing the attribute value and assertion value for comparison,
   characters are not case folded in the Map preparation step, and only
   numericString Insignificant Character Handling is applied in the
   Insignificant Character Handling step.

   The LDAP definition for the numericStringMatch matching rule is:

      ( 2.5.13.8 NAME 'numericStringMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )

   The numericStringMatch rule is an equality matching rule.







Legg                        Standards Track                    [Page 38]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


4.2.23.  numericStringOrderingMatch

   The numericStringOrderingMatch rule compares an assertion value of
   the Numeric String syntax to an attribute value of a syntax (e.g.,
   the Numeric String syntax) whose corresponding ASN.1 type is
   NumericString.

   The rule evaluates to TRUE if and only if, in the code point
   collation order, the prepared attribute value character string
   appears earlier than the prepared assertion value character string;
   i.e., the attribute value is "less than" the assertion value.

   In preparing the attribute value and assertion value for comparison,
   characters are not case folded in the Map preparation step, and only
   numericString Insignificant Character Handling is applied in the
   Insignificant Character Handling step.

   The rule is identical to the caseIgnoreOrderingMatch rule except that
   all space characters are skipped during comparison (case is
   irrelevant as the characters are numeric).

   The LDAP definition for the numericStringOrderingMatch matching rule
   is:

      ( 2.5.13.9 NAME 'numericStringOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )

   The numericStringOrderingMatch rule is an ordering matching rule.

4.2.24.  numericStringSubstringsMatch

   The numericStringSubstringsMatch rule compares an assertion value of
   the Substring Assertion syntax to an attribute value of a syntax
   (e.g., the Numeric String syntax) whose corresponding ASN.1 type is
   NumericString.

   The rule evaluates to TRUE if and only if (1) the prepared substrings
   of the assertion value match disjoint portions of the prepared
   attribute value character string in the order of the substrings in
   the assertion value, (2) an <initial> substring, if present, matches
   the beginning of the prepared attribute value character string, and
   (3) a <final> substring, if present, matches the end of the prepared
   attribute value character string.  A prepared substring matches a
   portion of the prepared attribute value character string if
   corresponding characters have the same code point.

   In preparing the attribute value and assertion value for comparison,
   characters are not case folded in the Map preparation step, and only



Legg                        Standards Track                    [Page 39]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   numericString Insignificant Character Handling is applied in the
   Insignificant Character Handling step.

   The LDAP definition for the numericStringSubstringsMatch matching
   rule is:

      ( 2.5.13.10 NAME 'numericStringSubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   The numericStringSubstringsMatch rule is a substrings matching rule.

4.2.25.  objectIdentifierFirstComponentMatch

   The objectIdentifierFirstComponentMatch rule compares an assertion
   value of the OID syntax to an attribute value of a syntax (e.g., the
   Attribute Type Description, DIT Content Rule Description, LDAP Syntax
   Description, Matching Rule Description, Matching Rule Use
   Description, Name Form Description, or Object Class Description
   syntax) whose corresponding ASN.1 type is a SEQUENCE with a mandatory
   first component of the OBJECT IDENTIFIER ASN.1 type.

   Note that the assertion syntax of this matching rule differs from the
   attribute syntax of attributes for which this is the equality
   matching rule.

   The rule evaluates to TRUE if and only if the assertion value matches
   the first component of the attribute value using the rules of
   objectIdentifierMatch.

   The LDAP definition for the objectIdentifierFirstComponentMatch
   matching rule is:

      ( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )

   The objectIdentifierFirstComponentMatch rule is an equality matching
   rule.  When using objectIdentifierFirstComponentMatch to compare two
   attribute values (of an applicable syntax), an assertion value must
   first be derived from one of the attribute values.  An assertion
   value can be derived from an attribute value by taking the first
   component of that attribute value.

4.2.26.  objectIdentifierMatch

   The objectIdentifierMatch rule compares an assertion value of the OID
   syntax to an attribute value of a syntax (e.g., the OID syntax) whose
   corresponding ASN.1 type is OBJECT IDENTIFIER.




Legg                        Standards Track                    [Page 40]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   The rule evaluates to TRUE if and only if the assertion value and the
   attribute value represent the same object identifier; that is, the
   same sequence of integers, whether represented explicitly in the
   <numericoid> form of <oid> or implicitly in the <descr> form (see
   [RFC4512]).

   If an LDAP client supplies an assertion value in the <descr> form and
   the chosen descriptor is not recognized by the server, then the
   objectIdentifierMatch rule evaluates to Undefined.

   The LDAP definition for the objectIdentifierMatch matching rule is:

      ( 2.5.13.0 NAME 'objectIdentifierMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )

   The objectIdentifierMatch rule is an equality matching rule.

4.2.27.  octetStringMatch

   The octetStringMatch rule compares an assertion value of the Octet
   String syntax to an attribute value of a syntax (e.g., the Octet
   String or JPEG syntax) whose corresponding ASN.1 type is the OCTET
   STRING ASN.1 type.

   The rule evaluates to TRUE if and only if the attribute value and the
   assertion value are the same length and corresponding octets (by
   position) are the same.

   The LDAP definition for the octetStringMatch matching rule is:

      ( 2.5.13.17 NAME 'octetStringMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

   The octetStringMatch rule is an equality matching rule.

4.2.28.  octetStringOrderingMatch

   The octetStringOrderingMatch rule compares an assertion value of the
   Octet String syntax to an attribute value of a syntax (e.g., the
   Octet String or JPEG syntax) whose corresponding ASN.1 type is the
   OCTET STRING ASN.1 type.

   The rule evaluates to TRUE if and only if the attribute value appears
   earlier in the collation order than the assertion value.  The rule
   compares octet strings from the first octet to the last octet, and
   from the most significant bit to the least significant bit within the
   octet.  The first occurrence of a different bit determines the
   ordering of the strings.  A zero bit precedes a one bit.  If the



Legg                        Standards Track                    [Page 41]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   strings contain different numbers of octets but the longer string is
   identical to the shorter string up to the length of the shorter
   string, then the shorter string precedes the longer string.

   The LDAP definition for the octetStringOrderingMatch matching rule
   is:

      ( 2.5.13.18 NAME 'octetStringOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

   The octetStringOrderingMatch rule is an ordering matching rule.

4.2.29.  telephoneNumberMatch

   The telephoneNumberMatch rule compares an assertion value of the
   Telephone Number syntax to an attribute value of a syntax (e.g., the
   Telephone Number syntax) whose corresponding ASN.1 type is a
   PrintableString representing a telephone number.

   The rule evaluates to TRUE if and only if the prepared attribute
   value character string and the prepared assertion value character
   string have the same number of characters and corresponding
   characters have the same code point.

   In preparing the attribute value and assertion value for comparison,
   characters are case folded in the Map preparation step, and only
   telephoneNumber Insignificant Character Handling is applied in the
   Insignificant Character Handling step.

   The LDAP definition for the telephoneNumberMatch matching rule is:

      ( 2.5.13.20 NAME 'telephoneNumberMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

   The telephoneNumberMatch rule is an equality matching rule.

4.2.30.  telephoneNumberSubstringsMatch

   The telephoneNumberSubstringsMatch rule compares an assertion value
   of the Substring Assertion syntax to an attribute value of a syntax
   (e.g., the Telephone Number syntax) whose corresponding ASN.1 type is
   a PrintableString representing a telephone number.

   The rule evaluates to TRUE if and only if (1) the prepared substrings
   of the assertion value match disjoint portions of the prepared
   attribute value character string in the order of the substrings in
   the assertion value, (2) an <initial> substring, if present, matches
   the beginning of the prepared attribute value character string, and



Legg                        Standards Track                    [Page 42]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   (3) a <final> substring, if present, matches the end of the prepared
   attribute value character string.  A prepared substring matches a
   portion of the prepared attribute value character string if
   corresponding characters have the same code point.

   In preparing the attribute value and assertion value substrings for
   comparison, characters are case folded in the Map preparation step,
   and only telephoneNumber Insignificant Character Handling is applied
   in the Insignificant Character Handling step.

   The LDAP definition for the telephoneNumberSubstringsMatch matching
   rule is:

      ( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   The telephoneNumberSubstringsMatch rule is a substrings matching
   rule.

4.2.31.  uniqueMemberMatch

   The uniqueMemberMatch rule compares an assertion value of the Name
   And Optional UID syntax to an attribute value of a syntax (e.g., the
   Name And Optional UID syntax) whose corresponding ASN.1 type is
   NameAndOptionalUID.

   The rule evaluates to TRUE if and only if the <distinguishedName>
   components of the assertion value and attribute value match according
   to the distinguishedNameMatch rule and either, (1) the <BitString>
   component is absent from both the attribute value and assertion
   value, or (2) the <BitString> component is present in both the
   attribute value and the assertion value and the <BitString> component
   of the assertion value matches the <BitString> component of the
   attribute value according to the bitStringMatch rule.

   Note that this matching rule has been altered from its description in
   X.520 [X.520] in order to make the matching rule commutative.  Server
   implementors should consider using the original X.520 semantics
   (where the matching was less exact) for approximate matching of
   attributes with uniqueMemberMatch as the equality matching rule.

   The LDAP definition for the uniqueMemberMatch matching rule is:

      ( 2.5.13.23 NAME 'uniqueMemberMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )

   The uniqueMemberMatch rule is an equality matching rule.




Legg                        Standards Track                    [Page 43]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


4.2.32.  wordMatch

   The wordMatch rule compares an assertion value of the Directory
   String syntax to an attribute value of a syntax (e.g., the Directory
   String syntax) whose corresponding ASN.1 type is DirectoryString.

   The rule evaluates to TRUE if and only if the assertion value word
   matches, according to the semantics of caseIgnoreMatch, any word in
   the attribute value.  The precise definition of a word is
   implementation specific.

   The LDAP definition for the wordMatch rule is:

      ( 2.5.13.32 NAME 'wordMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

5.  Security Considerations

   In general, the LDAP-specific encodings for syntaxes defined in this
   document do not define canonical encodings.  That is, a
   transformation from an LDAP-specific encoding into some other
   encoding (e.g., BER) and back into the LDAP-specific encoding will
   not necessarily reproduce exactly the original octets of the LDAP-
   specific encoding.  Therefore, an LDAP-specific encoding should not
   be used where a canonical encoding is required.

   Furthermore, the LDAP-specific encodings do not necessarily enable an
   alternative encoding of values of the Directory String and DN
   syntaxes to be reconstructed; e.g., a transformation from a
   Distinguished Encoding Rules (DER) [BER] encoding to an LDAP-specific
   encoding and back to a DER encoding may not reproduce the original
   DER encoding.  Therefore, LDAP-specific encodings should not be used
   where reversibility to DER is needed; e.g., for the verification of
   digital signatures.  Instead, DER or a DER-reversible encoding should
   be used.

   When interpreting security-sensitive fields (in particular, fields
   used to grant or deny access), implementations MUST ensure that any
   matching rule comparisons are done on the underlying abstract value,
   regardless of the particular encoding used.

6.  Acknowledgements

   This document is primarily a revision of RFC 2252 by M. Wahl, A.
   Coulbeck, T. Howes, and S. Kille.  RFC 2252 was a product of the IETF
   ASID Working Group.





Legg                        Standards Track                    [Page 44]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   This document is based on input from the IETF LDAPBIS working group.
   The author would like to thank Kathy Dally for editing the early
   drafts of this document, and Jim Sermersheim and Kurt Zeilenga for
   their significant contributions to this revision.

7.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has updated the LDAP
   descriptors registry [BCP64] as indicated by the following templates:

      Subject: Request for LDAP Descriptor Registration Update
      Descriptor (short name): see comment
      Object Identifier: see comment
      Person & email address to contact for further information:
        Steven Legg <steven.legg@eb2bcom.com>
      Usage: see comment
      Specification: RFC 4517
      Author/Change Controller: IESG

      NAME                              Type  OID
      ------------------------------------------------------------------
      bitStringMatch                       M  2.5.13.16
      booleanMatch                         M  2.5.13.13
      caseExactIA5Match                    M  1.3.6.1.4.1.1466.109.114.1
      caseExactMatch                       M  2.5.13.5
      caseExactOrderingMatch               M  2.5.13.6
      caseExactSubstringsMatch             M  2.5.13.7
      caseIgnoreIA5Match                   M  1.3.6.1.4.1.1466.109.114.2
      caseIgnoreListMatch                  M  2.5.13.11
      caseIgnoreListSubstringsMatch        M  2.5.13.12
      caseIgnoreMatch                      M  2.5.13.2
      caseIgnoreOrderingMatch              M  2.5.13.3
      caseIgnoreSubstringsMatch            M  2.5.13.4
      directoryStringFirstComponentMatch   M  2.5.13.31
      distinguishedNameMatch               M  2.5.13.1
      generalizedTimeMatch                 M  2.5.13.27
      generalizedTimeOrderingMatch         M  2.5.13.28
      integerFirstComponentMatch           M  2.5.13.29
      integerMatch                         M  2.5.13.14
      integerOrderingMatch                 M  2.5.13.15
      keywordMatch                         M  2.5.13.33
      numericStringMatch                   M  2.5.13.8
      numericStringOrderingMatch           M  2.5.13.9
      numericStringSubstringsMatch         M  2.5.13.10
      objectIdentifierFirstComponentMatch  M  2.5.13.30
      octetStringMatch                     M  2.5.13.17
      octetStringOrderingMatch             M  2.5.13.18
      telephoneNumberMatch                 M  2.5.13.20



Legg                        Standards Track                    [Page 45]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


      telephoneNumberSubstringsMatch       M  2.5.13.21
      uniqueMemberMatch                    M  2.5.13.23
      wordMatch                            M  2.5.13.32

      The descriptor for the object identifier 2.5.13.0 was incorrectly
      registered as objectIdentifiersMatch (extraneous \`s') in BCP 64.
      It has been changed to the following, with a reference to
      RFC 4517.

      NAME                              Type  OID
      ------------------------------------------------------------------
      objectIdentifierMatch                M  2.5.13.0

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): caseIgnoreIA5SubstringsMatch
      Object Identifier: 1.3.6.1.4.1.1466.109.114.3
      Person & email address to contact for further information:
        Steven Legg <steven.legg@eb2bcom.com>
      Usage: other (M)
      Specification: RFC 4517
      Author/Change Controller: IESG

8.  References

8.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3629]  Yergeau, F., "UTF-8, a transformation format of ISO
              10646", STD 63, RFC 3629, November 2003.

   [RFC4234]  Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", RFC 4234, October 2005.

   [RFC4510]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC 4510, June
              2006.

   [RFC4511]  Sermersheim, J., Ed., "Lightweight Directory Access
              Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512, June
              2006.






Legg                        Standards Track                    [Page 46]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   [RFC4514]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): String Representation of Distinguished Names", RFC
              4514, June 2006.

   [RFC4518]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Internationalized String Preparation", RFC 4518,
              June 2006.

   [RFC4520]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [E.123]    Notation for national and international telephone numbers,
              ITU-T Recommendation E.123, 1988.

   [FAX]      Standardization of Group 3 facsimile apparatus for
              document transmission - Terminal Equipment and Protocols
              for Telematic Services, ITU-T Recommendation T.4, 1993

   [T.50]     International Reference Alphabet (IRA) (Formerly
              International Alphabet No. 5 or IA5) Information
              Technology - 7-Bit Coded Character Set for Information
              Interchange, ITU-T Recommendation T.50, 1992

   [X.420]    ITU-T Recommendation X.420 (1996) | ISO/IEC 10021-7:1997,
              Information Technology - Message Handling Systems (MHS):
              Interpersonal messaging system

   [X.501]    ITU-T Recommendation X.501 (1993) | ISO/IEC 9594-2:1994,
              Information Technology - Open Systems Interconnection -
              The Directory: Models

   [X.520]    ITU-T Recommendation X.520 (1993) | ISO/IEC 9594-6:1994,
              Information Technology - Open Systems Interconnection -
              The Directory: Selected attribute types

   [ASN.1]    ITU-T Recommendation X.680 (07/02) | ISO/IEC 8824-1:2002,
              Information technology - Abstract Syntax Notation One
              (ASN.1): Specification of basic notation

   [ISO3166]  ISO 3166, "Codes for the representation of names of
              countries".

   [ISO8601]  ISO 8601:2004, "Data elements and interchange formats --
              Information interchange -- Representation of dates and
              times".





Legg                        Standards Track                    [Page 47]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   [UCS]      Universal Multiple-Octet Coded Character Set (UCS) -
              Architecture and Basic Multilingual Plane, ISO/IEC 10646-
              1:  1993 (with amendments).

   [JPEG]     JPEG File Interchange Format (Version 1.02).  Eric
              Hamilton, C-Cube Microsystems, Milpitas, CA, September 1,
              1992.

8.2.  Informative References

   [RFC4519]  Sciberras, A., Ed., "Lightweight Directory Access Protocol
              (LDAP): Schema for User Applications", RFC 4519, June
              2006.

   [RFC4523]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP) Schema Definitions for X.509 Certificates", RFC
              4523, June 2006.

   [X.500]    ITU-T Recommendation X.500 (1993) | ISO/IEC 9594-1:1994,
              Information Technology - Open Systems Interconnection -
              The Directory: Overview of concepts, models and services

   [BER]      ITU-T Recommendation X.690 (07/02) | ISO/IEC 8825-1:2002,
              Information technology - ASN.1 encoding rules:
              Specification of Basic Encoding Rules (BER), Canonical
              Encoding Rules (CER) and Distinguished Encoding Rules
              (DER)
























Legg                        Standards Track                    [Page 48]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


Appendix A. Summary of Syntax Object Identifiers

   The following list summarizes the object identifiers assigned to the
   syntaxes defined in this document.

      Syntax                           OBJECT IDENTIFIER
      ==============================================================
      Attribute Type Description       1.3.6.1.4.1.1466.115.121.1.3
      Bit String                       1.3.6.1.4.1.1466.115.121.1.6
      Boolean                          1.3.6.1.4.1.1466.115.121.1.7
      Country String                   1.3.6.1.4.1.1466.115.121.1.11
      Delivery Method                  1.3.6.1.4.1.1466.115.121.1.14
      Directory String                 1.3.6.1.4.1.1466.115.121.1.15
      DIT Content Rule Description     1.3.6.1.4.1.1466.115.121.1.16
      DIT Structure Rule Description   1.3.6.1.4.1.1466.115.121.1.17
      DN                               1.3.6.1.4.1.1466.115.121.1.12
      Enhanced Guide                   1.3.6.1.4.1.1466.115.121.1.21
      Facsimile Telephone Number       1.3.6.1.4.1.1466.115.121.1.22
      Fax                              1.3.6.1.4.1.1466.115.121.1.23
      Generalized Time                 1.3.6.1.4.1.1466.115.121.1.24
      Guide                            1.3.6.1.4.1.1466.115.121.1.25
      IA5 String                       1.3.6.1.4.1.1466.115.121.1.26
      Integer                          1.3.6.1.4.1.1466.115.121.1.27
      JPEG                             1.3.6.1.4.1.1466.115.121.1.28
      LDAP Syntax Description          1.3.6.1.4.1.1466.115.121.1.54
      Matching Rule Description        1.3.6.1.4.1.1466.115.121.1.30
      Matching Rule Use Description    1.3.6.1.4.1.1466.115.121.1.31
      Name And Optional UID            1.3.6.1.4.1.1466.115.121.1.34
      Name Form Description            1.3.6.1.4.1.1466.115.121.1.35
      Numeric String                   1.3.6.1.4.1.1466.115.121.1.36
      Object Class Description         1.3.6.1.4.1.1466.115.121.1.37
      Octet String                     1.3.6.1.4.1.1466.115.121.1.40
      OID                              1.3.6.1.4.1.1466.115.121.1.38
      Other Mailbox                    1.3.6.1.4.1.1466.115.121.1.39
      Postal Address                   1.3.6.1.4.1.1466.115.121.1.41
      Printable String                 1.3.6.1.4.1.1466.115.121.1.44
      Substring Assertion              1.3.6.1.4.1.1466.115.121.1.58
      Telephone Number                 1.3.6.1.4.1.1466.115.121.1.50
      Teletex Terminal Identifier      1.3.6.1.4.1.1466.115.121.1.51
      Telex Number                     1.3.6.1.4.1.1466.115.121.1.52
      UTC Time                         1.3.6.1.4.1.1466.115.121.1.53

Appendix B. Changes from RFC 2252

   This annex lists the significant differences between this
   specification and RFC 2252.





Legg                        Standards Track                    [Page 49]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   This annex is provided for informational purposes only.  It is not a
   normative part of this specification.

   1.  The IESG Note has been removed.

   2.  The major part of Sections 4, 5 and 7 has been moved to [RFC4512]
       and revised.  Changes to the parts of these sections moved to
       [RFC4512] are detailed in [RFC4512].

   3.  BNF descriptions of syntax formats have been replaced by ABNF
       [RFC4234] specifications.

   4.  The ambiguous statement in RFC 2252, Section 4.3 regarding the
       use of a backslash quoting mechanism to escape separator symbols
       has been removed.  The escaping mechanism is now explicitly
       represented in the ABNF for the syntaxes where this provision
       applies.

   5.  The description of each of the LDAP syntaxes has been expanded so
       that they are less dependent on knowledge of X.500 for
       interpretation.

   6.  The relationship of LDAP syntaxes to corresponding ASN.1 type
       definitions has been made explicit.

   7.  The set of characters allowed in a <PrintableString> (formerly
       <printablestring>) has been corrected to align with the
       PrintableString ASN.1 type in [ASN.1].  Specifically, the double
       quote character has been removed and the single quote character
       and equals sign have been added.

   8.  Values of the Directory String, Printable String and Telephone
       Number syntaxes are now required to have at least one character.

   9.  The <DITContentRuleDescription>, <NameFormDescription> and
       <DITStructureRuleDescription> rules have been moved to [RFC4512].

   10. The corresponding ASN.1 type for the Other Mailbox syntax has
       been incorporated from RFC 1274.

   11. A corresponding ASN.1 type for the LDAP Syntax Description syntax
       has been invented.

   12. The Binary syntax has been removed because it was not adequately
       specified, implementations with different incompatible
       interpretations exist, and it was confused with the ;binary
       transfer encoding.




Legg                        Standards Track                    [Page 50]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


   13. All discussion of transfer options, including the ";binary"
       option, has been removed.  All imperatives regarding binary
       transfer of values have been removed.

   14. The Delivery Method, Enhanced Guide, Guide, Octet String, Teletex
       Terminal Identifier and Telex Number syntaxes from RFC 2256 have
       been incorporated.

   15. The <criteria> rule for the Enhanced Guide and Guide syntaxes has
       been extended to accommodate empty "and" and "or" expressions.

   16. An encoding for the <ttx-value> rule in the Teletex Terminal
       Identifier syntax has been defined.

   17. The PKI-related syntaxes (Certificate, Certificate List and
       Certificate Pair) have been removed.  They are reintroduced in
       [RFC4523] (as is the Supported Algorithm syntax from RFC 2256).

   18. The MHS OR Address syntax has been removed since its
       specification (in RFC 2156) is not at draft standard maturity.

   19. The DL Submit Permission syntax has been removed as it depends on
       the MHS OR Address syntax.

   20. The Presentation Address syntax has been removed since its
       specification (in RFC 1278) is not at draft standard maturity.

   21. The ACI Item, Access Point, Audio, Data Quality, DSA Quality, DSE
       Type, LDAP Schema Description, Master And Shadow Access Points,
       Modify Rights, Protocol Information, Subtree Specification,
       Supplier Information, Supplier Or Consumer and Supplier And
       Consumer syntaxes have been removed.  These syntaxes are
       referenced in RFC 2252, but not defined.

   22. The LDAP Schema Definition syntax (defined in RFC 2927) and the
       Mail Preference syntax have been removed on the grounds that they
       are out of scope for the core specification.

   23. The description of each of the matching rules has been expanded
       so that they are less dependent on knowledge of X.500 for
       interpretation.

   24. The caseIgnoreIA5SubstringsMatch matching rule from RFC 2798 has
       been added.

   25. The caseIgnoreListSubstringsMatch, caseIgnoreOrderingMatch and
       caseIgnoreSubstringsMatch matching rules have been added to the
       list of matching rules for which the provisions for handling



Legg                        Standards Track                    [Page 51]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


       leading, trailing and multiple adjoining whitespace characters
       apply (now through string preparation).  This is consistent with
       the definitions of these matching rules in X.500.  The
       caseIgnoreIA5SubstringsMatch rule has also been added to the
       list.

   26. The specification of the octetStringMatch matching rule from
       RFC 2256 has been added to this document.

   27. The presentationAddressMatch matching rule has been removed as it
       depends on an assertion syntax (Presentation Address) that is not
       at draft standard maturity.

   28. The protocolInformationMatch matching rule has been removed as it
       depends on an undefined assertion syntax (Protocol Information).

   29. The definitive reference for ASN.1 has been changed from X.208 to
       X.680 since X.680 is the version of ASN.1 referred to by X.500.

   30. The specification of the caseIgnoreListSubstringsMatch matching
       rule from RFC 2798 & X.520 has been added.

   31. String preparation algorithms have been applied to the character
       string matching rules.

   32. The specifications of the booleanMatch, caseExactMatch,
       caseExactOrderingMatch, caseExactSubstringsMatch,
       directoryStringFirstComponentMatch, integerOrderingMatch,
       keywordMatch, numericStringOrderingMatch,
       octetStringOrderingMatch and wordMatch matching rules from
       RFC 3698 & X.520 have been added.

Author's Address

   Steven Legg
   eB2Bcom
   Suite3, Woodhouse Corporate Centre
   935 Station Street
   Box Hill North, Victoria 3129
   AUSTRALIA

   Phone: +61 3 9896 7830
   Fax: +61 3 9896 7801
   EMail: steven.legg@eb2bcom.com







Legg                        Standards Track                    [Page 52]

RFC 4517           LDAP: Syntaxes and Matching Rules           June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Legg                        Standards Track                    [Page 53]

alt-openldap11-devel/rfc/rfc4527.txt000064400000037163150410163210012775 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4527                           OpenLDAP Foundation
Category: Standards Track                                      June 2006


              Lightweight Directory Access Protocol (LDAP)
                          Read Entry Controls


Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document specifies an extension to the Lightweight Directory
   Access Protocol (LDAP) to allow the client to read the target entry
   of an update operation.  The client may request to read the entry
   before and/or after the modifications are applied.  These reads are
   done as an atomic part of the update operation.

Table of Contents

   1. Background and Intent of Use ....................................2
   2. Terminology .....................................................2
   3. Read Entry Controls .............................................3
      3.1. The Pre-Read Controls ......................................3
      3.2. The Post-Read Controls .....................................3
   4. Interaction with Other Controls .................................4
   5. Security Considerations .........................................4
   6. IANA Considerations .............................................5
      6.1. Object Identifier ..........................................5
      6.2. LDAP Protocol Mechanisms ...................................5
   7. Acknowledgement .................................................5
   8. References ......................................................6
      8.1. Normative References .......................................6
      8.2. Informative References .....................................7






Zeilenga                    Standards Track                     [Page 1]

RFC 4527                LDAP Read Entry Controls               June 2006


1.  Background and Intent of Use

   This document specifies an extension to the Lightweight Directory
   Access Protocol (LDAP) [RFC4510] to allow the client to read the
   target entry of an update operation (e.g., Add, Delete, Modify,
   ModifyDN).  The extension utilizes controls [RFC4511] attached to
   update requests to request and return copies of the target entry.
   One request control, called the Pre-Read request control, indicates
   that a copy of the entry before application of update is to be
   returned.  Another control, called the Post-Read request control,
   indicates that a copy of the entry after application of the update is
   to be returned.  Each request control has a corresponding response
   control used to return the entry.

   To ensure proper isolation, the controls are processed as an atomic
   part of the update operation.

   The functionality offered by these controls is based upon similar
   functionality in the X.500 Directory Access Protocol (DAP) [X.511].

   The Pre-Read controls may be used to obtain replaced or deleted
   values of modified attributes or a copy of the entry being deleted.

   The Post-Read controls may be used to obtain values of operational
   attributes, such as the 'entryUUID' [RFC4530] and 'modifyTimestamp'
   [RFC4512] attributes, updated by the server as part of the update
   operation.

2. Terminology

   Protocol elements are described using ASN.1 [X.680] with implicit
   tags.  The term "BER-encoded" means the element is to be encoded
   using the Basic Encoding Rules [X.690] under the restrictions
   detailed in Section 5.1 of [RFC4511].

   DN stands for Distinguished Name.
   DSA stands for Directory System Agent (i.e., a directory server).
   DSE stands for DSA-specific Entry.

   In this document, the key words "MUST", "MUST NOT", "REQUIRED",
   "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
   and "OPTIONAL" are to be interpreted as described in BCP 14
   [RFC2119].








Zeilenga                    Standards Track                     [Page 2]

RFC 4527                LDAP Read Entry Controls               June 2006


3.  Read Entry Controls

3.1.  The Pre-Read Controls

   The Pre-Read request and response controls are identified by the
   1.3.6.1.1.13.1 object identifier.  Servers implementing these
   controls SHOULD publish 1.3.6.1.1.13.1 as a value of the
   'supportedControl' [RFC4512] in their root DSE.

   The Pre-Read request control is a LDAP Control [RFC4511] whose
   controlType is 1.3.6.1.1.13.1 and whose controlValue is a BER-encoded
   AttributeSelection [RFC4511], as extended by [RFC3673].  The
   criticality may be TRUE or FALSE.  This control is appropriate for
   the modifyRequest, delRequest, and modDNRequest LDAP messages.

   The corresponding response control is a LDAP Control whose
   controlType is 1.3.6.1.1.13.1 and whose the controlValue, an OCTET
   STRING, contains a BER-encoded SearchResultEntry.  The criticality
   may be TRUE or FALSE.  This control is appropriate for the
   modifyResponse, delResponse, and modDNResponse LDAP messages with a
   resultCode of success (0).

   When the request control is attached to an appropriate update LDAP
   request, the control requests the return of a copy of the target
   entry prior to the application of the update.  The AttributeSelection
   indicates, as discussed in [RFC4511][RFC3673], which attributes are
   requested to appear in the copy.  The server is to return a
   SearchResultEntry containing, subject to access controls and other
   constraints, values of the requested attributes.

   The normal processing of the update operation and the processing of
   this control MUST be performed as one atomic action isolated from
   other update operations.

   If the update operation fails (in either normal or control
   processing), no Pre-Read response control is provided.

3.2.  The Post-Read Controls

   The Post-Read request and response controls are identified by the
   1.3.6.1.1.13.2 object identifier.  Servers implementing these
   controls SHOULD publish 1.3.6.1.1.13.2 as a value of the
   'supportedControl' [RFC4512] in their root DSE.

   The Post-Read request control is a LDAP Control [RFC4511] whose
   controlType is 1.3.6.1.1.13.2 and whose controlValue, an OCTET
   STRING, contains a BER-encoded AttributeSelection [RFC4511], as
   extended by [RFC3673].  The criticality may be TRUE or FALSE.  This



Zeilenga                    Standards Track                     [Page 3]

RFC 4527                LDAP Read Entry Controls               June 2006


   control is appropriate for the addRequest, modifyRequest, and
   modDNRequest LDAP messages.

   The corresponding response control is a LDAP Control whose
   controlType is 1.3.6.1.1.13.2 and whose controlValue is a BER-encoded
   SearchResultEntry.  The criticality may be TRUE or FALSE.  This
   control is appropriate for the addResponse, modifyResponse, and
   modDNResponse LDAP messages with a resultCode of success (0).

   When the request control is attached to an appropriate update LDAP
   request, the control requests the return of a copy of the target
   entry after the application of the update.  The AttributeSelection
   indicates, as discussed in [RFC4511][RFC3673], which attributes are
   requested to appear in the copy.  The server is to return a
   SearchResultEntry containing, subject to access controls and other
   constraints, values of the requested attributes.

   The normal processing of the update operation and the processing of
   this control MUST be performed as one atomic action isolated from
   other update operations.

   If the update operation fails (in either normal or control
   processing), no Post-Read response control is provided.

4.  Interaction with Other Controls

   The Pre-Read and Post-Read controls may be combined with each other
   and/or with a variety of other controls.  When combined with the
   assertion control [RFC4528] and/or the manageDsaIT control [RFC3296],
   the semantics of each control included in the combination applies.
   The Pre-Read and Post-Read controls may be combined with other
   controls as detailed in other technical specifications.

5.  Security Considerations

   The controls defined in this document extend update operations to
   support read capabilities.  Servers MUST ensure that the client is
   authorized for reading of the information provided in this control
   and that the client is authorized to perform the requested directory
   update.

   Security considerations for the update operations [RFC4511] extended
   by this control, as well as general LDAP security considerations
   [RFC4510], generally apply to implementation and use of this
   extension






Zeilenga                    Standards Track                     [Page 4]

RFC 4527                LDAP Read Entry Controls               June 2006


6.  IANA Considerations

   Registration of the following protocol values [RFC4520] have been
   completed by the IANA.

6.1.  Object Identifier

   The IANA has registered an LDAP Object Identifier to identify LDAP
   protocol elements defined in this document.

       Subject: Request for LDAP Object Identifier Registration
       Person & email address to contact for further information:
            Kurt Zeilenga <kurt@OpenLDAP.org>
       Specification: RFC 4527
       Author/Change Controller: IESG
       Comments: Identifies the LDAP Read Entry Controls

6.2.  LDAP Protocol Mechanisms

   The IANA has registered the LDAP Protocol Mechanism described in this
   document.

       Subject: Request for LDAP Protocol Mechanism Registration
       Object Identifier: 1.3.6.1.1.13.1
       Description: LDAP Pre-read Control
       Person & email address to contact for further information:
            Kurt Zeilenga <kurt@openldap.org>
       Usage: Control
       Specification: RFC 4527
       Author/Change Controller: IESG
       Comments: none

       Subject: Request for LDAP Protocol Mechanism Registration
       Object Identifier: 1.3.6.1.1.13.2
       Description: LDAP Post-read Control
       Person & email address to contact for further information:
            Kurt Zeilenga <kurt@openldap.org>
       Usage: Control
       Specification: RFC 4527
       Author/Change Controller: IESG
       Comments: none

7.  Acknowledgement

   The LDAP Pre-Read and Post-Read controls are modeled after similar
   capabilities offered in the DAP [X.511].





Zeilenga                    Standards Track                     [Page 5]

RFC 4527                LDAP Read Entry Controls               June 2006


8.  References

8.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3296]     Zeilenga, K., "Named Subordinate References in
                 Lightweight Directory Access Protocol (LDAP)
                 Directories", RFC 3296, July 2002.

   [RFC3673]     Zeilenga, K., "Lightweight Directory Access Protocol
                 version 3 (LDAPv3): All Operational Attributes", RFC
                 3673, December 2003.

   [RFC4510]     Zeilenga, K., Ed, "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [RFC4528]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP) Assertion Control", RFC 4528, June 2006.

   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(1997) (also ISO/IEC 8824-1:1998).

   [X.690]       International Telecommunication Union -
                 Telecommunication Standardization Sector,
                 "Specification of ASN.1 encoding rules: Basic Encoding
                 Rules (BER), Canonical Encoding Rules (CER), and
                 Distinguished Encoding Rules (DER)", X.690(1997) (also
                 ISO/IEC 8825-1:1998).











Zeilenga                    Standards Track                     [Page 6]

RFC 4527                LDAP Read Entry Controls               June 2006


8.2.  Informative References

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [RFC4530]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP) EntryUUID Operational Attribute", RFC 4530, June
                 2006.

   [X.511]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory: Abstract Service Definition", X.511(1993)
                 (also ISO/IEC 9594-3:1993).

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org






























Zeilenga                    Standards Track                     [Page 7]

RFC 4527                LDAP Read Entry Controls               June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                     [Page 8]

alt-openldap11-devel/rfc/rfc3062.txt000064400000027037150410163210012765 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 3062                           OpenLDAP Foundation
Category: Standards Track                                  February 2001


                LDAP Password Modify Extended Operation

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2001).  All Rights Reserved.

Abstract

   The integration of the Lightweight Directory Access Protocol (LDAP)
   and external authentication services has introduced non-DN
   authentication identities and allowed for non-directory storage of
   passwords.  As such, mechanisms which update the directory (e.g.,
   Modify) cannot be used to change a user's password.  This document
   describes an LDAP extended operation to allow modification of user
   passwords which is not dependent upon the form of the authentication
   identity nor the password storage mechanism used.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", and "MAY" in this document are
   to be interpreted as described in RFC 2119.

1.  Background and Intent of Use

   Lightweight Directory Access Protocol (LDAP) [RFC2251] is designed to
   support an number of authentication mechanisms including simple user
   name/password pairs.  Traditionally, LDAP users where identified by
   the Distinguished Name [RFC2253] of a directory entry and this entry
   contained a userPassword [RFC2256] attribute containing one or more
   passwords.

   The protocol does not mandate that passwords associated with a user
   be stored in the directory server.  The server may use any attribute
   suitable for password storage (e.g., userPassword), or use non-
   directory storage.




Zeilenga                    Standards Track                     [Page 1]

RFC 3062        LDAP Password Modify Extended Operation    February 2001


   The integration [RFC2829] of application neutral SASL [RFC2222]
   services which support simple username/password mechanisms (such as
   DIGEST-MD5) has introduced non-LDAP DN authentication identity forms
   and made storage of passwords the responsibility of the SASL service
   provider.

   LDAP update operations are designed to act upon attributes of an
   entry within the directory.  LDAP update operations cannot be used to
   modify a user's password when the user is not represented by a DN,
   does not have a entry, or when that password used by the server is
   not stored as an attribute of an entry.  An alternative mechanism is
   needed.

   This document describes an LDAP Extended Operation intended to allow
   directory clients to update user passwords.  The user may or may not
   be associated with a directory entry.  The user may or may not be
   represented as an LDAP DN.  The user's password may or may not be
   stored in the directory.

   The operation SHOULD NOT be used without adequate security protection
   as the operation affords no privacy or integrity protect itself.
   This operation SHALL NOT be used anonymously.

2.  Password Modify Request and Response

   The Password Modify operation is an LDAPv3 Extended Operation
   [RFC2251, Section 4.12] and is identified by the OBJECT IDENTIFIER
   passwdModifyOID.  This section details the syntax of the protocol
   request and response.

   passwdModifyOID OBJECT IDENTIFIER ::= 1.3.6.1.4.1.4203.1.11.1

   PasswdModifyRequestValue ::= SEQUENCE {
     userIdentity    [0]  OCTET STRING OPTIONAL
     oldPasswd       [1]  OCTET STRING OPTIONAL
     newPasswd       [2]  OCTET STRING OPTIONAL }

   PasswdModifyResponseValue ::= SEQUENCE {
     genPasswd       [0]     OCTET STRING OPTIONAL }

2.1.  Password Modify Request

   A Password Modify request is an ExtendedRequest with the requestName
   field containing passwdModifyOID OID and optionally provides a
   requestValue field.  If the requestValue field is provided, it SHALL
   contain a PasswdModifyRequestValue with one or more fields present.





Zeilenga                    Standards Track                     [Page 2]

RFC 3062        LDAP Password Modify Extended Operation    February 2001


   The userIdentity field, if present, SHALL contain an octet string
   representation of the user associated with the request.  This string
   may or may not be an LDAPDN [RFC2253].  If no userIdentity field is
   present, the request acts up upon the password of the user currently
   associated with the LDAP session.

   The oldPasswd field, if present, SHALL contain the user's current
   password.

   The newPasswd field, if present, SHALL contain the desired password
   for this user.

2.2.  Password Modify Response

   A Password Modify response is an ExtendedResponse where the
   responseName field is absent and the response field is optional.  The
   response field, if present, SHALL contain a PasswdModifyResponseValue
   with genPasswd field present.

   The genPasswd field, if present, SHALL contain a generated password
   for the user.

   If an resultCode other than success (0) is indicated in the response,
   the response field MUST be absent.

3.  Operation Requirements

   Clients SHOULD NOT submit a Password Modification request without
   ensuring adequate security safeguards are in place.  Servers SHOULD
   return a non-success resultCode if sufficient security protection are
   not in place.

   Servers SHOULD indicate their support for this extended operation by
   providing PasswdModifyOID as a value of the supportedExtension
   attribute type in their root DSE.  A server MAY choose to advertise
   this extension only when the client is authorized and/or has
   established the necessary security protections to use this operation.
   Clients SHOULD verify the server implements this extended operation
   prior to attempting the operation by asserting the supportedExtension
   attribute contains a value of PasswdModifyOID.

   The server SHALL only return success upon successfully changing the
   user's password.  The server SHALL leave the password unmodified and
   return a non-success resultCode otherwise.

   If the server does not recognize provided fields or does not support
   the combination of fields provided, it SHALL NOT change the user
   password.



Zeilenga                    Standards Track                     [Page 3]

RFC 3062        LDAP Password Modify Extended Operation    February 2001


   If oldPasswd is present and the provided value cannot be verified or
   is incorrect, the server SHALL NOT change the user password.  If
   oldPasswd is not present, the server MAY use other policy to
   determine whether or not to change the password.

   The server SHALL NOT generate a password on behalf of the client if
   the client has provided a newPasswd.  In absence of a client provided
   newPasswd, the server SHALL either generate a password on behalf of
   the client or return a non-success result code.  The server MUST
   provide the generated password upon success as the value of the
   genPasswd field.

   The server MAY return adminLimitExceeded, busy,
   confidentialityRequired, operationsError, unavailable,
   unwillingToPerform, or other non-success resultCode as appropriate to
   indicate that it was unable to successfully complete the operation.

   Servers MAY implement administrative policies which restrict this
   operation.

4.  Security Considerations

   This operation is used to modify user passwords.  The operation
   itself does not provide any security protection to ensure integrity
   and/or confidentiality of the information.  Use of this operation is
   strongly discouraged when privacy protections are not in place to
   guarantee confidentiality and may result in the disclosure of the
   password to unauthorized parties.  This extension MUST be used with
   confidentiality protection, such as Start TLS [RFC 2830].  The NULL
   cipher suite MUST NOT be used.

5. Bibliography

   [RFC2219]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2222]  Myers, J., "Simple Authentication and Security Layer
              (SASL)", RFC 2222, October 1997.

   [RFC2251]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252]  Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
              "Lightweight Directory Access Protocol (v3): Attribute
              Syntax Definitions", RFC 2252, December 1997.






Zeilenga                    Standards Track                     [Page 4]

RFC 3062        LDAP Password Modify Extended Operation    February 2001


   [RFC2253]  Wahl, M., Kille,S. and T. Howes, "Lightweight Directory
              Access Protocol (v3): UTF-8 String Representation of
              Distinguished Names", RFC 2253, December 1997.

   [RFC2256]  Wahl, M., "A Summary of the X.500(96) User Schema for use
              with LDAPv3", RFC 2256, December 1997.

   [RFC2829]  Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
              "Authentication Methods for LDAP", RFC 2829, May 2000.

   [RFC2830]  Hodges, J., Morgan, R. and M. Wahl, "Lightweight Directory
              Access Protocol (v3): Extension for Transport Layer
              Security", RFC 2830, May 2000.

6.  Acknowledgment

   This document borrows from a number of IETF documents and is based
   upon input from the IETF LDAPext working group.

7.  Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org


























Zeilenga                    Standards Track                     [Page 5]

RFC 3062        LDAP Password Modify Extended Operation    February 2001


8.  Full Copyright Statement

   Copyright (C) The Internet Society (2001).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Zeilenga                    Standards Track                     [Page 6]

alt-openldap11-devel/rfc/rfc3727.txt000064400000020151150410163210012763 0ustar00





Network Working Group                                            S. Legg
Request for Comments: 3727                           Adacel Technologies
Category: Standards Track                                  February 2004


                    ASN.1 Module Definition for the
                LDAP and X.500 Component Matching Rules

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).  All Rights Reserved.

Abstract

   This document updates the specification of the component matching
   rules for Lightweight Directory Access Protocol (LDAP) and X.500
   directories (RFC3687) by collecting the Abstract Syntax Notation One
   (ASN.1) definitions of the component matching rules into an
   appropriately identified ASN.1 module so that other specifications
   may reference the component matching rule definitions from within
   their own ASN.1 modules.

1.  Introduction

   The structure or data type of data held in an attribute of a
   Lightweight Directory Access Protocol (LDAP) [LDAP] or X.500 [X500]
   directory is described by the attribute's syntax.  Attribute syntaxes
   range from simple data types, such as text string, integer, or
   boolean, to complex data types, for example, the syntaxes of the
   directory schema operational attributes.  RFC 3687 [CMR] defines a
   generic way of matching user selected components in a directory
   attribute value of any arbitrarily complex attribute syntax.

   This document updates RFC 3687 by collecting the Abstract Syntax
   Notation One (ASN.1) [ASN1] definitions of RFC 3687 into an
   appropriately identified ASN.1 module so that other specifications
   may reference these definitions from within their own ASN.1 modules.






Legg                        Standards Track                     [Page 1]

RFC 3727             Module for Component Matching         February 2004


2.  Module Definition for Component Matching

   ComponentMatching
       {iso(1) 2 36 79672281 xed(3) module(0) component-matching(4)}

   --  Copyright (C) The Internet Society (2004).  This version of
   --  this ASN.1 module is part of RFC 3727; see the RFC itself
   --  for full legal notices.

   DEFINITIONS
   EXPLICIT TAGS
   EXTENSIBILITY IMPLIED ::= BEGIN

   IMPORTS
       MATCHING-RULE,
       RelativeDistinguishedName
           FROM InformationFramework
               {joint-iso-itu-t ds(5) module(1)
                   informationFramework(1) 4} ;

   ComponentAssertion ::= SEQUENCE {
       component         ComponentReference (SIZE(1..MAX)) OPTIONAL,
       useDefaultValues  BOOLEAN DEFAULT TRUE,
       rule              MATCHING-RULE.&id,
       value             MATCHING-RULE.&AssertionType }

   ComponentReference ::= UTF8String

   ComponentFilter ::= CHOICE {
       item  [0] ComponentAssertion,
       and   [1] SEQUENCE OF ComponentFilter,
       or    [2] SEQUENCE OF ComponentFilter,
       not   [3] ComponentFilter }

   componentFilterMatch MATCHING-RULE ::= {
       SYNTAX  ComponentFilter
       ID      { 1 2 36 79672281 1 13 2 } }

   allComponentsMatch MATCHING-RULE ::= {
       ID      { 1 2 36 79672281 1 13 6 } }

   directoryComponentsMatch MATCHING-RULE ::= {
       ID      { 1 2 36 79672281 1 13 7 } }


   -- Additional Useful Matching Rules --

   rdnMatch MATCHING-RULE ::= {



Legg                        Standards Track                     [Page 2]

RFC 3727             Module for Component Matching         February 2004


       SYNTAX  RelativeDistinguishedName
       ID      { 1 2 36 79672281 1 13 3 } }

   presentMatch MATCHING-RULE ::= {
       SYNTAX  NULL
       ID      { 1 2 36 79672281 1 13 5 } }

   END

   The InformationFramework ASN.1 module from which the MATCHING-RULE
   and RelativeDistinguishedName definitions are imported is defined in
   X.501 [X501].

   The object identifiers used in this document have been assigned for
   use in specifying the component matching rules by Adacel
   Technologies, under an arc assigned to Adacel by Standards Australia.

3.  Security Considerations

   This document collects together the ASN.1 definitions of the
   component matching rules into an ASN.1 module, but does not modify
   those definitions in any way.  See RFC 3687 [CMR] for the security
   considerations of using the component matching rules.

4.  References

4.1.  Normative References

   [CMR]   Legg, S., "Lightweight Directory Access Protocol (LDAP) and
           X.500 Component Matching Rules", RFC 3687, February 2004.

   [X501]  ITU-T Recommendation X.501 (1993) | ISO/IEC 9594-2:1994,
           Information Technology - Open Systems Interconnection - The
           Directory: Models

   [ASN1]  ITU-T Recommendation X.680 (07/02) | ISO/IEC 8824-1:2002,
           Information technology - Abstract Syntax Notation One
           (ASN.1): Specification of basic notation

4.2.  Informative References

   [LDAP]  Hodges, J. and R. Morgan, "Lightweight Directory Access
           Protocol (v3): Technical Specification", RFC 3377, September
           2002.

   [X500]  ITU-T Recommendation X.500 (1993) | ISO/IEC 9594-1:1994,
           Information Technology - Open Systems Interconnection - The
           Directory: Overview of concepts, models and services



Legg                        Standards Track                     [Page 3]

RFC 3727             Module for Component Matching         February 2004


5.  Author's Address

   Steven Legg
   Adacel Technologies Ltd.
   250 Bay Street
   Brighton, Victoria 3186
   AUSTRALIA

   Phone: +61 3 8530 7710
   Fax:   +61 3 8530 7888
   EMail: steven.legg@adacel.com.au








































Legg                        Standards Track                     [Page 4]

RFC 3727             Module for Component Matching         February 2004


6.  Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78 and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
   REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE
   INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed
   to pertain to the implementation or use of the technology
   described in this document or the extent to which any license
   under such rights might or might not be available; nor does it
   represent that it has made any independent effort to identify any
   such rights.  Information on the procedures with respect to
   rights in RFC documents can be found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use
   of such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository
   at http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention
   any copyrights, patents or patent applications, or other
   proprietary rights that may cover technology that may be required
   to implement this standard.  Please address the information to the
   IETF at ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.









Legg                        Standards Track                     [Page 5]

alt-openldap11-devel/rfc/rfc3687.txt000064400000274000150410163210012774 0ustar00





Network Working Group                                            S. Legg
Request for Comments: 3687                           Adacel Technologies
Category: Standards Track                                  February 2004


             Lightweight Directory Access Protocol (LDAP)
                   and X.500 Component Matching Rules

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).  All Rights Reserved.

Abstract

   The syntaxes of attributes in a Lightweight Directory Access Protocol
   (LDAP) or X.500 directory range from simple data types, such as text
   string, integer, or boolean, to complex structured data types, such
   as the syntaxes of the directory schema operational attributes.
   Matching rules defined for the complex syntaxes usually only provide
   the most immediately useful matching capability.  This document
   defines generic matching rules that can match any user selected
   component parts in an attribute value of any arbitrarily complex
   attribute syntax.




















Legg                        Standards Track                     [Page 1]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
   2.  Conventions. . . . . . . . . . . . . . . . . . . . . . . . . .  4
   3.  ComponentAssertion . . . . . . . . . . . . . . . . . . . . . .  5
       3.1.  Component Reference. . . . . . . . . . . . . . . . . . .  6
             3.1.1.  Component Type Substitutions . . . . . . . . . .  7
             3.1.2.  Referencing SET, SEQUENCE and CHOICE Components.  8
             3.1.3.  Referencing SET OF and SEQUENCE OF Components. .  9
             3.1.4.  Referencing Components of Parameterized Types. . 10
             3.1.5.  Component Referencing Example. . . . . . . . . . 10
             3.1.6.  Referencing Components of Open Types . . . . . . 12
                     3.1.6.1. Open Type Referencing Example . . . . . 12
             3.1.7.  Referencing Contained Types. . . . . . . . . . . 14
                     3.1.7.1. Contained Type Referencing Example. . . 14
       3.2.  Matching of Components . . . . . . . . . . . . . . . . . 15
             3.2.1.  Applicability of Existing Matching Rules . . . . 17
                     3.2.1.1. String Matching . . . . . . . . . . . . 17
                     3.2.1.2. Telephone Number Matching . . . . . . . 17
                     3.2.1.3. Distinguished Name Matching . . . . . . 18
             3.2.2.  Additional Useful Matching Rules . . . . . . . . 18
                     3.2.2.1. The rdnMatch Matching Rule. . . . . . . 18
                     3.2.2.2. The presentMatch Matching Rule. . . . . 19
             3.2.3.  Summary of Useful Matching Rules . . . . . . . . 20
   4.  ComponentFilter. . . . . . . . . . . . . . . . . . . . . . . . 21
   5.  The componentFilterMatch Matching Rule . . . . . . . . . . . . 22
   6.  Equality Matching of Complex Components. . . . . . . . . . . . 24
       6.1.  The OpenAssertionType Syntax . . . . . . . . . . . . . . 24
       6.2.  The allComponentsMatch Matching Rule . . . . . . . . . . 25
       6.3.  Deriving Component Equality Matching Rules . . . . . . . 27
       6.4.  The directoryComponentsMatch Matching Rule . . . . . . . 28
   7.  Component Matching Examples. . . . . . . . . . . . . . . . . . 30
   8.  Security Considerations. . . . . . . . . . . . . . . . . . . . 37
   9.  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 37
   10. IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 37
   11. References . . . . . . . . . . . . . . . . . . . . . . . . . . 38
       11.1.  Normative References. . . . . . . . . . . . . . . . . . 38
       11.2.  Informative References. . . . . . . . . . . . . . . . . 40
   12. Intellectual Property Statement. . . . . . . . . . . . . . . . 40
   13. Author's Address . . . . . . . . . . . . . . . . . . . . . . . 41
   14. Full Copyright Statement . . . . . . . . . . . . . . . . . . . 42










Legg                        Standards Track                     [Page 2]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


1.  Introduction

   The structure or data type of data held in an attribute of a
   Lightweight Directory Access Protocol (LDAP) [7] or X.500 [19]
   directory is described by the attribute's syntax.  Attribute syntaxes
   range from simple data types, such as text string, integer, or
   boolean, to complex data types, for example, the syntaxes of the
   directory schema operational attributes.

   In X.500, the attribute syntaxes are explicitly described by Abstract
   Syntax Notation One (ASN.1) [13] type definitions.  ASN.1 type
   notation has a number of simple data types (e.g., PrintableString,
   INTEGER, BOOLEAN), and combining types (i.e., SET, SEQUENCE, SET OF,
   SEQUENCE OF, and CHOICE) for constructing arbitrarily complex data
   types from simpler component types.  In LDAP, the attribute syntaxes
   are usually described in Augmented Backus-Naur Form (ABNF) [2],
   though there is an implied association between the LDAP attribute
   syntaxes and the X.500 ASN.1 types.  To a large extent, the data
   types of attribute values in either an LDAP or X.500 directory are
   described by ASN.1 types.  This formal description can be exploited
   to identify component parts of an attribute value for a variety of
   purposes.  This document addresses attribute value matching.

   With any complex attribute syntax there is normally a requirement to
   partially match an attribute value of that syntax by matching only
   selected components of the value.  Typically, matching rules specific
   to the attribute syntax are defined to fill this need.  These highly
   specific matching rules usually only provide the most immediately
   useful matching capability.  Some complex attribute syntaxes don't
   even have an equality matching rule let alone any additional matching
   rules for partial matching.  This document defines a generic way of
   matching user selected components in an attribute value of any
   arbitrarily complex attribute syntax, where that syntax is described
   using ASN.1 type notation.  All of the type notations defined in
   X.680 [13] are supported.

   Section 3 describes the ComponentAssertion, a testable assertion
   about the value of a component of an attribute value of any complex
   syntax.

   Section 4 introduces the ComponentFilter assertion, which is an
   expression of ComponentAssertions.  The ComponentFilter enables more
   powerful filter matching of components in an attribute value.

   Section 5 defines the componentFilterMatch matching rule, which
   enables a ComponentFilter to be evaluated against attribute values.





Legg                        Standards Track                     [Page 3]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   Section 6 defines matching rules for component-wise equality matching
   of attribute values of any syntax described by an ASN.1 type
   definition.

   Examples showing the usage of componentFilterMatch are in Section 7.

   For a new attribute syntax, the Generic String Encoding Rules [9] and
   the specifications in sections 3 to 6 of this document make it
   possible to fully and precisely define the LDAP-specific encoding,
   the LDAP and X.500 binary encoding (and possibly other ASN.1
   encodings in the future), a suitable equality matching rule, and a
   comprehensive collection of component matching capabilities, by
   simply writing down an ASN.1 type definition for the syntax.  These
   implicit definitions are also automatically extended if the ASN.1
   type is later extended.  The algorithmic relationship between the
   ASN.1 type definition, the various encodings and the component
   matching behaviour makes directory server implementation support for
   the component matching rules amenable to automatic code generation
   from ASN.1 type definitions.

   Schema designers have the choice of storing related items of data as
   a single attribute value of a complex syntax in some entry, or as a
   subordinate entry where the related data items are stored as separate
   attribute values of simpler syntaxes.  The inability to search
   component parts of a complex syntax has been used as an argument for
   favouring the subordinate entries approach.  The component matching
   rules provide the analogous matching capability on an attribute value
   of a complex syntax that a search filter has on a subordinate entry.

   Most LDAP syntaxes have corresponding ASN.1 type definitions, though
   they are usually not reproduced or referenced alongside the formal
   definition of the LDAP syntax.  Syntaxes defined with only a
   character string encoding, i.e., without an explicit or implied
   corresponding ASN.1 type definition, cannot use the component
   matching capabilities described in this document unless and until a
   semantically equivalent ASN.1 type definition is defined for them.

2.  Conventions

   Throughout this document "type" shall be taken to mean an ASN.1 type
   unless explicitly qualified as an attribute type, and "value" shall
   be taken to mean an ASN.1 value unless explicitly qualified as an
   attribute value.








Legg                        Standards Track                     [Page 4]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   Note that "ASN.1 value" does not mean a Basic Encoding Rules (BER)
   [17] encoded value.  The ASN.1 value is an abstract concept that is
   independent of any particular encoding.  BER is just one possible
   encoding of an ASN.1 value.  The component matching rules operate at
   the abstract level without regard for the possible encodings of a
   value.

   Attribute type and matching rule definitions in this document are
   provided in both the X.500 [10] and LDAP [4] description formats.
   Note that the LDAP descriptions have been rendered with additional
   white-space and line breaks for the sake of readability.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED" and "MAY" in this document are
   to be interpreted as described in BCP 14, RFC 2119 [1].  The key word
   "OPTIONAL" is exclusively used with its ASN.1 meaning.

3.  ComponentAssertion

   A ComponentAssertion is an assertion about the presence, or values
   of, components within an ASN.1 value, i.e., an instance of an ASN.1
   type.  The ASN.1 value is typically an attribute value, where the
   ASN.1 type is the syntax of the attribute.  However, a
   ComponentAssertion may also be applied to a component part of an
   attribute value.  The assertion evaluates to either TRUE, FALSE or
   Undefined for each tested ASN.1 value.

   A ComponentAssertion is described by the following ASN.1 type
   (assumed to be defined with "EXPLICIT TAGS" in force):

      ComponentAssertion ::= SEQUENCE {
          component         ComponentReference (SIZE(1..MAX)) OPTIONAL,
          useDefaultValues  BOOLEAN DEFAULT TRUE,
          rule              MATCHING-RULE.&id,
          value             MATCHING-RULE.&AssertionType }

      ComponentReference ::= UTF8String

   MATCHING-RULE.&id equates to the OBJECT IDENTIFIER of a matching
   rule.  MATCHING-RULE.&AssertionType is an open type (formerly known
   as the ANY type).

   The "component" field of a ComponentAssertion identifies which
   component part of a value of some ASN.1 type is to be tested, the
   "useDefaultValues" field indicates whether DEFAULT values are to be
   substituted for absent component values, the "rule" field indicates





Legg                        Standards Track                     [Page 5]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   how the component is to be tested, and the "value" field is an
   asserted ASN.1 value against which the component is tested.  The
   ASN.1 type of the asserted value is determined by the chosen rule.

   The fields of a ComponentAssertion are described in detail in the
   following sections.

3.1.  Component Reference

   The component field in a ComponentAssertion is a UTF-8 character
   string [6] whose textual content is a component reference,
   identifying a component part of some ASN.1 type or value.  A
   component reference conforms to the following ABNF [2], which extends
   the notation defined in Clause 14 of X.680 [13]:

      component-reference = ComponentId *( "." ComponentId )
      ComponentId         = identifier /
                            from-beginning /
                            count /
                            from-end /       ; extends Clause 14
                            content /        ; extends Clause 14
                            select /         ; extends Clause 14
                            all

      identifier          = lowercase *alphanumeric
                               *(hyphen 1*alphanumeric)
      alphanumeric        = uppercase / lowercase / decimal-digit
      uppercase           = %x41-5A  ; "A" to "Z"
      lowercase           = %x61-7A  ; "a" to "z"
      hyphen              = "-"

      from-beginning      = positive-number
      count               = "0"
      from-end            = "-" positive-number
      content             = %x63.6F.6E.74.65.6E.74 ; "content"
      select              = "(" Value *( "," Value ) ")"
      all                 = "*"


      positive-number     = non-zero-digit *decimal-digit

      decimal-digit       = %x30-39  ; "0" to "9"
      non-zero-digit      = %x31-39  ; "1" to "9"








Legg                        Standards Track                     [Page 6]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   An <identifier> conforms to the definition of an identifier in ASN.1
   notation (Clause 11.3 of X.680 [13]).  It begins with a lowercase
   letter and is followed by zero or more letters, digits, and hyphens.
   A hyphen is not permitted to be the last character and a hyphen is
   not permitted to be followed by another hyphen.

   The <Value> rule is described by the Generic String Encoding Rules
   (GSER) [9].

   A component reference is a sequence of one or more ComponentIds where
   each successive ComponentId identifies either an inner component at
   the next level of nesting of an ASN.1 combining type, i.e., SET,
   SEQUENCE, SET OF, SEQUENCE OF, or CHOICE, or a specific type within
   an ASN.1 open type.

   A component reference is always considered in the context of a
   particular complex ASN.1 type.  When applied to the ASN.1 type the
   component reference identifies a specific component type.  When
   applied to a value of the ASN.1 type a component reference identifies
   zero, one or more component values of that component type.  The
   component values are potentially in a DEFAULT value if
   useDefaultValues is TRUE.  The specific component type identified by
   the component reference determines what matching rules are capable of
   being used to match the component values.

   The component field in a ComponentAssertion may also be absent, in
   which case the identified component type is the ASN.1 type to which
   the ComponentAssertion is applied, and the identified component value
   is the whole ASN.1 value.

   A valid component reference for a particular complex ASN.1 type is
   constructed by starting with the outermost combining type and
   repeatedly selecting one of the permissible forms of ComponentId to
   identify successively deeper nested components.  A component
   reference MAY identify a component with a complex ASN.1 type, i.e.,
   it is not required that the component type identified by a component
   reference be a simple ASN.1 type.

3.1.1.  Component Type Substitutions

   ASN.1 type notation has a number of constructs for referencing other
   defined types, and constructs that are irrelevant for matching
   purposes.  These constructs are not represented in a component
   reference in any way and substitutions of the component type are
   performed to eliminate them from further consideration.  These
   substitutions automatically occur prior to each ComponentId, whether
   constructing or interpreting a component reference, but do not occur
   after the last ComponentId, except as allowed by Section 3.2.



Legg                        Standards Track                     [Page 7]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   If the ASN.1 type is an ASN.1 type reference then the component type
   is taken to be the actual definition on the right hand side of the
   type assignment for the referenced type.

   If the ASN.1 type is a tagged type then the component type is taken
   to be the type without the tag.

   If the ASN.1 type is a constrained type (see X.680 [13] and X.682
   [15] for the details of ASN.1 constraint notation) then the component
   type is taken to be the type without the constraint.

   If the ASN.1 type is an ObjectClassFieldType (Clause 14 of X.681
   [14]) that denotes a specific ASN.1 type (e.g., MATCHING-RULE.&id
   denotes the OBJECT IDENTIFIER type) then the component type is taken
   to be the denoted type.  Section 3.1.6 describes the case where the
   ObjectClassFieldType denotes an open type.

   If the ASN.1 type is a selection type other than one used in the list
   of components for a SET or SEQUENCE type then the component type is
   taken to be the selected alternative type from the named CHOICE.

   If the ASN.1 type is a TypeFromObject (Clause 15 of X.681 [14]) then
   the component type is taken to be the denoted type.

   If the ASN.1 type is a ValueSetFromObjects (Clause 15 of X.681 [14])
   then the component type is taken to be the governing type of the
   denoted values.

3.1.2.  Referencing SET, SEQUENCE and CHOICE Components

   If the ASN.1 type is a SET or SEQUENCE type then the <identifier>
   form of ComponentId may be used to identify the component type within
   that SET or SEQUENCE having that identifier.  If <identifier>
   references an OPTIONAL component type and that component is not
   present in a particular value then there are no corresponding
   component values.  If <identifier> references a DEFAULT component
   type and useDefaultValues is TRUE (the default setting for
   useDefaultValues) and that component is not present in a particular
   value then the component value is taken to be the default value.  If
   <identifier> references a DEFAULT component type and useDefaultValues
   is FALSE and that component is not present in a particular value then
   there are no corresponding component values.

   If the ASN.1 type is a CHOICE type then the <identifier> form of
   ComponentId may be used to identify the alternative type within that
   CHOICE having that identifier.  If <identifier> references an
   alternative other than the one used in a particular value then there
   are no corresponding component values.



Legg                        Standards Track                     [Page 8]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   The COMPONENTS OF notation in Clause 24 of X.680 [13] augments the
   defined list of components in a SET or SEQUENCE type by including all
   the components of another defined SET or SEQUENCE type respectively.
   These included components are referenced directly by identifier as
   though they were defined in-line in the SET or SEQUENCE type
   containing the COMPONENTS OF notation.

   The SelectionType (Clause 29 of X.680 [13]), when used in the list of
   components for a SET or SEQUENCE type, includes a single component
   from a defined CHOICE type.  This included component is referenced
   directly by identifier as though it was defined in-line in the SET or
   SEQUENCE type.

   The REAL type is treated as though it is the SEQUENCE type defined in
   Clause 20.5 of X.680 [13].

   The EMBEDDED PDV type is treated as though it is the SEQUENCE type
   defined in Clause 33.5 of X.680 [13].

   The EXTERNAL type is treated as though it is the SEQUENCE type
   defined in Clause 8.18.1 of X.690 [17].

   The unrestricted CHARACTER STRING type is treated as though it is the
   SEQUENCE type defined in Clause 40.5 of X.680 [13].

   The INSTANCE OF type is treated as though it is the SEQUENCE type
   defined in Annex C of X.681 [14].

   The <identifier> form MUST NOT be used on any other ASN.1 type.

3.1.3.  Referencing SET OF and SEQUENCE OF Components

   If the ASN.1 type is a SET OF or SEQUENCE OF type then the
   <from-beginning>, <from-end>, <count> and <all> forms of ComponentId
   may be used.

   The <from-beginning> form of ComponentId may be used to identify one
   instance (i.e., value) of the component type of the SET OF or
   SEQUENCE OF type (e.g., if Foo ::= SET OF Bar, then Bar is the
   component type), where the instances are numbered from one upwards.
   If <from-beginning> references a higher numbered instance than the
   last instance in a particular value of the SET OF or SEQUENCE OF type
   then there is no corresponding component value.

   The <from-end> form of ComponentId may be used to identify one
   instance of the component type of the SET OF or SEQUENCE OF type,
   where "-1" is the last instance, "-2" is the second last instance,




Legg                        Standards Track                     [Page 9]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   and so on.  If <from-end> references a lower numbered instance than
   the first instance in a particular value of the SET OF or SEQUENCE OF
   type then there is no corresponding component value.

   The <count> form of ComponentId identifies a notional count of the
   number of instances of the component type in a value of the SET OF or
   SEQUENCE OF type.  This count is not explicitly represented but for
   matching purposes it has an assumed ASN.1 type of INTEGER (0..MAX).
   A ComponentId of the <count> form, if used, MUST be the last
   ComponentId in a component reference.

   The <all> form of ComponentId may be used to simultaneously identify
   all instances of the component type of the SET OF or SEQUENCE OF
   type.  It is through the <all> form that a component reference can
   identify more than one component value.  However, if a particular
   value of the SET OF or SEQUENCE OF type is an empty list, then there
   are no corresponding component values.

   Where multiple component values are identified, the remaining
   ComponentIds in the component reference, if any, can identify zero,
   one or more subcomponent values for each of the higher level
   component values.

   The corresponding ASN.1 type for the <from-beginning>, <from-end>,
   and <all> forms of ComponentId is the component type of the SET OF or
   SEQUENCE OF type.

   The <from-beginning>, <count>, <from-end> and <all> forms MUST NOT be
   used on ASN.1 types other than SET OF or SEQUENCE OF.

3.1.4.  Referencing Components of Parameterized Types

   A component reference cannot be formed for a parameterized type
   unless the type has been used with actual parameters, in which case
   the type is treated as though the DummyReferences [16] have been
   substituted with the actual parameters.

3.1.5.  Component Referencing Example

   Consider the following ASN.1 type definitions.

      ExampleType ::= SEQUENCE {
          part1       [0] INTEGER,
          part2       [1] ExampleSet,
          part3       [2] SET OF OBJECT IDENTIFIER,
          part4       [3] ExampleChoice }





Legg                        Standards Track                    [Page 10]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      ExampleSet ::= SET {
          option      PrintableString,
          setting     BOOLEAN }

      ExampleChoice ::= CHOICE {
          eeny-meeny  BIT STRING,
          miney-mo    OCTET STRING }

   Following are component references constructed with respect to the
   type ExampleType.

   The component reference "part1" identifies a component of a value of
   ExampleType having the ASN.1 tagged type [0] INTEGER.

   The component reference "part2" identifies a component of a value of
   ExampleType having the ASN.1 type of [1] ExampleSet

   The component reference "part2.option" identifies a component of a
   value of ExampleType having the ASN.1 type of PrintableString.  A
   ComponentAssertion could also be applied to a value of ASN.1 type
   ExampleSet, in which case the component reference "option" would
   identify the same kind of information.

   The component reference "part3" identifies a component of a value of
   ExampleType having the ASN.1 type of [2] SET OF OBJECT IDENTIFIER.

   The component reference "part3.2" identifies the second instance of
   the part3 SET OF.  The instance has the ASN.1 type of OBJECT
   IDENTIFIER.

   The component reference "part3.0" identifies the count of the number
   of instances in the part3 SET OF.  The count has the corresponding
   ASN.1 type of INTEGER (0..MAX).

   The component reference "part3.*" identifies all the instances in the
   part3 SET OF.  Each instance has the ASN.1 type of OBJECT IDENTIFIER.

   The component reference "part4" identifies a component of a value of
   ExampleType having the ASN.1 type of [3] ExampleChoice.

   The component reference "part4.miney-mo" identifies a component of a
   value of ExampleType having the ASN.1 type of OCTET STRING.









Legg                        Standards Track                    [Page 11]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


3.1.6.  Referencing Components of Open Types

   If a sequence of ComponentIds identifies an ObjectClassFieldType
   denoting an open type (e.g., ATTRIBUTE.&Type denotes an open type)
   then the ASN.1 type of the component varies.  An open type is
   typically constrained by some other component(s) in an outer
   enclosing type, either formally through the use of a component
   relation constraint [15], or informally in the accompanying text, so
   the actual ASN.1 type of a value of the open type will generally be
   known.  The constraint will also limit the range of permissible
   types.  The <select> form of ComponentId may be used to identify one
   of these permissible types in an open type.  Subcomponents of that
   type can then be identified with further ComponentIds.

   The other components constraining the open type are termed the
   referenced components [15].  The <select> form contains a list of one
   or more values which take the place of the value(s) of the referenced
   component(s) to uniquely identify one of the permissible types of the
   open type.

   Where the open type is constrained by a component relation
   constraint, there is a <Value> in the <select> form for each of the
   referenced components in the component relation constraint, appearing
   in the same order.  The ASN.1 type of each of these values is the
   same as the ASN.1 type of the corresponding referenced component.
   The type of a referenced component is potentially any ASN.1 type
   however it is typically an OBJECT IDENTIFIER or INTEGER, which means
   that the <Value> in the <select> form of ComponentId will nearly
   always be an <ObjectIdentifierValue> or <IntegerValue> [9].
   Furthermore, component relation constraints typically have only one
   referenced component.

   Where the open type is not constrained by a component relation
   constraint, the specification introducing the syntax containing the
   open type should explicitly nominate the referenced components and
   their order, so that the <select> form can be used.

   If an instance of <select> contains a value other than the value of
   the referenced component used in a particular value of the outer
   enclosing type then there are no corresponding component values for
   the open type.

3.1.6.1.  Open Type Referencing Example

   The ASN.1 type AttributeTypeAndValue [10] describes a single
   attribute value of a nominated attribute type.





Legg                        Standards Track                    [Page 12]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      AttributeTypeAndValue ::= SEQUENCE {
          type    ATTRIBUTE.&id ({SupportedAttributes}),
          value   ATTRIBUTE.&Type ({SupportedAttributes}{@type}) }

   ATTRIBUTE.&id denotes an OBJECT IDENTIFIER and
   ({SupportedAttributes}) constrains the OBJECT IDENTIFIER to be a
   supported attribute type.

   ATTRIBUTE.&Type denotes an open type, in this case an attribute
   value, and ({SupportedAttributes}{@type}) is a component relation
   constraint that constrains the open type to be of the attribute
   syntax for the attribute type.  The component relation constraint
   references only the "type" component, which has the ASN.1 type of
   OBJECT IDENTIFIER, thus if the <select> form of ComponentId is used
   to identify attribute values of specific attribute types it will
   contain a single OBJECT IDENTIFIER value.

   The component reference "value" on AttributeTypeAndValue refers to
   the open type.

   One of the X.500 standard attributes is facsimileTelephoneNumber
   [12], which is identified with the OBJECT IDENTIFIER 2.5.4.23, and is
   defined to have the following syntax.

      FacsimileTelephoneNumber ::= SEQUENCE {
          telephoneNumber PrintableString(SIZE(1..ub-telephone-number)),
          parameters      G3FacsimileNonBasicParameters OPTIONAL }

   The component reference "value.(2.5.4.23)" on AttributeTypeAndValue
   specifies an attribute value with the FacsimileTelephoneNumber
   syntax.

   The component reference "value.(2.5.4.23).telephoneNumber" on
   AttributeTypeAndValue identifies the telephoneNumber component of a
   facsimileTelephoneNumber attribute value.  The component reference
   "value.(facsimileTelephoneNumber)" is equivalent to
   "value.(2.5.4.23)".

   If the AttributeTypeAndValue ASN.1 value contains an attribute type
   other than facsimileTelephoneNumber then there are no corresponding
   component values for the component references "value.(2.5.4.23)" and
   "value.(2.5.4.23).telephoneNumber".









Legg                        Standards Track                    [Page 13]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


3.1.7.  Referencing Contained Types

   Sometimes the contents of a BIT STRING or OCTET STRING value are
   required to be the encodings of other ASN.1 values of specific ASN.1
   types.  For example, the extnValue component of the Extension type
   component in the Certificate type [11] is an OCTET STRING that is
   required to contain a Distinguished Encoding Rules (DER) [17]
   encoding of a certificate extension value.  It is useful to be able
   to refer to the embedded encoded value and its components.  An
   embedded encoded value is here referred to as a contained value and
   its associated type as the contained type.

   If the ASN.1 type is a BIT STRING or OCTET STRING type containing
   encodings of other ASN.1 values then the <content> form of
   ComponentId may be used to identify the contained type.
   Subcomponents of that type can then be identified with further
   ComponentIds.

   The contained type may be (effectively) an open type, constrained by
   some other component in an outer enclosing type (e.g., in a
   certificate Extension, extnValue is constrained by the chosen
   extnId).  In these cases the next ComponentId, if any, MUST be of the
   <select> form.

   For the purpose of building component references, the content of the
   extnValue OCTET STRING in the Extension type is assumed to be an open
   type having a notional component relation constraint with the extnId
   component as the single referenced component, i.e.,

      EXTENSION.&ExtnType ({ExtensionSet}{@extnId})

   The data-value component of the associated types for the EMBEDDED PDV
   and CHARACTER STRING types is an OCTET STRING containing the encoding
   of a data value described by the identification component.  For the
   purpose of building component references, the content of the
   data-value OCTET STRING in these types is assumed to be an open type
   having a notional component relation constraint with the
   identification component as the single referenced component.

3.1.7.1.  Contained Type Referencing Example

   The Extension ASN.1 type [11] describes a single certificate
   extension value of a nominated extension type.








Legg                        Standards Track                    [Page 14]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      Extension ::= SEQUENCE {
          extnId     EXTENSION.&id ({ExtensionSet}),
          critical   BOOLEAN DEFAULT FALSE,
          extnValue  OCTET STRING
              -- contains a DER encoding of a value of type &ExtnType
              -- for the extension object identified by extnId -- }

   EXTENSION.&id denotes an OBJECT IDENTIFIER and ({ExtensionSet})
   constrains the OBJECT IDENTIFIER to be the identifier of a supported
   certificate extension.

   The component reference "extnValue" on Extension refers to a
   component type of OCTET STRING.  The corresponding component values
   will be OCTET STRING values.  The component reference
   "extnValue.content" on Extension refers to the type of the contained
   type, which in this case is an open type.

   One of the X.509 [11] standard extensions is basicConstraints, which
   is identified with the OBJECT IDENTIFIER 2.5.29.19 and is defined to
   have the following syntax.

      BasicConstraintsSyntax ::= SEQUENCE {
          cA                 BOOLEAN DEFAULT FALSE,
          pathLenConstraint  INTEGER (0..MAX) OPTIONAL }

   The component reference "extnValue.content.(2.5.29.19)" on Extension
   specifies a BasicConstraintsSyntax extension value and the component
   reference "extnValue.content.(2.5.29.19).cA" identifies the cA
   component of a BasicConstraintsSyntax extension value.

3.2.  Matching of Components

   The rule in a ComponentAssertion specifies how the zero, one or more
   component values identified by the component reference are tested by
   the assertion.  Attribute matching rules are used to specify the
   semantics of the test.

   Each matching rule has a notional set of attribute syntaxes
   (typically one), defined as ASN.1 types, to which it may be applied.
   When used in a ComponentAssertion these matching rules apply to the
   same ASN.1 types, only in this context the corresponding ASN.1 values
   are not necessarily complete attribute values.

   Note that the referenced component type may be a tagged and/or
   constrained version of the expected attribute syntax (e.g.,
   [0] INTEGER, whereas integerMatch would expect simply INTEGER), or an
   open type.  Additional type substitutions of the kind described in




Legg                        Standards Track                    [Page 15]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   Section 3.1.1 are performed as required to reduce the component type
   to the same type as the attribute syntax expected by the matching
   rule.

   If a matching rule applies to more than one attribute syntax (e.g.,
   objectIdentifierFirstComponentMatch [12]) then the minimum number of
   substitutions required to conform to any one of those syntaxes is
   performed.  If a matching rule can apply to any attribute syntax
   (e.g., the allComponentsMatch rule defined in Section 6.2) then the
   referenced component type is used as is, with no additional
   substitutions.

   The value in a ComponentAssertion will be of the assertion syntax
   (i.e., ASN.1 type) required by the chosen matching rule.  Note that
   the assertion syntax of a matching rule is not necessarily the same
   as the attribute syntax(es) to which the rule may be applied.

   Some matching rules do not have a fixed assertion syntax (e.g.,
   allComponentsMatch).  The required assertion syntax is determined in
   each instance of use by the syntax of the attribute type to which the
   matching rule is applied.  For these rules the ASN.1 type of the
   referenced component is used in place of an attribute syntax to
   decide the required assertion syntax.

   The ComponentAssertion is Undefined if:

   a) the matching rule in the ComponentAssertion is not known to the
      evaluating procedure,

   b) the matching rule is not applicable to the referenced component
      type, even with the additional type substitutions,

   c) the value in the ComponentAssertion does not conform to the
      assertion syntax defined for the matching rule,

   d) some part of the component reference identifies an open type in
      the tested value that cannot be decoded, or

   e) the implementation does not support the particular combination of
      component reference and matching rule.

   If the ComponentAssertion is not Undefined then the
   ComponentAssertion evaluates to TRUE if there is at least one
   component value for which the matching rule applied to that component
   value returns TRUE, and evaluates to FALSE otherwise (which includes
   the case where there are no component values).





Legg                        Standards Track                    [Page 16]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


3.2.1.  Applicability of Existing Matching Rules

3.2.1.1.  String Matching

   ASN.1 has a number of built in restricted character string types with
   different character sets and/or different character encodings.  A
   directory user generally has little interest in the particular
   character set or encoding used to represent a character string
   component value, and some directory server implementations make no
   distinction between the different string types in their internal
   representation of values.  So rather than define string matching
   rules for each of the restricted character string types, the existing
   case ignore and case exact string matching rules are extended to
   apply to component values of any of the restricted character string
   types and any ChoiceOfStrings type [9], in addition to component
   values of the DirectoryString type.  This extension is only for the
   purposes of component matching described in this document.

   The relevant string matching rules are: caseIgnoreMatch,
   caseIgnoreOrderingMatch, caseIgnoreSubstringsMatch, caseExactMatch,
   caseExactOrderingMatch and caseExactSubstringsMatch.  The relevant
   restricted character string types are: NumericString,
   PrintableString, VisibleString, IA5String, UTF8String, BMPString,
   UniversalString, TeletexString, VideotexString, GraphicString and
   GeneralString.  A ChoiceOfStrings type is a purely syntactic CHOICE
   of these ASN.1 string types.  Note that GSER [9] declares each and
   every use of the DirectoryString{} parameterized type to be a
   ChoiceOfStrings type.

   The assertion syntax of the string matching rules is still
   DirectoryString regardless of the string syntax of the component
   being matched.  Thus an implementation will be called upon to compare
   a DirectoryString value to a value of one of the restricted character
   string types, or a ChoiceOfStrings type.  As is the case when
   comparing two DirectoryStrings where the chosen alternatives are of
   different string types, the comparison proceeds so long as the
   corresponding characters are representable in both character sets.
   Otherwise matching returns FALSE.

3.2.1.2.  Telephone Number Matching

   Early editions of X.520 [12] gave the syntax of the telephoneNumber
   attribute as a constrained PrintableString.  The fourth edition of
   X.520 equates the ASN.1 type name TelephoneNumber to the constrained
   PrintableString and uses TelephoneNumber as the attribute and
   assertion syntax.  For the purposes of component matching,





Legg                        Standards Track                    [Page 17]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   telephoneNumberMatch and telephoneNumberSubstringsMatch are permitted
   to be applied to any PrintableString value, as well as to
   TelephoneNumber values.

3.2.1.3.  Distinguished Name Matching

   The DistinguishedName type is defined by assignment to be the same as
   the RDNSequence type, however RDNSequence is sometimes directly used
   in other type definitions.  For the purposes of component matching,
   distinguishedNameMatch is also permitted to be applied to values of
   the RDNSequence type.

3.2.2.  Additional Useful Matching Rules

   This section defines additional matching rules that may prove useful
   in ComponentAssertions.  These rules may also be used in
   extensibleMatch search filters [3].

3.2.2.1.  The rdnMatch Matching Rule

   The distinguishedNameMatch matching rule can match whole
   distinguished names but it is sometimes useful to be able to match
   specific Relative Distinguished Names (RDNs) in a Distinguished Name
   (DN) without regard for the other RDNs in the DN.  The rdnMatch
   matching rule allows component RDNs of a DN to be tested.

   The LDAP-style definitions for rdnMatch and its assertion syntax are:

      ( 1.2.36.79672281.1.13.3 NAME 'rdnMatch'
          SYNTAX 1.2.36.79672281.1.5.0 )

      ( 1.2.36.79672281.1.5.0 DESC 'RDN' )

   The LDAP-specific encoding for a value of the RDN syntax is given by
   the <RelativeDistinguishedNameValue> rule [9].

   The X.500-style definition for rdnMatch is:

      rdnMatch MATCHING-RULE ::= {
          SYNTAX  RelativeDistinguishedName
          ID      { 1 2 36 79672281 1 13 3 } }

   The rdnMatch rule evaluates to true if the component value and
   assertion value are the same RDN, using the same RDN comparison
   method as distinguishedNameMatch.






Legg                        Standards Track                    [Page 18]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   When using rdnMatch to match components of DNs it is important to
   note that the LDAP-specific encoding of a DN [5] reverses the order
   of the RDNs.  So for the DN represented in LDAP as
   "cn=Steven Legg,o=Adacel,c=AU", the RDN "cn=Steven Legg" corresponds
   to the component reference "3", or alternatively, "-1".

3.2.2.2.  The presentMatch Matching Rule

   At times it would be useful to test not if a specific value of a
   particular component is present, but whether any value of a
   particular component is present.  The presentMatch matching rule
   allows the presence of a particular component value to be tested.

   The LDAP-style definitions for presentMatch and its assertion syntax
   are:

      ( 1.2.36.79672281.1.13.5 NAME 'presentMatch'
          SYNTAX 1.2.36.79672281.1.5.1 )

      ( 1.2.36.79672281.1.5.1 DESC 'NULL' )

   The LDAP-specific encoding for a value of the NULL syntax is given by
   the <NullValue> rule [9].

   The X.500-style definition for presentMatch is:

      presentMatch MATCHING-RULE ::= {
          SYNTAX  NULL
          ID      { 1 2 36 79672281 1 13 5 } }

   When used in a extensible match filter item, presentMatch behaves
   like the "present" case of a regular search filter.  In a
   ComponentAssertion, presentMatch evaluates to TRUE if and only if the
   component reference identifies one or more component values,
   regardless of the actual component value contents.  Note that if
   useDefaultValues is TRUE then the identified component values may be
   (part of) a DEFAULT value.

   The notional count referenced by the <count> form of ComponentId is
   taken to be present if the SET OF value is present, and absent
   otherwise.  Note that in ASN.1 notation an absent SET OF value is
   distinctly different from a SET OF value that is present but empty.
   It is up to the specification using the ASN.1 notation to decide
   whether the distinction matters.  Often an empty SET OF component and
   an absent SET OF component are treated as semantically equivalent.
   If a SET OF value is present, but empty, a presentMatch on the SET OF
   component SHALL return TRUE and the notional count SHALL be regarded
   as present and equal to zero.



Legg                        Standards Track                    [Page 19]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


3.2.3.  Summary of Useful Matching Rules

   The following is a non-exhaustive list of useful matching rules and
   the ASN.1 types to which they can be applied, taking account of all
   the extensions described in Section 3.2.1, and the new matching rules
   defined in Section 3.2.2.

      +================================+==============================+
      | Matching Rule                  | ASN.1 Type                   |
      +================================+==============================+
      | bitStringMatch                 | BIT STRING                   |
      +--------------------------------+------------------------------+
      | booleanMatch                   | BOOLEAN                      |
      +--------------------------------+------------------------------+
      | caseIgnoreMatch                | NumericString                |
      | caseIgnoreOrderingMatch        | PrintableString              |
      | caseIgnoreSubstringsMatch      | VisibleString (ISO646String) |
      | caseExactMatch                 | IA5String                    |
      | caseExactOrderingMatch         | UTF8String                   |
      | caseExactSubstringsMatch       | BMPString (UCS-2, UNICODE)   |
      |                                | UniversalString (UCS-4)      |
      |                                | TeletexString (T61String)    |
      |                                | VideotexString               |
      |                                | GraphicString                |
      |                                | GeneralString                |
      |                                | any ChoiceOfStrings type     |
      +--------------------------------+------------------------------+
      | caseIgnoreIA5Match             | IA5String                    |
      | caseExactIA5Match              |                              |
      +--------------------------------+------------------------------+
      | distinguishedNameMatch         | DistinguishedName            |
      |                                | RDNSequence                  |
      +--------------------------------+------------------------------+
      | generalizedTimeMatch           | GeneralizedTime              |
      | generalizedTimeOrderingMatch   |                              |
      +--------------------------------+------------------------------+
      | integerMatch                   | INTEGER                      |
      | integerOrderingMatch           |                              |
      +--------------------------------+------------------------------+
      | numericStringMatch             | NumericString                |
      | numericStringOrderingMatch     |                              |
      | numericStringSubstringsMatch   |                              |
      +--------------------------------+------------------------------+
      | objectIdentifierMatch          | OBJECT IDENTIFIER            |
      +--------------------------------+------------------------------+
      | octetStringMatch               | OCTET STRING                 |
      | octetStringOrderingMatch       |                              |
      | octetStringSubstringsMatch     |                              |



Legg                        Standards Track                    [Page 20]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      +--------------------------------+------------------------------+
      | presentMatch                   | any ASN.1 type               |
      +--------------------------------+------------------------------+
      | rdnMatch                       | RelativeDistinguishedName    |
      +--------------------------------+------------------------------+
      | telephoneNumberMatch           | PrintableString              |
      | telephoneNumberSubstringsMatch | TelephoneNumber              |
      +--------------------------------+------------------------------+
      | uTCTimeMatch                   | UTCTime                      |
      | uTCTimeOrderingMatch           |                              |
      +--------------------------------+------------------------------+

   Note that the allComponentsMatch matching rule defined in Section 6.2
   can be used for equality matching of values of the ENUMERATED, NULL,
   REAL and RELATIVE-OID ASN.1 types, among other things.

4.  ComponentFilter

   The ComponentAssertion allows the value(s) of any one component type
   in a complex ASN.1 type to be matched, but there is often a desire to
   match the values of more than one component type.  A ComponentFilter
   is an assertion about the presence, or values of, multiple components
   within an ASN.1 value.

   The ComponentFilter assertion, an expression of ComponentAssertions,
   evaluates to either TRUE, FALSE or Undefined for each tested ASN.1
   value.

   A ComponentFilter is described by the following ASN.1 type (assumed
   to be defined with "EXPLICIT TAGS" in force):

      ComponentFilter ::= CHOICE {
          item  [0] ComponentAssertion,
          and   [1] SEQUENCE OF ComponentFilter,
          or    [2] SEQUENCE OF ComponentFilter,
          not   [3] ComponentFilter }

   Note: despite the use of SEQUENCE OF instead of SET OF for the "and"
   and "or" alternatives in ComponentFilter, the order of the component
   filters is not significant.

   A ComponentFilter that is a ComponentAssertion evaluates to TRUE if
   the ComponentAssertion is TRUE, evaluates to FALSE if the
   ComponentAssertion is FALSE, and evaluates to Undefined otherwise.







Legg                        Standards Track                    [Page 21]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   The "and" of a sequence of component filters evaluates to TRUE if the
   sequence is empty or if each component filter evaluates to TRUE,
   evaluates to FALSE if at least one component filter is FALSE, and
   evaluates to Undefined otherwise.

   The "or" of a sequence of component filters evaluates to FALSE if the
   sequence is empty or if each component filter evaluates to FALSE,
   evaluates to TRUE if at least one component filter is TRUE, and
   evaluates to Undefined otherwise.

   The "not" of a component filter evaluates to TRUE if the component
   filter is FALSE, evaluates to FALSE if the component filter is TRUE,
   and evaluates to Undefined otherwise.

5.  The componentFilterMatch Matching Rule

   The componentFilterMatch matching rule allows a ComponentFilter to be
   applied to an attribute value.  The result of the matching rule is
   the result of applying the ComponentFilter to the attribute value.

   The LDAP-style definitions for componentFilterMatch and its assertion
   syntax are:

      ( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch'
          SYNTAX 1.2.36.79672281.1.5.2 )

      ( 1.2.36.79672281.1.5.2 DESC 'ComponentFilter' )

   The LDAP-specific encoding for the ComponentFilter assertion syntax
   is specified by GSER [9].

   As a convenience to implementors, an equivalent ABNF description of
   the GSER encoding for ComponentFilter is provided here.  In the event
   that there is a discrepancy between this ABNF and the encoding
   determined by GSER, GSER is to be taken as definitive.  The GSER
   encoding of a ComponentFilter is described by the following
   equivalent ABNF:

      ComponentFilter = filter-item /
                        and-filter /
                        or-filter /
                        not-filter

      filter-item     = item-chosen ComponentAssertion
      and-filter      = and-chosen  SequenceOfComponentFilter
      or-filter       = or-chosen   SequenceOfComponentFilter
      not-filter      = not-chosen  ComponentFilter




Legg                        Standards Track                    [Page 22]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      item-chosen     = %x69.74.65.6D.3A  ; "item:"
      and-chosen      = %x61.6E.64.3A     ; "and:"
      or-chosen       = %x6F.72.3A        ; "or:"
      not-chosen      = %x6E.6F.74.3A     ; "not:"

      SequenceOfComponentFilter = "{" [ sp ComponentFilter
                                     *( "," sp ComponentFilter) ] sp "}"

      ComponentAssertion = "{" [ sp component "," ]
                               [ sp useDefaultValues "," ]
                                 sp rule ","
                                 sp assertion-value sp "}"
      component          = component-label msp StringValue
      useDefaultValues   = use-defaults-label msp BooleanValue
      rule               = rule-label msp ObjectIdentifierValue
      assertion-value    = value-label msp Value

      component-label    = %x63.6F.6D.70.6F.6E.65.6E.74  ; "component"
      use-defaults-label = %x75.73.65.44.65.66.61.75.6C.74.56.61.6C.75
                           %x65.73                  ; "useDefaultValues"
      rule-label         = %x72.75.6C.65            ; "rule"
      value-label        = %x76.61.6C.75.65         ; "value"

      sp                 =  *%x20  ; zero, one or more space characters
      msp                = 1*%x20  ; one or more space characters

   The ABNF for <Value>, <StringValue>, <ObjectIdentifierValue> and
   <BooleanValue> is defined by GSER [9].

   The ABNF descriptions of LDAP-specific encodings for attribute
   syntaxes typically do not clearly or consistently delineate the
   component parts of an attribute value.  A regular and uniform
   character string encoding for arbitrary component data types is
   needed to encode the assertion value in a ComponentAssertion.  The
   <Value> rule from GSER provides a human readable text encoding for a
   component value of any arbitrary ASN.1 type.

   The X.500-style definition [10] for componentFilterMatch is:

      componentFilterMatch MATCHING-RULE ::= {
          SYNTAX  ComponentFilter
          ID      { 1 2 36 79672281 1 13 2 } }

   A ComponentAssertion can potentially use any matching rule, including
   componentFilterMatch, so componentFilterMatch may be nested.  The
   component references in a nested componentFilterMatch are relative to





Legg                        Standards Track                    [Page 23]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   the component corresponding to the containing ComponentAssertion.  In
   Section 7, an example search on the seeAlso attribute shows this
   usage.

6.  Equality Matching of Complex Components

   It is possible to test if an attribute value of a complex ASN.1
   syntax is the same as some purported (i.e., assertion) value by using
   a complicated ComponentFilter that tests if corresponding components
   are the same.  However, it would be more convenient to be able to
   present a whole assertion value to a matching rule that could do the
   component-wise comparison of an attribute value with the assertion
   value for any arbitrary attribute syntax.  Similarly, the ability to
   do a straightforward equality comparison of a component value that is
   itself of a complex ASN.1 type would also be convenient.

   It would be difficult to define a single matching rule that
   simultaneously satisfies all notions of what the equality matching
   semantics should be.  For example, in some instances a case sensitive
   comparison of string components may be preferable to a case
   insensitive comparison.  Therefore a basic equality matching rule,
   allComponentsMatch, is defined in Section 6.2, and the means to
   derive new matching rules from it with slightly different equality
   matching semantics are described in Section 6.3.

   The directoryComponentsMatch defined in Section 6.4 is a derivation
   of allComponentsMatch that suits typical uses of the directory.
   Other specifications are free to derive new rules from
   allComponentsMatch or directoryComponentsMatch, that suit their usage
   of the directory.

   The allComponentsMatch rule, the directoryComponentsMatch rule and
   any matching rules derived from them are collectively called
   component equality matching rules.

6.1.  The OpenAssertionType Syntax

   The component equality matching rules have a variable assertion
   syntax.  In X.500 this is indicated by omitting the optional SYNTAX
   field in the MATCHING-RULE information object.  The assertion syntax
   then defaults to the target attribute's syntax in actual usage,
   unless the description of the matching rule says otherwise.  The
   SYNTAX field in the LDAP-specific encoding of a
   MatchingRuleDescription is mandatory, so the OpenAssertionType syntax
   is defined to fill the same role.  That is, the OpenAssertionType
   syntax is semantically equivalent to an omitted SYNTAX field in an
   X.500 MATCHING-RULE information object.  OpenAssertionType MUST NOT
   be used as the attribute syntax in an attribute type definition.



Legg                        Standards Track                    [Page 24]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   Unless explicitly varied by the description of a particular matching
   rule, if an OpenAssertionType assertion value appears in a
   ComponentAssertion its LDAP-specific encoding is described by the
   <Value> rule in GSER [9], otherwise its LDAP-specific encoding is the
   encoding defined for the syntax of the attribute type to which the
   matching rule with the OpenAssertionType assertion syntax is applied.

   The LDAP definition for the OpenAssertionType syntax is:

      ( 1.2.36.79672281.1.5.3 DESC 'OpenAssertionType' )

6.2.  The allComponentsMatch Matching Rule

   The LDAP-style definition for allComponentsMatch is:

      ( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch'
          SYNTAX 1.2.36.79672281.1.5.3 )

   The X.500-style definition for allComponentsMatch is:

      allComponentsMatch MATCHING-RULE ::= {
          ID      { 1 2 36 79672281 1 13 6 } }

   When allComponentsMatch is used in a ComponentAssertion the assertion
   syntax is the same as the ASN.1 type of the identified component.
   Otherwise, the assertion syntax of allComponentsMatch is the same as
   the attribute syntax of the attribute to which the matching rule is
   applied.

   Broadly speaking, this matching rule evaluates to true if and only if
   corresponding components of the assertion value and the attribute or
   component value are the same.

   In detail, equality is determined by the following cases applied
   recursively.

   a) Two values of a SET or SEQUENCE type are the same if and only if,
      for each component type, the corresponding component values are
      either,

      1) both absent,

      2) both present and the same, or

      3) absent or the same as the DEFAULT value for the component, if a
         DEFAULT value is defined.





Legg                        Standards Track                    [Page 25]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


         Values of an EMBEDDED PDV, EXTERNAL, unrestricted CHARACTER
         STRING, or INSTANCE OF type are compared according to their
         respective associated SEQUENCE type (see Section 3.1.2).

   b) Two values of a SEQUENCE OF type are the same if and only if, the
      values have the same number of (possibly duplicated) instances and
      corresponding instances are the same.

   c) Two values of a SET OF type are the same if and only if, the
      values have the same number of instances and each distinct
      instance occurs in both values the same number of times, i.e.,
      both values have the same instances, including duplicates, but in
      any order.

   d) Two values of a CHOICE type are the same if and only if, both
      values are of the same chosen alternative and the component values
      are the same.

   e) Two BIT STRING values are the same if and only if the values have
      the same number of bits and corresponding bits are the same.  If
      the BIT STRING type is defined with a named bit list then trailing
      zero bits in the values are treated as absent for the purposes of
      this comparison.

   f) Two BOOLEAN values are the same if and only if both are TRUE or
      both are FALSE.

   g) Two values of a string type are the same if and only if the values
      have the same number of characters and corresponding characters
      are the same.  Letter case is significant.  For the purposes of
      allComponentsMatch, the string types are NumericString,
      PrintableString, TeletexString (T61String), VideotexString,
      IA5String, GraphicString, VisibleString (ISO646String),
      GeneralString, UniversalString, BMPString, UTF8String,
      GeneralizedTime, UTCTime and ObjectDescriptor.

   h) Two INTEGER values are the same if and only if the integers are
      equal.

   i) Two ENUMERATED values are the same if and only if the enumeration
      item identifiers are the same (equivalently, if the integer values
      associated with the identifiers are equal).

   j) Two NULL values are always the same, unconditionally.

   k) Two OBJECT IDENTIFIER values are the same if and only if the
      values have the same number of arcs and corresponding arcs are the
      same.



Legg                        Standards Track                    [Page 26]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   l) Two OCTET STRING values are the same if and only if the values
      have the same number of octets and corresponding octets are the
      same.

   m) Two REAL values are the same if and only if they are both the same
      special value, or neither is a special value and they have the
      same base and represent the same real number.  The special values
      for REAL are zero, PLUS-INFINITY and MINUS-INFINITY.

   n) Two RELATIVE-OID values are the same if and only if the values
      have the same number of arcs and corresponding arcs are the same.
      The respective starting nodes for the RELATIVE-OID values are
      disregarded in the comparison, i.e., they are assumed to be the
      same.

   o) Two values of an open type are the same if and only if both are of
      the same ASN.1 type and are the same according to that type.  If
      the actual ASN.1 type of the values is unknown then the
      allComponentsMatch rule evaluates to Undefined.

   Tags and constraints, being part of the type definition and not part
   of the abstract values, are ignored for matching purposes.

   The allComponentsMatch rule may be used as the defined equality
   matching rule for an attribute.

6.3.  Deriving Component Equality Matching Rules

   A new component equality matching rule with more refined matching
   semantics may be derived from allComponentsMatch, or any other
   component equality matching rule, using the convention described in
   this section.

   The matching behaviour of a derived component equality matching rule
   is specified by nominating, for each of one or more identified
   components, a commutative equality matching rule that will be used to
   match values of that component.  This overrides the matching that
   would otherwise occur for values of that component using the base
   rule for the derivation.  These overrides can be conveniently
   represented as rows in a table of the following form.

      Component   |  Matching Rule
      ============+===============
                  |
                  |






Legg                        Standards Track                    [Page 27]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   Usually, all component values of a particular ASN.1 type are to be
   matched the same way.  An ASN.1 type reference (e.g.,
   DistinguishedName) or an ASN.1 built-in type name (e.g., INTEGER) in
   the Component column of the table specifies that the nominated
   equality matching rule is to be applied to all values of the named
   type, regardless of context.

   An ASN.1 type reference with a component reference appended
   (separated by a ".")  specifies that the nominated matching rule
   applies only to the identified components of values of the named
   type.  Other component values that happen to be of the same ASN.1
   type are not selected.

   Additional type substitutions as described in Section 3.2 are assumed
   to be performed to align the component type with the matching rule
   assertion syntax.

   Conceptually, the rows in a table for the base rule are appended to
   the rows in the table for a derived rule for the purpose of deciding
   the matching semantics of the derived rule.  Notionally,
   allComponentsMatch has an empty table.

   A row specifying values of an outer containing type (e.g.,
   DistinguishedName) takes precedence over a row specifying values of
   an inner component type (e.g., RelativeDistinguishedName), regardless
   of their order in the table.  Specifying a row for component values
   of an inner type is only useful if a value of the type can also
   appear on its own, or as a component of values of a different outer
   type.  For example, if there is a row for DistinguishedName then a
   row for RelativeDistinguishedName can only ever apply to
   RelativeDistinguishedName component values that are not part of a
   DistinguishedName.  A row for values of an outer type in the table
   for the base rule takes precedence over a row for values of an inner
   type in the table for the derived rule.

   Where more than one row applies to a particular component value the
   earlier row takes precedence over the later row.  Thus rows in the
   table for the derived rule take precedence over any rows for the same
   component in the table for the base rule.

6.4.  The directoryComponentsMatch Matching Rule

   The directoryComponentsMatch matching rule is derived from the
   allComponentsMatch matching rule.







Legg                        Standards Track                    [Page 28]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   The LDAP-style definition for directoryComponentsMatch is:

      ( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch'
          SYNTAX 1.2.36.79672281.1.5.3 )

   The X.500-style definition for directoryComponentsMatch is:

      directoryComponentsMatch MATCHING-RULE ::= {
          ID      { 1 2 36 79672281 1 13 7 } }

   The matching semantics of directoryComponentsMatch are described by
   the following table, using the convention described in Section 6.3.

      ASN.1 Type                               | Matching Rule
      =========================================+========================
      RDNSequence                              | distinguishedNameMatch
      RelativeDistinguishedName                | rdnMatch
      TelephoneNumber                          | telephoneNumberMatch
      FacsimileTelephoneNumber.telephoneNumber | telephoneNumberMatch
      NumericString                            | numericStringMatch
      GeneralizedTime                          | generalizedTimeMatch
      UTCTime                                  | uTCTimeMatch
      DirectoryString{}                        | caseIgnoreMatch
      BMPString                                | caseIgnoreMatch
      GeneralString                            | caseIgnoreMatch
      GraphicString                            | caseIgnoreMatch
      IA5String                                | caseIgnoreMatch
      PrintableString                          | caseIgnoreMatch
      TeletexString                            | caseIgnoreMatch
      UniversalString                          | caseIgnoreMatch
      UTF8String                               | caseIgnoreMatch
      VideotexString                           | caseIgnoreMatch
      VisibleString                            | caseIgnoreMatch

   Notes:

   1) The DistinguishedName type is defined by assignment to be the same
      as the RDNSequence type.  Some types (e.g., Name and LocalName)
      directly reference RDNSequence rather than DistinguishedName.
      Specifying RDNSequence captures all these DN-like types.

   2) A RelativeDistinguishedName value is only matched by rdnMatch if
      it is not part of an RDNSequence value.

   3) The telephone number component of the FacsimileTelephoneNumber
      ASN.1 type [12] is defined as a constrained PrintableString.
      PrintableString component values that are part of a
      FacsimileTelephoneNumber value can be identified separately from



Legg                        Standards Track                    [Page 29]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      other components of PrintableString type by the specifier
      FacsimileTelephoneNumber.telephoneNumber, so that
      telephoneNumberMatch can be selectively applied.  The fourth
      edition of X.520 defines the telephoneNumber component of
      FacsimileTelephoneNumber to be of the type TelephoneNumber, making
      the row for FacsimileTelephoneNumber.telephoneNumber components
      redundant.

   The directoryComponentsMatch rule may be used as the defined equality
   matching rule for an attribute.

7.  Component Matching Examples

   This section contains examples of search filters using the
   componentFilterMatch matching rule.  The filters are described using
   the string representation of LDAP search filters [18].  Note that
   this representation requires asterisks to be escaped in assertion
   values (in these examples the assertion values are all
   <ComponentAssertion> encodings).  The asterisks have not been escaped
   in these examples for the sake of clarity, and to avoid confusing the
   protocol representation of LDAP search filter assertion values, where
   such escaping does not apply.  Line breaks and indenting have been
   added only as an aid to readability.

   The example search filters using componentFilterMatch are all single
   extensible match filter items, though there is no reason why
   componentFilterMatch can't be used in more complicated search
   filters.

   The first examples describe searches over the objectClasses schema
   operational attribute, which has an attribute syntax described by the
   ASN.1 type ObjectClassDescription [10], and holds the definitions of
   the object classes known to a directory server.  The definition of
   ObjectClassDescription is as follows:

      ObjectClassDescription ::= SEQUENCE {
          identifier       OBJECT-CLASS.&id,
          name             SET OF DirectoryString {ub-schema} OPTIONAL,
          description      DirectoryString {ub-schema} OPTIONAL,
          obsolete         BOOLEAN DEFAULT FALSE,
          information  [0] ObjectClassInformation }

      ObjectClassInformation ::= SEQUENCE {
          subclassOf       SET OF OBJECT-CLASS.&id OPTIONAL,
          kind             ObjectClassKind DEFAULT structural,
          mandatories  [3] SET OF ATTRIBUTE.&id OPTIONAL,
          optionals    [4] SET OF ATTRIBUTE.&id OPTIONAL }




Legg                        Standards Track                    [Page 30]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      ObjectClassKind ::= ENUMERATED {
          abstract     (0),
          structural   (1),
          auxiliary    (2) }

   OBJECT-CLASS.&id and ATTRIBUTE.&id are equivalent to the OBJECT
   IDENTIFIER ASN.1 type.  A value of OBJECT-CLASS.&id is an OBJECT
   IDENTIFIER for an object class.  A value of ATTRIBUTE.&id is an
   OBJECT IDENTIFIER for an attribute type.

   The following search filter finds the object class definition for the
   object class identified by the OBJECT IDENTIFIER 2.5.6.18:

      (objectClasses:componentFilterMatch:=
           item:{ component "identifier",
                  rule objectIdentifierMatch, value 2.5.6.18 })

   A match on the "identifier" component of objectClasses values is
   equivalent to the objectIdentifierFirstComponentMatch matching rule
   applied to attribute values of the objectClasses attribute type.  The
   componentFilterMatch matching rule subsumes the functionality of the
   objectIdentifierFirstComponentMatch, integerFirstComponentMatch and
   directoryStringFirstComponentMatch matching rules.

   The following search filter finds the object class definition for the
   object class called foobar:

      (objectClasses:componentFilterMatch:=
          item:{ component "name.*",
                 rule caseIgnoreMatch, value "foobar" })

   An object class definition can have multiple names and the above
   filter will match an objectClasses value if any one of the names is
   "foobar".

   The component reference "name.0" identifies the notional count of the
   number of names in an object class definition.  The following search
   filter finds object class definitions with exactly one name:

      (objectClasses:componentFilterMatch:=
          item:{ component "name.0", rule integerMatch, value 1 })

   The "description" component of an ObjectClassDescription is defined
   to be an OPTIONAL DirectoryString.  The following search filter finds
   object class definitions that have descriptions, regardless of the
   contents of the description string:





Legg                        Standards Track                    [Page 31]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      (objectClasses:componentFilterMatch:=
          item:{ component "description",
                 rule presentMatch, value NULL })

   The presentMatch returns TRUE if the description component is present
   and FALSE otherwise.

   The following search filter finds object class definitions that don't
   have descriptions:

      (objectClasses:componentFilterMatch:=
          not:item:{ component "description",
                     rule presentMatch, value NULL })

   The following search filter finds object class definitions with the
   word "bogus" in the description:

      (objectClasses:componentFilterMatch:=
          item:{ component "description",
                 rule caseIgnoreSubstringsMatch,
                 value { any:"bogus" } })

   The assertion value is of the SubstringAssertion syntax, i.e.,

      SubstringAssertion ::= SEQUENCE OF CHOICE {
          initial      [0] DirectoryString {ub-match},
          any          [1] DirectoryString {ub-match},
          final        [2] DirectoryString {ub-match} }

   The "obsolete" component of an ObjectClassDescription is defined to
   be DEFAULT FALSE.  An object class is obsolete if the "obsolete"
   component is present and set to TRUE.  The following search filter
   finds all obsolete object classes:

      (objectClasses:componentFilterMatch:=
          item:{ component "obsolete", rule booleanMatch, value TRUE })

   An object class is not obsolete if the "obsolete" component is not
   present, in which case it defaults to FALSE, or is present but is
   explicitly set to FALSE.  The following search filter finds all non-
   obsolete object classes:

      (objectClasses:componentFilterMatch:=
          item:{ component "obsolete", rule booleanMatch, value FALSE })

   The useDefaultValues flag in the ComponentAssertion defaults to TRUE
   so the componentFilterMatch rule treats an absent "obsolete"
   component as being present and set to FALSE.  The following search



Legg                        Standards Track                    [Page 32]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   filter finds only object class definitions where the "obsolete"
   component has been explicitly set to FALSE, rather than implicitly
   defaulting to FALSE:

      (objectClasses:componentFilterMatch:=
          item:{ component "obsolete", useDefaultValues FALSE,
                 rule booleanMatch, value FALSE })

   With the useDefaultValues flag set to FALSE, if the "obsolete"
   component is absent the component reference identifies no component
   value and the matching rule will return FALSE.  The matching rule can
   only return TRUE if the component is present and set to FALSE.

   The "information.kind" component of the ObjectClassDescription is an
   ENUMERATED type.  The allComponentsMatch matching rule can be used to
   match values of an ENUMERATED type.  The following search filter
   finds object class definitions for auxiliary object classes:

      (objectClasses:componentFilterMatch:=
          item:{ component "information.kind",
                 rule allComponentsMatch, value auxiliary })

   The following search filter finds auxiliary object classes with
   commonName (cn or 2.5.4.3) as a mandatory attribute:

      (objectClasses:componentFilterMatch:=and:{
          item:{ component "information.kind",
                 rule allComponentsMatch, value auxiliary },
          item:{ component "information.mandatories.*",
                 rule objectIdentifierMatch, value cn } })

   The following search filter finds auxiliary object classes with
   commonName as a mandatory or optional attribute:

      (objectClasses:componentFilterMatch:=and:{
          item:{ component "information.kind",
                 rule allComponentsMatch, value auxiliary },
          or:{
              item:{ component "information.mandatories.*",
                     rule objectIdentifierMatch, value cn },
              item:{ component "information.optionals.*",
                     rule objectIdentifierMatch, value cn } } })

   Extra care is required when matching optional SEQUENCE OF or SET OF
   components because of the distinction between an absent list of
   instances and a present, but empty, list of instances.  The following
   search filter finds object class definitions with less than three




Legg                        Standards Track                    [Page 33]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   names, including object class definitions with a present but empty
   list of names, but does not find object class definitions with an
   absent list of names:

      (objectClasses:componentFilterMatch:=
          item:{ component "name.0",
                 rule integerOrderingMatch, value 3 })

   If the "name" component is absent the "name.0" component is also
   considered to be absent and the ComponentAssertion evaluates to
   FALSE.  If the "name" component is present, but empty, the "name.0"
   component is also present and equal to zero, so the
   ComponentAssertion evaluates to TRUE.  To also find the object class
   definitions with an absent list of names the following search filter
   would be used:

      (objectClasses:componentFilterMatch:=or:{
          not:item:{ component "name", rule presentMatch, value NULL },
          item:{ component "name.0",
                 rule integerOrderingMatch, value 3 } })

   Distinguished names embedded in other syntaxes can be matched with a
   componentFilterMatch.  The uniqueMember attribute type has an
   attribute syntax described by the ASN.1 type NameAndOptionalUID.

      NameAndOptionalUID ::= SEQUENCE {
          dn        DistinguishedName,
          uid       UniqueIdentifier OPTIONAL }

   The following search filter finds values of the uniqueMember
   attribute containing the author's DN:

      (uniqueMember:componentFilterMatch:=
          item:{ component "dn",
                 rule distinguishedNameMatch,
                 value "cn=Steven Legg,o=Adacel,c=AU" })

   The DistinguishedName and RelativeDistinguishedName ASN.1 types are
   also complex ASN.1 types so the component matching rules can be
   applied to their inner components.

      DistinguishedName   ::= RDNSequence

      RDNSequence ::= SEQUENCE OF RelativeDistinguishedName

      RelativeDistinguishedName ::= SET SIZE (1..MAX) OF
          AttributeTypeAndValue




Legg                        Standards Track                    [Page 34]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      AttributeTypeAndValue ::= SEQUENCE {
          type        AttributeType ({SupportedAttributes}),
          value       AttributeValue ({SupportedAttributes}{@type}) }

      AttributeType ::= ATTRIBUTE.&id

      AttributeValue ::= ATTRIBUTE.&Type

   ATTRIBUTE.&Type is an open type.  A value of ATTRIBUTE.&Type is
   constrained by the type component of AttributeTypeAndValue to be of
   the attribute syntax of the nominated attribute type.  Note: the
   fourth edition of X.500 extends and renames the AttributeTypeAndValue
   SEQUENCE type.

   The seeAlso attribute has the DistinguishedName syntax.  The
   following search filter finds seeAlso attribute values containing the
   RDN, "o=Adacel", anywhere in the DN:

      (seeAlso:componentFilterMatch:=
          item:{ component "*", rule rdnMatch, value "o=Adacel" })

   The following search filter finds all seeAlso attribute values with
   "cn=Steven Legg" as the RDN of the named entry (i.e., the "first" RDN
   in an LDAPDN or the "last" RDN in an X.500 DN):

      (seeAlso:componentFilterMatch:=
          item:{ component "-1",
                 rule rdnMatch, value "cn=Steven Legg" })

   The following search filter finds all seeAlso attribute values naming
   entries in the DIT subtree of "o=Adacel,c=AU":

      (seeAlso:componentFilterMatch:=and:{
          item:{ component "1", rule rdnMatch, value "c=AU" },
          item:{ component "2", rule rdnMatch, value "o=Adacel" } })

   The following search filter finds all seeAlso attribute values
   containing the naming attribute types commonName (cn) and
   telephoneNumber in the same RDN:

      (seeAlso:componentFilterMatch:=
          item:{ component "*", rule componentFilterMatch,
                 value and:{
                     item:{ component "*.type",
                            rule objectIdentifierMatch, value cn },
                     item:{ component "*.type",
                            rule objectIdentifierMatch,
                            value telephoneNumber } } })



Legg                        Standards Track                    [Page 35]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   The following search filter would find all seeAlso attribute values
   containing the attribute types commonName and telephoneNumber, but
   not necessarily in the same RDN:

      (seeAlso:componentFilterMatch:=and:{
          item:{ component "*.*.type",
                 rule objectIdentifierMatch, value cn },
          item:{ component "*.*.type",
                 rule objectIdentifierMatch, value telephoneNumber } })

   The following search filter finds all seeAlso attribute values
   containing the word "Adacel" in any organizationalUnitName (ou)
   attribute value in any AttributeTypeAndValue of any RDN:

      (seeAlso:componentFilterMatch:=
          item:{ component "*.*.value.(2.5.4.11)",
                 rule caseIgnoreSubstringsMatch,
                 value { any:"Adacel" } })

   The component reference "*.*.value" identifies an open type, in this
   case an attribute value.  In a particular AttributeTypeAndValue, if
   the attribute type is not organizationalUnitName then the
   ComponentAssertion evaluates to FALSE.  Otherwise the substring
   assertion is evaluated against the attribute value.

   Absent component references in ComponentAssertions can be exploited
   to avoid false positive matches on multi-valued attributes.  For
   example, suppose there is a multi-valued attribute named
   productCodes, defined to have the Integer syntax
   (1.3.6.1.4.1.1466.115.121.1.27).  Consider the following search
   filter:

      (&(!(productCodes:integerOrderingMatch:=3))
        (productCodes:integerOrderingMatch:=8))

   An entry whose productCodes attribute contains only the values 1 and
   10 will match the above filter.  The first subfilter is satisfied by
   the value 10 (10 is not less than 3), and the second subfilter is
   satisfied by the value 1 (1 is less than 8).  The following search
   filter can be used instead to only match entries that have a
   productCodes value in the range 3 to 7, because the ComponentFilter
   is evaluated against each productCodes value in isolation:

      (productCodes:componentFilterMatch:= and:{
           not:item:{ rule integerOrderingMatch, value 3 },
          item:{ rule integerOrderingMatch, value 8 } })





Legg                        Standards Track                    [Page 36]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   An entry whose productCodes attribute contains only the values 1 and
   10 will not match the above filter.

8.  Security Considerations

   The component matching rules described in this document allow for a
   compact specification of matching capabilities that could otherwise
   have been defined by a plethora of specific matching rules, i.e.,
   despite their expressiveness and flexibility the component matching
   rules do not behave in a way uncharacteristic of other matching
   rules, so the security issues for component matching rules are no
   different than for any other matching rule.  However, because the
   component matching rules are applicable to any attribute syntax,
   support for them in a directory server may allow searching of
   attributes that were previously unsearchable by virtue of there not
   being a suitable matching rule.  Such attribute types ought to be
   properly protected with appropriate access controls.  A generic,
   interoperable access control mechanism has not yet been developed,
   however, and implementors should be aware of the interaction of that
   lack with the increased risk of exposure described above.

9.  Acknowledgements

   The author would like to thank Tom Gindin for private email
   discussions that clarified and refined the ideas presented in this
   document.

10.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has updated the LDAP
   descriptors registry [8] as indicated by the following templates:

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): componentFilterMatch
      Object Identifier: 1.2.36.79672281.1.13.2
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: other (matching rule)
      Specification: RFC 3687
      Author/Change Controller: IESG











Legg                        Standards Track                    [Page 37]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): rdnMatch
      Object Identifier: 1.2.36.79672281.1.13.3
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: other (matching rule)
      Specification: RFC 3687
      Author/Change Controller: IESG

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): presentMatch
      Object Identifier: 1.2.36.79672281.1.13.5
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: other (matching rule)
      Specification: RFC 3687
      Author/Change Controller: IESG

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): allComponentsMatch
      Object Identifier: 1.2.36.79672281.1.13.6
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: other (matching rule)
      Specification: RFC 3687
      Author/Change Controller: IESG

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): directoryComponentsMatch
      Object Identifier: 1.2.36.79672281.1.13.7
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: other (matching rule)
      Specification: RFC 3687
      Author/Change Controller: IESG

   The object identifiers have been assigned for use in this
   specification by Adacel Technologies, under an arc assigned to Adacel
   by Standards Australia.

11.  References

11.1.  Normative References

   [1]   Bradner, S., "Key words for use in RFCs to Indicate Requirement
         Levels", BCP 14, RFC 2119, March 1997.





Legg                        Standards Track                    [Page 38]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   [2]   Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
         Specifications: ABNF", RFC 2234, November 1997.

   [3]   Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access
         Protocol (v3)", RFC 2251, December 1997.

   [4]   Wahl, M., Coulbeck, A., Howes, T. and S. Kille, "Lightweight
         Directory Access Protocol (v3): Attribute Syntax Definitions",
         RFC 2252, December 1997.

   [5]   Wahl, M., Kille S. and T. Howes. "Lightweight Directory Access
         Protocol (v3): UTF-8 String Representation of Distinguished
         Names", RFC 2253, December 1997.

   [6]   Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD
         63, RFC 3629, November 2003.

   [7]   Hodges, J. and R. Morgan, "Lightweight Directory Access
         Protocol (v3): Technical Specification", RFC 3377, September
         2002.

   [8]   Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
         Considerations for the Lightweight Directory Access Protocol
         (LDAP)", BCP 64, RFC 3383, September 2002.

   [9]   Legg, S., "Generic String Encoding Rules (GSER) for ASN.1
         Types", RFC 3641, October 2003.

   [10]  ITU-T Recommendation X.501 (1993) | ISO/IEC 9594-2:1994,
         Information Technology - Open Systems Interconnection - The
         Directory: Models

   [11]  ITU-T Recommendation X.509 (1997) | ISO/IEC 9594-8:1998,
         Information Technology - Open Systems Interconnection - The
         Directory: Authentication Framework

   [12]  ITU-T Recommendation X.520 (1993) | ISO/IEC 9594-6:1994,
         Information technology - Open Systems Interconnection - The
         Directory: Selected attribute types

   [13]  ITU-T Recommendation X.680 (07/02) | ISO/IEC 8824-1:2002,
         Information technology - Abstract Syntax Notation One (ASN.1):
         Specification of basic notation

   [14]  ITU-T Recommendation X.681 (07/02) | ISO/IEC 8824-2:2002,
         Information technology - Abstract Syntax Notation One (ASN.1):
         Information object specification




Legg                        Standards Track                    [Page 39]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


   [15]  ITU-T Recommendation X.682 (07/02) | ISO/IEC 8824-3:2002,
         Information technology - Abstract Syntax Notation One (ASN.1):
         Constraint specification

   [16]  ITU-T Recommendation X.683 (07/02) | ISO/IEC 8824-4:2002,
         Information technology - Abstract Syntax Notation One (ASN.1):
         Parameterization of ASN.1 specifications

   [17]  ITU-T Recommendation X.690 (07/02) | ISO/IEC 8825-1,
         Information technology - ASN.1 encoding rules: Specification of
         Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and
         Distinguished Encoding Rules (DER)

12.2.  Informative References

   [18]  Howes, T., "The String Representation of LDAP Search Filters",
         RFC 2254, December 1997.

   [19]  ITU-T Recommendation X.500 (1993) | ISO/IEC 9594-1:1994,
         Information Technology - Open Systems Interconnection - The
         Directory: Overview of concepts, models and services

12.  Intellectual Property Statement

   The IETF takes no position regarding the validity or scope of any
   intellectual property or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; neither does it represent that it
   has made any effort to identify any such rights.  Information on the
   IETF's procedures with respect to rights in standards-track and
   standards-related documentation can be found in BCP-11. Copies of
   claims of rights made available for publication and any assurances of
   licenses to be made available, or the result of an attempt made to
   obtain a general license or permission for the use of such
   proprietary rights by implementors or users of this specification can
   be obtained from the IETF Secretariat.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights which may cover technology that may be required to practice
   this standard.  Please address the information to the IETF Executive
   Director.








Legg                        Standards Track                    [Page 40]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


13.  Author's Address

   Steven Legg
   Adacel Technologies Ltd.
   250 Bay Street
   Brighton, Victoria 3186
   AUSTRALIA

   Phone: +61 3 8530 7710
   Fax:   +61 3 8530 7888
   EMail: steven.legg@adacel.com.au








































Legg                        Standards Track                    [Page 41]

RFC 3687        LDAP and X.500 Component Matching Rules    February 2004


14.  Full Copyright Statement

   Copyright (C) The Internet Society (2004).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assignees.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Legg                        Standards Track                    [Page 42]

alt-openldap11-devel/rfc/rfc3088.txt000064400000046017150410163210012774 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 3088                           OpenLDAP Foundation
Category: Experimental                                        April 2001


                         OpenLDAP Root Service
                 An experimental LDAP referral service

Status of this Memo

   This memo defines an Experimental Protocol for the Internet
   community.  It does not specify an Internet standard of any kind.
   Discussion and suggestions for improvement are requested.
   Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2001).  All Rights Reserved.

Abstract

   The OpenLDAP Project is operating an experimental LDAP (Lightweight
   Directory Access Protocol) referral service known as the "OpenLDAP
   Root Service".  The automated system generates referrals based upon
   service location information published in DNS SRV RRs (Domain Name
   System location of services resource records).  This document
   describes this service.

1. Background

   LDAP [RFC2251] directories use a hierarchical naming scheme inherited
   from X.500 [X500].  Traditionally, X.500 deployments have used a
   geo-political naming scheme (e.g., CN=Jane
   Doe,OU=Engineering,O=Example,ST=CA,C=US).  However, registration
   infrastructure and location services in many portions of the naming
   hierarchical are inadequate or nonexistent.

   The construction of a global directory requires a robust registration
   infrastructure and location service.  Use of Internet domain-based
   naming [RFC2247] (e.g., UID=jdoe,DC=eng,DC=example,DC=net) allows
   LDAP directory services to leverage the existing DNS [RFC1034]
   registration infrastructure and DNS SRV [RFC2782] resource records
   can be used to locate services [LOCATE].








Zeilenga                      Experimental                      [Page 1]

RFC 3088                 OpenLDAP Root Service                April 2001


1.1.  The Glue

   Most existing LDAP implementations do not support location of
   directory services using DNS SRV resource records.  However, most
   servers support generation of referrals to "superior" server(s).
   This service provides a "root" LDAP service which servers may use as
   their superior referral service.

   Client may also use the service directly to locate services
   associated with an arbitrary Distinguished Name [RFC2253] within the
   domain based hierarchy.

   Notice:
     The mechanisms used by service are experimental.  The descriptions
     provided by this document are not definitive.  Definitive
     mechanisms shall be published in a Standard Track document(s).

2. Generating Referrals based upon DNS SRV RRs

   This service returns referrals generated from DNS SRV resource
   records [RFC2782].

2.1. DN to Domain Name Mapping

   The service maps a DN [RFC2253] to a fully qualified domain name
   using the following algorithm:

       domain = null;
       foreach RDN left-to-right        // [1]

       {
           if not multi-valued RDN and
               RDN.type == domainComponent
           {
               if ( domain == null || domain == "." )
               {   // start
                   domain = "";
               }
               else
               {   // append separator
                   domain .= ".";
               }

               if ( RDN.value == "."  )
               {   // root
                   domain = ".";
               }
               else



Zeilenga                      Experimental                      [Page 2]

RFC 3088                 OpenLDAP Root Service                April 2001


               {   // append domainComponent
                   domain .= RDN.value;
               }
               continue;
           }
           domain = null;
       }

   Examples:

       Distinguished Name              Domain
       -----------------------------   ------------
       DC=example,DC=net               example.net
       UID=jdoe,DC=example,DC=net      example.net
       DC=.                            .            [2]
       DC=example,DC=net,DC=.          .            [3]
       DC=example,DC=.,DC=net          net          [4]
       DC=example.net                  example.net  [5]
       CN=Jane Doe,O=example,C=US      null
       UID=jdoe,DC=example,C=US        null
       DC=example,O=example,DC=net     net
       DC=example+O=example,DC=net     net
       DC=example,C=US+DC=net          null

   Notes:

   0) A later incarnation will use a Standard Track mechanism.

   1) A later incarnation of this service may use a right-to-left
      algorithm.

   2) RFC 2247 does not state how one can map the domain representing
      the root of the domain tree to a DN.  We suggest the root of the
      domain tree be mapped to "DC=." and that this be reversable.

   3) RFC 2247 states that domain "example.net" should be mapped to the
      DN "DC=example,DC=net", not to "DC=example,DC=net,DC=.".  As it is
      not our intent to introduce or support an alternative domain to DN
      mapping, the algorithm ignores domainComponents to the left of
      "DC=.".

   4) RFC 2247 states that domain "example.net" should be mapped to the
      DN "DC=example,DC=net", not to "DC=example,DC=.,DC=net".  As it is
      not our intent to introduce or support an alternative domain to DN
      mapping, the algorithm ignores domainComponents to the left of
      "DC=." and "DC=." itself if further domainComponents are found to
      the right.




Zeilenga                      Experimental                      [Page 3]

RFC 3088                 OpenLDAP Root Service                April 2001


   5) RFC 2247 states that value of an DC attribute type is a domain
      component.  It should not contain multiple domain components.  A
      later incarnation of this service may map this domain to null or
      be coded to return invalid DN error.

   If the domain is null or ".", the service aborts further processing
   and returns noSuchObject.  Later incarnation of this service may
   abort processing if the resulting domain is a top-level domain.

2.2. Locating LDAP services

   The root service locates services associated with a given fully
   qualified domain name by querying the Domain Name System for LDAP SRV
   resource records.  For the domain example.net, the service would do a
   issue a SRV query for the domain "_ldap._tcp.example.net".  A
   successful query will return one or more resource records of the
   form:

     _ldap._tcp.example.net. IN SRV 0 0 389 ldap.example.net.

   If no LDAP SRV resource records are returned or any DNS error occurs,
   the service aborts further processing and returns noSuchObject.
   Later incarnations of this service will better handle transient
   errors.

2.3. Constructing an LDAP Referrals

   For each DNS SRV resource record returned for the domain, a LDAP URL
   [RFC2255] is constructed.  For the above resource record, the URL
   would be:

     ldap://ldap.example.net:389/

   These URLs are then returned in the referral.  The URLs are currently
   returned in resolver order.  That is, the server itself does not make
   use of priority or weight information in the SRV resource records.  A
   later incarnation of this service may.

3. Protocol Operations

   This section describes how the service performs basic LDAP
   operations.  The service supports operations extended through certain
   controls as described in a later section.








Zeilenga                      Experimental                      [Page 4]

RFC 3088                 OpenLDAP Root Service                April 2001


3.1. Basic Operations

   Basic (add, compare, delete, modify, rename, search) operations
   return a referral result if the target (or base) DN can be mapped to
   a set of LDAP URLs as described above.  Otherwise a noSuchObject
   response or other appropriate response is returned.

3.2. Bind Operation

   The service accepts "anonymous" bind specifying version 2 or version
   3 of the protocol.  All other bind requests will return a non-
   successful resultCode.  In particular, clients which submit clear
   text credentials will be sent an unwillingToPerform resultCode with a
   cautionary text regarding providing passwords to strangers.

   As this service is read-only, LDAPv3 authentication [RFC2829] is not
   supported.

3.3. Unbind Operations

   Upon receipt of an unbind request, the server abandons all
   outstanding requests made by client and disconnects.

3.4. Extended Operations

   The service currently does recognize any extended operation.  Later
   incarnations of the service may support Start TLS [RFC2830] and other
   operations.

3.5. Update Operations

   A later incarnation of this service may return unwillingToPerform for
   all update operations as this is an unauthenticated service.

4. Controls

   The service supports the ManageDSAit control.  Unsupported controls
   are serviced per RFC 2251.

4.1. ManageDSAit Control

   The server recognizes and honors the ManageDSAit control [NAMEDREF]
   provided with operations.

   If DNS location information is available for the base DN itself, the
   service will return unwillingToPerform for non-search operations.
   For search operations, an entry will be returned if within scope and
   matches the provided filter.  For example:



Zeilenga                      Experimental                      [Page 5]

RFC 3088                 OpenLDAP Root Service                April 2001


       c: searchRequest {
           base="DC=example,DC=net"
           scope=base
           filter=(objectClass=*)
           ManageDSAit
       }

       s: searchEntry {
           dn: DC=example,DC=net
           objectClass: referral
           objectClass: extensibleObject
           dc: example
           ref: ldap://ldap.example.net:389/
           associatedDomain: example.net
       }
       s: searchResult {
           success
       }

   If DNS location information is available for the DC portion of a
   subordinate entry, the service will return noSuchObject with the
   matchedDN set to the DC portion of the base for search and update
   operations.

       c: searchRequest {
           base="CN=subordinate,DC=example,DC=net"
           scope=base
           filter=(objectClass=*)
           ManageDSAit
       }

       s: searchResult {
           noSuchObject
           matchedDN="DC=example,DC=net"
       }

5. Using the Service

   Servers may be configured to refer superior requests to
   <ldap://root.openldap.org:389>.

   Though clients may use the service directly, this is not encouraged.
   Clients should use a local service and only use this service when
   referred to it.

   The service supports LDAPv3 and LDAPv2+ [LDAPv2+] clients over
   TCP/IPv4.  Future incarnations of this service may support TCP/IPv6
   or other transport/internet protocols.



Zeilenga                      Experimental                      [Page 6]

RFC 3088                 OpenLDAP Root Service                April 2001


6. Lessons Learned

6.1. Scaling / Reliability

   This service currently runs on a single host.  This host and
   associated network resources are not yet exhausted.  If they do
   become exhausted, we believe we can easily scale to meet the demand
   through common distributed load balancing technics.  The service can
   also easily be duplicated locally.

6.2. Protocol interoperability

   This service has able avoided known interoperability issues in
   supporting variants of LDAP.

6.2.1. LDAPv3

   The server implements all features of LDAPv3 [RFC2251] necessary to
   provide the service.

6.2.2. LDAPv2

   LDAPv2 [RFC1777] does not support the return of referrals and hence
   may not be referred to this service.  Though a LDAPv2 client could
   connect and issue requests to this service, the client would treat
   any referral returned to it as an unknown error.

6.2.3. LDAPv2+

   LDAPv2+ [LDAPv2+] provides a number of extensions to LDAPv2,
   including referrals.  LDAPv2+, like LDAPv3, does not require a bind
   operation before issuing of other operations.  As the referral
   representation differ between LDAPv2+ and LDAPv3, the service returns
   LDAPv3 referrals in this case.  However, as commonly deployed LDAPv2+
   clients issue bind requests (for compatibility with LDAPv2 servers),
   this has not generated any interoperability issues (yet).

   A future incarnation of this service may drop support for LDAPv2+
   (and LDAPv2).

6.2.4. CLDAP

   CLDAP [RFC1798] does not support the return of referrals and hence is
   not supported.







Zeilenga                      Experimental                      [Page 7]

RFC 3088                 OpenLDAP Root Service                April 2001


7. Security Considerations

   This service provides information to "anonymous" clients.  This
   information is derived from the public directories, namely the Domain
   Name System.

   The use of authentication would require clients to disclose
   information to the service.  This would be an unnecessary invasion of
   privacy.

   The lack of encryption allows eavesdropping upon client requests and
   responses.  A later incarnation of this service may support
   encryption (such as via Start TLS [RFC2830]).

   Information integrity protection is not provided by the service.  The
   service is subject to varies forms of DNS spoofing and attacks.  LDAP
   session or operation integrity would provide false sense of security
   concerning the integrity of DNS information.  A later incarnation of
   this service may support DNSSEC and provide integrity protection (via
   SASL, TLS, or IPSEC).

   The service is subject to a variety of denial of service attacks.
   The service is capable of blocking access by a number of factors.
   This capability have yet to be used and likely would be ineffective
   in preventing sophisticated attacks.  Later incarnations of this
   service will likely need better protection from such attacks.

8. Conclusions

   DNS is good glue.  By leveraging of the Domain Name System, global
   LDAP directories may be built without requiring a protocol specific
   registration infrastructures.

   In addition, use of DNS service location allows global directories to
   be built "ad hoc".  That is, anyone with a domain name can
   participate.  There is no requirement that the superior domain
   participate.

9. Additional Information

   Additional information about the OpenLDAP Project and the OpenLDAP
   Root Service can be found at <http://www.openldap.org/>.









Zeilenga                      Experimental                      [Page 8]

RFC 3088                 OpenLDAP Root Service                April 2001


10. Author's Address

   Kurt Zeilenga
   OpenLDAP Foundation

   EMail: kurt@openldap.org

11. Acknowledgments

   Internet hosting for this experiment is provided by the Internet
   Software Consortium <http://www.isc.org/>.  Computing resources were
   provided by Net Boolean Incorporated <http://www.boolean.net/>.  This
   experiment would not have been possible without the contributions of
   numerous volunteers of the open source community.  Mechanisms
   described in this document are based upon those introduced in
   [RFC2247] and [LOCATE].

References

   [RFC1034]  Mockapetris, P., "Domain Names - Concepts and Facilities",
              STD 13, RFC 1034, November 1987.

   [RFC1777]  Yeong, W., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol", RFC 1777, March 1995.

   [RFC1798]  Young, A., "Connection-less Lightweight Directory Access
              Protocol", RFC 1798, June 1995.

   [RFC2119]  Bradner, S., "Key Words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2247]  Kille, S., Wahl, M., Grimstad, A., Huber, R. and S.
              Sataluri, "Using Domains in LDAP/X.500 Distinguished
              Names", RFC 2247, January 1998.

   [RFC2251]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2253]  Wahl, M., Kille, S. and T. Howes, "Lightweight Directory
              Access Protocol (v3): UTF-8 String Representation of
              Distinguished Names", RFC 2253, December 1997.

   [RFC2255]  Howes, T. and M. Smith, "The LDAP URL Format", RFC 2255,
              December 1997.

   [RFC2782]  Gulbrandsen, A., Vixie, P. and L. Esibov, "A DNS RR for
              specifying the location of services (DNS SRV)", RFC 2782,
              February 2000.



Zeilenga                      Experimental                      [Page 9]

RFC 3088                 OpenLDAP Root Service                April 2001


   [RFC2829]  Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
              "Authentication Methods for LDAP", RFC 2829, May 2000.

   [RFC2830]  Hodges, J., Morgan, R. and M. Wahl, "Lightweight Directory
              Access Protocol (v3): Extension for Transport Layer
              Security", RFC 2830, May 2000.

   [LOCATE]   IETF LDAPext WG, "Discovering LDAP Services with DNS",
              Work in Progress.

   [LDAPv2+]  University of Michigan LDAP Team, "Referrals within the
              LDAPv2 Protocol", August 1996.

   [NAMEDREF] Zeilenga, K. (editor), "Named Subordinate References in
              LDAP Directories", Work in Progress.

   [X500]     ITU-T Rec. X.500, "The Directory: Overview of Concepts,
              Models and Service",  1993.

































Zeilenga                      Experimental                     [Page 10]

RFC 3088                 OpenLDAP Root Service                April 2001


Full Copyright Statement

   Copyright (C) The Internet Society (2001).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Zeilenga                      Experimental                     [Page 11]

alt-openldap11-devel/rfc/rfc2589.txt000064400000064347150410163220013010 0ustar00





Network Working Group                                         Y. Yaacovi
Request for Comments: 2589                                     Microsoft
Category: Standards Track                                        M. Wahl
                                            Innosoft International, Inc.
                                                             T. Genovese
                                                               Microsoft
                                                                May 1999


              Lightweight Directory Access Protocol (v3):
               Extensions for Dynamic Directory Services

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

1.  Abstract

   This document defines the requirements for dynamic directory services
   and specifies the format of request and response extended operations
   for supporting client-server interoperation in a dynamic directories
   environment.

   The Lightweight Directory Access Protocol (LDAP) [1] supports
   lightweight access to static directory services, allowing relatively
   fast search and update access.  Static directory services store
   information about people that persists in its accuracy and value over
   a long period of time.

   Dynamic directory services are different in that they store
   information that only persists in its accuracy and value when it is
   being periodically refreshed.  This information is stored as dynamic
   entries in the directory.  A typical use will be a client or a person
   that is either online - in which case it has an entry in the
   directory, or is offline - in which case its entry disappears from
   the directory.  Though the protocol operations and attributes used by
   dynamic directory services are similar to the ones used for static
   directory services, clients that store dynamic information in the
   directory need to periodically refresh this information, in order to
   prevent it from disappearing.  If dynamic entries are not refreshed



Yaacovi, et al.             Standards Track                     [Page 1]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


   within a given timeout, they will be removed from the directory.  For
   example, this will happen if the client that set them goes offline.

   A flow control mechanism from the server is also described that
   allows a server to inform clients how often they should refresh their
   presence.

2. Requirements

   The protocol extensions must allow accessing dynamic information in a
   directory in a standard LDAP manner, to allow clients to access
   static and dynamic information in the same way.

   By definition, dynamic entries are not persistent and clients may go
   away gracefully or not.  The proposed extensions must offer a way for
   a server to tell if entries are still valid, and to do this in a way
   that is scalable.  There also must be a mechanism for clients to
   reestablish their entry with the server.

   There must be a way for clients to find out, in a standard LDAP
   manner, if servers support the dynamic extensions.

   Finally, to allow clients to broadly use the dynamic extensions, the
   extensions need to be registered as standard LDAP extended
   operations.

3. Description of Approach

   The Lightweight Directory Access Protocol (LDAP) [1] permits
   additional operation requests and responses to be added to the
   protocol.  This proposal takes advantage of these to support
   directories which contain dynamic information in a manner which is
   fully integrated with LDAP.

   The approach described in this proposal defines dynamic entries in
   order to allow implementing directories with dynamic information.  An
   implementation of dynamic directories, must be able to support
   dynamic directory entries.

3.1. Dynamic Entries and the dynamicObject object class

   A dynamic entry is an object in the directory tree which has a time-
   to-live associated with it.  This time-to-live is set when the entry
   is created.  The time-to-live is automatically decremented, and when
   it expires the dynamic entry disappears.  By invoking the refresh
   extended operation (defined below) to re-set the time-to-live, a
   client can cause the entry to remain present a while longer.




Yaacovi, et al.             Standards Track                     [Page 2]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


   A dynamic entry is created by including the objectClass value given
   in section 5 in the list of attributes when adding an entry.  This
   method is subject to standard access control restrictions.

   The extended operation covered here, allows a client to refresh a
   dynamic entry by invoking, at intervals, refresh operations
   containing that entry's name.  Dynamic entries will be treated the
   same as non-dynamic entries when processing search, compare, add,
   delete, modify and modifyDN operations.  However if clients stop
   sending refresh operations for an entry, then the server will
   automatically and without notification remove that entry from the
   directory.  This removal will be treated the same as if the entry had
   been deleted by an LDAP protocol operation.

   There is no way to change a static entry into a dynamic one and
   vice-versa.  If the client is using Modify with an objectClass of
   dynamicObject on a static entry, the server must return a service
   error either "objectClassModsProhibited" (if the server does not
   allow objectClass modifications at all) or "objectClassViolation" (if
   the server does allow objectClass modifications in general).

   A dynamic entry may be removed by the client using the delete
   operation.  This operation will be subject to access control
   restrictions.

   A non-dynamic entry cannot be added subordinate to a dynamic entry:
   the server must return an appropriate update or service error if this
   is attempted.

   The support of dynamic attributes of an otherwise static object, are
   outside the scope of this document.

3.2 Dynamic meetings (conferences)

   The way dynamicObject is defined, it has a time-to-live associated
   with it, and that's about it.  Though the most common dynamic object
   is a person object, there is no specific type associated with the
   dynamicObject as defined here.  By the use of the dynamic object's
   attributes, one can make this object represent practically anything.

   Specifically, Meetings (conferences) can be represented by dynamic
   objects.  While full-featured meeting support requires special
   semantics and handling by the server (and is not in the scope of this
   document), the extensions described here, provide basic meetings
   support.  A meeting object can be refreshed by the meeting
   participants, and when it is not, the meeting entry disappears.  The
   one meeting type that is naturally supported by the dynamic
   extensions is creator-owned meeting.



Yaacovi, et al.             Standards Track                     [Page 3]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


3.2.1 Creator-owned meetings

   Creator-owned meetings are created by a client that sets the time-
   to-live attribute for the entry, and it is this client's
   responsibility to refresh the meeting entry, so that it will not
   disappear.  Others might join the meeting, by modifying the
   appropriate attribute, but they are not allowed to refresh the entry.
   When the client that created the entry goes away, it can delete the
   meeting entry, or it might disappear when its time-to-live expires.
   This is consistent with the common model for dynamicObject as
   described above.

4. Protocol Additions

4.1 Refresh Request

   Refresh is a protocol operation sent by a client to tell the server
   that the client is still alive and the dynamic directory entry is
   still accurate and valuable.  The client sends a Refresh request
   periodically based on the value of the client refresh period (CRP).
   The server can request that the client change this value.  As long as
   the server receives a Refresh request within the timeout period, the
   directory entry is guaranteed to persist on the server.  Client
   implementers should be aware that since the intervening network
   between the client and server is unreliable, a Refresh request packet
   may be delayed or lost while in transit.  If this occurs, the entry
   may disappear, and the client will need to detect this and re-add the
   entry.

   A client may request this operation by transmitting an LDAP PDU
   containing an ExtendedRequest.  An LDAP ExtendedRequest is defined as
   follows:

         ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
                 requestName             [0] LDAPOID,
                 requestValue            [1] OCTET STRING OPTIONAL }

   The requestName field must be set to the string
   "1.3.6.1.4.1.1466.101.119.1".

   The requestValue field will contain as a value the DER-encoding of
   the following ASN.1 data type:

        SEQUENCE {
                entryName  [0] LDAPDN,
                requestTtl [1] INTEGER
        }




Yaacovi, et al.             Standards Track                     [Page 4]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


   The entryName field is the UTF-8 string representation of the name of
   the dynamic entry [3].  This entry must already exist.

   The requestTtl is a time in seconds (between 1 and 31557600) that the
   client requests that the entry exists in the directory before being
   automatically removed.  Servers are not required to accept this value
   and might return a different TTL value to the client.  Clients must
   be able to use this server-dictated value as their CRP.

4.2 Refresh Response

   If a server implements this extension, then when the request is made
   it will return an LDAP PDU containing an ExtendedResponse.  An LDAP
   ExtendedResponse is defined as follows:

       ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
               COMPONENTS OF LDAPResult,
               responseName     [10] LDAPOID OPTIONAL,
               response         [11] OCTET STRING OPTIONAL }

   The responseName field contains the same string as that present in
   the request.

   The response field will contain as a value the DER-encoding of the
   following ASN.1 data type:

        SEQUENCE {
                responseTtl [1] INTEGER
        }

   The responseTtl field is the time in seconds which the server chooses
   to have as the time-to-live field for that entry.  It must not be any
   smaller than that which the client requested, and it may be larger.
   However, to allow servers to maintain a relatively accurate
   directory, and to prevent clients from abusing the dynamic
   extensions, servers are permitted to shorten a client-requested
   time-to-live value, down to a minimum of 86400 seconds (one day).

   If the operation was successful, the errorCode field in the
   standardResponse part of an ExtendedResponse will be set to success.

   In case of an error, the responseTtl field will have the value 0, and
   the errorCode field will contain an appropriate value, as follows: If
   the entry named by entryName could not be located, the errorCode
   field will contain "noSuchObject".  If the entry is not dynamic, the
   errorCode field will contain "objectClassViolation".  If the
   requester does not have permission to refresh the entry, the




Yaacovi, et al.             Standards Track                     [Page 5]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


   errorCode field will contain "insufficientAccessRights".  If the
   requestTtl field is too large, the errorCode field will contain
   "sizeLimitExceeded".

   If a server does not implement this extension, it will return an LDAP
   PDU containing an ExtendedResponse, which contains only the
   standardResponse element (the responseName and response elements will
   be absent).  The LDAPResult element will indicate the protocolError
   result code.

   This request is permitted to be invoked when LDAP is carried by a
   connectionless transport.

   When using a connection-oriented transport, there is no requirement
   that this operation be on the same particular connection as any
   other.  A client may open multiple connections, or close and then
   reopen a connection.

4.3 X.500/DAP Modify(97)

   X.500/DAP servers can map the Refresh request and response operations
   into the X.500/DAP Modify(97) operation.

5. Schema Additions

   All dynamic entries must have the dynamicObject value in their
   objectClass attribute.  This object class is defined as follows
   (using the ObjectClassDescription notation of [2]):

   ( 1.3.6.1.4.1.1466.101.119.2 NAME 'dynamicObject'
     DESC 'This class, if present in an entry, indicates that this entry
           has a limited lifetime and may disappear automatically when
           its time-to-live has reached 0.  There are no mandatory
           attributes of this class, however if the client has not
           supplied a value for the entryTtl attribute, the server will
           provide one.'
     SUP top AUXILIARY )

   Furthermore, the dynamic entry must have the following operational
   attribute.  It is described using the AttributeTypeDescription
   notation of [2]:

   ( 1.3.6.1.4.1.1466.101.119.3 NAME 'entryTtl'
     DESC 'This operational attribute is maintained by the server and
           appears to be present in every dynamic entry.  The attribute
           is not present when the entry does not contain the
           dynamicObject object class. The value of this attribute is
           the time in seconds that the entry will continue to exist



Yaacovi, et al.             Standards Track                     [Page 6]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


           before disappearing from the directory.  In the absence of
           intervening refresh operations, the values returned by
           reading the attribute in two successive searches are
           guaranteed to be nonincreasing.  The smallest permissible
           value is 0, indicating that the entry may disappear without
           warning.  The attribute is marked NO-USER-MODIFICATION since
           it may only be changed using the refresh operation.'
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE
     NO-USER-MODIFICATION USAGE dSAOperation )

   To allow servers to support dynamic entries in only a part of the
   DIT, the following operational attribute is defined.   It is
   described using the AttributeTypeDescription notation of [2]:

   ( 1.3.6.1.4.1.1466.101.119.4 NAME 'dynamicSubtrees'
     DESC 'This operational attribute is maintained by the server and is
           present in the Root DSE, if the server supports the dynamic
           extensions described in this memo. The attribute contains a
           list of all the subtrees in this directory for which the
           server supports the dynamic extensions.'
     SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION
     USAGE dSAOperation )

6. Client and Server Requirements

6.1 Client Requirements

   Clients can find out if a server supports the dynamic extensions by
   checking the supportedExtension field in the root DSE, to see if the
   OBJECT IDENTIFIER described in section 4 is present. Since servers
   may select to support the dynamic extensions in only some of the
   subtrees of the DIT, clients must check the dynamicSubtrees
   operational attribute in the root DSE to find out if the dynamic
   extensions are supported on a specific subtree.

   Once a dynamic entry has been created, clients are responsible for
   invoking the refresh extended operation, in order to keep that entry
   present in the directory.

   Clients must not expect that a dynamic entry will be present in the
   DIT after it has timed out, however it must not require that the
   server remove the entry immediately (some servers may only process
   timing out entries at intervals).  If the client wishes to ensure the
   entry does not exist it should issue a RemoveRequest for that entry.

   Initially, a client needs to know how often it should send refresh
   requests to the server.  This value is defined as the CRP (Client
   Refresh Period) and is set by the server based on the entryTtl.



Yaacovi, et al.             Standards Track                     [Page 7]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


   Since the LDAP AddRequest operation is left unchanged and is not
   modified in this proposal to return this value, a client must issue a
   Refresh extended operation immediately after an Add that created a
   dynamic entry.  The Refresh Response will return the CRP (in
   responseTtl) to the client.

   Clients must not issue the refresh request for dynamic entries which
   they have not created.  If an anonymous client attempts to do so, a
   server is permitted to return insufficientAccessRights (50) in the
   RefreshResponse, enforcing the client to bind first. Please note that
   servers which allow anonymous clients to create and refresh dynamic
   entries will not be able to enforce the above.

   Clients should always be ready to handle the case in which their
   entry timed out.  In such a case, the Refresh operation will fail
   with an error code such as noSuchObject, and the client is expected
   to re-create its entry.

   Clients should be prepared to experience refresh operations failing
   with protocolError, even though the add and any previous refresh
   requests succeeded.  This might happen if a proxy between the client
   and the server goes down, and another proxy is used which does not
   support the Refresh extended operation.

6.2 Server Requirements

   Servers are responsible for removing dynamic entries when they time
   out.  Servers are not required to do this immediately.

   Servers must enforce the structural rules listed in above section 3.

   Servers must ensure that the operational attribute described in
   section 5 is present in dynamic entries

   Servers may permit anonymous users to refresh entries. However, to
   eliminate the possibility of a malicious use of the Refresh
   operation, servers may require the refreshing client to bind first. A
   server implementation can achieve this by presenting ACLs on the
   entryTtl attribute, and returning insufficientAccessRights (50) in
   the RefreshResponse, if the client is not allowed to refresh the
   entry. Doing this, though, might have performance implications on the
   server and might impact the server's scalability.

   Servers may require that a client which attempts to create a dynamic
   entry have a remove permission for that entry.

   Servers which implement the dynamic extensions must have the OBJECT
   IDENTIFIER, described above in section 4 for the request and



Yaacovi, et al.             Standards Track                     [Page 8]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


   response, present as a value of the supportedExtension field in the
   root DSE.  They must also have as values in the attributeTypes and
   objectClasses attributes of their subschema subentries, the
   AttributeTypeDescription and ObjectClassDescription from section 5.

   Servers can limit the support of the dynamic extensions to only some
   of the subtrees in the DIT. Servers indicate for which subtrees they
   support the extensions, by specifying the OIDs for the supported
   subtrees in the dynamicSubtrees attribute described in section 5. If
   a server supports the dynamic extensions for all naming contexts it
   holds, the dynamicSubtrees attribute may be absent.

7. Implementation issues

7.1 Storage of dynamic information

   Dynamic information is expected to change very often.  In addition,
   Refresh requests are expected to arrive at the server very often.
   Disk-based databases that static directory services often use are
   likely inappropriate for storing dynamic information.  We recommend
   that server implementations store dynamic entries in memory
   sufficient to avoid paging.  This is not a requirement.

   We expect LDAP servers to be able to store static and dynamic
   entries.  If an LDAP server does not support dynamic entries, it
   should respond with an error code such as objectClassViolation.

7.2 Client refresh behavior

   In some cases, the client might not get a Refresh response.  This may
   happen as a result of a server crash after receiving the Refresh
   request, the TCP/IP socket timing out in the connection case, or the
   UDP packet getting lost in the connection-less case.

   It is recommended that in such a case, the client will retry the
   Refresh operation immediately, and if this Refresh request does not
   get a response as well, it will resort to its original Refresh cycle,
   i.e.  send a Refresh request at its Client Refresh Period (CRP).

7.3 Configuration of refresh times

   We recommend that servers will provide administrators with the
   ability to configure the default client refresh period (CRP), and
   also a minimum and maximum CRP values. This, together with allowing
   administrators to request that the server will not change the CRP
   dynamically, will allow administrators to set CRP values which will
   enforce a low refresh traffic, or - on the other extreme, an highly
   up-to-date directory.



Yaacovi, et al.             Standards Track                     [Page 9]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


8. Replication

   Replication is only partially addressed in this memo. There is a
   separate effort in progress at the IETF on replication of static and
   dynamic directories.

   it is allowed to replicate a dynamic entry or a static entry with
   dynamic attributes. Since the entryTtl is expressed as a relative
   time (how many seconds till the entry will expire), replicating it
   means that the replicated entry will be "off" by the replication
   time.

9. Localization

   The are no localization issues for this extended operation.

10. Security Considerations

   Standard LDAP security rules and support apply for the extensions
   described in this document, and there are no special security issues
   for these extensions. Please note, though, that servers may permit
   anonymous clients to refresh entries which they did not create.
   Servers are also permitted to control a refresh access to an entry by
   requiring clients to bind before issuing a RefreshRequest. This will
   have implications on the server performance and scalability.

   Also, Care should be taken in making use of information obtained from
   directory servers that has been supplied by client, as it may now be
   out of date.  In many networks, for example, IP addresses are
   automatically assigned when a host connects to the network, and may
   be reassigned if that host later disconnects.  An IP address obtained
   from the directory may no longer be assigned to the host that placed
   the address in the directory.  This issue is not specific to LDAP or
   dynamic directories.

11. Acknowledgments

   Design ideas included in this document are based on those discussed
   in ASID and other IETF Working Groups.












Yaacovi, et al.             Standards Track                    [Page 10]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


12. Authors' Addresses

   Yoram Yaacovi
   Microsoft
   One Microsoft way
   Redmond, WA 98052
   USA

   Phone:  +1 206-936-9629
   EMail:  yoramy@microsoft.com


   Mark Wahl
   Innosoft International, Inc.
   8911 Capital of Texas Hwy #4140
   Austin, TX 78759
   USA

   Email: M.Wahl@innosoft.com


   Tony Genovese
   Microsoft
   One Microsoft way
   Redmond, WA 98052
   USA

   Phone:  +1 206-703-0852
   EMail:  tonyg@microsoft.com

13. Bibliography

   [1] Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access
       Protocol (Version 3)", RFC 2251, December 1997.

   [2] Wahl, M. Coulbeck, A., Howes, T. and S. Kille, "Lightweight
       Directory Access Protocol (v3): Attribute Syntax Definitions",
       RFC 2252, December 1997.

   [3] Wahl, M. and S. Kille, "Lightweight Directory Access Protocol
       (v3): UTF-8 String Representation of Distinguished Names", RFC
       2253, December 1997.









Yaacovi, et al.             Standards Track                    [Page 11]

RFC 2589    LDAPv3 Extensions for Dynamic Directory Services    May 1999


14.  Full Copyright Statement

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Yaacovi, et al.             Standards Track                    [Page 12]

alt-openldap11-devel/rfc/rfc4373.txt000064400000074563150410163220013002 0ustar00





Network Working Group                                        R. Harrison
Request for Comments: 4373                                J. Sermersheim
Category: Informational                                     Novell, Inc.
                                                                 Y. Dong
                                                            January 2006


             Lightweight Directory Access Protocol (LDAP)
                Bulk Update/Replication Protocol (LBURP)

Status of This Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   The Lightweight Directory Access Protocol (LDAP) Bulk
   Update/Replication Protocol (LBURP) allows an LDAP client to perform
   a bulk update to an LDAP server.  The protocol frames a sequenced set
   of update operations within a pair of LDAP extended operations to
   notify the server that the update operations in the framed set are
   related in such a way that the ordering of all operations can be
   preserved during processing even when they are sent asynchronously by
   the client.  Update operations can be grouped within a single
   protocol message to maximize the efficiency of client-server
   communication.

   The protocol is suitable for efficiently making a substantial set of
   updates to the entries in an LDAP server.
















Harrison, et al.             Informational                      [Page 1]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


Table of Contents

   1. Introduction ....................................................3
   2. Conventions Used in This Document ...............................3
   3. Overview of Protocol ............................................3
      3.1. Update Initiation ..........................................4
      3.2. Update Stream ..............................................4
           3.2.1. LBURPUpdateRequest ..................................4
           3.2.2. LBURPUpdateResponse .................................4
      3.3. Update Termination .........................................4
      3.4. Applicability of Protocol ..................................5
   4. Description of Protocol Flow ....................................5
   5. Elements of Protocol ............................................6
      5.1. StartLBURPRequest ..........................................7
           5.1.1. updateStyleOID ......................................7
      5.2. StartLBURPResponse .........................................7
           5.2.1. maxOperations .......................................8
      5.3. LBURPUpdateRequest .........................................8
           5.3.1. sequenceNumber ......................................8
           5.3.2. UpdateOperationList .................................9
      5.4. LBURPUpdateResponse ........................................9
           5.4.1. OperationResults ...................................10
                  5.4.1.1. operationNumber ...........................10
                  5.4.1.2. ldapResult ................................10
      5.5. EndLBURPRequest ...........................................10
           5.5.1. sequenceNumber .....................................10
      5.6. EndLBURPResponse ..........................................11
   6. Semantics of the Incremental Update Style ......................11
   7. General LBURP Semantics ........................................11
   8. Security Considerations ........................................12
   9. IANA Considerations ............................................13
      9.1. LDAP Object Identifier Registrations ......................13
   10. Normative References ..........................................14
   11. Informative References ........................................14

















Harrison, et al.             Informational                      [Page 2]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


1.  Introduction

   The Lightweight Directory Access Protocol (LDAP) Bulk
   Update/Replication Protocol (LBURP) arose from the need to allow an
   LDAP client to efficiently present large quantities of updates to an
   LDAP server and have the LDAP server efficiently process them.  LBURP
   introduces a minimum of new operational functionality to the LDAP
   protocol because the update requests sent by the client encapsulate
   standard LDAP [RFC2251] update operations.  However, this protocol
   greatly facilitates bulk updates by allowing the client to send the
   update operations asynchronously and still allow the server to
   maintain proper ordering of the operations.  It also allows the
   server to recognize the client's intent to perform a potentially
   large set of update operations and then to change its processing
   strategy to more efficiently process the operations.

2.  Conventions Used in This Document

   Imperative keywords defined in RFC 2119 [RFC2119] are used in this
   document, and carry the meanings described there.

   All Basic Encoding Rules (BER) [X.690] encodings follow the
   conventions found in section 5.1 of [RFC2251].

   The term "supplier" applies to an LDAP client or an LDAP server
   (acting as a client) that supplies a set of update operations to a
   consumer.

   The term "consumer" applies to an LDAP server that consumes (i.e.,
   processes) the sequenced set of update operations sent to it by a
   supplier.

3.  Overview of Protocol

   LBURP frames a set of update operations within a pair of LDAP
   extended operations that mark the beginning and end of the update
   set.  These updates are sent via LDAP extended operations, each
   containing a sequence number and a list of one or more update
   operations to be performed by the consumer.  Except for the fact that
   they are grouped together as part of a larger LDAP message, the
   update operations in each subset are encoded as LDAP update
   operations and use the LDAP Abstract Syntax Notation One (ASN.1)
   [X.680] message types specified in [RFC2251].








Harrison, et al.             Informational                      [Page 3]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


3.1.  Update Initiation

   The protocol is initiated when a supplier sends a StartLBURPRequest
   extended operation to a consumer as a notification that a stream of
   associated LBURPUpdateRequests will follow.  The supplier associates
   semantics with this stream of requests by including the Object
   Identifier (OID) of the bulk update/replication style in the
   StartLBURPRequest.  The consumer responds to the StartLBURPRequest
   with a StartLBURPResponse message.

3.2.  Update Stream

   After the consumer responds with a StartLBURPResponse, the supplier
   sends a stream of LBURPUpdateRequest messages to the consumer.
   Messages within this stream may be sent asynchronously to maximize
   the efficiency of the transfer.  The consumer responds to each
   LBURPUpdateRequest with an LBURPUpdateResponse message.

3.2.1.  LBURPUpdateRequest

   Each LBURPUpdateRequest contains a sequence number identifying its
   relative position within the update stream and an UpdateOperationList
   containing an ordered list of LDAP update operations to be applied to
   the Directory Information Tree (DIT).  The sequence number enables
   the consumer to process LBURPUpdateRequest messages in the order they
   were sent by the supplier even when they are sent asynchronously.
   The consumer processes each LBURPUpdateRequest according to the
   sequence number by applying the LDAP update operations in its
   UpdateOperationList to the DIT in the order they are listed.

3.2.2.  LBURPUpdateResponse

   When the consumer has processed the update operations from an
   UpdateOperationList, it sends an LBURPUpdateResponse to the supplier
   indicating the success or failure of the update operations contained
   within the corresponding LBURPUpdateRequest.

3.3.  Update Termination

   After the supplier has sent all of its LBURPUpdateRequest messages,
   it sends an EndLBURPRequest message to the consumer to terminate the
   update stream.  Upon servicing all LBURPOperation requests and
   receiving the EndLBURPRequest, the consumer responds with an
   EndLBURPResponse, and the update is complete.







Harrison, et al.             Informational                      [Page 4]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


3.4.  Applicability of Protocol

   LBURP is designed to facilitate the bulk update of LDAP servers.  It
   can also be used to synchronize directory information between a
   single master and multiple slaves.

   No attempt is made to deal with the issues associated with multiple-
   master replication environments (such as keeping modification times
   of attribute values) so that updates to the same entry on different
   replicas can be correctly ordered.  For this reason, when LBURP alone
   is used for replication, proper convergence of the data between all
   replicas can only be assured in a single-master replication
   environment.

4.  Description of Protocol Flow

   This section describes the LBURP protocol flow and the information
   contained in each protocol message.  Throughout this section, the
   client or server acting as a supplier is indicated by the letter "S",
   and the server acting as a consumer is indicated by the letter "C".
   The construct "S -> C" indicates that the supplier is sending an LDAP
   message to the consumer, and "C -> S" indicates that the consumer is
   sending an LDAP message to the supplier.  Note that the protocol flow
   below assumes that a properly authenticated LDAP session has already
   been established between the supplier and consumer.

       S -> C: StartLBURPRequest message.  The parameter is:

                  1) OID for the LBURP update style (see section 5.1.1).

       C -> S: StartLBURPResponse message.  The parameter is:

                  1) An optional maxOperations instruction
                     (see section 5.2.1).

       S -> C: An update stream consisting of zero or more
               LBURPUpdateRequest messages.  The requests MAY be sent
               asynchronously.  The parameters are:

                  1) A sequence number specifying the order of
                     this LBURPUpdateRequest with respect to the
                     other LBURPUpdateRequest messages in the update
                     stream (see section 5.3.1).

                  2) LBURPUpdateRequest.updateOperationList, a list
                     of one or more LDAP update operations (see section
                     5.3.2).




Harrison, et al.             Informational                      [Page 5]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


               The consumer processes the LBURPUpdateRequest messages
               in the order of their sequence numbers and applies the
               LDAP update operations contained within each
               LBURPUpdateRequest to the DIT in the order they are
               listed.

       C -> S: LBURPUpdateResponse message.  This is sent when the
               consumer completes processing the update operations
               from each LBURPUpdateRequest.updateOperationList.

       S -> C: EndLBURPRequest message.  This is sent after the
               supplier sends all of its LBURPUpdateRequest messages
               to the consumer.  The parameter is:

                  1) A sequence number that is one greater than the
                     sequence number of the last LBURPUpdateRequest
                     message in the update stream.  This allows the
                     EndLBURPRequest to also be sent asynchronously.

       C -> S: EndLBURPResponse message.  This is sent in response to
               the EndLBURPRequest after the consumer has serviced
               all LBURPOperation requests.

5.  Elements of Protocol

   LBURP uses two LDAP ExtendedRequest messages--StartLBURPRequest and
   EndLBURPRequest--to initiate and terminate the protocol.  A third
   LDAP ExtendedRequest message--LBURPUpdateRequest--is used to send
   update operations from the supplier to the consumer.  These three
   requests along with their corresponding responses comprise the entire
   protocol.

   LBURP request messages are defined in terms of the LDAP
   ExtendedRequest [RFC2251] as follows:

        ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
            requestName    [0] LDAPOID,
            requestValue   [1] OCTET STRING OPTIONAL
        }

   LBURP response messages are defined in terms of the LDAP
   ExtendedResponse [RFC2251] as follows:

       ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
           COMPONENTS of LDAPResult,
           responseName  [10] LDAPOID OPTIONAL,
           response      [11] OCTET STRING OPTIONAL
        }



Harrison, et al.             Informational                      [Page 6]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


5.1.  StartLBURPRequest

   The requestName value of the StartLBURPRequest is OID 1.3.6.1.1.17.1.

   The requestValue of the StartLBURPRequest contains the BER-encoding
   of the following ASN.1:

       StartLBURPRequestValue ::= SEQUENCE {
           updateStyleOID LDAPOID
       }

   LDAPOID is defined in [RFC2251], section 4.1.2.

5.1.1.  updateStyleOID

   The updateStyleOID is an OID that uniquely identifies the LBURP
   update style being used.  This document defines one LBURP update
   semantic style that can be transmitted between the StartLBURPRequest
   and EndLBURPRequest.  The updateStyleOID is included in the protocol
   for future expansion of additional update styles.  For example, a
   future specification might define an update style with semantics to
   replace all existing entries with a new set of entries and thus only
   allows the Add operation.

   The updateStyleOID for the LBURP Incremental Update style is
   1.3.6.1.1.17.7.  The semantics of this update style are described in
   section 6.

5.2.  StartLBURPResponse

   The responseName of the StartLBURPResponse is the OID 1.3.6.1.1.17.2.

   The optional response element contains the BER-encoding of the
   following ASN.1:

       StartLBURPResponseValue ::= maxOperations

       maxOperations ::= INTEGER (0 .. maxInt)

       maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --











Harrison, et al.             Informational                      [Page 7]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


5.2.1.  maxOperations

   When present, the value of maxOperations instructs the supplier to
   send no more than that number of update operations per
   LBURPUpdateRequest.updateOperationList (see section 5.3.2).  If the
   consumer does not send a maxOperations value, it MUST be prepared to
   accept any number of update operations per
   LBURPUpdateRequest.updateOperationList.  The supplier MAY send fewer
   but MUST NOT send more than maxOperations update operations in a
   single LBURPUpdateRequest.updateOperationList.

5.3.  LBURPUpdateRequest

   The LBURPUpdateRequest message is used to send a set of zero or more
   LDAP update operations from the supplier to the consumer along with
   sequencing information that enables the consumer to maintain the
   proper sequencing of multiple asynchronous LBURPUpdateRequest
   messages.

   The requestName of the LBURPUpdateRequest is the OID 1.3.6.1.1.17.5.

   The requestValue of an LBURPOperation contains the BER-encoding of
   the following ASN.1:

       LBURPUpdateRequestValue ::= SEQUENCE {
           sequenceNumber INTEGER (1 .. maxInt),
           updateOperationList UpdateOperationList
       }

5.3.1.  sequenceNumber

   The sequenceNumber orders associated LBURPOperation requests.  This
   enables the consumer to process LBURPOperation requests in the order
   specified by the supplier.  The supplier MUST set the value of
   sequenceNumber of the first LBURPUpdateRequest to 1, and MUST
   increment the value of sequenceNumber by 1 for each succeeding
   LBURPUpdateRequest.  In the unlikely event that the number of
   LBURPUpdateRequest messages exceeds maxInt, a sequenceNumber value of
   1 is deemed to be the succeeding sequence number following a sequence
   number of maxInt.











Harrison, et al.             Informational                      [Page 8]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


5.3.2.  UpdateOperationList

   The UpdateOperationList is a list of one or more standard LDAP update
   requests and is defined as follows:

       UpdateOperationList ::= SEQUENCE OF SEQUENCE{
           updateOperation CHOICE {
              addRequest       AddRequest,
              modifyRequest    ModifyRequest,
              delRequest       DelRequest,
              modDNRequest     ModifyDNRequest
           },
           controls       [0] Controls OPTIONAL
       }

   AddRequest, ModifyRequest, DelRequest, and ModifyDNRequest are
   defined in [RFC2251], sections 4.6, 4.7, 4.8, and 4.9.

   The LDAP update requests in the UpdateOperationList MUST be applied
   to the DIT in the order in which they are listed.

5.4.  LBURPUpdateResponse

   An LBURPUpdateResponse message is sent from the consumer to the
   supplier to signal that all of the update operations from the
   UpdateOperationList of an LBURPUpdateRequest have been completed and
   to give the results for the update operations from that list.

   The responseName of the LBURPUpdateResponse is the OID
   1.3.6.1.1.17.6.

   If the consumer server cannot successfully decode an
   LBURPUpdateRequest in its entirety, the resultCode for the
   corresponding LBURPUpdateResponse is set to protocolError and the
   response element is omitted.  Updates from the LBURPUpdateRequest
   SHALL NOT be committed to the DIT in this circumstance.

   If the status of all of the update operations being reported by an
   LBURPUpdateResponse message is success, the resultCode of the
   LBURPUpdateResponse message is set to success and the response
   element is omitted.

   If the status of any of the update operations being reported by an
   LBURPUpdateResponse message is something other than success, the
   resultCode for the entire LBURPUpdateResponse is set to other to
   signal that the response element is present.





Harrison, et al.             Informational                      [Page 9]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


5.4.1.  OperationResults

   When a response element is included in an LBURPUpdateResponse
   message, it contains the BER-encoding of the following ASN.1:

       OperationResults ::= SEQUENCE OF OperationResult

       OperationResult ::= SEQUENCE {
          operationNumber    INTEGER,
          ldapResult         LDAPResult
       }

   An OperationResult is included for each operation from the
   UpdateOperationList that failed during processing.

5.4.1.1.  operationNumber

   The operationNumber identifies the LDAP update operation from the
   UpdateOperationList of the LBURPUpdateRequest that failed.
   Operations are numbered beginning at 1.

5.4.1.2.  ldapResult

   The ldapResult included in the OperationResult is the same ldapResult
   that would be sent for the update operation that failed if it had
   failed while being processed as a normal LDAP update operation.
   LDAPResult is defined in [RFC2251], section 4.1.10.

5.5.  EndLBURPRequest

   The requestName of the EndLBURPRequest is the OID 1.3.6.1.1.17.3.

   The requestValue contains the BER-encoding of the following ASN.1:

        EndLBURPRequestValue::= SEQUENCE {
            sequenceNumber INTEGER (1 .. maxInt)
        }

5.5.1.  sequenceNumber

   The value in sequenceNumber is one greater than the last
   LBURPUpdateRequest.sequenceNumber in the update stream.  It allows
   the server to know when it has received all outstanding asynchronous
   LBURPUpdateRequests.







Harrison, et al.             Informational                     [Page 10]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


5.6.  EndLBURPResponse

   The responseName of the EndLBURPResponse is the OID 1.3.6.1.1.17.4.

   There is no response element in the EndLBURPResponse message.

6.  Semantics of the Incremental Update Style

   The initial state of entries in the consumer's DIT plus the
   LBURPUpdateRequest messages in the update stream collectively
   represent the desired final state of the consumer's DIT.  All LDAP
   update operations defined in [RFC2251]--Add, Modify, Delete, and
   Modify DN--are allowed in the incremental update stream.  All of the
   semantics of those operations are in effect, so for instance, an
   attempt to add an entry that already exists will fail just as it
   would during a normal LDAP Add operation.

7.  General LBURP Semantics

   The consumer server may take any action required to efficiently
   process the updates sent via LBURP, as long as the final state is
   equivalent to that which would have been achieved if the updates in
   the update stream had been applied to the DIT using normal LDAP
   update operations.

   The LBURPUpdateRequest messages that form the update stream MAY be
   sent asynchronously by the supplier to the consumer.  This means that
   the supplier need not wait for an LBURPUpdateResponse message for one
   LBURPUpdateRequest message before sending the next LBURPUpdateRequest
   message.

   When the LBURP update stream contains a request that affects multiple
   Directory System Agents (DSAs), the consumer MAY choose to perform
   the request or return a resultCode value of affectsMultipleDSAs.  As
   with any LDAP operation, a consumer MAY send a resultCode value of
   referral as part of the OperationResult element for any operation on
   an entry that it does not contain.  If the consumer is configured to
   do so, it MAY chain on behalf of the supplier to complete the update
   operation instead.

   While a consumer server is processing an LBURP update stream, it may
   choose not to service LDAP requests on other connections.  This
   provision is designed to allow implementers the freedom to implement
   highly-efficient methods of handling the update stream without being
   constrained by the need to maintain a live, working DIT database
   while doing so.





Harrison, et al.             Informational                     [Page 11]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


   If a consumer chooses to refuse LDAP operation requests from other
   suppliers during LBURP update, it is RECOMMENDED that the consumer
   refer those requests to another server that has the appropriate data
   to complete the operation.

   Unless attribute values specifying timestamps are included as part of
   the update stream, updates made using LBURP are treated the same as
   other LDAP operations wherein they are deemed to occur at the
   present.  Consumers MAY store timestamp values sent by suppliers but
   are not required to do so.

   Implementations may choose to perform the operations in the update
   stream with special permissions to improve performance.

   Consumer implementations should include functionality to detect and
   terminate connections on which an LBURP session has been initiated
   but information (such as the EndLBURPRequest) needed to complete the
   LBURP session is never received.  A timeout is one mechanism that can
   be used to accomplish this.

8.  Security Considerations

   Implementations should ensure that a supplier making an LBURP request
   is properly authenticated and authorized to make the updates
   requested.  There is a potential for loss of data if updates are made
   to the DIT without proper authorization.  If LBURP is used for
   replication, implementers should note that unlike other replication
   protocols, no existing replication agreement between supplier and
   consumer is required.  These risks increase if the consumer server
   also processes the update stream with special permissions to improve
   performance.  For these reasons, implementers should carefully
   consider which permissions should be required to perform LBURP
   operations and take steps to ensure that only connections with
   appropriate authorization are allowed to perform them.

   The data contained in the update stream may contain passwords and
   other sensitive data.  Care should be taken to properly safeguard
   this information while in transit between supplier and consumer.  The
   StartTLS [RFC2830] operation is one mechanism that can be used to
   provide data confidentiality and integrity services for this purpose.

   As with any asynchronous LDAP operation, it may be possible for an
   LBURP supplier to send asynchronous LBURPUpdateRequest messages to
   the consumer faster than the consumer can process them.  Consumer
   implementers should take steps to prevent LBURP suppliers from
   interfering with the normal operation of a consumer server by issuing
   a rapid stream of asynchronous LBURPUpdateRequest messages.




Harrison, et al.             Informational                     [Page 12]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


9.  IANA Considerations

   Registration of the following values has been made by the IANA
   [RFC3383].

9.1.  LDAP Object Identifier Registrations

   The IANA has registered LDAP Object Identifiers identifying the
   protocol elements defined in this technical specification.  The
   following registration template was provided:

   Subject: Request for LDAP OID Registration
   Person & email address to contact for further information:
       Roger Harrison
       rharrison@novell.com
   Specification: RFC 4373
   Author/Change Controller: IESG
   Comments:
   Seven delegations will be made under the assigned OID.  The
   following 6 OIDs are Protocol Mechanism OIDs of type "E"
   (supportedExtension):

   1.3.6.1.1.17.1 StartLBURPRequest LDAP ExtendedRequest message
   1.3.6.1.1.17.2 StartLBURPResponse LDAP ExtendedResponse message
   1.3.6.1.1.17.3 EndLBURPRequest LDAP ExtendedRequest message
   1.3.6.1.1.17.4 EndLBURPResponse LDAP ExtendedResponse message
   1.3.6.1.1.17.5 LBURPUpdateRequest LDAP ExtendedRequest message
   1.3.6.1.1.17.6 LBURPUpdateResponse LDAP ExtendedResponse message

   The following 1 OID is a Protocol Mechanism OID of type "F"
   (supportedFeature):

   1.3.6.1.1.17.7 LBURP Incremental Update style OID


















Harrison, et al.             Informational                     [Page 13]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


10.  Normative References

   [RFC2119]  Bradner, S., "Key Words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251]  Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [X.680]    ITU-T Recommendation X.680 (07/2002) | ISO/IEC 8824-1:2002
              "Information Technology - Abstract Syntax Notation One
              (ASN.1): Specification of basic notation"

   [X.690]    ITU-T Rec. X.690 (07/2002) | ISO/IEC 8825-1:2002,
              "Information technology - ASN.1 encoding rules:
              Specification of Basic Encoding Rules (BER), Canonical
              Encoding Rules (CER) and Distinguished Encoding Rules
              (DER)", 2002.

11.  Informative References

   [RFC2830]  Hodges, J., Morgan, R., and M. Wahl, "Lightweight
              Directory Access Protocol (v3): Extension for Transport
              Layer Security", RFC 2830, May 2000.
























Harrison, et al.             Informational                     [Page 14]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


Authors' Addresses

   Roger Harrison
   Novell, Inc.
   1800 S. Novell Place
   Provo, UT 84606

   Phone: +1 801 861 2642
   EMail: rharrison@novell.com


   Jim Sermersheim
   Novell, Inc.
   1800 S. Novell Place
   Provo, UT 84606

   Phone: +1 801 861 3088
   EMail: jimse@novell.com


   Yulin Dong

   EMail: yulindong@gmail.com




























Harrison, et al.             Informational                     [Page 15]

RFC 4373         LDAP Bulk Update/Replication Protocol      January 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Harrison, et al.             Informational                     [Page 16]

alt-openldap11-devel/rfc/rfc4524.txt000064400000143021150410163220012762 0ustar00





Network Working Group                                   K. Zeilenga, Ed.
Request for Comments: 4524                           OpenLDAP Foundation
Obsoletes: 1274                                                June 2006
Updates: 2247, 2798
Category: Standards Track


                        COSINE LDAP/X.500 Schema

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document provides a collection of schema elements for use with
   the Lightweight Directory Access Protocol (LDAP) from the COSINE and
   Internet X.500 pilot projects.

   This document obsoletes RFC 1274 and updates RFCs 2247 and 2798.

Table of Contents

   1. Introduction ....................................................3
      1.1. Relationship to Other Documents ............................3
      1.2. Terminology and Conventions ................................4
   2. COSINE Attribute Types ..........................................4
      2.1. associatedDomain ...........................................4
      2.2. associatedName .............................................5
      2.3. buildingName ...............................................5
      2.4. co .........................................................5
      2.5. documentAuthor .............................................6
      2.6. documentIdentifier .........................................6
      2.7. documentLocation ...........................................6
      2.8. documentPublisher ..........................................7
      2.9. documentTitle ..............................................7
      2.10. documentVersion ...........................................7
      2.11. drink .....................................................8
      2.12. homePhone .................................................8
      2.13. homePostalAddress .........................................8



Zeilenga                    Standards Track                     [Page 1]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


      2.14. host ......................................................9
      2.15. info ......................................................9
      2.16. mail ......................................................9
      2.17. manager ..................................................10
      2.18. mobile ...................................................10
      2.19. organizationalStatus .....................................11
      2.20. pager ....................................................11
      2.21. personalTitle ............................................11
      2.22. roomNumber ...............................................12
      2.23. secretary ................................................12
      2.24. uniqueIdentifier .........................................12
      2.25. userClass ................................................13
   3. COSINE Object Classes ..........................................13
      3.1. account ...................................................13
      3.2. document ..................................................14
      3.3. documentSeries ............................................14
      3.4. domain ....................................................15
      3.5. domainRelatedObject .......................................16
      3.6. friendlyCountry ...........................................16
      3.7. rFC822LocalPart ...........................................17
      3.8. room ......................................................18
      3.9. simpleSecurityObject ......................................18
   4. Security Considerations ........................................18
   5. IANA Considerations ............................................19
   6. Acknowledgements ...............................................20
   7. References .....................................................20
      7.1. Normative References ......................................20
      7.2. Informative References ....................................21
   Appendix A.  Changes since RFC 1274 ...............................23
      A.1.  LDAP Short Names .........................................23
      A.2.  pilotObject ..............................................23
      A.3.  pilotPerson ..............................................23
      A.4.  dNSDomain ................................................24
      A.5.  pilotDSA and qualityLabelledData .........................24
      A.6.  Attribute Syntaxes .......................................24
   Appendix B.  Changes since RFC 2247 ...............................24















Zeilenga                    Standards Track                     [Page 2]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


1.  Introduction

   In the late 1980s, X.500 Directory Services were standardized by the
   CCITT (Commite' Consultatif International de Telegraphique et
   Telephonique), now a part of the ITU (International Telephone Union).
   This lead to Directory Service piloting activities in the early
   1990s, including the COSINE (Co-operation and Open Systems
   Interconnection in Europe) PARADISE Project pilot [COSINEpilot] in
   Europe.  Motivated by needs for large-scale directory pilots, RFC
   1274 was published to standardize the directory schema and naming
   architecture for use in the COSINE and other Internet X.500 pilots
   [RFC1274].

   In the years that followed, X.500 Directory Services have evolved to
   incorporate new capabilities and even new protocols.  In particular,
   the Lightweight Directory Access Protocol (LDAP) [RFC4510] was
   introduced in the early 1990s [RFC1487], with Version 3 of LDAP
   introduced in the late 1990s [RFC2251] and subsequently revised in
   2005 [RFC4510].

   While much of the material in RFC 1274 has been superceded by
   subsequently published ITU-T Recommendations and IETF RFCs, many of
   the schema elements lack standardized schema descriptions for use in
   modern X.500 and LDAP directory services despite the fact that these
   schema elements are in wide use today.  As the old schema
   descriptions cannot be used without adaptation, interoperability
   issues may arise due to lack of standardized modern schema
   descriptions.

   This document addresses these issues by offering standardized schema
   descriptions, where needed, for widely used COSINE schema elements.

1.1.  Relationship to Other Documents

   This document, together with [RFC4519] and [RFC4517], obsoletes RFC
   1274 in its entirety.  [RFC4519] replaces Sections 9.3.1 (Userid) and
   9.3.21 (Domain Component) of RFC 1274.  [RFC4517] replaces Section
   9.4 (Generally useful syntaxes) of RFC 1274.

   This document replaces the remainder of RFC 1274.  Appendix A
   discusses changes since RFC 1274, as well as why certain schema
   elements were not brought forward in this revision of the COSINE
   schema.  All elements not brought are to be regarded as Historic.

   The description of the 'domain' object class provided in this
   document supercedes that found in RFC 2247.  That is, Section 3.4 of
   this document replaces Section 5.2 of [RFC2247].




Zeilenga                    Standards Track                     [Page 3]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   Some of the schema elements specified here were described in RFC 2798
   (inetOrgPerson schema).  This document supersedes these descriptions.
   This document, together with [RFC4519], replaces Section 9.1.3 of RFC
   2798.

1.2.  Terminology and Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

   DIT stands for Directory Information Tree.
   DN stands for Distinguished Name.
   DSA stands for Directory System Agent, a server.
   DSE stands for DSA-Specific Entry.
   DUA stands for Directory User Agent, a client.

   These terms are discussed in [RFC4512].

   Schema definitions are provided using LDAP description formats
   [RFC4512].  Definitions provided here are formatted (line wrapped)
   for readability.

2.  COSINE Attribute Types

   This section details COSINE attribute types for use in LDAP.

2.1.  associatedDomain

   The 'associatedDomain' attribute specifies DNS [RFC1034][RFC2181]
   host names [RFC1123] that are associated with an object.   That is,
   values of this attribute should conform to the following ABNF:

    domain = root / label *( DOT label )
    root   = SPACE
    label  = LETDIG [ *61( LETDIG / HYPHEN ) LETDIG ]
    LETDIG = %x30-39 / %x41-5A / %x61-7A ; "0" - "9" / "A"-"Z" / "a"-"z"
    SPACE  = %x20                        ; space (" ")
    HYPHEN = %x2D                        ; hyphen ("-")
    DOT    = %x2E                        ; period (".")

   For example, the entry in the DIT with a DN <DC=example,DC=com> might
   have an associated domain of "example.com".

      ( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain'
        EQUALITY caseIgnoreIA5Match
        SUBSTR caseIgnoreIA5SubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )



Zeilenga                    Standards Track                     [Page 4]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   The IA5String (1.3.6.1.4.1.1466.115.121.1.26) syntax and the
   'caseIgnoreIA5Match' and 'caseIgnoreIA5SubstringsMatch' rules are
   described in [RFC4517].

   Note that the directory will not ensure that values of this attribute
   conform to the <domain> production provided above.  It is the
   application's responsibility to ensure that domains it stores in this
   attribute are appropriately represented.

   Also note that applications supporting Internationalized Domain Names
   SHALL use the ToASCII method [RFC3490] to produce <label> components
   of the <domain> production.

2.2.  associatedName

   The 'associatedName' attribute specifies names of entries in the
   organizational DIT associated with a DNS domain [RFC1034][RFC2181].

      ( 0.9.2342.19200300.100.1.38 NAME 'associatedName'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

   The DistinguishedName (1.3.6.1.4.1.1466.115.121.1.12) syntax and the
   'distinguishedNameMatch' rule are described in [RFC4517].

2.3.  buildingName

   The 'buildingName' attribute specifies names of the buildings where
   an organization or organizational unit is based, for example, "The
   White House".

      ( 0.9.2342.19200300.100.1.48 NAME 'buildingName'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.4.  co

   The 'co' (Friendly Country Name) attribute specifies names of
   countries in human-readable format, for example, "Germany" and
   "Federal Republic of Germany".  It is commonly used in conjunction
   with the 'c' (Country Name) [RFC4519] attribute (whose values are
   restricted to the two-letter codes defined in [ISO3166]).




Zeilenga                    Standards Track                     [Page 5]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


      ( 0.9.2342.19200300.100.1.43 NAME 'co'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.5.  documentAuthor

   The 'documentAuthor' attribute specifies the distinguished names of
   authors (or editors) of a document.  For example,

      ( 0.9.2342.19200300.100.1.14 NAME 'documentAuthor'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

   The DistinguishedName (1.3.6.1.4.1.1466.115.121.1.12) syntax and the
   'distinguishedNameMatch' rule are described in [RFC4517].

2.6.  documentIdentifier

   The 'documentIdentifier' attribute specifies unique identifiers for a
   document.  A document may be identified by more than one unique
   identifier.  For example, RFC 3383 and BCP 64 are unique identifiers
   that (presently) refer to the same document.

      ( 0.9.2342.19200300.100.1.11 NAME 'documentIdentifier'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.7.  documentLocation

   The 'documentLocation' attribute specifies locations of the document
   original.

      ( 0.9.2342.19200300.100.1.15 NAME 'documentLocation'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )





Zeilenga                    Standards Track                     [Page 6]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.8.  documentPublisher

   The 'documentPublisher' attribute is the persons and/or organizations
   that published the document.  Documents that are jointly published
   have one value for each publisher.

      ( 0.9.2342.19200300.100.1.56 NAME 'documentPublisher'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.9.  documentTitle

   The 'documentTitle' attribute specifies the titles of a document.
   Multiple values are allowed to accommodate both long and short
   titles, or other situations where a document has multiple titles, for
   example, "The Lightweight Directory Access Protocol Technical
   Specification" and "The LDAP Technical Specification".

      ( 0.9.2342.19200300.100.1.12 NAME 'documentTitle'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.10.  documentVersion

   The 'documentVersion' attribute specifies the version information of
   a document.

      ( 0.9.2342.19200300.100.1.13 NAME 'documentVersion'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )






Zeilenga                    Standards Track                     [Page 7]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.11.  drink

   The 'drink' (favoriteDrink) attribute specifies the favorite drinks
   of an object (or person), for instance, "cola" and "beer".

      ( 0.9.2342.19200300.100.1.5 NAME 'drink'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.12.  homePhone

   The 'homePhone' (Home Telephone Number) attribute specifies home
   telephone numbers (e.g., "+1 775 555 1234") associated with a person.

      ( 0.9.2342.19200300.100.1.20 NAME 'homePhone'
        EQUALITY telephoneNumberMatch
        SUBSTR telephoneNumberSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

   The telephoneNumber (1.3.6.1.4.1.1466.115.121.1.50) syntax and the
   'telephoneNumberMatch' and 'telephoneNumberSubstringsMatch' rules are
   described in [RFC4517].

2.13.  homePostalAddress

   The 'homePostalAddress' attribute specifies home postal addresses for
   an object.  Each value should be limited to up to 6 directory strings
   of 30 characters each.  (Note: It is not intended that the directory
   service enforce these limits.)

      ( 0.9.2342.19200300.100.1.39 NAME 'homePostalAddress'
        EQUALITY caseIgnoreListMatch
        SUBSTR caseIgnoreListSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )

   The PostalAddress (1.3.6.1.4.1.1466.115.121.1.41) syntax and the
   'caseIgnoreListMatch' and 'caseIgnoreListSubstringsMatch' rules are
   described in [RFC4517].




Zeilenga                    Standards Track                     [Page 8]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


2.14.  host

   The 'host' attribute specifies host computers, generally by their
   primary fully qualified domain name (e.g., my-host.example.com).

      ( 0.9.2342.19200300.100.1.9 NAME 'host'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.15.  info

   The 'info' attribute specifies any general information pertinent to
   an object.  This information is not necessarily descriptive of the
   object.

   Applications should not attach specific semantics to values of this
   attribute.  The 'description' attribute [RFC4519] is available for
   specifying descriptive information pertinent to an object.

      ( 0.9.2342.19200300.100.1.4 NAME 'info'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{2048} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.16.  mail

   The 'mail' (rfc822mailbox) attribute type holds Internet mail
   addresses in Mailbox [RFC2821] form (e.g., user@example.com).

      ( 0.9.2342.19200300.100.1.3 NAME 'mail'
        EQUALITY caseIgnoreIA5Match
        SUBSTR caseIgnoreIA5SubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )

   The IA5String (1.3.6.1.4.1.1466.115.121.1.26) syntax and the
   'caseIgnoreIA5Match' and 'caseIgnoreIA5SubstringsMatch' rules are
   described in [RFC4517].





Zeilenga                    Standards Track                     [Page 9]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   Note that the directory will not ensure that values of this attribute
   conform to the <Mailbox> production [RFC2821].  It is the
   application's responsibility to ensure that domains it stores in this
   attribute are appropriately represented.

   Additionally, the directory will compare values per the matching
   rules named in the above attribute type description.  As these rules
   differ from rules that normally apply to <Mailbox> comparisons,
   operational issues may arise.  For example, the assertion
   (mail=joe@example.com) will match "JOE@example.com" even though the
   <local-parts> differ.  Also, where a user has two <Mailbox>es whose
   addresses differ only by case of the <local-part>, both cannot be
   listed as values of the user's mail attribute (as they are considered
   equal by the 'caseIgnoreIA5Match' rule).

   Also note that applications supporting internationalized domain names
   SHALL use the ToASCII method [RFC3490] to produce <sub-domain>
   components of the <Mailbox> production.

2.17.  manager

   The 'manager' attribute specifies managers, by distinguished name, of
   the person (or entity).

      ( 0.9.2342.19200300.100.1.10 NAME 'manager'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

   The DistinguishedName (1.3.6.1.4.1.1466.115.121.1.12) syntax and the
   'distinguishedNameMatch' rule are described in [RFC4517].

2.18.  mobile

   The 'mobile' (mobileTelephoneNumber) attribute specifies mobile
   telephone numbers (e.g., "+1 775 555 6789") associated with a person
   (or entity).

      ( 0.9.2342.19200300.100.1.41 NAME 'mobile'
        EQUALITY telephoneNumberMatch
        SUBSTR telephoneNumberSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

   The telephoneNumber (1.3.6.1.4.1.1466.115.121.1.50) syntax and the
   'telephoneNumberMatch' and 'telephoneNumberSubstringsMatch' rules are
   described in [RFC4517].






Zeilenga                    Standards Track                    [Page 10]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


2.19.  organizationalStatus

   The 'organizationalStatus' attribute specifies categories by which a
   person is often referred to in an organization.  Examples of usage in
   academia might include "undergraduate student", "researcher",
   "professor", and "staff".  Multiple values are allowed where the
   person is in multiple categories.

   Directory administrators and application designers SHOULD consider
   carefully the distinctions between this and the 'title' and
   'userClass' attributes.

      ( 0.9.2342.19200300.100.1.45 NAME 'organizationalStatus'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.20.  pager

   The 'pager' (pagerTelephoneNumber) attribute specifies pager
   telephone numbers (e.g., "+1 775 555 5555") for an object.

      ( 0.9.2342.19200300.100.1.42 NAME 'pager'
        EQUALITY telephoneNumberMatch
        SUBSTR telephoneNumberSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

   The telephoneNumber (1.3.6.1.4.1.1466.115.121.1.50) syntax and the
   'telephoneNumberMatch' and 'telephoneNumberSubstringsMatch' rules are
   described in [RFC4517].

2.21.  personalTitle

   The 'personalTitle' attribute specifies personal titles for a person.
   Examples of personal titles are "Frau", "Dr.", "Herr", and
   "Professor".

      ( 0.9.2342.19200300.100.1.40 NAME 'personalTitle'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )






Zeilenga                    Standards Track                    [Page 11]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.22.  roomNumber

   The 'roomNumber' attribute specifies the room number of an object.
   During periods of renumbering, or in other circumstances where a room
   has multiple valid room numbers associated with it, multiple values
   may be provided.  Note that the 'cn' (commonName) attribute type
   SHOULD be used for naming room objects.

      ( 0.9.2342.19200300.100.1.6 NAME 'roomNumber'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

2.23.  secretary

   The 'secretary' attribute specifies secretaries and/or administrative
   assistants, by distinguished name.

      ( 0.9.2342.19200300.100.1.21 NAME 'secretary'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

   The DistinguishedName (1.3.6.1.4.1.1466.115.121.1.12) syntax and the
   'distinguishedNameMatch' rule are described in [RFC4517].

2.24.  uniqueIdentifier

   The 'uniqueIdentifier' attribute specifies a unique identifier for an
   object represented in the Directory.  The domain within which the
   identifier is unique and the exact semantics of the identifier are
   for local definition.  For a person, this might be an institution-
   wide payroll number.  For an organizational unit, it might be a
   department code.

      ( 0.9.2342.19200300.100.1.44 NAME 'uniqueIdentifier'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )





Zeilenga                    Standards Track                    [Page 12]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

   Note: X.520 also describes an attribute called 'uniqueIdentifier'
         (2.5.4.45), which is called 'x500UniqueIdentifier' in LDAP
         [RFC4519].  The attribute detailed here ought not be confused
         with 'x500UniqueIdentifier'.

2.25.  userClass

   The 'userClass' attribute specifies categories of computer or
   application user.  The semantics placed on this attribute are for
   local interpretation.  Examples of current usage of this attribute in
   academia are "student", "staff", and "faculty".  Note that the
   'organizationalStatus' attribute type is now often preferred, as it
   makes no distinction between persons as opposed to users.

      ( 0.9.2342.19200300.100.1.8 NAME 'userClass'
        EQUALITY caseIgnoreMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax and the
   'caseIgnoreMatch' and 'caseIgnoreSubstringsMatch' rules are described
   in [RFC4517].

3.  COSINE Object Classes

   This section details COSINE object classes for use in LDAP.

3.1.  account

   The 'account' object class is used to define entries representing
   computer accounts.  The 'uid' attribute SHOULD be used for naming
   entries of this object class.

      ( 0.9.2342.19200300.100.4.5 NAME 'account'
        SUP top STRUCTURAL
        MUST uid
        MAY ( description $ seeAlso $ l $ o $ ou $ host ) )

   The 'top' object class is described in [RFC4512].  The 'description',
   'seeAlso', 'l', 'o', 'ou', and 'uid' attribute types are described in
   [RFC4519].  The 'host' attribute type is described in Section 2 of
   this document.





Zeilenga                    Standards Track                    [Page 13]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   3.3.  documentSeriesExample:

      dn: uid=kdz,cn=Accounts,dc=Example,dc=COM
      objectClass: account
      uid: kdz
      seeAlso: cn=Kurt D. Zeilenga,cn=Persons,dc=Example,dc=COM

3.2.  document

   The 'document' object class is used to define entries that represent
   documents.

      ( 0.9.2342.19200300.100.4.6 NAME 'document'
        SUP top STRUCTURAL
        MUST documentIdentifier
        MAY ( cn $ description $ seeAlso $ l $ o $ ou $
          documentTitle $ documentVersion $ documentAuthor $
          documentLocation $ documentPublisher ) )

   The 'top' object class is described in [RFC4512].  The 'cn',
   'description', 'seeAlso', 'l', 'o', and 'ou' attribute types are
   described in [RFC4519].  The 'documentIdentifier', 'documentTitle',
   'documentVersion', 'documentAuthor', 'documentLocation', and
   'documentPublisher' attribute types are described in Section 2 of
   this document.

   Example:

      dn: documentIdentifier=RFC 4524,cn=RFC,dc=Example,dc=COM
      objectClass: document
      documentIdentifier: RFC 4524
      documentTitle: COSINE LDAP/X.500 Schema
      documentAuthor: cn=Kurt D. Zeilenga,cn=Persons,dc=Example,dc=COM
      documentLocation: http://www.rfc-editor.org/rfc/rfc4524.txt
      documentPublisher: Internet Engineering Task Force
      description: A collection of schema elements for use in LDAP
      description: Obsoletes RFC 1274
      seeAlso: documentIdentifier=RFC 4510,cn=RFC,dc=Example,dc=COM
      seeAlso: documentIdentifier=RFC 1274,cn=RFC,dc=Example,dc=COM

3.3.  documentSeries

   The 'documentSeries' object class is used to define an entry that
   represents a series of documents (e.g., The Request For Comments
   memos).






Zeilenga                    Standards Track                    [Page 14]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


      ( 0.9.2342.19200300.100.4.9 NAME 'documentSeries'
        SUP top STRUCTURAL
        MUST cn
        MAY ( description $ l $ o $ ou $ seeAlso $
          telephonenumber ) )

   The 'top' object class is described in [RFC4512].  The 'description',
   'l', 'o', 'ou', 'seeAlso', and 'telephoneNumber' attribute types are
   described in [RFC4519].

   Example:

      dn: cn=RFC,dc=Example,dc=COM
      objectClass: documentSeries
      cn: Request for Comments
      cn: RFC
      description: a series of memos about the Internet

3.4.  domain

   The 'domain' object class is used to define entries that represent
   DNS domains for objects that are not organizations, organizational
   units, or other kinds of objects more appropriately defined using an
   object class specific to the kind of object being defined (e.g.,
   'organization', 'organizationUnit').

   The 'dc' attribute should be used for naming entries of the 'domain'
   object class.

      ( 0.9.2342.19200300.100.4.13 NAME 'domain'
        SUP top STRUCTURAL
        MUST dc
        MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
          x121Address $ registeredAddress $ destinationIndicator $
          preferredDeliveryMethod $ telexNumber $
          teletexTerminalIdentifier $ telephoneNumber $
          internationaliSDNNumber $ facsimileTelephoneNumber $ street $
          postOfficeBox $ postalCode $ postalAddress $
          physicalDeliveryOfficeName $ st $ l $ description $ o $
          associatedName ) )

   The 'top' object class and the 'dc', 'userPassword', 'searchGuide',
   'seeAlso', 'businessCategory', 'x121Address', 'registeredAddress',
   'destinationIndicator', 'preferredDeliveryMethod', 'telexNumber',
   'teletexTerminalIdentifier', 'telephoneNumber',
   'internationaliSDNNumber', 'facsimileTelephoneNumber', 'street',
   'postOfficeBox', 'postalCode', 'postalAddress',
   'physicalDeliveryOfficeName', 'st', 'l', 'description', and 'o' types



Zeilenga                    Standards Track                    [Page 15]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   are described in [RFC4519].  The 'associatedName' attribute type is
   described in Section 2 of this document.

   Example:

      dn: dc=com
      objectClass: domain
      dc: com
      description: the .COM TLD

3.5.  domainRelatedObject

   The 'domainRelatedObject' object class is used to define entries that
   represent DNS domains that are "equivalent" to an X.500 domain, e.g.,
   an organization or organizational unit.

      ( 0.9.2342.19200300.100.4.17 NAME 'domainRelatedObject'
        SUP top AUXILIARY
        MUST associatedDomain )

   The 'top' object class is described in [RFC4512].  The
   'associatedDomain' attribute type is described in Section 2 of this
   document.

   Example:

      dn: dc=example,dc=com
      objectClass: organization
      objectClass: dcObject
      objectClass: domainRelatedObject
      dc: example
      associatedDomain: example.com
      o: Example Organization

   The 'organization' and 'dcObject' object classes and the 'dc' and 'o'
   attribute types are described in [RFC4519].

3.6.  friendlyCountry

   The 'friendlyCountry' object class is used to define entries
   representing countries in the DIT.  The object class is used to allow
   friendlier naming of countries than that allowed by the object class
   'country' [RFC4519].

      ( 0.9.2342.19200300.100.4.18 NAME 'friendlyCountry'
        SUP country STRUCTURAL
        MUST co )




Zeilenga                    Standards Track                    [Page 16]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   The 'country' object class is described in [RFC4519].  The 'co'
   attribute type is described in Section 2 of this document.

   Example:

      dn: c=DE
      objectClass: country
      objectClass: friendlyCountry
      c: DE
      co: Deutschland
      co: Germany
      co: Federal Republic of Germany
      co: FRG

   The 'c' attribute type is described in [RFC4519].

3.7.  rFC822LocalPart

   The 'rFC822LocalPart' object class is used to define entries that
   represent the local part of Internet mail addresses [RFC2822].  This
   treats the local part of the address as a 'domain' object.

      ( 0.9.2342.19200300.100.4.14 NAME 'rFC822localPart'
        SUP domain STRUCTURAL
        MAY ( cn $ description $ destinationIndicator $
          facsimileTelephoneNumber $ internationaliSDNNumber $
          physicalDeliveryOfficeName $ postalAddress $ postalCode $
          postOfficeBox $ preferredDeliveryMethod $ registeredAddress $
          seeAlso $ sn $ street $ telephoneNumber $
          teletexTerminalIdentifier $ telexNumber $ x121Address ) )

   The 'domain' object class is described in Section 3.4 of this
   document.  The 'cn', 'description', 'destinationIndicator',
   'facsimileTelephoneNumber', 'internationaliSDNNumber,
   'physicalDeliveryOfficeName', 'postalAddress', 'postalCode',
   'postOfficeBox', 'preferredDeliveryMethod', 'registeredAddress',
   'seeAlso', 'sn, 'street', 'telephoneNumber',
   'teletexTerminalIdentifier', 'telexNumber', and 'x121Address'
   attribute types are described in [RFC4519].

   Example:

      dn: dc=kdz,dc=example,dc=com
      objectClass: domain
      objectClass: rFC822LocalPart
      dc: kdz
      associatedName: cn=Kurt D. Zeilenga,cn=Persons,dc=Example,dc=COM




Zeilenga                    Standards Track                    [Page 17]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   The 'dc' attribute type is described in [RFC4519].

3.8.  room

   The 'room' object class is used to define entries representing rooms.
   The 'cn' (commonName) attribute SHOULD be used for naming entries of
   this object class.

      ( 0.9.2342.19200300.100.4.7 NAME 'room'
        SUP top STRUCTURAL
        MUST cn
        MAY ( roomNumber $ description $ seeAlso $ telephoneNumber ) )

   The 'top' object class is described in [RFC4512].  The 'cn',
   'description', 'seeAlso', and 'telephoneNumber' attribute types are
   described in [RFC4519].  The 'roomNumber' attribute type is described
   in Section 2 of this document.

      dn: cn=conference room,dc=example,dc=com
      objectClass: room
      cn: conference room
      telephoneNumber: +1 755 555 1111

3.9.  simpleSecurityObject

   The 'simpleSecurityObject' object class is used to require an entry
   to have a 'userPassword' attribute when the entry's structural object
   class does not require (or allow) the 'userPassword attribute'.

      ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject'
        SUP top AUXILIARY
        MUST userPassword )

   The 'top' object class is described in [RFC4512].  The 'userPassword'
   attribute type is described in [RFC4519].

      dn: dc=kdz,dc=Example,dc=COM
      objectClass: account
      objectClass: simpleSecurityObject
      uid: kdz
      userPassword: My Password
      seeAlso: cn=Kurt D. Zeilenga,cn=Persons,dc=Example,dc=COM

4.  Security Considerations

   General LDAP security considerations [RFC4510] are applicable to the
   use of this schema.  Additional considerations are noted above where
   appropriate.



Zeilenga                    Standards Track                    [Page 18]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   Directories administrators should ensure that access to sensitive
   information be restricted to authorized entities and that appropriate
   data security services, including data integrity and data
   confidentiality, are used to protect against eavesdropping.

   Simple authentication (e.g., plain text passwords) mechanisms should
   only be used when adequate data security services are in place.  LDAP
   offers reasonably strong authentication and data security services
   [RFC4513].

5.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has updated the LDAP
   descriptors registry [RFC4520] as indicated in the following
   template:

      Subject: Request for LDAP Descriptor Registration Update
      Descriptor (short name): see comment
      Object Identifier: see comments
      Person & email address to contact for further information:
          Kurt Zeilenga <kurt@OpenLDAP.org>
      Usage: see comments
      Specification: RFC 4524
      Author/Change Controller: IESG
      Comments:

      The following descriptors have been updated to refer to RFC 4524.

        NAME                           Type OID
        ------------------------       ---- --------------------------
        account                        O    0.9.2342.19200300.100.4.5
        associatedDomain               A    0.9.2342.19200300.100.1.37
        associatedName                 A    0.9.2342.19200300.100.1.38
        buildingName                   A    0.9.2342.19200300.100.1.48
        co                             A    0.9.2342.19200300.100.1.43
        document                       O    0.9.2342.19200300.100.4.6
        documentAuthor                 A    0.9.2342.19200300.100.1.14
        documentIdentifier             A    0.9.2342.19200300.100.1.11
        documentLocation               A    0.9.2342.19200300.100.1.15
        documentPublisher              A    0.9.2342.19200300.100.1.56
        documentSeries                 O    0.9.2342.19200300.100.4.8
        documentTitle                  A    0.9.2342.19200300.100.1.12
        documentVersion                A    0.9.2342.19200300.100.1.13
        domain                         O    0.9.2342.19200300.100.4.13
        domainRelatedObject            O    0.9.2342.19200300.100.4.17
        drink                          A    0.9.2342.19200300.100.1.5
        favouriteDrink                 A*   0.9.2342.19200300.100.1.5
        friendlyCountry                O    0.9.2342.19200300.100.4.18



Zeilenga                    Standards Track                    [Page 19]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


        friendlyCountryName            A*   0.9.2342.19200300.100.1.43
        homePhone                      A    0.9.2342.19200300.100.1.20
        homePostalAddress              A    0.9.2342.19200300.100.1.39
        homeTelephone                  A*   0.9.2342.19200300.100.1.20
        host                           A    0.9.2342.19200300.100.1.9
        info                           A    0.9.2342.19200300.100.1.4
        mail                           A    0.9.2342.19200300.100.1.3
        manager                        A    0.9.2342.19200300.100.1.10
        mobile                         A    0.9.2342.19200300.100.1.41
        mobileTelephoneNumber          A*   0.9.2342.19200300.100.1.41
        organizationalStatus           A    0.9.2342.19200300.100.1.45
        pager                          A    0.9.2342.19200300.100.1.42
        pagerTelephoneNumber           A*   0.9.2342.19200300.100.1.42
        personalTitle                  A    0.9.2342.19200300.100.1.40
        rFC822LocalPart                O    0.9.2342.19200300.100.4.14
        rfc822Mailbox                  A*   0.9.2342.19200300.100.1.3
        room                           O    0.9.2342.19200300.100.4.7
        roomNumber                     A    0.9.2342.19200300.100.1.6
        secretary                      A    0.9.2342.19200300.100.1.21
        simpleSecurityObject           O    0.9.2342.19200300.100.4.19
        singleLevelQuality             A    0.9.2342.19200300.100.1.50
        uniqueIdentifier               A    0.9.2342.19200300.100.1.44
        userClass                      A    0.9.2342.19200300.100.1.8

      where Type A is Attribute, Type O is ObjectClass, and *
      indicates that the registration is historic in nature.

6.  Acknowledgements

   This document is based on RFC 1274, by Paul Barker and Steve Kille,
   as well as on RFC 2247, by Steve Kill, Mark Wahl, Al Grimstad, Rick
   Huber, and Sri Satulari.

7.  References

7.1.  Normative References

   [RFC1034]     Mockapetris, P., "Domain names - concepts and
                 facilities", STD 13, RFC 1034, November 1987.

   [RFC1123]     Braden, R., "Requirements for Internet Hosts -
                 Application and Support", STD 3, RFC 1123, October
                 1989.

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.





Zeilenga                    Standards Track                    [Page 20]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   [RFC2181]     Elz, R. and R. Bush, "Clarifications to the DNS
                 Specification", RFC 2181, July 1997.

   [RFC2247]     Kille, S., Wahl, M., Grimstad, A., Huber, R., and S.
                 Sataluri, "Using Domains in LDAP/X.500 Distinguished
                 Names", RFC 2247, January 1998.

   [RFC2821]     Klensin, J., Ed., "Simple Mail Transfer Protocol", RFC
                 2821, April 2001.

   [RFC2822]     Resnick, P., "Internet Message Format", RFC 2822, April
                 2001.

   [RFC3490]     Faltstrom, P., Hoffman, P., and A. Costello,
                 "Internationalizing Domain Names in Applications
                 (IDNA)", RFC 3490, March 2003.

   [RFC4510]     Zeilenga, K., Ed.,  "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [RFC4513]     Harrison, R., "Lightweight Directory Access Protocol
                 (LDAP): Authentication Methods and Security
                 Mechanisms", RFC 4513, June 2006.

   [RFC4517]     Legg, S., Ed., "Lightweight Directory Access Protocol
                 (LDAP): Syntaxes and Matching Rules", RC 4517, June
                 2006.

   [RFC4519]     Sciberras, A., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Schema for User Applications", RFC
                 4519, June 2006.

   [X.501]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Models," X.501(1993) (also ISO/IEC 9594-
                 2:1994).

7.2.  Informative References

   [COSINEpilot] Goodman, D., "PARADISE" section of the March 1991
                 INTERNET MONTHLY REPORTS (p. 28-29),
                 http://www.iana.org/periodic-reports/imr-mar91.txt




Zeilenga                    Standards Track                    [Page 21]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


   [ISO3166]     International Organization for Standardization, "Codes
                 for the representation of names of countries", ISO
                 3166.

   [RFC1274]     Barker, P. and S. Kille, "The COSINE and Internet X.500
                 Schema", RFC 1274, November 1991.

   [RFC1279]     Hardcastle-Kille, S., "X.500 and Domains", RFC 1279,
                 November 1991.

   [RFC1487]     Yeong, W., Howes, T., and S. Kille, "X.500 Lightweight
                 Directory Access Protocol", RFC 1487, July 1993.

   [RFC2251]     Wahl, M., Howes, T., and S. Kille, "Lightweight
                 Directory Access Protocol (v3)", RFC 2251, December
                 1997.

   [RFC2798]     Smith, M., "Definition of the inetOrgPerson LDAP Object
                 Class", RFC 2798, April 2000.

   [RFC3494]     Zeilenga, K., "Lightweight Directory Access Protocol
                 version 2 (LDAPv2) to Historic Status", RFC 3494, March
                 2003.

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520.
























Zeilenga                    Standards Track                    [Page 22]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


Appendix A.  Changes since RFC 1274

   This document represents a substantial rewrite of RFC 1274.  The
   following sections summarize the substantive changes.

A.1.  LDAP Short Names

   A number of COSINE attribute types have short names in LDAP.

      X.500 Name              LDAP Short Name
      -------------           ---------------
      domainComponent         dc
      favoriteDrink           drink
      friendCountryName       co
      homeTelephoneNumber     homePhone
      mobileTelephoneNumber   mobile
      pagerTelephoneNumber    pager
      rfc822Mailbox           mail
      userid                  uid

   While the LDAP short names are generally used in LDAP, some
   implementations may (for legacy reasons [RFC3494]) recognize the
   attribute type by its X.500 name.  Hence, the X.500 names have been
   reserved solely for this purpose.

   Note: 'uid' and 'dc' are described in [RFC4519].

A.2.  pilotObject

   The 'pilotObject' object class was not brought forward as its
   function is largely replaced by operational attributes introduced in
   X.500(93) [X.501] and version 3 of LDAP [RFC4512].  For instance, the
   function of the 'lastModifiedBy' and 'lastModifiedTime' attribute
   types is now served by the 'creatorsName', 'createTimestamp',
   'modifiersName', and 'modifyTimestamp' operational attributes
   [RFC4512].

A.3.  pilotPerson

   The 'pilotPerson' object class was not brought forward as its
   function is largely replaced by the 'organizationalPerson' [RFC4512]
   object class and its subclasses, such as 'inetOrgPerson' [RFC2798].

   Most of the related attribute types (e.g., 'mail', 'manager') were
   brought forward as they are used in other object classes.






Zeilenga                    Standards Track                    [Page 23]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


A.4.  dNSDomain

   The 'dNSDomain' object class and related attribute types were not
   brought forward as its use is primarily experimental [RFC1279].

A.5.  pilotDSA and qualityLabelledData

   The 'pilotDSA' and 'qualityLabelledData' object classes, as well as
   related attribute types, were not brought forward as its use is
   primarily experimental [QoS].

A.6.  Attribute Syntaxes

   RFC 1274 defined and used caseIgnoreIA5StringSyntax attribute syntax.
   This has been replaced with the IA5String syntax and appropriate
   matching rules in 'mail' and 'associatedDomain'.

   RFC 1274 restricted 'mail' to have non-zero length values.  This
   restriction is not reflected in the IA5String syntax used in the
   definitions provided in this specification.  However, as values are
   to conform to the <Mailbox> production, the 'mail' should not contain
   zero-length values.  Unfortunately, the directory service will not
   enforce this restriction.

Appendix B.  Changes since RFC 2247

   The 'domainNameForm' name form was not brought forward as
   specification of name forms used in LDAP is left to a future
   specification.

Editor's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org















Zeilenga                    Standards Track                    [Page 24]

RFC 4524                COSINE LDAP/X.500 Schema               June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                    [Page 25]

alt-openldap11-devel/rfc/rfc3928.txt000064400000212310150410163220012767 0ustar00





Network Working Group                                  R. Megginson, Ed.
Request for Comments: 3928                 Netscape Communications Corp.
Category: Standards Track                                       M. Smith
                                                     Pearl Crescent, LLC
                                                            O. Natkovich
                                                                   Yahoo
                                                               J. Parham
                                                   Microsoft Corporation
                                                            October 2004


             Lightweight Directory Access Protocol (LDAP)
                     Client Update Protocol (LCUP)

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).

Abstract

   This document defines the Lightweight Directory Access Protocol
   (LDAP) Client Update Protocol (LCUP).  The protocol is intended to
   allow an LDAP client to synchronize with the content of a directory
   information tree (DIT) stored by an LDAP server and to be notified
   about the changes to that content.


















Megginson, et al.           Standards Track                     [Page 1]

RFC 3928              LDAP Client Update Protocol           October 2004


Table of Contents

   1.  Overview . . . . . . . . . . . . . . . . . . . . . . . . . . .  3
   2.  Applicability. . . . . . . . . . . . . . . . . . . . . . . . .  4
   3.  Specification of Protocol Elements . . . . . . . . . . . . . .  5
       3.1.  ASN.1 Considerations . . . . . . . . . . . . . . . . . .  5
       3.2.  Universally Unique Identifiers . . . . . . . . . . . . .  5
       3.3.  LCUP Scheme and LCUP Cookie. . . . . . . . . . . . . . .  5
       3.4.  LCUP Context . . . . . . . . . . . . . . . . . . . . . .  6
       3.5.  Additional LDAP Result Codes defined by LCUP . . . . . .  6
       3.6.  Sync Request Control . . . . . . . . . . . . . . . . . .  7
       3.7.  Sync Update Control. . . . . . . . . . . . . . . . . . .  7
       3.8.  Sync Done Control. . . . . . . . . . . . . . . . . . . .  8
   4.  Protocol Usage and Flow. . . . . . . . . . . . . . . . . . . .  8
       4.1.  LCUP Search Requests . . . . . . . . . . . . . . . . . .  8
             4.1.1. Initial Synchronization and Full Resync . . . . .  9
             4.1.2. Incremental or Update Synchronization . . . . . . 10
             4.1.3. Persistent Only . . . . . . . . . . . . . . . . . 10
       4.2.  LCUP Search Responses. . . . . . . . . . . . . . . . . . 10
             4.2.1. Sync Update Informational Responses . . . . . . . 11
             4.2.2. Cookie Return Frequency . . . . . . . . . . . . . 11
             4.2.3. Definition of an Entry That Has Entered the
                    Result Set. . . . . . . . . . . . . . . . . . . . 12
             4.2.4. Definition of an Entry That Has Changed . . . . . 13
             4.2.5. Definition of an Entry That Has Left the
                    Result Set. . . . . . . . . . . . . . . . . . . . 13
             4.2.6. Results For Entries Present in the Result Set . . 14
             4.2.7. Results For Entries That Have Left the Result
                    Set . . . . . . . . . . . . . . . . . . . . . . . 14
       4.3. Responses Requiring Special Consideration . . . . . . . . 15
             4.3.1. Returning Results During the Persistent Phase . . 15
             4.3.2. No Mixing of Sync Phase with Persist Phase. . . . 16
             4.3.3. Returning Updated Results During the Sync Phase . 16
             4.3.4. Operational Attributes and Administrative
                    Entries . . . . . . . . . . . . . . . . . . . . . 16
             4.3.5. Virtual Attributes. . . . . . . . . . . . . . . . 17
             4.3.6. Modify DN and Delete Operations Applied to
                    Subtrees. . . . . . . . . . . . . . . . . . . . . 17
             4.3.7. Convergence Guarantees. . . . . . . . . . . . . . 18
       4.4.  LCUP Search Termination. . . . . . . . . . . . . . . . . 18
             4.4.1. Server Initiated Termination. . . . . . . . . . . 18
             4.4.2. Client Initiated Termination. . . . . . . . . . . 19
       4.5.  Size and Time Limits . . . . . . . . . . . . . . . . . . 19
       4.6.  Operations on the Same Connection. . . . . . . . . . . . 19
       4.7.  Interactions with Other Controls . . . . . . . . . . . . 19
       4.8.  Replication Considerations . . . . . . . . . . . . . . . 20
   5.  Client Side Considerations . . . . . . . . . . . . . . . . . . 20
       5.1.  Using Cookies with Different Search Criteria . . . . . . 20



Megginson, et al.           Standards Track                     [Page 2]

RFC 3928              LDAP Client Update Protocol           October 2004


       5.2.  Renaming the Base Object . . . . . . . . . . . . . . . . 20
       5.3.  Use of Persistent Searches With Respect to Resources . . 21
       5.4.  Continuation References to Other LCUP Contexts . . . . . 21
       5.5.  Referral Handling. . . . . . . . . . . . . . . . . . . . 21
       5.6.  Multiple Copies of Same Entry During Sync Phase. . . . . 21
       5.7.  Handling Server Out of Resources Condition . . . . . . . 21
   6.  Server Implementation Considerations . . . . . . . . . . . . . 22
       6.1.  Server Support for UUIDs . . . . . . . . . . . . . . . . 22
       6.2.  Example of Using an RUV as the Cookie Value. . . . . . . 22
       6.3.  Cookie Support Issues. . . . . . . . . . . . . . . . . . 22
             6.3.1. Support for Multiple Cookie Schemes . . . . . . . 22
             6.3.2. Information Contained in the Cookie . . . . . . . 23
       6.4.  Persist Phase Response Time. . . . . . . . . . . . . . . 23
       6.5.  Scaling Considerations . . . . . . . . . . . . . . . . . 23
       6.6.  Alias Dereferencing. . . . . . . . . . . . . . . . . . . 24
   7.  Synchronizing Heterogeneous Data Stores. . . . . . . . . . . . 24
   8.  IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 24
   9.  Security Considerations. . . . . . . . . . . . . . . . . . . . 24
   10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 25
       10.1. Normative References . . . . . . . . . . . . . . . . . . 25
       10.2. Informative References . . . . . . . . . . . . . . . . . 26
   11. Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . . 26
   Appendix - Features Left Out of LCUP . . . . . . . . . . . . . . . 27
   Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 29
   Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 30

1.  Overview

   The LCUP protocol is intended to allow LDAP clients to synchronize
   with the content stored by LDAP servers.

   The problem areas addressed by the protocol include:

   -  Mobile clients that maintain a local read-only copy of the
      directory data.  While off-line, the client uses the local copy of
      the data.  When the client connects to the network, it
      synchronizes with the current directory content and can optionally
      receive notification about the changes that occur while it is on-
      line.  For example, a mail client can maintain a local copy of the
      corporate address book that it synchronizes with the master copy
      whenever the client is connected to the corporate network.

   -  Applications intending to synchronize heterogeneous data stores.
      A meta directory application, for instance, would periodically
      retrieve a list of modified entries from the directory, construct
      the changes and apply them to a foreign data store.





Megginson, et al.           Standards Track                     [Page 3]

RFC 3928              LDAP Client Update Protocol           October 2004


   -  Clients that need to take certain actions when a directory entry
      is modified.  For instance, an electronic mail repository may want
      to perform a "create mailbox" task when a new person entry is
      added to an LDAP directory and a "delete mailbox" task when a
      person entry is removed.

   The problem areas not being considered:

   -  Directory server to directory server synchronization.  The IETF is
      developing a LDAP replication protocol, called LDUP [RFC3384],
      which is specifically designed to address this problem area.

   There are currently several protocols in use for LDAP client server
   synchronization.  While each protocol addresses the needs of a
   particular group of clients (e.g., on-line clients or off-line
   clients), none satisfies the requirements of all clients in the
   target group.  For instance, a mobile client that was off-line and
   wants to become up to date with the server and stay up to date while
   connected can't be easily supported by any of the existing protocols.

   LCUP is designed such that the server does not need to maintain state
   information specific to individual clients.  The server may need to
   maintain additional state information about attribute modifications,
   deleted entries, and moved/renamed entries.  The clients are
   responsible for storing the information about how up to date they are
   with respect to the server's content.  LCUP design avoids the need
   for LCUP-specific update agreements to be made between client and
   server prior to LCUP use.  The client decides when and from where to
   retrieve the changes.  LCUP design requires clients to initiate the
   update session and "pull" the changes from server.

   LCUP operations are subject to administrative and access control
   policies enforced by the server.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14, RFC 2119
   [RFC2119].

2.  Applicability

   LCUP will work best if the following conditions are met:

   1) The server stores some degree of historical state or change
      information to reduce the amount of wire traffic required for
      incremental synchronizations.  The optimal balance between server
      state and wire traffic varies amongst implementations and usage
      scenarios, and is therefore left in the hands of implementers.



Megginson, et al.           Standards Track                     [Page 4]

RFC 3928              LDAP Client Update Protocol           October 2004


   2) The client cannot be assumed to understand the physical
      information model (virtual attributes, operational attributes,
      subentries, etc.) implemented by the server.  Optimizations would
      be possible if such assumptions could be made.

   3) Meta data changes and renames and deletions of large subtrees are
      very infrequent.  LCUP makes these assumptions in order to reduce
      client complexity required to deal with these special operations,
      though when they do occur they may result in a large number of
      incremental update messages or a full resync.

3.  Specification of Protocol Elements

   The following sections define the new elements required to use this
   protocol.

3.1.  ASN.1 Considerations

   Protocol elements are described using ASN.1 [X.680].  The term "BER-
   encoded" means the element is to be encoded using the Basic Encoding
   Rules [X.690] under the restrictions detailed in Section 5.1 of
   [RFC2251].  All ASN.1 in this document uses implicit tags.

3.2.  Universally Unique Identifiers

   Distinguished names can change, so are therefore unreliable as
   identifiers.  A Universally Unique Identifier (or UUID for short)
   MUST be used to uniquely identify entries used with LCUP.  The UUID
   is part of the Sync Update control value (see below) returned with
   each search result.  The server SHOULD provide the UUID as a single
   valued operational attribute of the entry (e.g., "entryUUID").  We
   RECOMMEND that the server provides a way to do efficient (i.e.,
   indexed) searches for values of UUID, e.g., by using a search filter
   like (entryUUID=<some UUID value>) to quickly search for and retrieve
   an entry based on its UUID.  Servers SHOULD use a UUID format as
   specified in [UUID].  The UUID used by LCUP is a value of the
   following ASN.1 type:

      LCUPUUID ::= OCTET STRING

3.3.  LCUP Scheme and LCUP Cookie

   The LCUP protocol uses a cookie to hold the state of the client's
   data with respect to the server's data.  Each cookie format is
   uniquely identified by its scheme.  The LCUP Scheme is a value of the
   following ASN.1 type:

      LCUPScheme ::= LDAPOID



Megginson, et al.           Standards Track                     [Page 5]

RFC 3928              LDAP Client Update Protocol           October 2004


   This is the OID which identifies the format of the LCUP Cookie value.
   The scheme OID, as all object identifiers, MUST be unique for a given
   cookie scheme.  The cookie value may be opaque or it may be exposed
   to LCUP clients.   For cookie schemes that expose their value, the
   preferred form of documentation is an RFC.  It is expected that there
   will be one or more standards track cookie schemes where the value
   format is exposed and described in detail.

   The LCUP Cookie is a value of the following ASN.1 type:

      LCUPCookie ::= OCTET STRING

   This is the actual data describing the state of the client's data.
   This value may be opaque, or its value may have some well-known
   format, depending on the scheme.

   Further uses of the LCUP Cookie value are described below.

3.4.  LCUP Context

   A part of the DIT which is enabled for LCUP is referred to as an LCUP
   Context.  A server may support one or more LCUP Contexts.  For
   example, a server with two naming contexts may support LCUP in one
   naming context but not the other, or support different LCUP cookie
   schemes in each naming context.  Each LCUP Context MAY use a
   different cookie scheme.  An LCUP search will not cross an LCUP
   Context boundary, but will instead return a SearchResultReference
   message, with the LDAP URL specifying the same host and port as
   currently being searched, and with the baseDN set to the baseDN of
   the new LCUP Context.  The client is then responsible for issuing
   another search using the new baseDN, and possibly a different cookie
   if that LCUP Context uses a different cookie.  The client is
   responsible for maintaining a mapping of the LDAP URL to its
   corresponding cookie.

3.5.  Additional LDAP Result Codes defined by LCUP

   Implementations of this specification SHALL recognize the following
   additional resultCode values.  The LDAP result code names and numbers
   defined in the following table have been assigned by IANA per RFC
   3383 [RFC3383].

   lcupResourcesExhausted  (113)  the server is running out of resources
   lcupSecurityViolation   (114)  the client is suspected of malicious
                                  actions
   lcupInvalidData         (115)  invalid scheme or cookie was supplied
                                  by the client




Megginson, et al.           Standards Track                     [Page 6]

RFC 3928              LDAP Client Update Protocol           October 2004


   lcupUnsupportedScheme   (116)  The cookie scheme is a valid OID but
                                  is not supported by this server
   lcupReloadRequired      (117)  indicates that client data needs to be
                                  reinitialized.  This reason is
                                  returned if the server does not
                                  contain sufficient information to
                                  synchronize the client or if the
                                  server's data was reloaded since the
                                  last synchronization session

   The uses of these codes are described below.

3.6.  Sync Request Control

   The Sync Request Control is an LDAP Control [RFC2251, Section 4.1.2]
   where the controlType is the object identifier 1.3.6.1.1.7.1 and the
   controlValue, an OCTET STRING, contains a BER-encoded
   syncRequestControlValue.

      syncRequestControlValue ::= SEQUENCE {
         updateType           ENUMERATED {
                                 syncOnly       (0),
                                 syncAndPersist (1),
                                 persistOnly    (2) },
         sendCookieInterval   [0] INTEGER    OPTIONAL,
         scheme               [1] LCUPScheme OPTIONAL,
         cookie               [2] LCUPCookie OPTIONAL
        }

   sendCookieInterval - the server SHOULD send the cookie back in the
   Sync Update control value (defined below) for every
   sendCookieInterval number of SearchResultEntry and
   SearchResultReference PDUs returned to the client.  For example, if
   the value is 5, the server SHOULD send the cookie back in the Sync
   Update control value for every 5 search results returned to the
   client.  If this value is absent, zero or less than zero, the server
   chooses the interval.

   The Sync Request Control is only applicable to the searchRequest
   message.  Use of this control is described below.

3.7.  Sync Update Control

   The Sync Update Control is an LDAP Control [RFC2251, Section 4.1.2]
   where the controlType is the object identifier 1.3.6.1.1.7.2 and the
   controlValue, an OCTET STRING, contains a BER-encoded
   syncUpdateControlValue.




Megginson, et al.           Standards Track                     [Page 7]

RFC 3928              LDAP Client Update Protocol           October 2004


      syncUpdateControlValue ::= SEQUENCE {
         stateUpdate   BOOLEAN,
         entryUUID     [0] LCUPUUID OPTIONAL, -- REQUIRED for entries --
         UUIDAttribute [1] AttributeType OPTIONAL,
         entryLeftSet  [2] BOOLEAN,
         persistPhase  [3] BOOLEAN,
         scheme        [4] LCUPScheme OPTIONAL,
         cookie        [5] LCUPCookie OPTIONAL
      }

   The field UUIDAttribute contains the name or OID of the attribute
   that the client should use to perform searches for entries based on
   the UUID.  The client should be able to use it in an equality search
   filter, e.g., "(<uuid attribute>=<entry UUID value>)" and should be
   able to use it in the attribute list of the search request to return
   its value.  The UUIDAttribute field may be omitted if the server does
   not support searching on the UUID values.

   The Sync Update Control is only applicable to SearchResultEntry and
   SearchResultReference messages.  Although entryUUID is OPTIONAL, it
   MUST be used with SearchResultEntry messages.  Use of this control is
   described below.

3.8.  Sync Done Control

   The Sync Done Control is an LDAP Control [RFC2251, Section 4.1.2]
   where the controlType is the object identifier 1.3.6.1.1.7.3 and the
   controlValue contains a BER-encoded syncDoneValue.

      syncDoneValue ::= SEQUENCE {
         scheme      [0] LCUPScheme OPTIONAL,
         cookie      [1] LCUPCookie OPTIONAL
      }

   The Sync Done Control is only applicable to SearchResultDone message.
   Use of this control is described below.

4.  Protocol Usage and Flow

4.1.  LCUP Search Requests

   A client initiates a synchronization or persistent search session
   with a server by attaching a Sync Request control to an LDAP
   searchRequest message.  The search specification determines the part
   of the directory information tree (DIT) the client wishes to
   synchronize with, the set of attributes it is interested in and the
   amount of data the client is willing to receive.  The Sync Request
   control contains the client's request specification.



Megginson, et al.           Standards Track                     [Page 8]

RFC 3928              LDAP Client Update Protocol           October 2004


   If there is an error condition, the server MUST immediately return a
   SearchResultDone message with the resultCode set to an error code.
   This table maps a condition to its corresponding behavior and
   resultCode.

   Condition                       Behavior or resultCode

   Sync Request Control is not     Server behaves as [RFC2251, Section
   supported                       4.1.2] - specifically, if the
                                   criticality of the control is FALSE,
                                   the server will process the request
                                   as a normal search request

   Scheme is not supported         lcupUnsupportedScheme

   A control value field is        lcupInvalidData
   invalid (e.g., illegal
   updateType, or the scheme is
   not a valid OID, or the cookie
   is invalid)

   Server is running out of        lcupResourcesExhausted
   resources

   Server suspects client of       lcupSecurityViolation
   malicious behavior (frequent
   connects/disconnects, etc.)

   The server cannot bring the     lcupReloadRequired
   client up to date (server data
   has been reloaded, or other
   changes prevent
   convergence)

4.1.1.  Initial Synchronization and Full Resync

   For an initial synchronization or full resync, the fields of the Sync
   Request control MUST be specified as follows:

   updateType         - MUST be set to syncOnly or syncAndPersist
   sendCookieInterval - MAY be set
   scheme             - MAY be set - if set, the server MUST use this
                        specified scheme or return lcupUnsupportedScheme
                        (see above) - if not set, the server MAY use any
                        scheme it supports.
   cookie             - MUST NOT be set





Megginson, et al.           Standards Track                     [Page 9]

RFC 3928              LDAP Client Update Protocol           October 2004


   If the request was successful, the client will receive results as
   described in the section "LCUP Search Responses" below.

4.1.2.  Incremental or Update Synchronization

   For an incremental or update synchronization, the fields of the Sync
   Request control MUST be specified as follows:

   updateType         - MUST be set to syncOnly or syncAndPersist
   sendCookieInterval - MAY be set
   scheme             - MUST be set
   cookie             - MUST be set

   The client SHOULD always use the latest cookie it received from the
   server.

   If the request was successful, the client will receive results as
   described in the section "LCUP Search Responses" below.

4.1.3.  Persistent Only

   For persistent only search request, the fields of the Sync Request
   MUST be specified as follows:

   updateType          - MUST be set to persistOnly
   sendCookieInterval  - MAY be set
   scheme              - MAY be set - if set, the server MUST use this
                         specified scheme or return
                         lcupUnsupportedScheme (see above) - if not set,
                         the server MAY use any scheme it supports.
   cookie              - MAY be set, but the server MUST ignore it

   If the request was successful, the client will receive results as
   described in the section "LCUP Search Responses" below.

4.2.  LCUP Search Responses

   In response to the client's LCUP request, the server returns zero or
   more SearchResultEntry or SearchResultReference PDUs that fit the
   client's specification, followed by a SearchResultDone PDU.  The
   behavior is as specified in [RFC2251 Section 4.5].  Each
   SearchResultEntry or SearchResultReference PDU also contains a Sync
   Update control that describes the LCUP state of the returned entry.
   The SearchResultDone PDU contains a Sync Done control.  The following
   sections specify behaviors in addition to [RFC2251 Section 4.5].






Megginson, et al.           Standards Track                    [Page 10]

RFC 3928              LDAP Client Update Protocol           October 2004


4.2.1 Sync Update Informational Responses

   The server may use the Sync Update control to return information not
   related to a particular entry.  It MAY do this at any time to return
   a cookie to the client, or to inform the client that the sync phase
   of a syncAndPersist search is complete and the persist phase has
   begun.  It MAY do this during the persist phase even though no entry
   has changed that would have normally triggered a response.  In order
   to do this, it is REQUIRED to return the following:

   -  A SearchResultEntry PDU with the objectName field set to the DN of
      the baseObject of the search request and with an empty attribute
      list.

   -  A Sync Update control value with the fields set to the following:

   stateUpdate   - MUST be set to TRUE
   entryUUID     - SHOULD be set to the UUID of the baseObject of the
                   search request
   entryLeftSet  - MUST be set to FALSE
   persistPhase  - MUST be FALSE if the search is in the sync phase of a
                   request, and MUST be TRUE if the search is in the
                   persist phase
   UUIDAttribute - SHOULD only be set if this is either the first result
                   returned or if the attribute has changed
   scheme        - MUST be set if the cookie is set and the cookie
                   format has changed; otherwise, it MAY be omitted
   cookie        - SHOULD be set

   If the server merely wants to return a cookie to the client, it
   should return as above with the cookie field set.

   During a syncAndPersist request, the server MUST return (as above)
   immediately after the last entry of the sync phase has been sent and
   before the first entry of the persist phase has been sent.  In this
   case, the persistPhase field MUST be set to TRUE.  This allows the
   client to know that the sync phase is complete and the persist phase
   is starting.

4.2.2 Cookie Return Frequency

   The cookie field of the Sync Update control value MAY be set in any
   returned result, during both the sync phase and the persist phase.
   The server should return the cookie to the client often enough for
   the client to resync in a reasonable period of time in case the
   search is disconnected or otherwise terminated.  The
   sendCookieInterval field in the Sync Request control is a suggestion




Megginson, et al.           Standards Track                    [Page 11]

RFC 3928              LDAP Client Update Protocol           October 2004


   to the server of how often to return the cookie in the Sync Update
   control.  The server SHOULD respect this value.

   The scheme field of the Sync Update control value MUST be set if the
   cookie is set and the cookie format has changed; otherwise, it MAY be
   omitted.

   Some clients may have unreliable connections, for example, a wireless
   device or a WAN connection.  These clients may want to insure that
   the cookie is returned often in the Sync Update control value, so
   that if they have to reconnect, they do not have to process many
   redundant entries.  These clients should set the sendCookieInterval
   in the Sync Request control value to a low number, perhaps even 1.
   Some clients may have a limited bandwidth connection, and may not
   want to receive the cookie very often, or even at all (however, the
   cookie is always sent back in the Sync Done control value upon
   successful completion).  These clients should set the
   sendCookieInterval in the Sync Request control value to a high
   number.

   A reasonable behavior of the server is to return the cookie only when
   data in the LCUP context has changed, even if the client has
   specified a frequent sendCookieInterval.  If nothing has changed, the
   server can probably save some bandwidth by not returning the cookie.

4.2.3.  Definition of an Entry That Has Entered the Result Set

   An entry SHALL BE considered to have entered the client's search
   result set if one of the following conditions is met:

   -  During the sync phase for an incremental sync operation, the entry
      is present in the search result set but was not present before;
      this can be due to the entry being added via an LDAP Add
      operation, or by the entry being moved into the result set by an
      LDAP Modify DN operation, or by some modification to the entry
      that causes it to enter the result set (e.g., adding an attribute
      value that matches the clients search filter), or by some meta-
      data change that causes the entry to enter the result set (e.g.,
      relaxing of some access control that permits the entry to be
      visible to the client).

   -  During the persist phase for a persistent search operation, the
      entry enters the search result set; this can be due to the entry
      being added via an LDAP Add operation, or by the entry being moved
      into the result set by an LDAP Modify DN operation, or by some
      modification to the entry that causes it to enter the result set
      (e.g., adding an attribute value that matches the clients search
      filter), or by some meta-data change that causes the entry to



Megginson, et al.           Standards Track                    [Page 12]

RFC 3928              LDAP Client Update Protocol           October 2004


      enter the result set (e.g., relaxing of some access control that
      permits the entry to be visible to the client).

4.2.4.  Definition of an Entry That Has Changed

   An entry SHALL BE considered to be changed if one or more of the
   attributes in the attribute list in the search request have been
   modified.  For example, if the search request listed the attributes
   "cn sn uid", and there is an entry in the client's search result set
   with the "cn" attribute that has been modified, the entry is
   considered to be modified.  The modification may be due to an LDAP
   Modify operation or by some change to the meta-data for the entry
   (e.g., virtual attributes) that causes some change to the value of
   the specified attributes.

   The converse of this is that an entry SHALL NOT BE considered to be
   changed if none of the attributes in the attribute list of the search
   request are modified attributes of the entry.  For example, if the
   search request listed the attributes "cn sn uid", and there is an
   entry in the client's search result set with the "foo" attribute that
   has been modified, and none of the "cn" or "sn" or "uid" attributes
   have been modified, the entry is NOT considered to be changed.

4.2.5.  Definition of an Entry That Has Left the Result Set

   An entry SHALL BE considered to have left the client's search result
   set if one of the following conditions is met:

   -  During the sync phase for an incremental sync operation, the entry
      is not present in the search result set but was present before;
      this can be due to the entry being deleted via an LDAP Delete
      operation, or by the entry leaving the result set via an LDAP
      Modify DN operation, or by some modification to the entry that
      causes it to leave the result set (e.g., changing/removing an
      attribute value so that it no longer matches the client's search
      filter), or by some meta-data change that causes the entry to
      leave the result set (e.g., adding of some access control that
      denies the entry to be visible to the client).

   -  During the persist phase for a persistent search operation, the
      entry leaves the search result set; this can be due to the entry
      being deleted via an LDAP Delete operation, or by the entry
      leaving the result set via an LDAP Modify DN operation, or by some
      modification to the entry that causes it to leave the result set
      (e.g., changing/removing an attribute value so that it no longer
      matches the client's search filter), or by some meta-data change





Megginson, et al.           Standards Track                    [Page 13]

RFC 3928              LDAP Client Update Protocol           October 2004


      that causes the entry to leave the result set (e.g., adding of
      some access control that denies the entry to be visible to the
      client).

4.2.6.  Results For Entries Present in the Result Set

   An entry SHOULD be returned as present under the following
   conditions:

   -  The request is an initial synchronization or full resync request
      and the entry is present in the client's search result set

   -  The request is an incremental synchronization and the entry has
      changed or entered the result set since the last sync

   -  The search is in the persist phase and the entry enters the result
      set or changes

   For a SearchResultEntry return, the fields of the Sync Update control
   value MUST be set as follows:

   stateUpdate   - MUST be set to FALSE
   entryUUID     - MUST be set to the UUID of the entry
   entryLeftSet  - MUST be set to FALSE
   persistPhase  - MUST be set to FALSE if during the sync phase or TRUE
                   if during the persist phase
   UUIDAttribute - SHOULD only be set if this is either the first result
                   returned or if the attribute has changed
   scheme        - as above
   cookie        - as above

   The searchResultReference return will look the same, except that the
   entryUUID is not required.  If it is specified, it MUST contain the
   UUID of the DSE holding the reference knowledge.

4.2.7.  Results For Entries That Have Left the Result Set

   An entry SHOULD be returned as having left the result set under the
   following conditions:

   -  The request is an incremental synchronization during the sync
      phase and the entry has left the result set

   -  The search is in the persist phase and the entry has left the
      result set






Megginson, et al.           Standards Track                    [Page 14]

RFC 3928              LDAP Client Update Protocol           October 2004


   -  The entry has left the result set as a result of an LDAP Delete or
      LDAP Modify DN operation against the entry itself (i.e., not as a
      result of an operation against its parent or ancestor)

   For a SearchResultEntry return where the entry has left the result
   set, the fields of the Sync Update control value MUST be set as
   follows:

   stateUpdate   - MUST be set to FALSE
   entryUUID     - MUST be set to the UUID of the entry that left the
                   result set
   entryLeftSet  - MUST be set to TRUE
   persistPhase  - MUST be set to FALSE if during the sync phase or TRUE
                   if during the persist phase
   UUIDAttribute - SHOULD only be set if this is either the first result
                   returned or if the attribute has changed
   scheme        - as above
   cookie        - as above

   The searchResultReference return will look the same, except that the
   entryUUID is not required.  If it is specified, it MUST contain the
   UUID of the DSE holding the reference knowledge.

   Some server implementations keep track of deleted entries using a
   tombstone - a hidden entry that keeps track of the state, but not all
   of the data, of an entry that has been deleted.  In this case, the
   tombstone may not contain all of the original attributes of the
   entry, and therefore it may be impossible for the server to determine
   if an entry should be removed from the result set based on the
   attributes in the client's search request.  Servers SHOULD keep
   enough information about the attributes in the deleted entries to
   determine if an entry should be removed from the result set.  Since
   this may not be possible, the server MAY return an entry as having
   left the result set even if it is not or never was in the client's
   result set.  Clients MUST ignore these notifications.

4.3.  Responses Requiring Special Consideration

   The following sections describe special handling that may be required
   when returning results.

4.3.1.  Returning Results During the Persistent Phase

   During the persistent phase, the server SHOULD return the changed
   entries to the client as quickly as possible.






Megginson, et al.           Standards Track                    [Page 15]

RFC 3928              LDAP Client Update Protocol           October 2004


4.3.2.  No Mixing of Sync Phase with Persist Phase

   During a sync phase, the server MUST NOT return any entries with the
   persistPhase flag set to TRUE, and during the persist phase, all
   entries returned MUST have the persistPhase flag set to TRUE.  The
   server MUST NOT mix and match sync phase entries with persist phase
   entries.  If there are any sync phase entries to return, they MUST be
   returned before any persist phase entries are returned.

4.3.3.  Returning Updated Results During the Sync Phase

   There may be updates to the entries in the result set of a sync phase
   search during the actual search operation.  If the DSA is under a
   heavy update load, and it attempts to send all of those updated
   entries to the client in addition to the other updates it was already
   planning to send for the sync phase, the server may never get to the
   end of the sync phase.  Therefore, it is left up to the discretion of
   the server implementation to decide when the client is "in sync" -
   that is, when to end a syncOnly request, or when to send the Sync
   Update Informational Response between the sync phase and the persist
   phase of a syncAndPersist request.  The server MAY send the same
   entry multiple times during the sync phase if the entry changes
   during the sync phase.

   A reasonable behavior is for the server to generate a cookie based on
   the server state at the time the client initiated the LCUP request,
   and only send entries up to that point during the sync phase. Entries
   updated after that point will be returned only during the persist
   phase of a syncAndPersist request, or only upon an incremental
   synchronization.

4.3.4.  Operational Attributes and Administrative Entries

   An operational attribute SHOULD be returned if it is specified in the
   attributes list and would normally be returned as subject to the
   constraints of [RFC2251 Section 4.5].  If the server does not support
   syncing of operational attributes, the server MUST return a
   SearchResultDone message with a resultCode of unwillingToPerform.

   LDAP Subentries [RFC3672] SHOULD be returned if they would normally
   be returned by the search request.  If the server does not support
   syncing of LDAP Subentries, and the server can determine from the
   search request that the client has requested LDAP Subentries to be
   returned (e.g., search control or search filter), the server MUST
   return a SearchResultDone message with a resultCode of
   unwillingToPerform.  Otherwise, the server MAY simply omit returning
   LDAP Subentries.




Megginson, et al.           Standards Track                    [Page 16]

RFC 3928              LDAP Client Update Protocol           October 2004


4.3.5.  Virtual Attributes

   An entry may have attributes whose presence in the entry, or presence
   of values of the attribute, is generated on the fly, possibly by some
   mechanism outside of the entry, elsewhere in the DIT.  An example of
   this is collective attributes [RFC3671].  These attributes shall be
   referred to in this document as virtual attributes.

   LCUP treats these attributes the same way as normal, non-virtual
   attributes.  A virtual attribute SHOULD be returned if it is
   specified in the attributes list and would normally be returned as
   subject to the constraints of [RFC2251 Section 4.5].  If the server
   does not support syncing of virtual attributes, the server MUST
   return a SearchResultDone message with a resultCode of
   unwillingToPerform.

   One consequence of this is that if you change the definition of a
   virtual attribute such that it makes the value of that attribute
   change in many entries in the client's search scope, this means that
   a server may have to return many entries to the client as a result of
   that one change.  It is not anticipated that this will be a frequent
   occurrence, and the server has the option to simply force the client
   to resync if necessary.

   It is also possible that a future LDAP control will allow the client
   to request only virtual or only non-virtual attributes.

4.3.6.  Modify DN and Delete Operations Applied to Subtrees

   There is a special case where a Modify DN or a Delete operation is
   applied to the base entry of a subtree, and either that base entry or
   entries in the subtree are within the scope of an LCUP search
   request.  In this case, all of the entries in the subtree are
   implicitly renamed or removed.

   In either of these cases, the server MUST do one of the following:

   -  treat all of these entries as having been renamed or removed and
      return each entry to the client as such

   -  decide that this would be prohibitively expensive, and force the
      client to resync

   If the search base object has been renamed, and the client has
   received a noSuchObject as the result of a search request, the client
   MAY use the entryUUID and UUIDAttribute to locate the new DN that is
   the result of the modify DN operation.




Megginson, et al.           Standards Track                    [Page 17]

RFC 3928              LDAP Client Update Protocol           October 2004


4.3.7.  Convergence Guarantees

   If at any time during an LCUP search, either during the sync phase or
   the persist phase, the server determines that it cannot guarantee
   that it can bring the client's copy of the data to eventual
   convergence, it SHOULD immediately terminate the LCUP search request
   and return a SearchResultDone message with a resultCode of
   lcupReloadRequired.  This can also happen at the beginning of an
   incremental synchronization request, if the client presents a cookie
   that is out of date or otherwise unable to be processed.  The client
   should then issue an initial synchronization request.

   This can happen, for example, if the data on the server is reloaded,
   or if there has been some change to the meta-data that makes it
   impossible for the server to determine if a particular entry should
   or should not be part of the search result set, or if the meta-data
   change makes it too resource intensive for the server to calculate
   the proper result set.

   The server can also return lcupReloadRequired if it determines that
   it would be more efficient for the client to perform a reload, for
   example, if too many entries have changed and a simple reload would
   be much faster.

4.4.  LCUP Search Termination

4.4.1.  Server Initiated Termination

   When the server has successfully finished processing the client's
   request, it attaches a Sync Done control to the SearchResultDone
   message and sends it to the client.  However, if the SearchResultDone
   message contains a resultCode that is not success or canceled, the
   Sync Done control MAY be omitted.  Although the LCUP cookie is
   OPTIONAL in the Sync Done control value, it MUST be set if the
   SearchResultDone resultCode is success or canceled.  The server
   SHOULD also set the cookie if the resultCode is
   lcupResourcesExhausted, timeLimitExceeded, sizeLimitExceeded, or
   adminLimitExceeded.  This allows the client to more easily resync
   later.  If some error occurred, either an LDAP search error (e.g.,
   insufficientAccessRights) or an LCUP error (e.g.,
   lcupUnsupportedScheme), the cookie MAY be omitted.  If the cookie is
   set, the scheme MUST be set also if the cookie format has changed,
   otherwise, it MAY be omitted.

   If server resources become tight, the server can terminate one or
   more search operations by sending a SearchResultDone message to the
   client(s) with a resultCode of lcupResourcesExhausted.  The server
   SHOULD attach a Sync Done control with the cookie set.  A server side



Megginson, et al.           Standards Track                    [Page 18]

RFC 3928              LDAP Client Update Protocol           October 2004


   policy is used to decide which searches to terminate.  This can also
   be used as a security mechanism to disconnect clients that are
   suspected of malicious actions, but if the server can infer that the
   client is malicious, the server SHOULD return lcupSecurityViolation
   instead.

4.4.2.  Client Initiated Termination

   If the client needs to terminate the synchronization process and it
   wishes to obtain the cookie that represents the current state of its
   data, it issues an LDAP Cancel operation [RFC3909].  The server
   responds immediately with a LDAP Cancel response [RFC3909].  The
   server MAY send any pending SearchResultEntry or
   SearchResultReference PDUs if the server cannot easily abort or
   remove those search results from its outgoing queue.  The server
   SHOULD send as few of these remaining messages as possible.  Finally,
   the server sends the message SearchResultDone with the Sync Done
   control attached.  If the search was successful up to that point, the
   resultCode field of the SearchResultDone message MUST be canceled
   [RFC3909], and the cookie MUST be set in the Sync Done control.  If
   there is an error condition, the server MAY return as described in
   section 4.4.1 above, or MAY return as described in [RFC3909].

   If the client is not interested in the state information, it can
   simply abandon the search operation or disconnect from the server.

4.5.  Size and Time Limits

   The server SHALL support size and time limits as specified in
   [RFC2251, Section 5].  The server SHOULD ensure that if the operation
   is terminated due to these conditions, the cookie is sent back to the
   client.

4.6.  Operations on the Same Connection

   It is permissible for the client to issue other LDAP operations on
   the connection used by the protocol.  Since each LDAP
   request/response carries a message id there will be no ambiguity
   about which PDU belongs to which operation.  By sharing the
   connection among multiple operations, the server will be able to
   conserve its resources.

4.7.  Interactions with Other Controls

   LCUP defines neither restrictions nor guarantees about the ability to
   use the controls defined in this document in conjunction with other
   LDAP controls, except for the following: A server MAY ignore non-
   critical controls supplied with the LCUP control.  A server MAY



Megginson, et al.           Standards Track                    [Page 19]

RFC 3928              LDAP Client Update Protocol           October 2004


   ignore an LCUP defined control if it is non-critical and it is
   supplied with other critical controls.  If a server receives a
   critical LCUP control with another critical control, and the server
   does not support both controls at the same time, the server SHOULD
   return unavailableCriticalExtension.

   It is up to the server implementation to determine if the server
   supports controls such as the Sort or VLV or similar controls that
   change the order of the entries sent to the client.  But note that it
   may be difficult or impossible for a server to perform an incremental
   synchronization in the presence of such controls, since the cookie
   will typically be based off a change number, or Change Sequence
   Number (CSN), or timestamp, or some criteria other than an
   alphabetical order.

4.8.  Replication Considerations

   Use of an LCUP cookie with multiple DSAs in a replicated environment
   is not defined by LCUP.   An implementation of LCUP may support
   continuation of an LCUP session with another DSA holding a replica of
   the LCUP context.  Clients MAY submit cookies returned by one DSA to
   a different DSA; it is up to the server to determine if a cookie is
   one they recognize or not and to return an appropriate result code if
   not.

5.  Client Side Considerations

5.1.  Using Cookies with Different Search Criteria

   The cookie received from the server after a synchronization session
   SHOULD only be used with the same search specification as the search
   that generated the cookie.  Some servers MAY allow the cookie to be
   used with a more restrictive search specification than the search
   that generated the cookie.  If the server does not support the
   cookie, it MUST return lcupInvalidCookie.  This is because the client
   can end up with an incomplete data store otherwise.  A more
   restrictive search specification is one that would generate a subset
   of the data produced by the original search specification.

5.2.  Renaming the Base Object

   Because an LCUP client specifies the area of the tree with which it
   wishes to synchronize through the standard LDAP search specification,
   the client can be returned noSuchObject error if the root of the
   synchronization area was renamed between the synchronization sessions
   or during a synchronization session.  If this condition occurs, the
   client can attempt to locate the root by using the root's UUID saved
   in client's local data store.  It then can repeat the synchronization



Megginson, et al.           Standards Track                    [Page 20]

RFC 3928              LDAP Client Update Protocol           October 2004


   request using the new search base.  In general, a client can detect
   that an entry was renamed and apply the changes received to the right
   entry by using the UUID rather than DN based addressing.

5.3.  Use of Persistent Searches With Respect to Resources

   Each active persistent operation requires that an open TCP connection
   be maintained between an LDAP client and an LDAP server that might
   not otherwise be kept open.  Therefore, client implementors are
   encouraged to avoid using persistent operations for non-essential
   tasks and to close idle LDAP connections as soon as practical.  The
   server may close connections if server resources become tight.

5.4.  Continuation References to Other LCUP Contexts

   The client MAY receive a continuation reference
   (SearchResultReference [RFC2251 SECTION 4.5.3]) if the search request
   spans multiple parts of the DIT, some of which may require a
   different LCUP cookie, some of which may not even be managed by LCUP.
   The client SHOULD maintain a cache of the LDAP URLs returned in the
   continuation references and the cookies associated with them.  The
   client is responsible for performing another LCUP search to follow
   the references, and SHOULD use the cookie corresponding to the LDAP
   URL for that reference (if it has a cookie).

5.5.  Referral Handling

   The client may receive a referral (Referral [RFC2251 SECTION 4.1.11])
   when the search base is a subordinate reference, and this will end
   the operation.

5.6.  Multiple Copies of Same Entry During Sync Phase

   The server MAY send the same entry multiple times during a sync phase
   if the entry changes during the sync phase.  The client SHOULD use
   the last sent copy of the entry as the current one.

5.7.  Handling Server Out of Resources Condition

   If the client receives an lcupResourcesExhausted or
   lcupSecurityViolation resultCode, the client SHOULD wait at least 5
   seconds before attempting another operation.  It is RECOMMENDED that
   the client use an exponential backoff strategy, but different clients
   may want to use different backoff strategies.







Megginson, et al.           Standards Track                    [Page 21]

RFC 3928              LDAP Client Update Protocol           October 2004


6.  Server Implementation Considerations

6.1.  Server Support for UUIDs

   Servers MUST support UUIDs.  UUIDs are required in the Sync Update
   control.  Additionally, server implementers SHOULD make the UUID
   values for the entries available as an attribute of the entry, and
   provide indexing or other mechanisms to allow clients to search for
   an entry using the UUID attribute in the search filter.  The
   syncUpdate control provides a field UUIDAttribute to allow the server
   to let the client know the name or OID of the attribute to use to
   search for an entry by UUID.

6.2.  Example of Using an RUV as the Cookie Value

   By design, the protocol supports multiple cookie schemes.  This is to
   allow different implementations the flexibility of storing any
   information applicable to their environment.  A reasonable
   implementation for an LDUP compliant server would be to use the
   Replica Update Vector (RUV).  For each master, RUV contains the
   largest CSN seen from this master.  In addition, RUV implemented by
   some directory servers (not yet in LDUP) contains replica generation
   - an opaque string that identifies the replica's data store.  The
   replica generation value changes whenever the replica's data is
   reloaded.  Replica generation is intended to signal the
   replication/synchronization peers that the replica's data was
   reloaded and that all other replicas need to be reinitialized.  RUV
   satisfies the three most important properties of the cookie: (1) it
   uniquely identifies the state of client's data, (2) it can be used to
   synchronize with multiple servers, and (3) it can be used to detect
   that the server's data was reloaded.  If RUV is used as the cookie,
   entries last modified by a particular master must be sent to the
   client in the order of their last modified CSN.  This ordering
   guarantees that the RUV can be updated after each entry is sent.

6.3. Cookie Support Issues

6.3.1.  Support for Multiple Cookie Schemes

   A server may support one or more LCUP cookie schemes.  It is expected
   that schemes will be published along with their OIDs as RFCs.  The
   server's DIT may be partitioned into different sections which may
   have different cookies associated with them.  For example, some
   servers may use some sort of replication mechanism to support LCUP.
   If so, the DIT may be partitioned into multiple replicas.  A client
   may send an LCUP search request that spans multiple replicas.  Some
   parts of the DIT spanned by the search request scope may support LCUP
   and some may not.  The server MUST send a SearchResultReference



Megginson, et al.           Standards Track                    [Page 22]

RFC 3928              LDAP Client Update Protocol           October 2004


   [RFC2251, SECTION 4.5.3] when the LCUP Context for a returned entry
   changes.  The server SHOULD send all references to other LCUP
   Contexts in the search scope first, in order to allow the clients to
   process these searches in parallel.  The LDAP URL(s) returned MUST
   contain the DN(s) of the base of another section of the DIT (however
   the server implementation has partitioned the DIT).  The client will
   then issue another LCUP search using the LDAP URL returned.  Each
   section of the DIT MAY require a different cookie value, so the
   client SHOULD maintain a cache, mapping the different LDAP URL values
   to different cookies.  If the cookie changes, the scheme may change
   as well, but the cookie scheme MUST be the same within a given LCUP
   Context.

6.3.2.  Information Contained in the Cookie

   The cookie must contain enough information to allow the server to
   determine whether the cookie can be safely used with the search
   specification it is attached to.  As discussed earlier in the
   document, the cookie SHOULD only be used with the search
   specification that is equal to the one for which the cookie was
   generated, but some servers MAY support using a cookie with a search
   specification that is more restrictive than the one used to generate
   the cookie.

6.4.  Persist Phase Response Time

   The specification makes no guarantees about how soon a server should
   send notification of a changed entry to the client during the persist
   phase.  This is intentional as any specific maximum delay would be
   impossible to meet in a distributed directory service implementation.
   Server implementers are encouraged to minimize the delay before
   sending notifications to ensure that clients' needs for timeliness of
   change notification are met.

6.5.  Scaling Considerations

   Implementers of servers that support the mechanism described in this
   document should ensure that their implementation scales well as the
   number of active persistent operations and the number of changes made
   in the directory increases.  Server implementers are also encouraged
   to support a large number of client connections if they need to
   support large numbers of persistent operations.









Megginson, et al.           Standards Track                    [Page 23]

RFC 3928              LDAP Client Update Protocol           October 2004


6.6.  Alias Dereferencing

   LCUP design does not consider issues associated with alias
   dereferencing in search.  Clients MUST specify derefAliases as either
   neverDerefAliases or derefFindingBaseObj.  Servers are to return
   protocolError if the client specifies either derefInSearching or
   derefAlways.

7.  Synchronizing Heterogeneous Data Stores

   Clients, like a meta directory join engine, synchronizing multiple
   writable data stores, will only work correctly if each piece of
   information comes from a single authoritative data source.  In a
   replicated environment, an LCUP Context should employ the same
   conflict resolution scheme across all its replicas.  This is because
   different systems have different notions of time and different update
   resolution procedures.  As a result, a change applied on one system
   can be discarded by the other, thus preventing the data stores from
   converging.

8.  IANA Considerations

   This document lists several values that have been registered by the
   IANA.  The following LDAP result codes have been assigned by IANA as
   described in section 3.6 of [RFC3383]:

      lcupResourcesExhausted    113
      lcupSecurityViolation     114
      lcupInvalidData           115
      lcupUnsupportedScheme     116
      lcupReloadRequired        117

   The three controls defined in this document have been registered as
   LDAP Protocol Mechanisms as described in section 3.2 of [RFC3383].
   One OID, 1.3.6.1.1.7, has been assigned by IANA as described in
   section 3.1 of [RFC3383].  The OIDs for the controls defined in this
   document are derived as follows from the one assigned by IANA:

      LCUP Sync Request Control    1.3.6.1.1.7.1
      LCUP Sync Update Control     1.3.6.1.1.7.2
      LCUP Sync Done Control       1.3.6.1.1.7.3

9.  Security Considerations

   In some situations, it may be important to prevent general exposure
   of information about changes that occur in an LDAP server. Therefore,
   servers that implement the mechanism described in this document
   SHOULD provide a means to enforce access control on the entries



Megginson, et al.           Standards Track                    [Page 24]

RFC 3928              LDAP Client Update Protocol           October 2004


   returned and MAY also provide specific access control mechanisms to
   control the use of the controls and extended operations defined in
   this document.

   As with normal LDAP search requests, a malicious client can initiate
   a large number of persistent search requests in an attempt to consume
   all available server resources and deny service to legitimate
   clients.  The protocol provides the means to stop malicious clients
   by disconnecting them from the server.  The servers that implement
   the mechanism SHOULD provide the means to detect the malicious
   clients. In addition, the servers SHOULD provide the means to limit
   the number of resources that can be consumed by a single client.

10.  References

10.1.  Normative References

   [RFC2119]    Bradner, S., "Key words for use in RFCs to Indicate
                Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251]    Wahl, M., Howes, T., and S. Kille, "Lightweight
                Directory Access Protocol (v3)", RFC 2251, December
                1997.

   [RFC3383]    Zeilenga, K., "Internet Assigned Numbers Authority
                (IANA) Considerations for Lightweight Directory Access
                Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [RFC3909]    Zeilenga, K., "Lightweight Directory Access Protocol
                (LDAP) Cancel Operation", RFC 3909, October 2004.

   [X.680]      ITU-T, "Abstract Syntax Notation One (ASN.1) -
                Specification of Basic Notation", X.680, 1994.

   [X.690]      ITU-T, "Specification of ASN.1 encoding rules:  Basic,
                Canonical, and Distinguished Encoding Rules", X.690,
                1994.

   [UUID]       International Organization for Standardization (ISO),
                "Information technology - Open Systems Interconnection -
                Remote Procedure Call", ISO/IEC 11578:1996.










Megginson, et al.           Standards Track                    [Page 25]

RFC 3928              LDAP Client Update Protocol           October 2004


10.2.  Informative References

   [RFC3384]    Stokes, E., Weiser, R., Moats, R., and R. Huber,
                "Lightweight Directory Access Protocol (version 3)
                Replication Requirements", RFC 3384, October 2002.

   [RFC3671]    Zeilenga, K., "Collective Attributes in the Lightweight
                Directory Access Protocol (LDAP)", RFC 3671, December
                2003.

   [RFC3672]    Zeilenga, K. and S. Legg, "Subentries in the Lightweight
                Directory Access Protocol (LDAP)", RFC 3672, December
                2003.

11.  Acknowledgments

   The LCUP protocol is based in part on the Persistent Search Change
   Notification Mechanism defined by Mark Smith, Gordon Good, Tim Howes,
   and Rob Weltman, the LDAPv3 Triggered Search Control defined by Mark
   Wahl, and the LDAP Control for Directory Synchronization defined by
   Michael Armijo.  The members of the IETF LDUP working group made
   significant contributions to this document.





























Megginson, et al.           Standards Track                    [Page 26]

RFC 3928              LDAP Client Update Protocol           October 2004


Appendix - Features Left Out of LCUP

   There are several features present in other protocols or considered
   useful by clients that are currently not included in the protocol
   primarily because they are difficult to implement on the server.
   These features are briefly discussed in this section.

Triggered Search Change Type

   This feature is present in the Triggered Search specification.  A
   flag is attached to each entry returned to the client indicating the
   reason why this entry is returned.  The possible reasons from the
   document are:

   -  notChange: the entry existed in the directory and matched the
      search at the time the operation is being performed,

   -  enteredSet: the entry entered the result,

   -  leftSet: the entry left the result,

   -  modified: the entry was part of the result set, was modified or
      renamed, and still is in the result set.

   The leftSet feature is particularly useful because it indicates to
   the client that an entry is no longer within the client's search
   specification and the client can remove the associated data from its
   data store.  Ironically, this feature is the hardest to implement on
   the server because the server does not keep track of the client's
   state and has no easy way of telling which entries moved out of scope
   between synchronization sessions with the client.  A compromise could
   be reached by only providing this feature for the operations that
   occur while the client is connected to the server.  This is easier to
   accomplish because the decision about the change type can be made
   based only on the change without need for any historical information.
   This, however, would add complexity to the protocol.

Persistent Search Change Type

   This feature is present in the Persistent Search specification.
   Persistent search has the notion of changeTypes.  The client
   specifies which type of updates will cause entries to be returned,
   and optionally whether the server tags each returned entry with the
   type of change that caused that entry to be returned.

   For LCUP, the intention is full synchronization, not partial.  Each
   entry returned by an LCUP search will have some change associated
   with it that may concern the client.  The client may have to have a



Megginson, et al.           Standards Track                    [Page 27]

RFC 3928              LDAP Client Update Protocol           October 2004


   local index of entries by DN or UUID to determine if the entry has
   been added or just modified.  It is easy for clients to determine if
   the entry has been deleted because the entryLeftSet value of the Sync
   Update control will be TRUE.

Sending Changes

   Some earlier synchronization protocols sent the client(s) only the
   modified attributes of the entry rather than the entire entry.  While
   this approach can significantly reduce the amount of data returned to
   the client, it has several disadvantages.  First, unless a separate
   mechanism (like the change type described above) is used to notify
   the client about entries moving into the search scope, sending only
   the changes can result in the client having an incomplete version of
   the data.  Let's consider an example.  An attribute of an entry is
   modified.  As a result of the change, the entry enters the scope of
   the client's search.  If only the changes are sent, the client would
   never see the initial data of the entry.  Second, this feature is
   hard to implement since the server might not contain sufficient
   information to construct the changes based solely on the server's
   state and the client's cookie.  On the other hand, this feature can
   be easily implemented by the client assuming that the client has the
   previous version of the data and can perform value by value
   comparisons.

Data Size Limits

   Some earlier synchronization protocols allowed clients to control the
   amount of data sent to them in the search response.  This feature was
   intended to allow clients with limited resources to process
   synchronization data in batches.  However, an LDAP search operation
   already provides the means for the client to specify the size limit
   by setting the sizeLimit field in the SearchRequest to the maximum
   number of entries the client is willing to receive.  While the
   granularity is not the same, the assumption is that regular LDAP
   clients that can deal with the limitations of the LDAP protocol will
   implement LCUP.

Data Ordering

   Some earlier synchronization protocols allowed a client to specify
   that parent entries should be sent before the children for add
   operations and children entries sent before their parents during
   delete operations.  This ordering helps clients to maintain a
   hierarchical view of the data in their data store.  While possibly
   useful, this feature is relatively hard to implement and is expensive
   to perform.




Megginson, et al.           Standards Track                    [Page 28]

RFC 3928              LDAP Client Update Protocol           October 2004


Authors' Addresses

   Rich Megginson
   Netscape Communications Corp., an America Online company.
   360 W. Caribbean Drive
   Sunnyvale, CA 94089
   USA

   Phone: +1 505 797-7762
   EMail: rmegginson0224@aol.com


   Olga Natkovich
   Yahoo, Inc.
   701 First Ave.
   Sunnyvale, CA 94089
   USA

   Phone: +1 408 349-6153
   EMail: olgan@yahoo-inc.com


   Mark Smith
   Pearl Crescent, LLC
   447 Marlpool Drive
   Saline, MI 48176
   USA

   Phone: +1 734 944-2856
   EMail: mcs@pearlcrescent.com


   Jeff Parham
   Microsoft Corporation
   One Microsoft Way
   Redmond, WA 98052-6399
   USA

   Phone: +1 425 882-8080
   EMail: jeffparh@microsoft.com











Megginson, et al.           Standards Track                    [Page 29]

RFC 3928              LDAP Client Update Protocol           October 2004


Full Copyright Statement

   Copyright (C) The Internet Society (2004).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and at www.rfc-editor.org, and except as set
   forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the ISOC's procedures with respect to rights in ISOC Documents can
   be found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at ietf-
   ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.







Megginson, et al.           Standards Track                    [Page 30]

alt-openldap11-devel/rfc/rfc4528.txt000064400000030373150410163220012773 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4528                           OpenLDAP Foundation
Category: Standards Track                                      June 2006


              Lightweight Directory Access Protocol (LDAP)
                           Assertion Control


Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document defines the Lightweight Directory Access Protocol
   (LDAP) Assertion Control, which allows a client to specify that a
   directory operation should only be processed if an assertion applied
   to the target entry of the operation is true.  It can be used to
   construct "test and set", "test and clear", and other conditional
   operations.

Table of Contents

   1. Overview ........................................................2
   2. Terminology .....................................................2
   3. The Assertion Control ...........................................2
   4. Security Considerations .........................................3
   5. IANA Considerations .............................................4
      5.1. Object Identifier ..........................................4
      5.2. LDAP Protocol Mechanism ....................................4
      5.3. LDAP Result Code ...........................................4
   6. Acknowledgements ................................................5
   7. References ......................................................5
      7.1. Normative References .......................................5
      7.2. Informative References .....................................5







Zeilenga                    Standards Track                     [Page 1]

RFC 4528                 LDAP Assertion Control                June 2006


1.  Overview

   This document defines the Lightweight Directory Access Protocol
   (LDAP) [RFC4510] assertion control.  The assertion control allows the
   client to specify a condition that must be true for the operation to
   be processed normally.  Otherwise, the operation is not performed.
   For instance, the control can be used with the Modify operation
   [RFC4511] to perform atomic "test and set" and "test and clear"
   operations.

   The control may be attached to any update operation to support
   conditional addition, deletion, modification, and renaming of the
   target object.  The asserted condition is evaluated as an integral
   part the operation.

   The control may also be used with the search operation.  Here, the
   assertion is applied to the base object of the search before
   searching for objects that match the search scope and filter.

   The control may also be used with the compare operation.  Here, it
   extends the compare operation to allow a more complex assertion.

2. Terminology

   Protocol elements are described using ASN.1 [X.680] with implicit
   tags.  The term "BER-encoded" means the element is to be encoded
   using the Basic Encoding Rules [X.690] under the restrictions
   detailed in Section 5.1 of [RFC4511].

   DSA stands for Directory System Agent (or server).
   DSE stands for DSA-specific Entry.

   In this document, the key words "MUST", "MUST NOT", "REQUIRED",
   "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
   and "OPTIONAL" are to be interpreted as described in BCP 14
   [RFC2119].

3.  The Assertion Control

   The assertion control is an LDAP Control [RFC4511] whose controlType
   is 1.3.6.1.1.12 and whose controlValue is a BER-encoded Filter
   [Protocol, Section 4.5.1].  The criticality may be TRUE or FALSE.
   There is no corresponding response control.

   The control is appropriate for both LDAP interrogation and update
   operations [RFC4511], including Add, Compare, Delete, Modify,
   ModifyDN (rename), and Search.  It is inappropriate for Abandon,
   Bind, Unbind, and StartTLS operations.



Zeilenga                    Standards Track                     [Page 2]

RFC 4528                 LDAP Assertion Control                June 2006


   When the control is attached to an LDAP request, the processing of
   the request is conditional on the evaluation of the Filter as applied
   against the target of the operation.  If the Filter evaluates to
   TRUE, then the request is processed normally.  If the Filter
   evaluates to FALSE or Undefined, then assertionFailed (122)
   resultCode is returned, and no further processing is performed.

   For Add, Compare, and ModifyDN operations, the target is indicated by
   the entry field in the request.  For Modify operations, the target is
   indicated by the object field.  For Delete operations, the target is
   indicated by the DelRequest type.  For Compare operations and all
   update operations, the evaluation of the assertion MUST be performed
   as an integral part of the operation.  That is, the evaluation of the
   assertion and the normal processing of the operation SHALL be done as
   one atomic action.

   For Search operations, the target is indicated by the baseObject
   field, and the evaluation is done after "finding" but before
   "searching" [RFC4511].  Hence, no entries or continuations references
   are returned if the assertion fails.

   Servers implementing this technical specification SHOULD publish the
   object identifier 1.3.6.1.1.12 as a value of the 'supportedControl'
   attribute [RFC4512] in their root DSE.  A server MAY choose to
   advertise this extension only when the client is authorized to use
   it.

   Other documents may specify how this control applies to other LDAP
   operations.  In doing so, they must state how the target entry is
   determined.

4.  Security Considerations

   The filter may, like other components of the request, contain
   sensitive information.  When it does, this information should be
   appropriately protected.

   As with any general assertion mechanism, the mechanism can be used to
   determine directory content.  Hence, this mechanism SHOULD be subject
   to appropriate access controls.

   Some assertions may be very complex, requiring significant time and
   resources to evaluate.  Hence, this mechanism SHOULD be subject to
   appropriate administrative controls.







Zeilenga                    Standards Track                     [Page 3]

RFC 4528                 LDAP Assertion Control                June 2006


   Security considerations for the base operations [RFC4511] extended by
   this control, as well as general LDAP security considerations
   [RFC4510], generally apply to implementation and use of this
   extension.

5.  IANA Considerations

5.1.  Object Identifier

   The IANA has assigned an LDAP Object Identifier [RFC4520] to identify
   the LDAP Assertion Control defined in this document.

       Subject: Request for LDAP Object Identifier Registration
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Specification: RFC 4528
       Author/Change Controller: IESG
       Comments:
           Identifies the LDAP Assertion Control

5.2.  LDAP Protocol Mechanism

   Registration of this protocol mechanism [RFC4520] is requested.

       Subject: Request for LDAP Protocol Mechanism Registration
       Object Identifier: 1.3.6.1.1.12
       Description: Assertion Control
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@openldap.org>
       Usage: Control
       Specification: RFC 4528
       Author/Change Controller: IESG
       Comments: none

5.3.  LDAP Result Code

   The IANA has assigned an LDAP Result Code [RFC4520] called
   'assertionFailed' (122).

       Subject: LDAP Result Code Registration
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Result Code Name: assertionFailed
       Specification: RFC 4528
       Author/Change Controller: IESG
       Comments:  none





Zeilenga                    Standards Track                     [Page 4]

RFC 4528                 LDAP Assertion Control                June 2006


6.  Acknowledgements

   The assertion control concept is attributed to Morteza Ansari.

7.  References

7.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(2002) (also ISO/IEC 8824-1:2002).

   [X.690]       International Telecommunication Union -
                 Telecommunication Standardization Sector,
                 "Specification of ASN.1 encoding rules: Basic Encoding
                 Rules (BER), Canonical Encoding Rules (CER), and
                 Distinguished Encoding Rules (DER)", X.690(2002) (also
                 ISO/IEC 8825-1:2002).

7.2.  Informative References

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org





Zeilenga                    Standards Track                     [Page 5]

RFC 4528                 LDAP Assertion Control                June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                     [Page 6]

alt-openldap11-devel/rfc/rfc4525.txt000064400000025763150410163220012777 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4525                           OpenLDAP Foundation
Category: Informational                                        June 2006


              Lightweight Directory Access Protocol (LDAP)
                       Modify-Increment Extension


Status of This Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document describes an extension to the Lightweight Directory
   Access Protocol (LDAP) Modify operation to support an increment
   capability.  This extension is useful in provisioning applications,
   especially when combined with the assertion control and/or the pre-
   read or post-read control extension.

Table of Contents

   1. Background and Intended Use .....................................1
   2. The Modify-Increment Extension ..................................2
   3. LDIF Support ....................................................2
   4. Security Considerations .........................................3
   5. IANA Considerations .............................................3
      5.1. Object Identifier ..........................................3
      5.2. LDAP Protocol Mechanism ....................................3
      5.3. LDAP Protocol Mechanism ....................................4
   6. References ......................................................4
      6.1. Normative References .......................................4
      6.2. Informative References .....................................5

1.  Background and Intended Use

   The Lightweight Directory Access Protocol (LDAP) [RFC4510] does not
   currently provide an operation to increment values of an attribute.
   A client must read the values of the attribute and then modify those
   values to increment them by the desired amount.  As the values may be
   updated by other clients between this add and modify, the client must



Zeilenga                     Informational                      [Page 1]

RFC 4525            LDAP Modify-Increment Extension            June 2006


   be careful to construct the modify request so that it fails in this
   case, and upon failure, to re-read the values and construct a new
   modify request.

   This document extends the LDAP Modify Operation [RFC4511] to support
   an increment values capability.  This feature is intended to be used
   with either the LDAP pre-read or post-read control extensions
   [RFC4527].  This feature may also be used with the LDAP assertion
   control extension [RFC4528] to provide test-and-increment
   functionality.

   In this document key words "MUST", "MUST NOT", "REQUIRED", "SHALL",
   "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
   "OPTIONAL" are to be interpreted as described in BCP 14 [RFC2119].

2.  The Modify-Increment Extension

   This document extends the LDAP Modify request to support a increment
   values capability.  Implementations of this extension SHALL support
   an additional ModifyRequest operation enumeration value increment
   (3), as described herein.  Implementations not supporting this
   extension will treat this value as they would an unlisted value,
   e.g., as a protocol error.

   The increment (3) operation value specifies that an increment values
   modification is requested.  All existing values of the modification
   attribute are to be incremented by the listed value.  The
   modification attribute must be appropriate for the request (e.g., it
   must have INTEGER or other increment-able values), and the
   modification must provide one and only one value.  If the attribute
   is not appropriate for the request, a constraintViolation or other
   appropriate error is to be returned.  If multiple values are
   provided, a protocolError is to be returned.

   Servers supporting this feature SHOULD publish the object identifier
   (OID) 1.3.6.1.1.14  as a value of the 'supportedFeatures' [RFC4512]
   attribute in the root DSE.  Clients supporting this feature SHOULD
   NOT use the feature unless they know the server supports it.

3. LDIF Support

   To represent Modify-Increment requests in LDAP Data Interchange
   Format [RFC2849], the ABNF [RFC4234] production <mod-spec> is
   extended as follows:

       mod-spec =/ "increment:" FILL AttributeDescription SEP
            attrval-spec "-" SEP




Zeilenga                     Informational                      [Page 2]

RFC 4525            LDAP Modify-Increment Extension            June 2006


   For example,

       # Increment uidNumber
       dn: cn=max-assigned uidNumber,dc=example,dc=com
       changetype: modify
       increment: uidNumber
       uidNumber: 1
       -

   This LDIF fragment represents a Modify request to increment the
   value(s) of uidNumber by 1.

4.  Security Considerations

   General LDAP security considerations [RFC4510], as well as those
   specific to the LDAP Modify [RFC4511], apply to this Modify-Increment
   extension.  Beyond these considerations, it is noted that
   introduction of this extension should reduce application complexity
   (by providing one operation for what presently requires multiple
   operations) and, hence, it may aid in the production of correct and
   secure implementations.

5.  IANA Considerations

   Registration of the following values [RFC4520] have been completed.

5.1.  Object Identifier

   The IANA has assigned an LDAP Object Identifier to identify the LDAP
   Modify-Increment feature, as defined in this document.

       Subject: Request for LDAP Object Identifier Registration
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Specification: RFC 4525
       Author/Change Controller: Author
       Comments:
           Identifies the LDAP Modify-Increment feature

5.2.  LDAP Protocol Mechanism

   The following LDAP Protocol Mechanism has been registered.

       Subject: Request for LDAP Protocol Mechanism Registration
       Object Identifier: 1.3.6.1.1.14
       Description: Modify-Increment
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@openldap.org>



Zeilenga                     Informational                      [Page 3]

RFC 4525            LDAP Modify-Increment Extension            June 2006


       Usage: Feature
       Specification: RFC 4525
       Author/Change Controller: Kurt Zeilenga <kurt@openldap.org>
       Comments: none

5.3.  LDAP Protocol Mechanism

   The IANA has assigned an LDAP ModifyRequest Operation Type (3)
   [RFC4520] for use in this document.

       Subject: Request for LDAP Protocol Mechanism Registration
       ModifyRequest Operation Name: increment
       Description: Modify-Increment
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@openldap.org>
       Usage: Feature
       Specification: RFC 4525
       Author/Change Controller: Kurt Zeilenga <kurt@openldap.org>
       Comments: none

6.  References

6.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4234]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
                 Specifications: ABNF", RFC 4234, October 2005.

   [RFC2849]     Good, G., "The LDAP Data Interchange Format (LDIF) -
                 Technical Specification", RFC 2849, June 2000.

   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.








Zeilenga                     Informational                      [Page 4]

RFC 4525            LDAP Modify-Increment Extension            June 2006


6.2.  Informative References

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [RFC4527]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP) Read Entry Controls", RFC 4527, June 2006.

   [RFC4528]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP) Assertion Control", RFC 4528, June 2006.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org

































Zeilenga                     Informational                      [Page 5]

RFC 4525            LDAP Modify-Increment Extension            June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                     Informational                      [Page 6]

alt-openldap11-devel/rfc/rfc2079.txt000064400000021065150410163220012770 0ustar00





Network Working Group                                          M. Smith
Request for Comments: 2079                      Netscape Communications
Category: Standards Track                                  January 1997


   Definition of an X.500 Attribute Type and an Object Class to Hold
                  Uniform Resource Identifiers (URIs)

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Abstract

   Uniform Resource Locators (URLs) are being widely used to specify the
   location of Internet resources.  There is an urgent need to be able
   to include URLs in directories that conform to the LDAP and X.500
   information models, and a desire to include other types of Uniform
   Resource Identifiers (URIs) as they are defined.  A number of
   independent groups are already experimenting with the inclusion of
   URLs in LDAP and X.500 directories.  This document builds on the
   experimentation to date and defines a new attribute type and an
   auxiliary object class to allow URIs, including URLs, to be stored in
   directory entries in a standard way.

Background and Intended Usage

   Uniform Resource Locators (URLs) as defined by [1] are the first of
   several types of Uniform Resource Identifiers (URIs) being defined by
   the IETF.  URIs are widely used on the Internet, most notably within
   Hypertext Markup Language [2] documents. This document defines an
   X.500 [3,4] attribute type called labeledURI and an auxiliary object
   class called labeledURIObject to hold all types of URIs, including
   URLs.  These definitions are designed for use in LDAP and X.500
   directories, and may be used in other contexts as well.












Smith                       Standards Track                     [Page 1]

RFC 2079          URI Attribute Type and Object Class       January 1997


Schema Definition of the labeledURI Attribute Type

   Name:             labeledURI
   ShortName:        None
   Description:      Uniform Resource Identifier with optional label
   OID:              umichAttributeType.57 (1.3.6.1.4.1.250.1.57)
   Syntax:           caseExactString
   SizeRestriction:  None
   SingleValued:     False

Discussion of the labeledURI Attribute Type

   The labeledURI attribute type has the caseExactString syntax (since
   URIs are case-sensitive) and it is multivalued.  Values placed in the
   attribute should consist of a URI (at the present time, a URL)
   optionally followed by one or more space characters and a label.
   Since space characters are not allowed to appear un-encoded in URIs,
   there is no ambiguity about where the label begins.  At the present
   time, the URI portion must comply with the URL specification [1].
   Multiple labeledURI values will generally indicate different
   resources that are all related to the X.500 object, but may indicate
   different locations for the same resource.

   The label is used to describe the resource to which the URI points,
   and is intended as a friendly name fit for human consumption.  This
   document does not propose any specific syntax for the label part.  In
   some cases it may be helpful to include in the label some indication
   of the kind and/or size of the resource referenced by the URI.

   Note that the label may include any characters allowed by the
   caseExactString syntax, but that the use of non-IA5 (non-ASCII)
   characters is discouraged as not all directory clients may handle
   them in the same manner.  If non-IA5 characters are included, they
   should be represented using the X.500 conventions, not the HTML
   conventions (e.g., the character that is an "a" with a ring above it
   should be encoded using the T.61 sequence 0xCA followed by an "a"
   character; do not use the HTML escape sequence "&aring").

Examples of labeledURI Attribute Values

   An example of a labeledURI attribute value that does not include a
   label:

                   ftp://ds.internic.net/rfc/rfc822.txt







Smith                       Standards Track                     [Page 2]

RFC 2079          URI Attribute Type and Object Class       January 1997


   An example of a labeledURI attribute value that contains a tilde
   character in the URL (special characters in a URL must be encoded as
   specified by the URL document [1]).  The label is "LDAP Home Page":

             http://www.umich.edu/%7Ersug/ldap/ LDAP Home Page

   Another example.  This one includes a hint in the label to help the
   user realize that the URL points to a photo image.

        http://champagne.inria.fr/Unites/rennes.gif Rennes [photo]

Schema Definition of the labeledURIObject Object Class

   Name:              labeledURIObject
   Description:       object that contains the URI attribute type
   OID:               umichObjectClass.15 (1.3.6.1.4.1.250.3.15)
   SubclassOf:        top
   MustContain:
   MayContain:        labeledURI

Discussion of the labeledURIObject Object Class

   The labeledURIObject class is a subclass of top and may contain the
   labeledURI attribute.  The intent is that this object class can be
   added to existing directory objects to allow for inclusion of URI
   values.  This approach does not preclude including the labeledURI
   attribute type directly in other object classes as appropriate.

Security Considerations

   Security considerations are not discussed in this memo, except to
   note that blindly inserting the label portion of a labeledURI
   attribute value into an HTML document is not recommended, as this may
   allow a malicious individual to include HTML tags in the label that
   mislead viewers of the entire document in which the labeledURI value
   was inserted.

Acknowledgments

   Paul-Andre Pays, Martijn Koster, Tim Howes, Rakesh Patel, Russ
   Wright, and Hallvard Furuseth provided invaluable assistance in the
   creation of this document.

   This material is based in part upon work supported by the National
   Science Foundation under Grant No. NCR-9416667.






Smith                       Standards Track                     [Page 3]

RFC 2079          URI Attribute Type and Object Class       January 1997


Appendix:  The labeledURL Attribute Type (Deprecated)

   An earlier draft of this document defined an additional attribute
   type called labeledURL.  This attribute type is deprecated, and
   should not be used when adding new values to directory entries.  The
   original motivation for including a separate attribute type to hold
   URLs was that this would better enable efficient progammatic access
   to specific types of URIs.  After some deliberation, the IETF-ASID
   working group concluded that it was better to simply have one
   attribute than two.

   The schema definition for labeledURL is included here for historical
   reference only.  Directory client software may want to support this
   schema definition (in addition to labeledURI) to ease the transition
   away from labeledURL for those sites that are using it.

   Name:             labeledURL
   ShortName:        None
   Description:      Uniform Resource Locator with optional label
   OID:              umichAttributeType.41 (1.3.6.1.4.1.250.1.41)
   Syntax:           caseExactString
   SizeRestriction:  None
   SingleValued:     False
   OID:              umichAttributeType.41 (1.3.6.1.4.1.250.1.41)

References

   [1] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform
   Resource Locators (URL)", RFC 1738, CERN, Xerox Corporation,
   University of Minnesota, December 1994.
   <URL:ftp://ds.internic.net/rfc/rfc1738.txt>

   [2] Berners-Lee, T., and D. Connolly, "Hypertext Markup Language -
   2.0", RFC 1866, <URL:ftp://ds.internic.net/rfc/rfc1866.txt>

   [3] The Directory: Overview of Concepts, Models and Service.  CCITT
   Recommendation X.500, 1988.

   [4] Information Processing Systems -- Open Systems Interconnection --
   The Directory: Overview of Concepts, Models and Service.  ISO/IEC JTC
   1/SC21; International Standard 9594-1, 1988.










Smith                       Standards Track                     [Page 4]

RFC 2079          URI Attribute Type and Object Class       January 1997


Author's Address

   Mark Smith
   Netscape Communications Corp.
   501 E. Middlefield Rd.
   Mountain View, CA 94043, USA

   Phone:  +1 415 937-3477
   EMail:  mcs@netscape.com










































Smith                       Standards Track                     [Page 5]

alt-openldap11-devel/rfc/rfc4515.txt000064400000056515150410163220012775 0ustar00





Network Working Group                                      M. Smith, Ed.
Request for Comments: 4515                           Pearl Crescent, LLC
Obsoletes: 2254                                                 T. Howes
Category: Standards Track                                  Opsware, Inc.
                                                               June 2006


             Lightweight Directory Access Protocol (LDAP):
                String Representation of Search Filters

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   Lightweight Directory Access Protocol (LDAP) search filters are
   transmitted in the LDAP protocol using a binary representation that
   is appropriate for use on the network.  This document defines a
   human-readable string representation of LDAP search filters that is
   appropriate for use in LDAP URLs (RFC 4516) and in other
   applications.

Table of Contents

   1. Introduction ....................................................2
   2. LDAP Search Filter Definition ...................................2
   3. String Search Filter Definition .................................3
   4. Examples ........................................................5
   5. Security Considerations .........................................7
   6. Normative References ............................................7
   7. Informative References ..........................................8
   8. Acknowledgements ................................................8
   Appendix A: Changes Since RFC 2254 .................................9
      A.1. Technical Changes ..........................................9
      A.2. Editorial Changes ..........................................9







Smith and Howes             Standards Track                     [Page 1]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


1.  Introduction

   The Lightweight Directory Access Protocol (LDAP) [RFC4510] defines a
   network representation of a search filter transmitted to an LDAP
   server.  Some applications may find it useful to have a common way of
   representing these search filters in a human-readable form; LDAP URLs
   [RFC4516] are an example of one such application.  This document
   defines a human-readable string format for representing the full
   range of possible LDAP version 3 search filters, including extended
   match filters.

   This document is a integral part of the LDAP technical specification
   [RFC4510], which obsoletes the previously defined LDAP technical
   specification, RFC 3377, in its entirety.

   This document replaces RFC 2254.  Changes to RFC 2254 are summarized
   in Appendix A.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

2.  LDAP Search Filter Definition

   An LDAP search filter is defined in Section 4.5.1 of [RFC4511] as
   follows:

        Filter ::= CHOICE {
            and                [0] SET SIZE (1..MAX) OF filter Filter,
            or                 [1] SET SIZE (1..MAX) OF filter Filter,
            not                [2] Filter,
            equalityMatch      [3] AttributeValueAssertion,
            substrings         [4] SubstringFilter,
            greaterOrEqual     [5] AttributeValueAssertion,
            lessOrEqual        [6] AttributeValueAssertion,
            present            [7] AttributeDescription,
            approxMatch        [8] AttributeValueAssertion,
            extensibleMatch    [9] MatchingRuleAssertion }

        SubstringFilter ::= SEQUENCE {
            type    AttributeDescription,
            -- initial and final can occur at most once
            substrings    SEQUENCE SIZE (1..MAX) OF substring CHOICE {
             initial        [0] AssertionValue,
             any            [1] AssertionValue,
             final          [2] AssertionValue } }





Smith and Howes             Standards Track                     [Page 2]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


        AttributeValueAssertion ::= SEQUENCE {
            attributeDesc   AttributeDescription,
            assertionValue  AssertionValue }

        MatchingRuleAssertion ::= SEQUENCE {
            matchingRule    [1] MatchingRuleId OPTIONAL,
            type            [2] AttributeDescription OPTIONAL,
            matchValue      [3] AssertionValue,
            dnAttributes    [4] BOOLEAN DEFAULT FALSE }

        AttributeDescription ::= LDAPString
                        -- Constrained to <attributedescription>
                        -- [RFC4512]

        AttributeValue ::= OCTET STRING

        MatchingRuleId ::= LDAPString

        AssertionValue ::= OCTET STRING

        LDAPString ::= OCTET STRING -- UTF-8 encoded,
                                    -- [Unicode] characters

   The AttributeDescription, as defined in [RFC4511], is a string
   representation of the attribute description that is discussed in
   [RFC4512].  The AttributeValue and AssertionValue OCTET STRING have
   the form defined in [RFC4517].  The Filter is encoded for
   transmission over a network using the Basic Encoding Rules (BER)
   defined in [X.690], with simplifications described in [RFC4511].

3.  String Search Filter Definition

   The string representation of an LDAP search filter is a string of
   UTF-8 [RFC3629] encoded Unicode characters [Unicode] that is defined
   by the following grammar, following the ABNF notation defined in
   [RFC4234].  The productions used that are not defined here are
   defined in Section 1.4 (Common ABNF Productions) of [RFC4512] unless
   otherwise noted.  The filter format uses a prefix notation.

      filter         = LPAREN filtercomp RPAREN
      filtercomp     = and / or / not / item
      and            = AMPERSAND filterlist
      or             = VERTBAR filterlist
      not            = EXCLAMATION filter
      filterlist     = 1*filter
      item           = simple / present / substring / extensible
      simple         = attr filtertype assertionvalue
      filtertype     = equal / approx / greaterorequal / lessorequal



Smith and Howes             Standards Track                     [Page 3]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


      equal          = EQUALS
      approx         = TILDE EQUALS
      greaterorequal = RANGLE EQUALS
      lessorequal    = LANGLE EQUALS
      extensible     = ( attr [dnattrs]
                           [matchingrule] COLON EQUALS assertionvalue )
                       / ( [dnattrs]
                            matchingrule COLON EQUALS assertionvalue )
      present        = attr EQUALS ASTERISK
      substring      = attr EQUALS [initial] any [final]
      initial        = assertionvalue
      any            = ASTERISK *(assertionvalue ASTERISK)
      final          = assertionvalue
      attr           = attributedescription
                         ; The attributedescription rule is defined in
                         ; Section 2.5 of [RFC4512].
      dnattrs        = COLON "dn"
      matchingrule   = COLON oid
      assertionvalue = valueencoding
      ; The <valueencoding> rule is used to encode an <AssertionValue>
      ; from Section 4.1.6 of [RFC4511].
      valueencoding  = 0*(normal / escaped)
      normal         = UTF1SUBSET / UTFMB
      escaped        = ESC HEX HEX
      UTF1SUBSET     = %x01-27 / %x2B-5B / %x5D-7F
                          ; UTF1SUBSET excludes 0x00 (NUL), LPAREN,
                          ; RPAREN, ASTERISK, and ESC.
      EXCLAMATION    = %x21 ; exclamation mark ("!")
      AMPERSAND      = %x26 ; ampersand (or AND symbol) ("&")
      ASTERISK       = %x2A ; asterisk ("*")
      COLON          = %x3A ; colon (":")
      VERTBAR        = %x7C ; vertical bar (or pipe) ("|")
      TILDE          = %x7E ; tilde ("~")

   Note that although both the <substring> and <present> productions in
   the grammar above can produce the "attr=*" construct, this construct
   is used only to denote a presence filter.

   The <valueencoding> rule ensures that the entire filter string is a
   valid UTF-8 string and provides that the octets that represent the
   ASCII characters "*" (ASCII 0x2a), "(" (ASCII 0x28), ")" (ASCII
   0x29), "\" (ASCII 0x5c), and NUL (ASCII 0x00) are represented as a
   backslash "\" (ASCII 0x5c) followed by the two hexadecimal digits
   representing the value of the encoded octet.







Smith and Howes             Standards Track                     [Page 4]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


   This simple escaping mechanism eliminates filter-parsing ambiguities
   and allows any filter that can be represented in LDAP to be
   represented as a NUL-terminated string.  Other octets that are part
   of the <normal> set may be escaped using this mechanism, for example,
   non-printing ASCII characters.

   For AssertionValues that contain UTF-8 character data, each octet of
   the character to be escaped is replaced by a backslash and two hex
   digits, which form a single octet in the code of the character.  For
   example, the filter checking whether the "cn" attribute contained a
   value with the character "*" anywhere in it would be represented as
   "(cn=*\2a*)".

   As indicated by the <valueencoding> rule, implementations MUST escape
   all octets greater than 0x7F that are not part of a valid UTF-8
   encoding sequence when they generate a string representation of a
   search filter.  Implementations SHOULD accept as input strings that
   are not valid UTF-8 strings.  This is necessary because RFC 2254 did
   not clearly define the term "string representation" (and in
   particular did not mention that the string representation of an LDAP
   search filter is a string of UTF-8-encoded Unicode characters).

4.  Examples

   This section gives a few examples of search filters written using
   this notation.

        (cn=Babs Jensen)
        (!(cn=Tim Howes))
        (&(objectClass=Person)(|(sn=Jensen)(cn=Babs J*)))
        (o=univ*of*mich*)
        (seeAlso=)

   The following examples illustrate the use of extensible matching.

        (cn:caseExactMatch:=Fred Flintstone)
        (cn:=Betty Rubble)
        (sn:dn:2.4.6.8.10:=Barney Rubble)
        (o:dn:=Ace Industry)
        (:1.2.3:=Wilma Flintstone)
        (:DN:2.4.6.8.10:=Dino)

   The first example shows use of the matching rule "caseExactMatch."

   The second example demonstrates use of a MatchingRuleAssertion form
   without a matchingRule.





Smith and Howes             Standards Track                     [Page 5]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


   The third example illustrates the use of the ":oid" notation to
   indicate that the matching rule identified by the OID "2.4.6.8.10"
   should be used when making comparisons, and that the attributes of an
   entry's distinguished name should be considered part of the entry
   when evaluating the match (indicated by the use of ":dn").

   The fourth example denotes an equality match, except that DN
   components should be considered part of the entry when doing the
   match.

   The fifth example is a filter that should be applied to any attribute
   supporting the matching rule given (since the <attr> has been
   omitted).

   The sixth and final example is also a filter that should be applied
   to any attribute supporting the matching rule given.  Attributes
   supporting the matching rule contained in the DN should also be
   considered.

   The following examples illustrate the use of the escaping mechanism.

        (o=Parens R Us \28for all your parenthetical needs\29)
        (cn=*\2A*)
        (filename=C:\5cMyFile)
        (bin=\00\00\00\04)
        (sn=Lu\c4\8di\c4\87)
        (1.3.6.1.4.1.1466.0=\04\02\48\69)

   The first example shows the use of the escaping mechanism to
   represent parenthesis characters.  The second shows how to represent
   a "*" in an assertion value, preventing it from being interpreted as
   a substring indicator.  The third illustrates the escaping of the
   backslash character.

   The fourth example shows a filter searching for the four-octet value
   00 00 00 04 (hex), illustrating the use of the escaping mechanism to
   represent arbitrary data, including NUL characters.

   The fifth example illustrates the use of the escaping mechanism to
   represent various non-ASCII UTF-8 characters.  Specifically, there
   are 5 characters in the <assertionvalue> portion of this example:
   LATIN CAPITAL LETTER L (U+004C), LATIN SMALL LETTER U (U+0075), LATIN
   SMALL LETTER C WITH CARON (U+010D), LATIN SMALL LETTER I (U+0069),
   and LATIN SMALL LETTER C WITH ACUTE (U+0107).

   The sixth and final example demonstrates assertion of a BER-encoded
   value.




Smith and Howes             Standards Track                     [Page 6]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


5.  Security Considerations

   This memo describes a string representation of LDAP search filters.
   While the representation itself has no known security implications,
   LDAP search filters do.  They are interpreted by LDAP servers to
   select entries from which data is retrieved.  LDAP servers should
   take care to protect the data they maintain from unauthorized access.

   Please refer to the Security Considerations sections of [RFC4511] and
   [RFC4513] for more information.

6.  Normative References

   [RFC2119]   Bradner, S., "Key words for use in RFCs to Indicate
               Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3629]   Yergeau, F., "UTF-8, a transformation format of ISO
               10646", STD 63, RFC 3629, November 2003.

   [RFC4234]   Crocker, D. and P. Overell, "Augmented BNF for Syntax
               Specifications: ABNF", RFC 4234, October 2005.

   [RFC4510]   Zeilenga, K., Ed., "Lightweight Directory Access Protocol
               (LDAP): Technical Specification Road Map", RFC 4510, June
               2006.

   [RFC4511]   Sermersheim, J., Ed., "Lightweight Directory Access
               Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]   Zeilenga, K., "Lightweight Directory Access Protocol
               (LDAP): Directory Information Models", RFC 4512, June
               2006.

   [RFC4513]   Harrison, R., Ed., "Lightweight Directory Access Protocol
               (LDAP): Authentication Methods and Security Mechanisms",
               RFC 4513, June 2006.

   [RFC4517]   Legg, S., Ed., "Lightweight Directory Access Protocol
               (LDAP): Syntaxes and Matching Rules", RFC 4517, June
               2006.

   [Unicode]   The Unicode Consortium, "The Unicode Standard, Version
               3.2.0" is defined by "The Unicode Standard, Version 3.0"
               (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-61633-5),
               as amended by the "Unicode Standard Annex #27: Unicode
               3.1" (http://www.unicode.org/reports/tr27/) and by the
               "Unicode Standard Annex #28: Unicode 3.2."




Smith and Howes             Standards Track                     [Page 7]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


7.  Informative References

   [RFC4516]   Smith, M., Ed. and T. Howes, "Lightweight Directory
               Access Protocol (LDAP): Uniform Resource Locator", RFC
               4516, June 2006.

   [X.690]     Specification of ASN.1 encoding rules: Basic, Canonical,
               and Distinguished Encoding Rules, ITU-T Recommendation
               X.690, 1994.

8.  Acknowledgements

   This document replaces RFC 2254 by Tim Howes.  RFC 2254 was a product
   of the IETF ASID Working Group.

   Changes included in this revised specification are based upon
   discussions among the authors, discussions within the LDAP (v3)
   Revision Working Group (ldapbis), and discussions within other IETF
   Working Groups.  The contributions of individuals in these working
   groups is gratefully acknowledged.































Smith and Howes             Standards Track                     [Page 8]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


Appendix A: Changes Since RFC 2254

A.1.  Technical Changes

   Replaced [ISO 10646] reference with [Unicode].

   The following technical changes were made to the contents of the
   "String Search Filter Definition" section:

   Added statement that the string representation is a string of UTF-8-
   encoded Unicode characters.

   Revised all of the ABNF to use common productions from [RFC4512].

   Replaced the "value" rule with a new "assertionvalue" rule within the
   "simple", "extensible", and "substring" ("initial", "any", and
   "final") rules.  This matches a change made in [RFC4517].

   Added "(" and ")" around the components of the <extensible>
   subproductions for clarity.

   Revised the "attr", "matchingrule", and "assertionvalue" ABNF to more
   precisely reference productions from the [RFC4512] and [RFC4511]
   documents.

   "String Search Filter Definition" section: replaced "greater" and
   "less" with "greaterorequal" and "lessorequal" to avoid confusion.

   Introduced the "valueencoding" and associated "normal" and "escaped"
   rules to reduce the dependence on descriptive text.  The "normal"
   production restricts filter strings to valid UTF-8 sequences.

   Added a statement about expected behavior in light of RFC 2254's lack
   of a clear definition of "string representation."

A.2.  Editorial Changes

   Changed document title to include "LDAP:" prefix.

   IESG Note: removed note about lack of satisfactory mandatory
   authentication mechanisms.

   Header and "Authors' Addresses" sections: added Mark Smith as the
   document editor and updated affiliation and contact information.

   "Table of Contents" and "Intellectual Property" sections: added.

   Copyright: updated per latest IETF guidelines.



Smith and Howes             Standards Track                     [Page 9]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


   "Abstract" section: separated from introductory material.

   "Introduction" section: new section; separated from the Abstract.
   Updated second paragraph to indicate that RFC 2254 is replaced by
   this document (instead of RFC 1960).  Added reference to the
   [RFC4510] document.

   "LDAP Search Filter Definition" section: made corrections to the LDAP
   search filter ABNF so it matches that used in [RFC4511].

   Clarified the definition of 'value' (now 'assertionvalue') to take
   into account the fact that it is not precisely an AttributeAssertion
   from [RFC4511] Section 4.1.6 (special handling is required for some
   characters).  Added a note that each octet of a character to be
   escaped is replaced by a backslash and two hex digits, which
   represent a single octet.

   "Examples" section: added four additional examples: (seeAlso=),
   (cn:=Betty Rubble), (:1.2.3:=Wilma Flintstone), and
   (1.3.6.1.4.1.1466.0=\04\02\48\69).  Replaced one occurrence of "a
   value" with "an assertion value".  Corrected the description of this
   example: (sn:dn:2.4.6.8.10:=Barney Rubble).  Replaced the numeric OID
   in the first extensible match example with "caseExactMatch" to
   demonstrate use of the descriptive form.  Used "DN" (uppercase) in
   the last extensible match example to remind the reader to treat the
   <dnattrs> production as case insensitive.  Reworded the description
   of the fourth escaping mechanism example to avoid making assumptions
   about byte order.  Added text to the fifth escaping mechanism example
   to spell out what the non-ASCII characters are in Unicode terms.

   "Security Considerations" section: added references to [RFC4511] and
   [RFC4513].

   "Normative References" section: renamed from "References" per new RFC
   guidelines.  Changed from [1] style to [RFC4511] style throughout the
   document.  Added entries for [Unicode], [RFC2119], [RFC4513],
   [RFC4512], and [RFC4510] and updated the UTF-8 reference.  Replaced
   RFC 822 reference with a reference to RFC 4234.

   "Informative References" section: (new section) moved [X.690] to this
   section.  Added a reference to [RFC4516].

   "Acknowledgements" section: added.

   "Appendix A: Changes Since RFC 2254" section: added.

   Surrounded the names of all ABNF productions with "<" and ">" where
   they are used in descriptive text.



Smith and Howes             Standards Track                    [Page 10]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


   Replaced all occurrences of "LDAPv3" with "LDAP."

Authors' Addresses

   Mark Smith, Editor
   Pearl Crescent, LLC
   447 Marlpool Dr.
   Saline, MI 48176
   USA

   Phone: +1 734 944-2856
   EMail: mcs@pearlcrescent.com


   Tim Howes
   Opsware, Inc.
   599 N. Mathilda Ave.
   Sunnyvale, CA 94085
   USA

   Phone: +1 408 744-7509
   EMail: howes@opsware.com





























Smith and Howes             Standards Track                    [Page 11]

RFC 4515     LDAP: String Representation of Search Filters     June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Smith and Howes             Standards Track                    [Page 12]

alt-openldap11-devel/rfc/rfc2649.txt000064400000047766150410163220013013 0ustar00





Network Working Group                                       B. Greenblatt
Request for Comments: 2649                                     P. Richard
Category: Experimental                                        August 1999


      An LDAP Control and Schema for Holding Operation Signatures

Status of this Memo

   This memo defines an Experimental Protocol for the Internet
   community.  It does not specify an Internet standard of any kind.
   Discussion and suggestions for improvement are requested.
   Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

Abstract

   In many environments clients require the ability to validiate the
   source and integrity of information provided by the directory.  This
   document describes an LDAP message control which allows for the
   retrieval of digitally signed information. This document defines an
   LDAP v3 based mechanism for signing directory operations in order to
   create a secure journal of changes that have been made to each
   directory entry.  Both client and server based signatures are
   supported.  An object class for subsequent retrieval are "journal
   entries" is also defined.  This document specifies LDAP v3 controls
   that enable this functionality.  It also defines an LDAP v3 schema
   that allows for subsequent browsing of the journal information.

Table of Contents

   1. Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   2
   1.1 Audit Trail Mechanism  . . . . . . . . . . . . . . . . . . .   2
   1.2. Handling the Delete Operation . . . . . . . . . . . . . . .   5
   2. Signed Results Mechanism  . . . . . . . . . . . . . . . . . .   6
   3. Security Considerations and Other Notes   . . . . . . . . . .   7
   4. References  . . . . . . . . . . . . . . . . . . . . . . . . .   8
   5. Authors' Addresses  . . . . . . . . . . . . . . . . . . . . .   9
   6. Full Copyright Statement  . . . . . . . . . . . . . . . . . .  10









Greenblatt & Richard          Experimental                      [Page 1]

RFC 2649                LDAP Control and Schema              August 1999


1.  Introduction

   In many environments clients require the ability to validiate the
   source and integrity of information provided by the directory.  This
   document describes an LDAP message control which allows for the
   retrieval of digitally signed information.  The perspective of this
   document is that the origin of the information that is stored in LDAP
   v3 accessible directories is the LDAP v3 client that creates the
   information.  The source and integrity of the information is
   guaranteed by allowing for the digital signing of the operations that
   make changes to entries in the directory.  The source and integrity
   of an individual LDAP connection can be guaranteed by making use of
   an underlying session layer that provides such services, such as TLS.
   Note that the integrity of an individual connection does not, in and
   of itself guarantee the integrity of the data that comes across the
   connection.  This is due to the fact that the LDAP server is only
   capable of providing information that it has stored.  In distributed
   and replicated environments, the fact that an entry has been
   successfully retrieved from a server may not be completely
   reassuring, if the entry in question was replicated from an untrusted
   domain.

   By making use of public key technology, and creating digitally signed
   transactions that are created by the LDAP v3 client as entries are
   created and modified, a complete journal of the history of the entry
   is available.  Since each entry in the journal has been digitally
   signed with the private key of the creator, or modifier of the entry,
   the source and integrity of the directory entry can be validated by
   verifying the signature of each entry in the journal.  Note that not
   all of the journal entries will have been signed by the same user.

1.1.  Audit Trail Mechanism

   Signed directory operations is a straightforward application of
   S/MIME technology that also leverages the extensible framework that
   is provided by LDAP version 3.  LDAP version 3 is defined in [4], and
   S/MIME is defined in [2].  The security used in S/MIME is based in
   the definitions in [1].  The basic idea is that the submitter of an
   LDAP operation that changes the directory information includes an
   LDAP version 3 control that includes either a signature of the
   operation, or a request that the LDAP server sign the operation on
   the behalf of the LDAP client.  The result of the operation (in
   addition to the change of the directory information), is additional
   information that is attached to directory objects, that includes the
   audit trail of signed operations.  The LDAP control is (OID =
   1.2.840.113549.6.0.0):





Greenblatt & Richard          Experimental                      [Page 2]

RFC 2649                LDAP Control and Schema              August 1999


      SignedOperation ::= CHOICE {
           signbyServer   NULL,
           signatureIncluded   OCTET STRING
       }

   If the SignatureIncluded CHOICE is used, then the OCTET string is
   just an S/MIME message of the multipart/signed variety, that is
   composed of a single piece, that is the signature of the directory
   operation.  Multipart/signed MIME objects are defined in [3].  If the
   SignbyServer CHOICE us used, then the LDAP server creates the
   signature on behalf of the client, using its own identity and not the
   identity of the client, in order to produce the audit trail entry.
   In either case the successful result of processing the control is the
   creation of additional information in the directory entry that is
   being modified or created. The signature of the LDAP operation is
   computed on the LDAPMessage prior to the inclusion of the
   SignedOperation control. The procedure is as follows:

      - Build LDAPMessage without the SignedOperation control
      - Compute signature on the above LDAPMessage
      - Create new LDAPMessage that includes the old MessageID,
        protocolOp and any control fields from the previous LDAPMessage,
        plus  the computed signature formatted as an S/MIME message.

   No control is defined for the server to return in the LDAPResult as
   defined in [4].  The LDAP server MAY attempt to parse and verify the
   signature included in the SignedOperation control, but is not
   required to.  The server can accept the signed operation without
   verifying the signature.  Signature verification can be quite a
   lengthy operation, requiring complex certificate chain traversals.
   This allows a more timely creation of the audit trail by the server.
   Any LDAP client browsing the directory that retrieves the 'Changes'
   (defined in the following paragraphs) attributes, should verify the
   signature of each value according to the local signature verification
   policies.  Even if the LDAP server verifies the signature contained
   in the singed operation, the LDAP client has no way of knowing what
   policies were followed by the server in order to verify the
   signature.

   If the LDAP server is unable to verify the signature and wishes to
   return an error then the error code unwillingToPerform(53) should be
   returned, and the entire LDAP operation fails.  In this situation, an
   appropriate message (e.g. "Unable to verify signature") MAY be
   included in the errorMessage of the LDAPResult.  The SignedOperation
   Control MAY be marked CRITICAL, and if it is CRITICAL then if the
   LDAP Server performs the LDAP operation, then must include the
   signature in the signedAuditTrail information.




Greenblatt & Richard          Experimental                      [Page 3]

RFC 2649                LDAP Control and Schema              August 1999


      The schema definition for the signedAuditTrail information is:

      ( 1.2.840.113549.6.1.0
      NAME 'signedAuditTrail'
      SUP top
      AUXILIARY
      MUST (
      Changes
      )
         )

      The format of the Changes attribute is:

      ( 1.2.840.113549.6.2.0
      NAME 'Changes'
      DESC 'a set of changes applied to an entry'
      SYNTAX 'Binary' )

      The actual format of the Changes attribute is:

      Changes ::= SEQUENCE {
           sequenceNumber [0] INTEGER (0 .. maxInt),
           signedOperation [1] OCTET STRING }

   The SignedOperation attribute is a multipart/signed S/MIME message.
   Part 1 of the message is the directory operation, and part 2 is the
   signature.  Sequence number 0 (if present) always indicates the
   starting point directory object as represented by the definitions in
   "A MIME Content-Type for Directory Information", as defined in [5].
   Subsequent sequence numbers indicate the sequence of changes that
   have been made to this directory object.  Note that the sequence of
   the changes can be verified due to the fact that the signed directory
   object will have a timestamp as part of the signature object, and
   that the sequence numbering as part of the change attribute should be
   considered to be an unverified aid to the LDAP client.  Sequence
   numbers are meaningful only within the context of a single directory
   entry, and LDAP servers are not expected to maintain these sequence
   numbers across all entries in the directory.

   Some LDAP servers will only allow operations that include the
   SignedOperation control.  This is indicated by the inclusion of a
   'signedDirectoryOperationSupport' attribute in the rootDSE.  This
   attribute is defined as:








Greenblatt & Richard          Experimental                      [Page 4]

RFC 2649                LDAP Control and Schema              August 1999


      1.2.840.113549.6.2.2
      NAME 'signedDirectoryOperationSupport'
      DESC 'how many of the LDAP operations must be signed'
      SYNTAX 'Integer' SINGLE-VALUE )

   The 'signedDirectoryOperationSupport' attribute above may have one of
   the values, '0', '1' or '2' with the following meanings:

      - '0' Directory Operations may be signed
      - '1' Directory Operations must always be signed
      - '2' Directory Operations must never be signed

   Some LDAP servers will desire that the audit trail be continuous, and
   not contain any gaps that would result from unsigned operations.
   Such server will include a signature on each LDAP operation that
   changes a directory entry, even when the LDAP client does not include
   a signed-Operation control.

1.2.  Handling the Delete Operation

   The LDAP Delete operation represents an interesting case for Signed
   Directory Operations.  This is due to the case that subsequent to the
   successful completion of the Delete Operation, the object that would
   have held the latest 'Changes' attribute no longer exists.  In order
   to handle this situation, a new object class is defined to represent
   a directory object that has been deleted.

      ( 1.2.840.113549.6.1.2
      NAME 'zombieObject'
      SUP top
      STRUCTURAL
      MUST (
      Cn $ Changes $ OriginalObject
      )
         )

      The format of the OriginalObject attribute is:

      ( 1.2.840.113549.6.2.1
      NAME OriginalObject
      DESC 'The LDAP URL of an object that has been deleted from the
      directory' SYNTAX 'Binary' )

   The OriginalObject attribute contains the URL of the object that was
   deleted from the directory.  It is formatted in accordance with RFC
   2255.  Directory servers that comply with this specification SHOULD
   create a zombieObject when performing the delete Operation that
   contains a SignedOperation LDAPControl.  The Cn attribute of the



Greenblatt & Richard          Experimental                      [Page 5]

RFC 2649                LDAP Control and Schema              August 1999


   zombieObject is synthesized by the LDAP server, and may or may not be
   related to the original name of the directory entry that was deleted.
   All changes attributes that were attached to the original entry are
   copied over to the zombieObject.  In addition the LDAP Server MUST
   attach the signature of the Delete operation as the last successful
   change that was made to the entry.

2.  Signed Results Mechanism

   A control is also defined that allows the LDAP v3 client to request
   that the server sign the results that it returns.  It is intended
   that this control is primarily used in concert with the LDAPSearch
   operation.  This control MAY be marked as CRITICAL.  If it is marked
   as CRITICAL and the LDAP Server supports this operation, then all
   search results MUST be returned with a signature as attached in the
   SignedResult control if it is willing to sign results for this user.
   If the server supports this control but does not wish to sign the
   results for this user then the error code unwillingToPerform(53)
   should be returned, and the LDAP search will have failed.  In this
   situation, an appropriate message (e.g. "Unwilling to sign results
   for you!") MUST be included in the errorMessage of the LDAPResult.
   If the LDAPSigType has the value FALSE then the client is requesting
   that the server not sign this operation.  This may be done in
   situations where servers are configured to always sign their
   operations.

   The LDAP control to include in the LDAP request is (OID =
   1.2.840.113549.6.0.1):

      DemandSignedResult ::=  LDAPSigType

      LDAPSigType ::= BOOLEAN

   In response to a DemandSignedResult control, the LDAP v3 server will
   return a SignedResult control in addition to the normal result as
   defined by the operation (assuming that the server understands the
   con- trol, and is willing to perform it).  The SignedResult control
   MUST NOT be marked CRITICAL.  Some LDAP v3 servers may be configured
   to sign all of their operations.  In this situation the server always
   returns a SignedResult control, unless instructed otherwise by the
   DemandSigne-dResult Control.  Since the SignedResult control is not
   marked critical, the LDAP client is allowed to ignore it.  The
   signature field below includes the signature of the enitre LDAPResult
   formatted as an S/MIME pkcs-7/signature object, as defined in [2].







Greenblatt & Richard          Experimental                      [Page 6]

RFC 2649                LDAP Control and Schema              August 1999


   The procedure for creating the signature of the signedResult control
   is the same as the procedure for the creation of the signedOperation
   control.  The LDAP control in the LDAP response is (OID =
   1.2.840.113549.6.0.2):

      SignedResult ::= CHOICE {
           signature     OCTET STRING }

3.  Security Considerations and Other Notes

      The base OIDs are:

      rsadsiLdap ::= {1 2 840 113549 6}
      rsadsiLdapControls ::=  {1 2 840 113549 6 0}
      rsadsiLdapObjectClasses ::= {1 2 840 113549 6 1}
      rsadsiLdapAttributes ::= {1 2 840 113549 6 2}


      The complete ASN.1 module for this specification is:

      SIGNEDOPERATIONS DEFINITIONS ::=
      BEGIN

      SignedOperation ::= CHOICE {
           signbyServer   NULL,
           signatureIncluded   OCTET STRING
       }

      Changes ::= SEQUENCE {
           sequenceNumber [0] INTEGER (0 .. maxInt),
           signedOperation [1] OCTET STRING }

      DemandSignedResult ::=  LDAPSigType

      LDAPSigType ::= BOOLEAN

      SignedResult ::= CHOICE {
           signature     OCTET STRING }


      END










Greenblatt & Richard          Experimental                      [Page 7]

RFC 2649                LDAP Control and Schema              August 1999


   If any of the controls in this specification are supported by an LDAP
   v3 server then that server MUST make available its certificate (if
   any) in the userCertificate attribute of its rootDSE object.  The
   UserCertificate attribute is defined in [6], and contains the public
   key of the server that is used in the creation of the various
   signatures defined in this specification.

   It is not the intention of this specification to provide a mechanism
   that guarantees the origin and integrity of LDAP v3 operations.  Such
   a service is best provided by the use of an underlying protocol such
   as TLS [8].  TLS defines additional features such as encryption and
   compression.  This specification does not define support for
   encrypted operations.

   This memo proposes protocol elements for transmission and storage of
   the digital signatures of LDAP operations.  Though the LDAP server
   may have verified the operation signatures prior to their storage and
   subsequent retrieval, it is prudent for LDAP clients to verify the
   signatures contained in the chained attribute upon their retrieval.
   The issuing Certification Authorities of the signer's certificate
   should also be consulted in order to determine if the signer's
   private key has been compromised or the certificate has been
   otherwise revoked.  Security considerations are discussed throughout
   this memo.

4.  References

   [1] Kaliski, B., "PKCS 7: Cryptographic Message Syntax Version 1-5",
       RFC 2315, March 1998.

   [2] Dusse, S., Hoffman, P., Ramsdell, B., Lundblade, L. and L.
       Repka., "S/MIME Version 2 Message Specification", RFC 2311, March
       1998.

   [3] Galvin, J., Murphy, S., Crocker, S. and N. Freed, "Security
       Multiparts for MIME: Multipart/Signed and Multipart/Encrypted",
       RFC 1847, October 1995.

   [4] Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access
       Protocol (v3)", RFC 2251, December 1997.

   [5] Howes, T., Smith, M. and F. Dawson, "A MIME Content-Type for
       Directory Information", RFC 2425, September 1998.

   [6] Wahl, M., "A Summary of the X.500(96) User Schema for use with
       LDAPv3", RFC 2256, December 1997.





Greenblatt & Richard          Experimental                      [Page 8]

RFC 2649                LDAP Control and Schema              August 1999


   [7] Howes, T. and M. Smith, "The LDAP URL Format", RFC 2255, December
       1997.

   [8] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC
       2246, January 1999.

5.  Authors' Addresses

   Bruce Greenblatt
   San Jose, CA 95119
   USA

   Phone: +1-408-224-5349
   EMail: bgreenblatt@directory-applications.com


   Pat Richard
   Xcert Software, Inc.
   Suite 1001 - 701 W. Georgia
   Vancouver, BC
   CANADA V6G 1C9

   EMail: patr@xcert.com




























Greenblatt & Richard          Experimental                      [Page 9]

RFC 2649                LDAP Control and Schema              August 1999


6.  Full Copyright Statement

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Greenblatt & Richard          Experimental                     [Page 10]

alt-openldap11-devel/rfc/rfc2714.txt000064400000034565150410163230012776 0ustar00





Network Working Group                                            V. Ryan
Request for Comments: 2714                                        R. Lee
Category: Informational                                      S. Seligman
                                                  Sun Microsystems, Inc.
                                                            October 1999


  Schema for Representing CORBA Object References in an LDAP Directory

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

Abstract

   CORBA [CORBA] is the Common Object Request Broker Architecture
   defined by the Object Management Group. This document defines the
   schema for representing CORBA object references in an LDAP directory
   [LDAPv3].

1. Introduction

   This document assumes that the reader has a general understanding of
   CORBA.

   Traditionally, LDAP directories have been used to store data. Users
   and programmers think of the directory as a hierarchy of directory
   entries, each containing a set of attributes.  You look up an entry
   from the directory and extract the attribute(s) of interest.  For
   example, you can look up a person's telephone number from the
   directory.  Alternatively, you can search the directory for entries
   with a particular set of attributes.  For example, you can search for
   all persons in the directory with the surname "Smith".

   CORBA applications require access to CORBA objects. Traditionally,
   CORBA applications have used the COS Naming service for storage and
   retrieval of CORBA object references. When deployed in environments
   with a directory, CORBA applications should be able to use the
   directory as a repository for CORBA object references. The directory
   provides a centrally administered, and possibly replicated, service
   for use by CORBA applications distributed across the network.




Ryan, et al.                 Informational                      [Page 1]

RFC 2714           Schema for CORBA Object References       October 1999


   For example, an application server may use the directory for
   "registering" CORBA objects representing the services that it
   manages, so that a client can later search the directory to locate
   those services as it needs.

   The motivation for this document is to define a common way for
   applications to store and retrieve CORBA object references from the
   directory.  Using this common schema, any CORBA application that
   needs to read or store CORBA object references in the directory can
   do so in an interoperable way.

   Note that this schema is defined for storing CORBA "object
   references," not CORBA objects in general. There might be other ways
   to store CORBA objects in an LDAP directory but they are not covered
   by this schema.

2. Representation of CORBA Object References

   This document defines schema elements to represent a CORBA object
   reference in LDAP directory. Applications in possession of a
   reference to an object can invoke calls on that object.  Such a
   reference is termed an "interoperable object reference," or IOR.
   Access to CORBA objects by using IORs is achieved transparently to
   the application, by means of the General Inter-ORB Protocol.

   A CORBA object reference is represented in the directory by the
   object class corbaObjectReference. corbaObjectReference is a subclass
   of the abstract corbaObject object class. corbaObjectReference is an
   auxiliary object class, which means that it needs to be mixed in with
   a structural object class.

   The object class corbaContainer is used in a directory entry which
   represents a CORBA object or object reference. It is a structural
   object class, and when representing an object reference, the
   corbaObjectReference object class would also need to be present in
   the entry.  corbaContainer is not required when a subclass of
   corbaObject (such as corbaObjectReference) is mixed in with another
   structural object class.

   The definitions for the object classes corbaObject,
   corbaObjectReference, and corbaContainer are presented in Section 4.

   The corbaObject class has two optional attributes: corbaRepositoryId
   and description.  corbaRepositoryId is a multivalued attribute that
   is used to store the repository ids of the interfaces implemented by
   a CORBA object.  description is used to store a textual description
   of a CORBA object.




Ryan, et al.                 Informational                      [Page 2]

RFC 2714           Schema for CORBA Object References       October 1999


   The corbaObjectReference class has one mandatory attribute: corbaIor.
   corbaIor is used to store the object's stringified IOR.

   corbaIor and corbaRepositoryId are defined in Section 3; description
   is defined in [v3Schema].

3. Attribute Type Definitions

   The following attribute types are defined in this document:

       corbaIor
       corbaRepositoryId

3.1 corbaIor

   This attribute stores the string representation of the interoperable
   object reference (IOR) for a CORBA object. An IOR is an opaque handle
   for the object which contains the information necessary to locate the
   object, even if the object is in another ORB.

   This attribute's syntax is 'IA5 String' and its case is
   insignificant.

   ( 1.3.6.1.4.1.42.2.27.4.1.14
    NAME 'corbaIor'
    DESC 'Stringified interoperable object reference of a CORBA object'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
    SINGLE-VALUE
   )

3.2 corbaRepositoryId

   Each CORBA interface has a unique "repository id" (also called "type
   id") that identifies the interface.  A CORBA object has one or more
   repository ids, one for each interface that it implements.

   The format of a repository id can be any string, but the OMG
   specifies four standard formats:

      a. IDL-style

       IDL:Prefix/ModuleName/InterfaceName:VersionNumber








Ryan, et al.                 Informational                      [Page 3]

RFC 2714           Schema for CORBA Object References       October 1999


   For example, the repository id for the "NamingContext" in OMG's COS
   Naming module is:  "IDL:omg.org/CosNaming/NamingContext:1.0".

      b. RMI-style

       RMI:ClassName:HashCode[:SUID]

   This format is used by RMI-IIOP remote objects [RMI-IIOP].
   "ClassName" is the fully qualified name of the class (for example,
   "java.lang.String"). "HashCode" is the object's hash code (that is,
   that obtained by invoking the "hashCode()" method).  "SUID" is the
   "stream unique identifier", which is a 64-bit number that uniquely
   identifies the serialization version of the class; SUID is optional
   in the repository id.

      c. DCE-style

       DCE:UUID

   This format is used for DCE/CORBA interoperability [CORBA-DCE].
   "UUID" represents a DCE UUID.

      d. "local"

   This format is defined by the local Object Request Broker (ORB).

   The corbaRepositoryId attribute is a multivalued attribute; each
   value records a single repository id of an interface implemented by
   the CORBA object.  This attribute need not contain a complete list of
   the interfaces implemented by the CORBA object.

   This attribute's syntax is 'Directory String' and its case is
   significant.  The values of this attribute are encoded using UTF-8.
   Some values may require translation from their native representation
   in order to be correctly encoded using UTF-8.

   ( 1.3.6.1.4.1.42.2.27.4.1.15
    NAME 'corbaRepositoryId'
    DESC 'Repository ids of interfaces implemented by a CORBA object'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   )









Ryan, et al.                 Informational                      [Page 4]

RFC 2714           Schema for CORBA Object References       October 1999


4. Object Class Definitions

   The following object classes are defined in this document:

       corbaContainer
       corbaObject
       corbaObjectReference

4.1 corbaContainer

   This structural object class represents a container for a CORBA
   object.

   ( 1.3.6.1.4.1.42.2.27.4.2.10
    NAME 'corbaContainer'
    DESC 'Container for a CORBA object'
    SUP top
    STRUCTURAL
    MUST ( cn )
   )

4.2 corbaObject

   This abstract object class is the root class for representing a CORBA
   object.

   ( 1.3.6.1.4.1.42.2.27.4.2.9
    NAME 'corbaObject'
    DESC 'CORBA object representation'
    SUP top
    ABSTRACT
    MAY ( corbaRepositoryId $ description )
   )

4.3 corbaObjectReference

   This auxiliary object class represents a CORBA object reference.  It
   must be mixed in with a structural object class.

   ( 1.3.6.1.4.1.42.2.27.4.2.11
    NAME 'corbaObjectReference'
    DESC 'CORBA interoperable object reference'
    SUP corbaObject
    AUXILIARY
    MUST ( corbaIor )
   )





Ryan, et al.                 Informational                      [Page 5]

RFC 2714           Schema for CORBA Object References       October 1999


5. Security Considerations

   Obtaining a reference to an object and storing it in the directory
   may make a handle to the object available to a wider audience.  This
   may have security implications.

6. Acknowledgements

   We would like to thank Sanjeev Krishnan of Sun Microsystems, Simon
   Nash of IBM, and Jeffrey Spirn of Oracle for their comments and
   suggestions.

7. References

   [CORBA]     The Object Management Group, "Common Object Request
               Broker Architecture Specification 2.2",
               http://www.omg.org

   [CORBA-DCE] Distributed Systems Technology Center and Digital
               Equipment Corporation, "DCE/CORBA Interworking
               Specification", May 1998.
               http://www.omg.org/library/schedule/
               DCE_CORBA_Interworking_RFP.html

   [LDAPv3]    Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
               Access Protocol (v3)", RFC 2251, December 1997.

   [RMI-IIOP]  IBM and Java Software, Sun Microsystems, Inc., "RMI over
               IIOP", June 1999.  http://java.sun.com/products/rmi-
               iiop/index.html

   [v3Schema]  Wahl, M., "A Summary of the X.500(96) User Schema for use
               with LDAPv3", RFC 2256, December 1997.


















Ryan, et al.                 Informational                      [Page 6]

RFC 2714           Schema for CORBA Object References       October 1999


8. Authors' Addresses

   Vincent Ryan
   Sun Microsystems, Inc.
   Mail Stop EDUB03
   901 San Antonio Road
   Palo Alto, CA 94303
   USA

   Phone: +353 1 819 9151
   EMail: vincent.ryan@ireland.sun.com


   Rosanna Lee
   Sun Microsystems, Inc.
   Mail Stop UCUP02-206
   901 San Antonio Road
   Palo Alto, CA 94303
   USA

   Phone: +1 408 863 3221
   EMail: rosanna.lee@eng.sun.com


   Scott Seligman
   Sun Microsystems, Inc.
   Mail Stop UCUP02-209
   901 San Antonio Road
   Palo Alto, CA 94303
   USA

   Phone: +1 408 863 3222
   EMail: scott.seligman@eng.sun.com


















Ryan, et al.                 Informational                      [Page 7]

RFC 2714           Schema for CORBA Object References       October 1999


9. Appendix  - LDAP Schema

   -- Attribute types --

   ( 1.3.6.1.4.1.42.2.27.4.1.14
    NAME 'corbaIor'
    DESC 'Stringified interoperable object reference of a CORBA object'
    EQUALITY caseIgnoreIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
    SINGLE-VALUE
   )

   ( 1.3.6.1.4.1.42.2.27.4.1.15
    NAME 'corbaRepositoryId'
    DESC 'Repository ids of interfaces implemented by a CORBA object'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   )

   -- from RFC-2256 --

   ( 2.5.4.13
    NAME 'description'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024}
   )

   -- Object classes --

   ( 1.3.6.1.4.1.42.2.27.4.2.9
    NAME 'corbaObject'
    DESC 'CORBA object representation'
    SUP top
    ABSTRACT
    MAY ( corbaRepositoryId $ description )
   )

   ( 1.3.6.1.4.1.42.2.27.4.2.10
    NAME 'corbaContainer'
    DESC 'Container for a CORBA object'
    SUP top
    STRUCTURAL
    MUST ( cn )
   )






Ryan, et al.                 Informational                      [Page 8]

RFC 2714           Schema for CORBA Object References       October 1999


   ( 1.3.6.1.4.1.42.2.27.4.2.11
    NAME 'corbaObjectReference'
    DESC 'CORBA interoperable object reference'
    SUP corbaObject
    AUXILIARY
    MUST ( corbaIor )
   )

   -- Matching rule from ISO X.520 --

   ( 2.5.13.5
    NAME 'caseExactMatch'
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   )





































Ryan, et al.                 Informational                      [Page 9]

RFC 2714           Schema for CORBA Object References       October 1999


10.  Full Copyright Statement

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Ryan, et al.                 Informational                     [Page 10]

alt-openldap11-devel/rfc/rfc4514.txt000064400000076163150410163230012776 0ustar00





Network Working Group                                   K. Zeilenga, Ed.
Request for Comments: 4514                           OpenLDAP Foundation
Obsoletes: 2253                                                June 2006
Category: Standards Track


             Lightweight Directory Access Protocol (LDAP):
              String Representation of Distinguished Names

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   The X.500 Directory uses distinguished names (DNs) as primary keys to
   entries in the directory.  This document defines the string
   representation used in the Lightweight Directory Access Protocol
   (LDAP) to transfer distinguished names.  The string representation is
   designed to give a clean representation of commonly used
   distinguished names, while being able to represent any distinguished
   name.

1.  Background and Intended Usage

   In X.500-based directory systems [X.500], including those accessed
   using the Lightweight Directory Access Protocol (LDAP) [RFC4510],
   distinguished names (DNs) are used to unambiguously refer to
   directory entries [X.501][RFC4512].

   The structure of a DN [X.501] is described in terms of ASN.1 [X.680].
   In the X.500 Directory Access Protocol [X.511] (and other ITU-defined
   directory protocols), DNs are encoded using the Basic Encoding Rules
   (BER) [X.690].  In LDAP, DNs are represented in the string form
   described in this document.

   It is important to have a common format to be able to unambiguously
   represent a distinguished name.  The primary goal of this
   specification is ease of encoding and decoding.  A secondary goal is
   to have names that are human readable.  It is not expected that LDAP



Zeilenga                    Standards Track                     [Page 1]

RFC 4514               LDAP: Distinguished Names               June 2006


   implementations with a human user interface would display these
   strings directly to the user, but that they would most likely be
   performing translations (such as expressing attribute type names in
   the local national language).

   This document defines the string representation of Distinguished
   Names used in LDAP [RFC4511][RFC4517].  Section 2 details the
   RECOMMENDED algorithm for converting a DN from its ASN.1 structured
   representation to a string.  Section 3 details how to convert a DN
   from a string to an ASN.1 structured representation.

   While other documents may define other algorithms for converting a DN
   from its ASN.1 structured representation to a string, all algorithms
   MUST produce strings that adhere to the requirements of Section 3.

   This document does not define a canonical string representation for
   DNs.  Comparison of DNs for equality is to be performed in accordance
   with the distinguishedNameMatch matching rule [RFC4517].

   This document is a integral part of the LDAP technical specification
   [RFC4510], which obsoletes the previously defined LDAP technical
   specification, RFC 3377, in its entirety.  This document obsoletes
   RFC 2253.  Changes since RFC 2253 are summarized in Appendix B.

   This specification assumes familiarity with X.500 [X.500] and the
   concept of Distinguished Name [X.501][RFC4512].

1.1.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

   Character names in this document use the notation for code points and
   names from the Unicode Standard [Unicode].  For example, the letter
   "a" may be represented as either <U+0061> or <LATIN SMALL LETTER A>.

   Note: a glossary of terms used in Unicode can be found in [Glossary].
   Information on the Unicode character encoding model can be found in
   [CharModel].











Zeilenga                    Standards Track                     [Page 2]

RFC 4514               LDAP: Distinguished Names               June 2006


2.  Converting DistinguishedName from ASN.1 to a String

   X.501 [X.501] defines the ASN.1 [X.680] structure of distinguished
   name.  The following is a variant provided for discussion purposes.

      DistinguishedName ::= RDNSequence

      RDNSequence ::= SEQUENCE OF RelativeDistinguishedName

      RelativeDistinguishedName ::= SET SIZE (1..MAX) OF
          AttributeTypeAndValue

      AttributeTypeAndValue ::= SEQUENCE {
          type  AttributeType,
          value AttributeValue }

   This section defines the RECOMMENDED algorithm for converting a
   distinguished name from an ASN.1-structured representation to a UTF-8
   [RFC3629] encoded Unicode [Unicode] character string representation.
   Other documents may describe other algorithms for converting a
   distinguished name to a string, but only strings that conform to the
   grammar defined in Section 3 SHALL be produced by LDAP
   implementations.

2.1.  Converting the RDNSequence

   If the RDNSequence is an empty sequence, the result is the empty or
   zero-length string.

   Otherwise, the output consists of the string encodings of each
   RelativeDistinguishedName in the RDNSequence (according to Section
   2.2), starting with the last element of the sequence and moving
   backwards toward the first.

   The encodings of adjoining RelativeDistinguishedNames are separated
   by a comma (',' U+002C) character.

2.2.  Converting RelativeDistinguishedName

   When converting from an ASN.1 RelativeDistinguishedName to a string,
   the output consists of the string encodings of each
   AttributeTypeAndValue (according to Section 2.3), in any order.

   Where there is a multi-valued RDN, the outputs from adjoining
   AttributeTypeAndValues are separated by a plus sign ('+' U+002B)
   character.





Zeilenga                    Standards Track                     [Page 3]

RFC 4514               LDAP: Distinguished Names               June 2006


2.3.  Converting AttributeTypeAndValue

   The AttributeTypeAndValue is encoded as the string representation of
   the AttributeType, followed by an equals sign ('=' U+003D) character,
   followed by the string representation of the AttributeValue.  The
   encoding of the AttributeValue is given in Section 2.4.

   If the AttributeType is defined to have a short name (descriptor)
   [RFC4512] and that short name is known to be registered [REGISTRY]
   [RFC4520] as identifying the AttributeType, that short name, a
   <descr>, is used.  Otherwise the AttributeType is encoded as the
   dotted-decimal encoding, a <numericoid>, of its OBJECT IDENTIFIER.
   The <descr> and <numericoid> are defined in [RFC4512].

   Implementations are not expected to dynamically update their
   knowledge of registered short names.  However, implementations SHOULD
   provide a mechanism to allow their knowledge of registered short
   names to be updated.

2.4.  Converting an AttributeValue from ASN.1 to a String

   If the AttributeType is of the dotted-decimal form, the
   AttributeValue is represented by an number sign ('#' U+0023)
   character followed by the hexadecimal encoding of each of the octets
   of the BER encoding of the X.500 AttributeValue.  This form is also
   used when the syntax of the AttributeValue does not have an LDAP-
   specific ([RFC4517], Section 3.1) string encoding defined for it, or
   the LDAP-specific string encoding is not restricted to UTF-8-encoded
   Unicode characters.  This form may also be used in other cases, such
   as when a reversible string representation is desired (see Section
   5.2).

   Otherwise, if the AttributeValue is of a syntax that has a LDAP-
   specific string encoding, the value is converted first to a UTF-8-
   encoded Unicode string according to its syntax specification (see
   [RFC4517], Section 3.3, for examples).  If that UTF-8-encoded Unicode
   string does not have any of the following characters that need
   escaping, then that string can be used as the string representation
   of the value.

      - a space (' ' U+0020) or number sign ('#' U+0023) occurring at
        the beginning of the string;

      - a space (' ' U+0020) character occurring at the end of the
        string;






Zeilenga                    Standards Track                     [Page 4]

RFC 4514               LDAP: Distinguished Names               June 2006


      - one of the characters '"', '+', ',', ';', '<', '>',  or '\'
        (U+0022, U+002B, U+002C, U+003B, U+003C, U+003E, or U+005C,
        respectively);

      - the null (U+0000) character.

   Other characters may be escaped.

   Each octet of the character to be escaped is replaced by a backslash
   and two hex digits, which form a single octet in the code of the
   character.  Alternatively, if and only if the character to be escaped
   is one of

      ' ', '"', '#', '+', ',', ';', '<', '=', '>', or '\'
      (U+0020, U+0022, U+0023, U+002B, U+002C, U+003B,
       U+003C, U+003D, U+003E, U+005C, respectively)

   it can be prefixed by a backslash ('\' U+005C).

   Examples of the escaping mechanism are shown in Section 4.

3.  Parsing a String Back to a Distinguished Name

   The string representation of Distinguished Names is restricted to
   UTF-8 [RFC3629] encoded Unicode [Unicode] characters.  The structure
   of this string representation is specified using the following
   Augmented BNF [RFC4234] grammar:

      distinguishedName = [ relativeDistinguishedName
          *( COMMA relativeDistinguishedName ) ]
      relativeDistinguishedName = attributeTypeAndValue
          *( PLUS attributeTypeAndValue )
      attributeTypeAndValue = attributeType EQUALS attributeValue
      attributeType = descr / numericoid
      attributeValue = string / hexstring

      ; The following characters are to be escaped when they appear
      ; in the value to be encoded: ESC, one of <escaped>, leading
      ; SHARP or SPACE, trailing SPACE, and NULL.
      string =   [ ( leadchar / pair ) [ *( stringchar / pair )
         ( trailchar / pair ) ] ]

      leadchar = LUTF1 / UTFMB
      LUTF1 = %x01-1F / %x21 / %x24-2A / %x2D-3A /
         %x3D / %x3F-5B / %x5D-7F

      trailchar  = TUTF1 / UTFMB
      TUTF1 = %x01-1F / %x21 / %x23-2A / %x2D-3A /



Zeilenga                    Standards Track                     [Page 5]

RFC 4514               LDAP: Distinguished Names               June 2006


         %x3D / %x3F-5B / %x5D-7F

      stringchar = SUTF1 / UTFMB
      SUTF1 = %x01-21 / %x23-2A / %x2D-3A /
         %x3D / %x3F-5B / %x5D-7F

      pair = ESC ( ESC / special / hexpair )
      special = escaped / SPACE / SHARP / EQUALS
      escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
      hexstring = SHARP 1*hexpair
      hexpair = HEX HEX

   where the productions <descr>, <numericoid>, <COMMA>, <DQUOTE>,
   <EQUALS>, <ESC>, <HEX>, <LANGLE>, <NULL>, <PLUS>, <RANGLE>, <SEMI>,
   <SPACE>, <SHARP>, and <UTFMB> are defined in [RFC4512].

   Each <attributeType>, either a <descr> or a <numericoid>, refers to
   an attribute type of an attribute value assertion (AVA).  The
   <attributeType> is followed by an <EQUALS> and an <attributeValue>.
   The <attributeValue> is either in <string> or <hexstring> form.

   If in <string> form, a LDAP string representation asserted value can
   be obtained by replacing (left to right, non-recursively) each <pair>
   appearing in the <string> as follows:

      replace <ESC><ESC> with <ESC>;
      replace <ESC><special> with <special>;
      replace <ESC><hexpair> with the octet indicated by the <hexpair>.

   If in <hexstring> form, a BER representation can be obtained from
   converting each <hexpair> of the <hexstring> to the octet indicated
   by the <hexpair>.

   There is one or more attribute value assertions, separated by <PLUS>,
   for a relative distinguished name.

   There is zero or more relative distinguished names, separated by
   <COMMA>, for a distinguished name.

   Implementations MUST recognize AttributeType name strings
   (descriptors) listed in the following table, but MAY recognize other
   name strings.









Zeilenga                    Standards Track                     [Page 6]

RFC 4514               LDAP: Distinguished Names               June 2006


      String  X.500 AttributeType
      ------  --------------------------------------------
      CN      commonName (2.5.4.3)
      L       localityName (2.5.4.7)
      ST      stateOrProvinceName (2.5.4.8)
      O       organizationName (2.5.4.10)
      OU      organizationalUnitName (2.5.4.11)
      C       countryName (2.5.4.6)
      STREET  streetAddress (2.5.4.9)
      DC      domainComponent (0.9.2342.19200300.100.1.25)
      UID     userId (0.9.2342.19200300.100.1.1)

   These attribute types are described in [RFC4519].

   Implementations MAY recognize other DN string representations.
   However, as there is no requirement that alternative DN string
   representations be recognized (and, if so, how), implementations
   SHOULD only generate DN strings in accordance with Section 2 of this
   document.

4.  Examples

   This notation is designed to be convenient for common forms of name.
   This section gives a few examples of distinguished names written
   using this notation.  First is a name containing three relative
   distinguished names (RDNs):

      UID=jsmith,DC=example,DC=net

   Here is an example of a name containing three RDNs, in which the
   first RDN is multi-valued:

      OU=Sales+CN=J.  Smith,DC=example,DC=net

   This example shows the method of escaping of a special characters
   appearing in a common name:

      CN=James \"Jim\" Smith\, III,DC=example,DC=net

   The following shows the method for encoding a value that contains a
   carriage return character:

      CN=Before\0dAfter,DC=example,DC=net

   In this RDN example, the type in the RDN is unrecognized, and the
   value is the BER encoding of an OCTET STRING containing two octets,
   0x48 and 0x69.




Zeilenga                    Standards Track                     [Page 7]

RFC 4514               LDAP: Distinguished Names               June 2006


      1.3.6.1.4.1.1466.0=#04024869

   Finally, this example shows an RDN whose commonName value consists of
   5 letters:

      Unicode Character                Code       UTF-8   Escaped
      -------------------------------  ------     ------  --------
      LATIN CAPITAL LETTER L           U+004C     0x4C    L
      LATIN SMALL LETTER U             U+0075     0x75    u
      LATIN SMALL LETTER C WITH CARON  U+010D     0xC48D  \C4\8D
      LATIN SMALL LETTER I             U+0069     0x69    i
      LATIN SMALL LETTER C WITH ACUTE  U+0107     0xC487  \C4\87

   This could be encoded in printable ASCII [ASCII] (useful for
   debugging purposes) as:

      CN=Lu\C4\8Di\C4\87

5.  Security Considerations

   The following security considerations are specific to the handling of
   distinguished names.  LDAP security considerations are discussed in
   [RFC4511] and other documents comprising the LDAP Technical
   Specification [RFC4510].

5.1.  Disclosure

   Distinguished Names typically consist of descriptive information
   about the entries they name, which can be people, organizations,
   devices, or other real-world objects.  This frequently includes some
   of the following kinds of information:

      - the common name of the object (i.e., a person's full name)
      - an email or TCP/IP address
      - its physical location (country, locality, city, street address)
      - organizational attributes (such as department name or
        affiliation)

   In some cases, such information can be considered sensitive.  In many
   countries, privacy laws exist that prohibit disclosure of certain
   kinds of descriptive information (e.g., email addresses).  Hence,
   server implementers are encouraged to support Directory Information
   Tree (DIT) structural rules and name forms [RFC4512], as these
   provide a mechanism for administrators to select appropriate naming
   attributes for entries.  Administrators are encouraged to use
   mechanisms, access controls, and other administrative controls that
   may be available to restrict use of attributes containing sensitive
   information in naming of entries.   Additionally, use of



Zeilenga                    Standards Track                     [Page 8]

RFC 4514               LDAP: Distinguished Names               June 2006


   authentication and data security services in LDAP [RFC4513][RFC4511]
   should be considered.

5.2.  Use of Distinguished Names in Security Applications

   The transformations of an AttributeValue value from its X.501 form to
   an LDAP string representation are not always reversible back to the
   same BER (Basic Encoding Rules) or DER (Distinguished Encoding Rules)
   form.  An example of a situation that requires the DER form of a
   distinguished name is the verification of an X.509 certificate.

   For example, a distinguished name consisting of one RDN with one AVA,
   in which the type is commonName and the value is of the TeletexString
   choice with the letters 'Sam', would be represented in LDAP as the
   string <CN=Sam>.  Another distinguished name in which the value is
   still 'Sam', but is of the PrintableString choice, would have the
   same representation <CN=Sam>.

   Applications that require the reconstruction of the DER form of the
   value SHOULD NOT use the string representation of attribute syntaxes
   when converting a distinguished name to the LDAP format.  Instead,
   they SHOULD use the hexadecimal form prefixed by the number sign ('#'
   U+0023) as described in the first paragraph of Section 2.4.

6.  Acknowledgements

   This document is an update to RFC 2253, by Mark Wahl, Tim Howes, and
   Steve Kille.  RFC 2253 was a product of the IETF ASID Working Group.

   This document is a product of the IETF LDAPBIS Working Group.

7.  References

7.1.  Normative References

   [REGISTRY]    IANA, Object Identifier Descriptors Registry,
                 <http://www.iana.org/assignments/ldap-parameters>.

   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
                 3.2.0" is defined by "The Unicode Standard, Version
                 3.0" (Reading, MA, Addison-Wesley, 2000.  ISBN 0-201-
                 61633-5), as amended by the "Unicode Standard Annex
                 #27: Unicode 3.1"
                 (http://www.unicode.org/reports/tr27/) and by the
                 "Unicode Standard Annex #28: Unicode 3.2"
                 (http://www.unicode.org/reports/tr28/).





Zeilenga                    Standards Track                     [Page 9]

RFC 4514               LDAP: Distinguished Names               June 2006


   [X.501]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Models," X.501(1993) (also ISO/IEC 9594-
                 2:1994).

   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(1997) (also ISO/IEC 8824-1:1998).

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3629]     Yergeau, F., "UTF-8, a transformation format of ISO
                 10646", STD 63, RFC 3629, November 2003.

   [RFC4234]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
                 Specifications: ABNF", RFC 4234, October 2005.

   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [RFC4513]     Harrison, R., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Authentication Methods and Security
                 Mechanisms", RFC 4513, June 2006.

   [RFC4517]     Legg, S., Ed., "Lightweight Directory Access Protocol
                 (LDAP): Syntaxes and Matching Rules", RFC 4517, June
                 2006.

   [RFC4519]     Sciberras, A., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Schema for User Applications", RFC
                 4519, June 2006.

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.






Zeilenga                    Standards Track                    [Page 10]

RFC 4514               LDAP: Distinguished Names               June 2006


7.2.  Informative References

   [ASCII]       Coded Character Set--7-bit American Standard Code for
                 Information Interchange, ANSI X3.4-1986.

   [CharModel]   Whistler, K. and M. Davis, "Unicode Technical Report
                 #17, Character Encoding Model", UTR17,
                 <http://www.unicode.org/unicode/reports/tr17/>, August
                 2000.

   [Glossary]    The Unicode Consortium, "Unicode Glossary",
                 <http://www.unicode.org/glossary/>.

   [X.500]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Overview of concepts, models and
                 services," X.500(1993) (also ISO/IEC 9594-1:1994).

   [X.511]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory: Abstract Service Definition", X.511(1993)
                 (also ISO/IEC 9594-3:1993).

   [X.690]       International Telecommunication Union -
                 Telecommunication Standardization Sector,
                 "Specification of ASN.1 encoding rules: Basic Encoding
                 Rules (BER), Canonical Encoding Rules (CER), and
                 Distinguished Encoding Rules (DER)", X.690(1997) (also
                 ISO/IEC 8825-1:1998).

   [RFC2849]     Good, G., "The LDAP Data Interchange Format (LDIF) -
                 Technical Specification", RFC 2849, June 2000.



















Zeilenga                    Standards Track                    [Page 11]

RFC 4514               LDAP: Distinguished Names               June 2006


Appendix A.  Presentation Issues

   This appendix is provided for informational purposes only; it is not
   a normative part of this specification.

   The string representation described in this document is not intended
   to be presented to humans without translation.  However, at times it
   may be desirable to present non-translated DN strings to users.  This
   section discusses presentation issues associated with non-translated
   DN strings.  Issues with presentation of translated DN strings are
   not discussed in this appendix.  Transcoding issues are also not
   discussed in this appendix.

   This appendix provides guidance for applications presenting DN
   strings to users.  This section is not comprehensive; it does not
   discuss all presentation issues that implementers may face.

   Not all user interfaces are capable of displaying the full set of
   Unicode characters.  Some Unicode characters are not displayable.

   It is recommended that human interfaces use the optional hex pair
   escaping mechanism (Section 2.3) to produce a string representation
   suitable for display to the user.  For example, an application can
   generate a DN string for display that escapes all non-printable
   characters appearing in the AttributeValue's string representation
   (as demonstrated in the final example of Section 4).

   When a DN string is displayed in free-form text, it is often
   necessary to distinguish the DN string from surrounding text.  While
   this is often done with whitespace (as demonstrated in Section 4), it
   is noted that DN strings may end with whitespace.  Careful readers of
   Section 3 will note that the characters '<' (U+003C) and '>' (U+003E)
   may only appear in the DN string if escaped.  These characters are
   intended to be used in free-form text to distinguish a DN string from
   surrounding text.  For example, <CN=Sam\ > distinguishes the string
   representation of the DN composed of one RDN consisting of the AVA
   (the commonName (CN) value 'Sam ') from the surrounding text.  It
   should be noted to the user that the wrapping '<' and '>' characters
   are not part of the DN string.

   DN strings can be quite long.  It is often desirable to line-wrap
   overly long DN strings in presentations.  Line wrapping should be
   done by inserting whitespace after the RDN separator character or, if
   necessary, after the AVA separator character.  It should be noted to
   the user that the inserted whitespace is not part of the DN string
   and is to be removed before use in LDAP.  For example, the following
   DN string is long:




Zeilenga                    Standards Track                    [Page 12]

RFC 4514               LDAP: Distinguished Names               June 2006


         CN=Kurt D.  Zeilenga,OU=Engineering,L=Redwood Shores,
         O=OpenLDAP Foundation,ST=California,C=US

   So it has been line-wrapped for readability.  The extra whitespace is
   to be removed before the DN string is used in LDAP.

   Inserting whitespace is not advised because it may not be obvious to
   the user which whitespace is part of the DN string and which
   whitespace was added for readability.

   Another alternative is to use the LDAP Data Interchange Format (LDIF)
   [RFC2849].  For example:

         # This entry has a long DN...
         dn: CN=Kurt D.  Zeilenga,OU=Engineering,L=Redwood Shores,
          O=OpenLDAP Foundation,ST=California,C=US
         CN: Kurt D.  Zeilenga
         SN: Zeilenga
         objectClass: person

Appendix B.  Changes Made since RFC 2253

   This appendix is provided for informational purposes only, it is not
   a normative part of this specification.

   The following substantive changes were made to RFC 2253:

      - Removed IESG Note.  The IESG Note has been addressed.
      - Replaced all references to ISO 10646-1 with [Unicode].
      - Clarified (in Section 1) that this document does not define a
        canonical string representation.
      - Clarified that Section 2 describes the RECOMMENDED encoding
        algorithm and that alternative algorithms are allowed.  Some
        encoding options described in RFC 2253 are now treated as
        alternative algorithms in this specification.
      - Revised specification (in Section 2) to allow short names of any
        registered attribute type to appear in string representations of
        DNs instead of being restricted to a "published table".  Removed
        "as an example" language.  Added statement (in Section 3)
        allowing recognition of additional names but require recognition
        of those names in the published table.  The table now appears in
        Section 3.
      - Removed specification of additional requirements for LDAPv2
        implementations which also support LDAPv3 (RFC 2253, Section 4)
        as LDAPv2 is now Historic.
      - Allowed recognition of alternative string representations.
      - Updated Section 2.4 to allow hex pair escaping of all characters
        and clarified escaping for when multiple octet UTF-8 encodings



Zeilenga                    Standards Track                    [Page 13]

RFC 4514               LDAP: Distinguished Names               June 2006


        are present.  Indicated that null (U+0000) character is to be
        escaped.  Indicated that equals sign ('=' U+003D) character may
        be escaped as '\='.
      - Rewrote Section 3 to use ABNF as defined in RFC 4234.
      - Updated the Section 3 ABNF.  Changes include:
        + allowed AttributeType short names of length 1 (e.g., 'L'),
        + used more restrictive <oid> production in AttributeTypes,
        + did not require escaping of equals sign ('=' U+003D)
          characters,
        + did not require escaping of non-leading number sign ('#'
          U+0023) characters,
        + allowed space (' ' U+0020) to be escaped as '\ ',
        + required hex escaping of null (U+0000) characters, and
        + removed LDAPv2-only constructs.
      - Updated Section 3 to describe how to parse elements of the
        grammar.
      - Rewrote examples.
      - Added reference to documentations containing general LDAP
        security considerations.
      - Added discussion of presentation issues (Appendix A).
      - Added this appendix.

   In addition, numerous editorial changes were made.

Editor's Address

   Kurt D.  Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org





















Zeilenga                    Standards Track                    [Page 14]

RFC 4514               LDAP: Distinguished Names               June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                    [Page 15]

alt-openldap11-devel/rfc/rfc4370.txt000064400000024600150410163230012763 0ustar00





Network Working Group                                         R. Weltman
Request for Comments: 4370                                  Yahoo!, Inc.
Category: Standards Track                                  February 2006


             Lightweight Directory Access Protocol (LDAP)
                     Proxied Authorization Control

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document defines the Lightweight Directory Access Protocol
   (LDAP) Proxy Authorization Control.  The Proxy Authorization Control
   allows a client to request that an operation be processed under a
   provided authorization identity instead of under the current
   authorization identity associated with the connection.

1.  Introduction

   Proxy authorization allows a client to request that an operation be
   processed under a provided authorization identity instead of under
   the current authorization identity associated with the connection.
   This document defines support for proxy authorization using the
   Control mechanism [RFC2251].  The Lightweight Directory Access
   Protocol [LDAPV3] supports the use of the Simple Authentication and
   Security Layer [SASL] for authentication and for supplying an
   authorization identity distinct from the authentication identity,
   where the authorization identity applies to the whole LDAP session.
   The Proxy Authorization Control provides a mechanism for specifying
   an authorization identity on a per-operation basis, benefiting
   clients that need to perform operations efficiently on behalf of
   multiple users.

   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
   used in this document are to be interpreted as described in
   [KEYWORDS].




Weltman                     Standards Track                     [Page 1]

RFC 4370           LDAP Proxied Authorization Control      February 2006


2.  Publishing Support for the Proxy Authorization Control

   Support for the Proxy Authorization Control is indicated by the
   presence of the Object Identifier (OID) "2.16.840.1.113730.3.4.18" in
   the supportedControl attribute [RFC2252] of a server's root
   DSA-specific Entry (DSE).

3.  Proxy Authorization Control

   A single Proxy Authorization Control may be included in any search,
   compare, modify, add, delete, or modify Distinguished Name (DN) or
   extended operation request message.  The exception is any extension
   that causes a change in authentication, authorization, or data
   confidentiality [RFC2829], such as Start TLS [LDAPTLS] as part of the
   controls field of the LDAPMessage, as defined in [RFC2251].

   The controlType of the proxy authorization control is
   "2.16.840.1.113730.3.4.18".

   The criticality MUST be present and MUST be TRUE.  This requirement
   protects clients from submitting a request that is executed with an
   unintended authorization identity.

   Clients MUST include the criticality flag and MUST set it to TRUE.
   Servers MUST reject any request containing a Proxy Authorization
   Control without a criticality flag or with the flag set to FALSE with
   a protocolError error.  These requirements protect clients from
   submitting a request that is executed with an unintended
   authorization identity.

   The controlValue SHALL be present and SHALL either contain an authzId
   [AUTH] representing the authorization identity for the request or be
   empty if an anonymous association is to be used.

   The mechanism for determining proxy access rights is specific to the
   server's proxy authorization policy.

   If the requested authorization identity is recognized by the server,
   and the client is authorized to adopt the requested authorization
   identity, the request will be executed as if submitted by the proxy
   authorization identity; otherwise, the result code 123 is returned.

4.  Implementation Considerations

   One possible interaction of proxy authorization and normal access
   control is illustrated here.  During evaluation of a search request,
   an entry that would have been returned for the search (if submitted
   by the proxy authorization identity directly) may not be returned if



Weltman                     Standards Track                     [Page 2]

RFC 4370           LDAP Proxied Authorization Control      February 2006


   the server finds that the requester does not have the right to assume
   the requested identity for searching the entry, even if the entry is
   within the scope of a search request under a base DN that does imply
   such rights.  This means that fewer results, or no results, may be
   returned than would be if the proxy authorization identity issued the
   request directly.  An example of such a case may be a system with
   fine-grained access control, where the proxy right requester has
   proxy rights at the top of a search tree, but not at or below a point
   or points within the tree.

5.  Security Considerations

   The Proxy Authorization Control method is subject to general LDAP
   security considerations [RFC2251] [AUTH] [LDAPTLS].  The control may
   be passed over a secure channel as well as over an insecure channel.

   The control allows for an additional authorization identity to be
   passed.  In some deployments, these identities may contain
   confidential information that requires privacy protection.

   Note that the server is responsible for determining if a proxy
   authorization request is to be honored. "Anonymous" users SHOULD NOT
   be allowed to assume the identity of others.

6.  IANA Considerations

   The OID "2.16.840.1.113730.3.4.18" is reserved for the Proxy
   Authorization Control.  It has been registered as an LDAP Protocol
   Mechanism [RFC3383].

   A result code (123) has been assigned by the IANA for the case where
   the server does not execute a request using the proxy authorization
   identity.

7.  Acknowledgements

   Mark Smith, formerly of Netscape Communications Corp., Mark Wahl,
   formerly of Sun Microsystems, Inc., Kurt Zeilenga of OpenLDAP
   Foundation, Jim Sermersheim of Novell, and Steven Legg of Adacel have
   contributed with reviews of this document.











Weltman                     Standards Track                     [Page 3]

RFC 4370           LDAP Proxied Authorization Control      February 2006


8.  Normative References

   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [LDAPV3]   Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

   [SASL]     Myers, J., "Simple Authentication and Security Layer
              (SASL)", RFC 2222, October 1997.

   [AUTH]     Wahl, M., Alvestrand, H., Hodges, J., and R. Morgan,
              "Authentication Methods for LDAP", RFC 2829, May 2000.

   [LDAPTLS]  Hodges, J., Morgan, R., and M. Wahl, "Lightweight
              Directory Access Protocol (v3): Extension for Transport
              Layer Security", RFC 2830, May 2000.

   [RFC2251]  Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252]  Wahl, M., Coulbeck, A., Howes, T., and S. Kille,
              "Lightweight Directory Access Protocol (v3): Attribute
              Syntax Definitions", RFC 2252, December 1997.

   [RFC2829]  Wahl, M., Alvestrand, H., Hodges, J., and R. Morgan,
              "Authentication Methods for LDAP", RFC 2829, May 2000.

   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

Author's Address

   Rob Weltman
   Yahoo!, Inc.
   701 First Avenue
   Sunnyvale, CA 94089
   USA

   Phone: +1 408 349-5504
   EMail: robw@worldspot.com








Weltman                     Standards Track                     [Page 4]

RFC 4370           LDAP Proxied Authorization Control      February 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Weltman                     Standards Track                     [Page 5]

alt-openldap11-devel/rfc/rfc4526.txt000064400000023561150410163230012773 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4526                           OpenLDAP Foundation
Category: Standards Track                                      June 2006


              Lightweight Directory Access Protocol (LDAP)
                    Absolute True and False Filters

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document extends the Lightweight Directory Access Protocol
   (LDAP) to support absolute True and False filters based upon similar
   capabilities found in X.500 directory systems.  The document also
   extends the String Representation of LDAP Search Filters to support
   these filters.

Table of Contents

   1. Background ......................................................1
   2. Absolute True and False Filters .................................2
   3. Security Considerations .........................................2
   4. IANA Considerations .............................................3
   5. References ......................................................3
      5.1. Normative References .......................................3
      5.2. Informative References .....................................3

1.  Background

   The X.500 Directory Access Protocol (DAP) [X.511] supports absolute
   True and False assertions.  An 'and' filter with zero elements always
   evaluates to True.  An 'or' filter with zero elements always
   evaluates to False.  These filters are commonly used when requesting
   DSA-specific Entries (DSEs) that do not necessarily have
   'objectClass' attributes; that is, where "(objectClass=*)" may
   evaluate to False.




Zeilenga                    Standards Track                     [Page 1]

RFC 4526          LDAP Absolute True and False Filters         June 2006


   Although LDAPv2 [RFC1777][RFC3494] placed no restriction on the
   number of elements in 'and' and 'or' filter sets, the LDAPv2 string
   representation [RFC1960][RFC3494] could not represent empty 'and' and
   'or' filter sets.  Due to this, absolute True or False filters were
   (unfortunately) eliminated from LDAPv3 [RFC4510].

   This documents extends LDAPv3 to support absolute True and False
   assertions by allowing empty 'and' and 'or' in Search filters
   [RFC4511] and extends the filter string representation [RFC4515] to
   allow empty filter lists.

   It is noted that certain search operations, such as those used to
   retrieve subschema information [RFC4512], require use of particular
   filters.  This document does not change these requirements.

   This feature is intended to allow a more direct mapping between DAP
   and LDAP (as needed to implement DAP-to-LDAP gateways).

   In this document, the key words "MUST", "MUST NOT", "REQUIRED",
   "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
   and "OPTIONAL" are to be interpreted as described in BCP 14
   [RFC2119].

2.  Absolute True and False Filters

   Implementations of this extension SHALL allow 'and' and 'or' choices
   with zero filter elements.

   An 'and' filter consisting of an empty set of filters SHALL evaluate
   to True.  This filter is represented by the string "(&)".

   An 'or' filter consisting of an empty set of filters SHALL evaluate
   to False.  This filter is represented by the string "(|)".

   Servers supporting this feature SHOULD publish the Object Identifier
   1.3.6.1.4.1.4203.1.5.3 as a value of the 'supportedFeatures'
   [RFC4512] attribute in the root DSE.

   Clients supporting this feature SHOULD NOT use the feature unless
   they know that the server supports it.

3.  Security Considerations

   The (re)introduction of absolute True and False filters is not
   believed to raise any new security considerations.

   Implementors of this (or any) LDAPv3 extension should be familiar
   with general LDAPv3 security considerations [RFC4510].



Zeilenga                    Standards Track                     [Page 2]

RFC 4526          LDAP Absolute True and False Filters         June 2006


4.  IANA Considerations

   Registration of this feature has been completed by the IANA
   [RFC4520].

   Subject: Request for LDAP Protocol Mechanism Registration Object
   Identifier: 1.3.6.1.4.1.4203.1.5.3 Description: True/False filters
   Person & email address to contact for further information:
        Kurt Zeilenga <kurt@openldap.org> Usage: Feature Specification:
   RFC 4526 Author/Change Controller: IESG Comments: none

   This OID was assigned [ASSIGN] by OpenLDAP Foundation, under its
   IANA-assigned private enterprise allocation [PRIVATE], for use in
   this specification.

5.  References

5.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4510]     Zeilenga, K., Ed, "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [RFC4515]     Smith, M., Ed. and T. Howes, "Lightweight Directory
                 Access Protocol (LDAP): String Representation of Search
                 Filters", RFC 4515, June 2006.

5.2.  Informative References

   [RFC1777]     Yeong, W., Howes, T., and S. Kille, "Lightweight
                 Directory Access Protocol", RFC 1777, March 1995.

   [RFC1960]     Howes, T., "A String Representation of LDAP Search
                 Filters", RFC 1960, June 1996.

   [RFC3494]     Zeilenga, K., "Lightweight Directory Access Protocol
                 version 2 (LDAPv2) to Historic Status", RFC 3494, March
                 2003.



Zeilenga                    Standards Track                     [Page 3]

RFC 4526          LDAP Absolute True and False Filters         June 2006


   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [X.500]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Overview of concepts, models and
                 services," X.500(1993) (also ISO/IEC 9594-1:1994).

   [X.501]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Models," X.501(1993) (also ISO/IEC 9594-
                 2:1994).

   [X.511]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory: Abstract Service Definition", X.511(1993)
                 (also ISO/IEC 9594-3:1993).

   [ASSIGN]      OpenLDAP Foundation, "OpenLDAP OID Delegations",
                 http://www.openldap.org/foundation/oid-delegate.txt.

   [PRIVATE]     IANA, "Private Enterprise Numbers",
                 http://www.iana.org/assignments/enterprise-numbers.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org




















Zeilenga                    Standards Track                     [Page 4]

RFC 4526          LDAP Absolute True and False Filters         June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                     [Page 5]

alt-openldap11-devel/rfc/rfc4013.txt000064400000031373150410163230012762 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4013                           OpenLDAP Foundation
Category: Standards Track                                  February 2005


       SASLprep: Stringprep Profile for User Names and Passwords

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2005).

Abstract

   This document describes how to prepare Unicode strings representing
   user names and passwords for comparison.  The document defines the
   "SASLprep" profile of the "stringprep" algorithm to be used for both
   user names and passwords.  This profile is intended to be used by
   Simple Authentication and Security Layer (SASL) mechanisms (such as
   PLAIN, CRAM-MD5, and DIGEST-MD5), as well as other protocols
   exchanging simple user names and/or passwords.

1.  Introduction

   The use of simple user names and passwords in authentication and
   authorization is pervasive on the Internet.  To increase the
   likelihood that user name and password input and comparison work in
   ways that make sense for typical users throughout the world, this
   document defines rules for preparing internationalized user names and
   passwords for comparison.  For simplicity and implementation ease, a
   single algorithm is defined for both user names and passwords.

   The algorithm assumes all strings are comprised of characters from
   the Unicode [Unicode] character set.

   This document defines the "SASLprep" profile of the "stringprep"
   algorithm [StringPrep].

   The profile is designed for use in Simple Authentication and Security
   Layer ([SASL]) mechanisms, such as [PLAIN], [CRAM-MD5], and
   [DIGEST-MD5].  It may be applicable where simple user names and



Zeilenga                    Standards Track                     [Page 1]

RFC 4013                        SASLprep                   February 2005


   passwords are used.  This profile is not intended for use in
   preparing identity strings that are not simple user names (e.g.,
   email addresses, domain names, distinguished names), or where
   identity or password strings that are not character data, or require
   different handling (e.g., case folding).

   This document does not alter the technical specification of any
   existing protocols.  Any specification that wishes to use the
   algorithm described in this document needs to explicitly incorporate
   this document and provide precise details as to where and how this
   algorithm is used by implementations of that specification.

2.  The SASLprep Profile

   This section defines the "SASLprep" profile of the "stringprep"
   algorithm [StringPrep].  This profile is intended for use in
   preparing strings representing simple user names and passwords.

   This profile uses Unicode 3.2 [Unicode].

   Character names in this document use the notation for code points and
   names from the Unicode Standard [Unicode].  For example, the letter
   "a" may be represented as either <U+0061> or <LATIN SMALL LETTER A>.
   In the lists of mappings and the prohibited characters, the "U+" is
   left off to make the lists easier to read.  The comments for
   character ranges are shown in square brackets (such as "[CONTROL
   CHARACTERS]") and do not come from the standard.

   Note: A glossary of terms used in Unicode can be found in [Glossary].
   Information on the Unicode character encoding model can be found in
   [CharModel].

2.1.  Mapping

   This profile specifies:

      -  non-ASCII space characters [StringPrep, C.1.2] that can be
         mapped to SPACE (U+0020), and

      -  the "commonly mapped to nothing" characters [StringPrep, B.1]
         that can be mapped to nothing.

2.2.  Normalization

   This profile specifies using Unicode normalization form KC, as
   described in Section 4 of [StringPrep].





Zeilenga                    Standards Track                     [Page 2]

RFC 4013                        SASLprep                   February 2005


2.3.  Prohibited Output

   This profile specifies the following characters as prohibited input:

      - Non-ASCII space characters [StringPrep, C.1.2]
      - ASCII control characters [StringPrep, C.2.1]
      - Non-ASCII control characters [StringPrep, C.2.2]
      - Private Use characters [StringPrep, C.3]
      - Non-character code points [StringPrep, C.4]
      - Surrogate code points [StringPrep, C.5]
      - Inappropriate for plain text characters [StringPrep, C.6]
      - Inappropriate for canonical representation characters
        [StringPrep, C.7]
      - Change display properties or deprecated characters
        [StringPrep, C.8]
      - Tagging characters [StringPrep, C.9]

2.4.  Bidirectional Characters

   This profile specifies checking bidirectional strings as described in
   [StringPrep, Section 6].

2.5.  Unassigned Code Points

   This profile specifies the [StringPrep, A.1] table as its list of
   unassigned code points.

3.  Examples

   The following table provides examples of how various character data
   is transformed by the SASLprep string preparation algorithm

   #  Input            Output     Comments
   -  -----            ------     --------
   1  I<U+00AD>X       IX         SOFT HYPHEN mapped to nothing
   2  user             user       no transformation
   3  USER             USER       case preserved, will not match #2
   4  <U+00AA>         a          output is NFKC, input in ISO 8859-1
   5  <U+2168>         IX         output is NFKC, will match #1
   6  <U+0007>                    Error - prohibited character
   7  <U+0627><U+0031>            Error - bidirectional check

4.  Security Considerations

   This profile is intended to prepare simple user name and password
   strings for comparison or use in cryptographic functions (e.g.,
   message digests).  The preparation algorithm was specifically
   designed such that its output is canonical, and it is well-formed.



Zeilenga                    Standards Track                     [Page 3]

RFC 4013                        SASLprep                   February 2005


   However, due to an anomaly [PR29] in the specification of Unicode
   normalization, canonical equivalence is not guaranteed for a select
   few character sequences.  These sequences, however, do not appear in
   well-formed text.  This specification was published despite this
   known technical problem.  It is expected that this specification will
   be revised before further progression on the Standards Track (after
   [Unicode] and/or [StringPrep] specifications have been updated to
   address this problem).

   It is not intended for preparing identity strings that are not simple
   user names (e.g., distinguished names, domain names), nor is the
   profile intended for use of simple user names that require different
   handling (such as case folding).  Protocols (or applications of those
   protocols) that have application-specific identity forms and/or
   comparison algorithms should use mechanisms specifically designed for
   these forms and algorithms.

   Application of string preparation may have an impact upon the
   feasibility of brute force and dictionary attacks.  While the number
   of possible prepared strings is less than the number of possible
   Unicode strings, the number of usable names and passwords is greater
   than as if only ASCII was used.  Though SASLprep eliminates some
   Unicode code point sequences as possible prepared strings, that
   elimination generally makes the (canonical) output forms practicable
   and prohibits nonsensical inputs.

   User names and passwords should be protected from eavesdropping.

   General "stringprep" and Unicode security considerations apply.  Both
   are discussed in [StringPrep].

5.  IANA Considerations

   This document details the "SASLprep" profile of the [StringPrep]
   protocol.  This profile has been registered in the stringprep profile
   registry.

      Name of this profile: SASLprep
      RFC in which the profile is defined: RFC 4013
      Indicator whether or not this is the newest version of the
      profile: This is the first version of the SASPprep profile.

6.  Acknowledgement

   This document borrows text from "Preparation of Internationalized
   Strings ('stringprep')" and "Nameprep: A Stringprep Profile for
   Internationalized Domain Names", both by Paul Hoffman and Marc
   Blanchet.  This document is a product of the IETF SASL WG.



Zeilenga                    Standards Track                     [Page 4]

RFC 4013                        SASLprep                   February 2005


7.  Normative References

   [StringPrep]  Hoffman, P. and M. Blanchet, "Preparation of
                 Internationalized Strings ("stringprep")", RFC 3454,
                 December 2002.

   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
                 3.2.0" is defined by "The Unicode Standard, Version
                 3.0" (Reading, MA, Addison-Wesley, 2000.  ISBN 0-201-
                 61633-5), as amended by the "Unicode Standard Annex
                 #27: Unicode 3.1"
                 (http://www.unicode.org/reports/tr27/) and by the
                 "Unicode Standard Annex #28: Unicode 3.2"
                 (http://www.unicode.org/reports/tr28/).

8.  Informative References

   [Glossary]    The Unicode Consortium, "Unicode Glossary",
                 <http://www.unicode.org/glossary/>.

   [CharModel]   Whistler, K. and M. Davis, "Unicode Technical Report
                 #17, Character Encoding Model", UTR17,
                 <http://www.unicode.org/unicode/reports/tr17/>, August
                 2000.

   [SASL]        Melnikov, A., Ed., "Simple Authentication and Security
                 Layer (SASL)", Work in Progress.

   [CRAM-MD5]    Nerenberg, L., "The CRAM-MD5 SASL Mechanism", Work in
                 Progress.

   [DIGEST-MD5]  Leach, P., Newman, C., and A. Melnikov, "Using Digest
                 Authentication as a SASL Mechanism", Work in Progress.

   [PLAIN]       Zeilenga, K., Ed., "The Plain SASL Mechanism", Work in
                 Progress.

   [PR29]        "Public Review Issue #29: Normalization Issue",
                 <http://www.unicode.org/review/pr-29.html>, February
                 2004.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org




Zeilenga                    Standards Track                     [Page 5]

RFC 4013                        SASLprep                   February 2005


Full Copyright Statement

   Copyright (C) The Internet Society (2005).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the IETF's procedures with respect to rights in IETF Documents can
   be found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at ietf-
   ipr@ietf.org.


Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.






Zeilenga                    Standards Track                     [Page 6]

alt-openldap11-devel/rfc/rfc3671.txt000064400000042770150410163230012776 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 3671                           OpenLDAP Foundation
Category: Standards Track                                  December 2003


                        Collective Attributes in
            the Lightweight Directory Access Protocol (LDAP)

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2003).  All Rights Reserved.

Abstract

   X.500 collective attributes allow common characteristics to be shared
   between collections of entries.  This document summarizes the X.500
   information model for collective attributes and describes use of
   collective attributes in LDAP (Lightweight Directory Access
   Protocol).  This document provides schema definitions for collective
   attributes for use in LDAP.

1.  Introduction

   In X.500 [X.500], a collective attribute is "a user attribute whose
   values are the same for each member of an entry collection" [X.501].
   This document details their use in the Lightweight Directory Access
   Protocol (LDAP) [RFC3377].

1.1.  Entry Collections

   A collection of entries is a grouping of object and alias entries
   based upon common properties or shared relationship between the
   corresponding entries which share certain attributes.  An entry
   collection consists of all entries within scope of a collective
   attributes subentry [RFC3672].  An entry can belong to several entry
   collections.







Zeilenga                    Standards Track                     [Page 1]

RFC 3671             Collective Attributes in LDAP         December 2003


1.2.  Collective Attributes

   Attributes shared by the entries comprising an entry collection are
   called collective attributes.  Values of collective attributes are
   visible but not updateable to clients accessing entries within the
   collection.  Collective attributes are updated (i.e., modified) via
   their associated collective attributes subentry.

   When an entry belongs to multiple entry collections, the entry's
   values of each collective attribute are combined such that
   independent sources of these values are not manifested to clients.

   Entries can specifically exclude a particular collective attribute by
   listing the attribute as a value of the collectiveExclusions
   attribute.  Like other user attributes, collective attributes are
   subject to a variety of controls including access, administrative,
   and content controls.

1.3.  Conventions

   Schema definitions are provided using LDAPv3 [RFC2251] description
   formats [RFC2252].  Definitions provided here are formatted (line
   wrapped) for readability.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

2.  System Schema for Collective Attributes

   The following operational attributes are used to manage Collective
   Attributes.  LDAP servers [RFC3377] MUST act in accordance with the
   X.500 Directory Models [X.501] when providing this service.

2.1.  collectiveAttributeSubentry

   Subentries of this object class are used to administer collective
   attributes and are referred to as collective attribute subentries.

      ( 2.5.17.2 NAME 'collectiveAttributeSubentry' AUXILIARY )

   A collective attribute subentry SHOULD contain at least one
   collective attribute.  The collective attributes contained within a
   collective attribute subentry are available for finding, searching,
   and comparison at every entry within the scope of the subentry.  The
   collective attributes, however, are administered (e.g., modified) via
   the subentry.




Zeilenga                    Standards Track                     [Page 2]

RFC 3671             Collective Attributes in LDAP         December 2003


   Implementations of this specification SHOULD support collective
   attribute subentries in both collectiveAttributeSpecificArea
   (2.5.23.5) and collectiveAttributeInnerArea (2.5.23.6) administrative
   areas [RFC3672][X.501].

2.2.  collectiveAttributeSubentries

   The collectiveAttributeSubentries operational attribute identifies
   all collective attribute subentries that affect the entry.

      ( 2.5.18.12 NAME 'collectiveAttributeSubentries'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
        USAGE directoryOperation NO-USER-MODIFICATION )

2.3.  collectiveExclusions

   The collectiveExclusions operational attribute allows particular
   collective attributes to be excluded from an entry.  It MAY appear in
   any entry and MAY have multiple values.

      ( 2.5.18.7 NAME 'collectiveExclusions'
        EQUALITY objectIdentifierMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
        USAGE directoryOperation )

   The descriptor excludeAllCollectiveAttributes is associated with the
   OID 2.5.18.0.  When this descriptor or OID is present as a value of
   the collectiveExclusions attribute, all collective attributes are
   excluded from an entry.

3.  Collective Attribute Types

   A userApplications attribute type can be defined to be COLLECTIVE
   [RFC2252].  This indicates that the same attribute values will appear
   in the entries of an entry collection subject to the use of the
   collectiveExclusions attribute and other administrative controls.
   These administrative controls MAY include DIT Content Rules, if
   implemented.

   Collective attribute types are commonly defined as subtypes of non-
   collective attribute types.  By convention, collective attributes are
   named by prefixing the name of their non-collective supertype with
   "c-".  For example, the collective telephone attribute is named
   c-TelephoneNumber after its non-collective supertype telephoneNumber.

   Non-collective attributes types SHALL NOT subtype collective
   attributes.



Zeilenga                    Standards Track                     [Page 3]

RFC 3671             Collective Attributes in LDAP         December 2003


   Collective attributes SHALL NOT be SINGLE-VALUED.  Collective
   attribute types SHALL NOT appear in the attribute types of an object
   class definition.

   Operational attributes SHALL NOT be defined to be collective.

   The remainder of section provides a summary of collective attributes
   derived from those defined in [X.520].  The SUPerior attribute types
   are described in [RFC 2256] for use with LDAP.

   Implementations of this specification SHOULD support the following
   collective attributes and MAY support additional collective
   attributes.

3.1.  Collective Locality Name

   The c-l attribute type specifies a locality name for a collection of
   entries.

      ( 2.5.4.7.1 NAME 'c-l'
        SUP l COLLECTIVE )

3.2.  Collective State or Province Name

   The c-st attribute type specifies a state or province name for a
   collection of entries.

      ( 2.5.4.8.1 NAME 'c-st'
        SUP st COLLECTIVE )

3.3.  Collective Street Address

   The c-street attribute type specifies a street address for a
   collection of entries.

      ( 2.5.4.9.1 NAME 'c-street'
        SUP street COLLECTIVE )

3.4.  Collective Organization Name

   The c-o attribute type specifies an organization name for a
   collection of entries.

      ( 2.5.4.10.1 NAME 'c-o'
        SUP o COLLECTIVE )






Zeilenga                    Standards Track                     [Page 4]

RFC 3671             Collective Attributes in LDAP         December 2003


3.5.  Collective Organizational Unit Name

   The c-ou attribute type specifies an organizational unit name for a
   collection of entries.

      ( 2.5.4.11.1 NAME 'c-ou'
        SUP ou COLLECTIVE )

3.6.  Collective Postal Address

   The c-PostalAddress attribute type specifies a postal address for a
   collection of entries.

      ( 2.5.4.16.1 NAME 'c-PostalAddress'
        SUP postalAddress COLLECTIVE )

3.7.  Collective Postal Code

   The c-PostalCode attribute type specifies a postal code for a
   collection of entries.

      ( 2.5.4.17.1 NAME 'c-PostalCode'
        SUP postalCode COLLECTIVE )

3.8.  Collective Post Office Box

   The c-PostOfficeBox attribute type specifies a post office box for a
   collection of entries.

      ( 2.5.4.18.1 NAME 'c-PostOfficeBox'
        SUP postOfficeBox COLLECTIVE )

3.9.  Collective Physical Delivery Office Name

   The c-PhysicalDeliveryOfficeName attribute type specifies a physical
   delivery office name for a collection of entries.

      ( 2.5.4.19.1 NAME 'c-PhysicalDeliveryOfficeName'
        SUP physicalDeliveryOfficeName COLLECTIVE )

3.10.  Collective Telephone Number

   The c-TelephoneNumber attribute type specifies a telephone number for
   a collection of entries.

      ( 2.5.4.20.1 NAME 'c-TelephoneNumber'
        SUP telephoneNumber COLLECTIVE )




Zeilenga                    Standards Track                     [Page 5]

RFC 3671             Collective Attributes in LDAP         December 2003


3.11.  Collective Telex Number

   The c-TelexNumber attribute type specifies a telex number for a
   collection of entries.

      ( 2.5.4.21.1 NAME 'c-TelexNumber'
        SUP telexNumber COLLECTIVE )

3.13.  Collective Facsimile Telephone Number

   The c-FacsimileTelephoneNumber attribute type specifies a facsimile
   telephone number for a collection of entries.

      ( 2.5.4.23.1 NAME 'c-FacsimileTelephoneNumber'

   SUP facsimileTelephoneNumber COLLECTIVE )

3.14.  Collective International ISDN Number

   The c-InternationalISDNNumber attribute type specifies an
   international ISDN number for a collection of entries.

      ( 2.5.4.25.1 NAME 'c-InternationalISDNNumber'
        SUP internationalISDNNumber COLLECTIVE )

4.  Security Considerations

   Collective attributes, like other attributes, are subject to access
   control restrictions and other administrative policy.  Generally
   speaking, collective attributes accessed via an entry in a collection
   are governed by rules restricting access to attributes of that entry.
   And collective attributes access via a subentry are governed by rules
   restricting access to attributes of that subentry.  However, as LDAP
   does not have a standard access model, the particulars of each
   server's access control system may differ.

   General LDAP security considerations [RFC3377] also apply.














Zeilenga                    Standards Track                     [Page 6]

RFC 3671             Collective Attributes in LDAP         December 2003


5.  IANA Considerations

   The IANA has registered the LDAP descriptors [RFC3383] defined in
   this technical specification.  The following registration template is
   suggested:

      Subject: Request for LDAP Descriptor Registration
      Descriptor see comments
      Object Identifier: see comment
      Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
      Usage: see comment
      Specification: RFC3671
      Author/Change Controller: IESG
      Comments:

         NAME                           Type OID
         ------------------------       ---- -----------------
         c-FacsimileTelephoneNumber     A    2.5.4.23.1
         c-InternationalISDNNumber      A    2.5.4.25.1
         c-PhysicalDeliveryOffice       A    2.5.4.19.1
         c-PostOfficeBox                A    2.5.4.18.1
         c-PostalAddress                A    2.5.4.16.1
         c-PostalCode                   A    2.5.4.17.1
         c-TelephoneNumber              A    2.5.4.20.1
         c-TelexNumber                  A    2.5.4.21.1
         c-l                            A    2.5.4.7.1
         c-o                            A    2.5.4.10.1
         c-ou                           A    2.5.4.11.1
         c-st                           A    2.5.4.8.1
         c-street                       A    2.5.4.9.1
         collectiveAttributeSubentries  A    2.5.18.12
         collectiveAttributeSubentry    O    2.5.17.2
         collectiveExclusions           A    2.5.18.7

      where Type A is Attribute and Type O is ObjectClass.

   The Object Identifiers used in this document were assigned by the
   ISO/IEC Joint Technical Committee 1 - Subcommittee 6 to identify
   elements of X.500 schema [X.520].  This document make no OID
   assignments, it only provides LDAP schema descriptions with existing
   elements of X.500 schema.









Zeilenga                    Standards Track                     [Page 7]

RFC 3671             Collective Attributes in LDAP         December 2003


6.  Intellectual Property Statement

   The IETF takes no position regarding the validity or scope of any
   intellectual property or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; neither does it represent that it
   has made any effort to identify any such rights.  Information on the
   IETF's procedures with respect to rights in standards-track and
   standards-related documentation can be found in BCP-11.  Copies of
   claims of rights made available for publication and any assurances of
   licenses to be made available, or the result of an attempt made to
   obtain a general license or permission for the use of such
   proprietary rights by implementors or users of this specification can
   be obtained from the IETF Secretariat.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights which may cover technology that may be required to practice
   this standard.  Please address the information to the IETF Executive
   Director.

7.  Acknowledgments

   This document is based upon the ITU Recommendations for the Directory
   [X.501][X.520].

8.  References

8.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252]  Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
              "Lightweight Directory Access Protocol (v3):  Attribute
              Syntax Definitions", RFC 2252, December 1997.

   [RFC2256]  Wahl, M., "A Summary of the X.500(96) User Schema for use
              with LDAPv3", RFC 2256, December 1997.

   [RFC3377]  Hodges, J. and R. L. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.




Zeilenga                    Standards Track                     [Page 8]

RFC 3671             Collective Attributes in LDAP         December 2003


   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [RFC3672]  Zeilenga, K. and S. Legg, "Subentries in Lightweight
              Directory Access Protocol (LDAP)", RFC 3672, December
              2003.

   [X.501]    "The Directory: Models", ITU-T Recommendation X.501, 1993.

8.2.  Informative References

   [X.500]    "The Directory: Overview of Concepts, Models", ITU-T
              Recommendation X.500, 1993.

   [X.520]    "The Directory: Selected Attribute Types", ITU-T
              Recommendation X.520, 1993.

9.  Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org



























Zeilenga                    Standards Track                     [Page 9]

RFC 3671             Collective Attributes in LDAP         December 2003


10.  Full Copyright Statement

   Copyright (C) The Internet Society (2003).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assignees.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Zeilenga                    Standards Track                    [Page 10]

alt-openldap11-devel/rfc/rfc3909.txt000064400000032157150410163230013000 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 3909                           OpenLDAP Foundation
Category: Standards Track                                   October 2004


             Lightweight Directory Access Protocol (LDAP)
                            Cancel Operation

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).

Abstract

   This specification describes a Lightweight Directory Access Protocol
   (LDAP) extended operation to cancel (or abandon) an outstanding
   operation.  Unlike the LDAP Abandon operation, but like the X.511
   Directory Access Protocol (DAP) Abandon operation, this operation has
   a response which provides an indication of its outcome.

1.  Background and Intent of Use

   The Lightweight Directory Access Protocol (LDAP) [RFC3377] provides
   an Abandon operation [RFC2251] which clients may use to cancel other
   operations.  The Abandon operation does not have a response and
   requires no response from the abandoned operation.  These semantics
   provide the client with no clear indication of the outcome of the
   Abandon operation.

   The X.511 Directory Access Protocol (DAP) [X.511] provides an Abandon
   operation which has a response and also requires the abandoned
   operation to return a response indicating it was canceled.  The LDAP
   Cancel operation is modeled after the DAP Abandon operation.

   The LDAP Cancel operation SHOULD be used instead of the LDAP Abandon
   operation when the client needs an indication of the outcome.  This
   operation may be used to cancel both interrogation and update
   operations.





Zeilenga                    Standards Track                     [Page 1]

RFC 3909                 LDAP Cancel Operation              October 2004


   Protocol elements are described using ASN.1 [X.680] with implicit
   tags.  The term "BER-encoded" means the element is to be encoded
   using the Basic Encoding Rules [X.690] under the restrictions
   detailed in Section 5.1 of [RFC2251].

   DSA stands for Directory System Agent (or server).
   DSE stands for DSA-specific Entry.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

2.  Cancel Operation

   The Cancel operation is defined as an LDAP Extended Operation
   [RFC2251, Section 4.12] identified by the object identifier
   1.3.6.1.1.8.  This section details the syntax of the Cancel request
   and response messages and defines additional LDAP resultCodes.

2.1.  Cancel Request

   The Cancel request is an ExtendedRequest with the requestName field
   containing 1.3.6.1.1.8 and a requestValue field which contains a
   BER-encoded cancelRequestValue value.

      cancelRequestValue ::= SEQUENCE {
          cancelID        MessageID
                          -- MessageID is as defined in [RFC2251]
      }

   The cancelID field contains the message ID associated with the
   operation to be canceled.

2.2.  Cancel Response

   A Cancel response is an ExtendedResponse where the responseName and
   response fields are absent.

2.3.  Additional Result Codes

   Implementations of this specification SHALL recognize the following
   additional resultCode values:

      canceled        (118)
      noSuchOperation (119)
      tooLate         (120)
      cannotCancel    (121)




Zeilenga                    Standards Track                     [Page 2]

RFC 3909                 LDAP Cancel Operation              October 2004


3.  Operational Semantics

   The function of the Cancel Operation is to request that the server
   cancel an outstanding operation issued within the same session.

   The client requests the cancelation of an outstanding operation by
   issuing a Cancel Response with a cancelID set to the message ID of
   the outstanding operation.  The Cancel Request itself has a distinct
   message ID.  Clients SHOULD NOT request the cancelation of an
   operation multiple times.

   If the server is willing and able to cancel the outstanding operation
   identified by the cancelId, the server SHALL return a Cancel Response
   with a success resultCode, and the canceled operation SHALL fail with
   canceled resultCode.  Otherwise the Cancel Response SHALL have a
   non-success resultCode and SHALL NOT have an impact upon the
   outstanding operation (if it exists).

   The protocolError resultCode is returned if the server is unable to
   parse the requestValue or the requestValue is absent,

   The noSuchOperation resultCode is returned if the server has no
   knowledge of the operation requested for cancelation.

   The cannotCancel resultCode is returned if the identified operation
   does not support cancelation or the cancel operation could not be
   performed.  The following classes of operations are not cancelable:

   -  operations which have no response,

   -  operations which create, alter, or destroy authentication and/or
      authorization associations,

   -  operations which establish, alter, or tear-down security services,
      and

   -  operations which abandon or cancel other operations.

   Specifically, the Abandon, Bind, Start TLS [RFC2830], Unbind, and
   Cancel operations are not cancelable.

   The Cancel operation cannot be abandoned.

   The tooLate resultCode is returned to indicate that it is too late to
   cancel the outstanding operation.  For example, the server may return
   tooLate for a request to cancel an outstanding modify operation which
   has already committed updates to the underlying data store.




Zeilenga                    Standards Track                     [Page 3]

RFC 3909                 LDAP Cancel Operation              October 2004


   Servers SHOULD indicate their support for this extended operation by
   providing 1.3.6.1.1.8 as a value of the 'supportedExtension'
   attribute type in their root DSE.  A server MAY choose to advertise
   this extension only when the client is authorized to use it.

4.  Security Considerations

   This operation is intended to allow a user to cancel operations they
   previously issued during the current LDAP association.  In certain
   cases, such as when the Proxy Authorization Control is in use,
   different outstanding operations may be processed under different
   LDAP associations.  Servers MUST NOT allow a user to cancel an
   operation belonging to another user.

   Some operations should not be cancelable for security reasons.  This
   specification disallows the cancelation of the Bind operation and
   Start TLS extended operation so as to avoid adding complexity to
   authentication, authorization, and security layer semantics.
   Designers of future extended operations and/or controls should
   disallow abandonment and cancelation when appropriate.

5.  IANA Considerations

   The following values [RFC3383] have been registered by the IANA.

5.1.  Object Identifier

   The IANA has registered upon Standards Action the LDAP Object
   Identifier 1.3.6.1.1.8 to identify the LDAP Cancel Operation as
   defined in this document.

      Subject: Request for LDAP Object Identifier Registration
      Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
      Specification: RFC 3909
      Author/Change Controller: IESG
      Comments:
           Identifies the LDAP Cancel Operation













Zeilenga                    Standards Track                     [Page 4]

RFC 3909                 LDAP Cancel Operation              October 2004


5.2.  LDAP Protocol Mechanism

   The IANA has registered upon Standards Action the LDAP Protocol
   Mechanism described in this document.

      Subject: LDAP Protocol Mechanism Registration
      Object Identifier: 1.3.6.1.1.8
      Description: LDAP Cancel Operation
      Person & email address to contact for further information:
           Kurt Zeilenga <kurt@openldap.org>
      Usage: Extended Operation
      Specification: RFC 3909
      Author/Change Controller: IESG
      Comments: none

5.3.  LDAP Result Codes

   The IANA has registered upon Standards Action the LDAP Result Codes
   described in this document.

      Subject: LDAP Result Code Registration
      Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
      Result Code Name: canceled (118)
      Result Code Name: noSuchOperation (119)
      Result Code Name: tooLate (120)
      Result Code Name: cannotCancel (121)
      Specification: RFC 3909
      Author/Change Controller: IESG

6.  Acknowledgment

   The LDAP Cancel operation is modeled after the X.511 DAP Abandon
   operation.

















Zeilenga                    Standards Track                     [Page 5]

RFC 3909                 LDAP Cancel Operation              October 2004


7.  References

7.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251]  Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2830]  Hodges, J., Morgan, R., and M. Wahl, "Lightweight
              Directory Access Protocol (v3): Extension for Transport
              Layer Security", RFC 2830, May 2000.

   [RFC3377]  Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

   [X.680]    International Telecommunication Union - Telecommunication
              Standardization Sector, "Abstract Syntax Notation One
              (ASN.1) - Specification of Basic Notation", X.680(1997)
              (also ISO/IEC 8824-1:1998).

   [X.690]    International Telecommunication Union - Telecommunication
              Standardization Sector, "Specification of ASN.1 encoding
              rules: Basic Encoding Rules (BER), Canonical Encoding
              Rules (CER), and Distinguished Encoding Rules (DER)",
              X.690(1997) (also ISO/IEC 8825-1:1998).

7.2.  Informative References

   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [X.511]    International Telecommunication Union - Telecommunication
              Standardization Sector, "The Directory: Abstract Service
              Definition", X.511(1993).

8.  Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org






Zeilenga                    Standards Track                     [Page 6]

RFC 3909                 LDAP Cancel Operation              October 2004


9.  Full Copyright Statement

   Copyright (C) The Internet Society (2004).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and at www.rfc-editor.org, and except as set
   forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the ISOC's procedures with respect to rights in ISOC Documents can
   be found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at ietf-
   ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.







Zeilenga                    Standards Track                     [Page 7]

alt-openldap11-devel/rfc/rfc5805.txt000064400000052333150410163230012773 0ustar00





Independent Submission                                       K. Zeilenga
Request for Comments: 5805                                 Isode Limited
Category: Experimental                                        March 2010
ISSN: 2070-1721


       Lightweight Directory Access Protocol (LDAP) Transactions

Abstract

   Lightweight Directory Access Protocol (LDAP) update operations, such
   as Add, Delete, and Modify operations, have atomic, consistency,
   isolation, durability (ACID) properties.  Each of these update
   operations act upon an entry.  It is often desirable to update two or
   more entries in a single unit of interaction, a transaction.
   Transactions are necessary to support a number of applications
   including resource provisioning.  This document extends LDAP to
   support transactions.

Status of This Memo

   This document is not an Internet Standards Track specification; it is
   published for examination, experimental implementation, and
   evaluation.

   This document defines an Experimental Protocol for the Internet
   community.  This is a contribution to the RFC Series, independently
   of any other RFC stream.  The RFC Editor has chosen to publish this
   document at its discretion and makes no statement about its value for
   implementation or deployment.  Documents approved for publication by
   the RFC Editor are not a candidate for any level of Internet
   Standard; see Section 2 of RFC 5741.

   Information about the current status of this document, any errata,
   and how to provide feedback on it may be obtained at
   http://www.rfc-editor.org/info/rfc5805.

Copyright Notice

   Copyright (c) 2010 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents
   (http://trustee.ietf.org/license-info) in effect on the date of
   publication of this document.  Please review these documents
   carefully, as they describe your rights and restrictions with respect
   to this document.



Zeilenga                      Experimental                      [Page 1]

RFC 5805                    LDAP Transactions                 March 2010


1.  Overview

   This document extends the Lightweight Directory Access Protocol
   (LDAP) [RFC4510] to allow clients to relate a number of update
   operations [RFC4511] and have them performed as one unit of
   interaction, a transaction.  As with distinct update operations, each
   transaction has atomic, consistency, isolation, and durability (ACID)
   properties [ACID].

   This extension consists of two extended operations, one control, and
   one unsolicited notification message.  The Start Transaction
   operation is used to obtain a transaction identifier.  This
   identifier is then attached to multiple update operations to indicate
   that they belong to the transaction using the Transaction
   Specification control.  The End Transaction is used to settle (commit
   or abort) the transaction.  The Aborted Transaction Notice is
   provided by the server to notify the client that the server is no
   longer willing or able to process an outstanding transaction.

1.1.  Conventions and Terminology

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in RFC 2119 [RFC2119].

   Protocol elements are described using ASN.1 [X.680] with implicit
   tags.  The term "BER-encoded" means the element is to be encoded
   using the Basic Encoding Rules [X.690] under the restrictions
   detailed in Section 5.1 of [RFC4511].

   DSA stands for "Directory System Agent" (a server).  DSE stands for
   "DSA-specific entry".

2.  Elements of an LDAP Transaction

2.1.  Start Transaction Request and Response

   A Start Transaction Request is an LDAPMessage of CHOICE extendedReq
   where the requestName is 1.3.6.1.1.21.1 and the requestValue is
   absent.

   A Start Transaction Response is an LDAPMessage of CHOICE extendedRes
   sent in response to a Start Transaction Request.  Its responseName is
   absent.  When the resultCode is success (0), responseValue is present
   and contains a transaction identifier.  Otherwise, the responseValue
   is absent.





Zeilenga                      Experimental                      [Page 2]

RFC 5805                    LDAP Transactions                 March 2010


2.2.  Transaction Specification Control

   A Transaction Specification Control is an LDAPControl where the
   controlType is 1.3.6.1.1.21.2, the criticality is TRUE, and the
   controlValue is a transaction identifier.  The control is appropriate
   for update requests including Add, Delete, Modify, and ModifyDN
   (Rename) requests [RFC4511], as well as the Password Modify requests
   [RFC3062].

   As discussed in Section 4, the Transaction Specification control can
   be used in conjunction with request controls appropriate for the
   update request.

2.3.  End Transactions Request and Response

   An End Transaction Request is an LDAPMessage of CHOICE extendedReq
   where the requestName is 1.3.6.1.1.21.3 and the requestValue is
   present and contains a BER-encoded txnEndReq.

      txnEndReq ::= SEQUENCE {
           commit         BOOLEAN DEFAULT TRUE,
           identifier     OCTET STRING }

   A commit value of TRUE indicates a request to commit the transaction
   identified by the identifier.  A commit value of FALSE indicates a
   request to abort the identified transaction.

   An End Transaction Response is an LDAPMessage sent in response to a
   End Transaction Request.  Its response name is absent.  The
   responseValue when present contains a BER-encoded txnEndRes.

      txnEndRes ::= SEQUENCE {
           messageID MessageID OPTIONAL,
                -- msgid associated with non-success resultCode
           updatesControls SEQUENCE OF updateControls SEQUENCE {
                messageID MessageID,
                     -- msgid associated with controls
                controls  Controls
           } OPTIONAL
      }
      -- where MessageID and Controls are as specified in RFC 4511

   The txnEndRes.messageID provides the message id of the update request
   associated with a non-success response.  txnEndRes.messageID is
   absent when resultCode of the End Transaction Response is success
   (0).





Zeilenga                      Experimental                      [Page 3]

RFC 5805                    LDAP Transactions                 March 2010


   The txnEndRes.updatesControls provides a facility for returning
   response controls that normally (i.e., in the absence of
   transactions) would be returned in an update response.  The
   updateControls.messageID provides the message id of the update
   request associated with the response controls provided in
   updateControls.controls.

   The txnEndRes.updatesControls is absent when there are no update
   response controls to return.

   If both txnEndRes.messageID and txnEndRes.updatesControl are absent,
   the responseValue of the End Transaction Response is absent.

2.4.  Aborted Transaction Notice

   The Aborted Transaction Notice is an Unsolicited Notification message
   where the responseName is 1.3.6.1.1.21.4 and responseValue is present
   and contains a transaction identifier.

3.  An LDAP Transaction

3.1.  Extension Discovery

   To allow clients to discover support for this extension, servers
   implementing this specification SHOULD publish 1.3.6.1.1.21.1 and
   1.3.6.1.1.21.3 as values of the 'supportedExtension' attribute
   [RFC4512] within the Root DSE, and publish the 1.3.6.1.1.21.2 as a
   value of the 'supportedControl' attribute [RFC4512] of the Root DSE.

   A server MAY choose to advertise this extension only when the client
   is authorized to use it.

3.2.  Starting a Transaction

   A client wishing to perform a sequence of directory updates as a
   transaction issues a Start Transaction Request.  A server that is
   willing and able to support transactions responds to this request
   with a Start Transaction Response providing a transaction identifier
   and with a resultCode of success (0).  Otherwise, the server responds
   with a Start Transaction Response with a resultCode other than
   success indicating the nature of the failure.

   The transaction identifier provided upon successful start of a
   transaction is used in subsequent protocol messages to identify this
   transaction.






Zeilenga                      Experimental                      [Page 4]

RFC 5805                    LDAP Transactions                 March 2010


3.3.  Specification of a Transaction

   The client then can issue one or more update requests, each with a
   Transaction Specification control containing the transaction
   identifier indicating the updates are to be processed as part of the
   transaction.  Each of these update requests MUST have a different
   MessageID value.  If the server is unwilling or unable to attempt to
   process the requested update operation as part of the transaction,
   the server immediately returns the appropriate response to the
   request with a resultCode indicating the nature of the failure.
   Otherwise, the server immediately returns a resultCode of success (0)
   and the defers further processing of the operation is then deferred
   until settlement.

   If the server becomes unwilling or unable to continue the
   specification of a transaction, the server issues an Aborted
   Transaction Notice with a non-success resultCode indicating the
   nature of the failure.  All operations that were to be processed as
   part of the transaction are implicitly abandoned.  Upon receipt of an
   Aborted Transaction Notice, the client is to discontinue all use of
   the transaction identifier as the transaction is null and void.  Any
   future use of identifier by the client will result in a response
   containing a non-success resultCode.

3.4.  Transaction Settlement

   A client requests settlement of transaction by issuing an End
   Transaction Request for the transaction indicating whether it desires
   the transaction to be committed or aborted.

   Upon receipt of a request to abort the transaction, the server is to
   abort the identified transaction (abandoning all operations that are
   part of the transaction) and indicate that it has done so by
   returning an End Transaction Response with a resultCode of success
   (0).

   Upon receipt of a request to commit the transaction, the server
   processes all update operations of the transaction as one atomic,
   durable, isolated, and consistent action with each requested update
   being processed in turn.  Either all of the requested updates are to
   be successfully applied or none of the requested are to be applied.
   The server returns an End Transaction Response with a resultCode of
   success (0) and no responseValue to indicate all the requested
   updates were applied.  Otherwise, the server returns an End
   Transaction Response with a non-success resultCode indicating the
   nature of the failure.  If the failure is associated with a





Zeilenga                      Experimental                      [Page 5]

RFC 5805                    LDAP Transactions                 March 2010


   particular update request, the txnEndRes.messageID in the
   responseValue is the message id of this update request.  If the
   failure was not associated with any particular update request, no
   txnEnd.messageID is provided.

   There is no requirement that a server serialize transactions or
   updates requested outside of a transaction.  That is, a server MAY
   process multiple commit requests (from one or more clients) acting
   upon different sets of entries concurrently.  A server MUST avoid
   deadlock.

3.5.  Miscellaneous Issues

   Transactions cannot be nested.

   Each LDAP transaction should be initiated, specified, and settled
   within a stable security context.  Between the Start Request and the
   End Response, the peers SHOULD avoid negotiating new security
   associations and/or layers.

   Upon receipt of a Bind or Unbind request, the server SHALL abort any
   and all outstanding transactions without notice and nullify their
   identifiers.

4.  Interaction with Other Extensions

   The LDAP Transaction extension may be used with many but not all LDAP
   control extensions designed to extend update (and possibly other)
   operations.  The subsections that follow discuss interaction with a
   number of control extensions.  Interaction with other control
   extensions may be discussed in other documents, in particular in
   control extension specifications.

4.1.  Assertion Control

   The Assertion [RFC4528] control is appropriate for use with update
   requests specified as part of a transaction.  The evaluation of the
   assertion is performed as part of the transaction.

   The Assertion control is inappropriate for use with either the Start
   or End Transaction Extended operations.

4.2.  ManageDsaIT Control

   The ManageDsaIT [RFC3296] control is appropriate for use with update
   requests specified as part of a transaction.





Zeilenga                      Experimental                      [Page 6]

RFC 5805                    LDAP Transactions                 March 2010


   The ManageDsaIT control is inappropriate for use with either the
   Start or End Transaction Extended operations.

4.4.  Proxied Authorization Control

   The Proxied Authorization [RFC4370] control is appropriate for use
   with the Start Transaction Extended operation, but not the End
   Transaction Extended operation or any update request specified as
   part of a transaction.

   To request that a transaction be performed under a different
   authorization, the client provides a Proxied Authorization control
   with the Transaction Start Request.  If the client is not authorized
   to assume the requested authorization identity, the server is to
   return the authorizationDenied (123) resultCode in its response.
   Otherwise, further processing of the request and transaction is
   performed under the requested authorization identity.

   Any proxied authorization request attached to an update request
   specified as part of a transaction, or attached to a Transaction End
   Request, is to be regarded as a protocol error.

4.5.  Read Entry Controls

   The Pre- and Post-Read Entry [RFC4527] request control are
   appropriate for use with update requests specified as part of a
   transaction.

   The response control produced in response to a Pre- or Post-Read
   Entry request control is returned in the txnEndRes.updatesControls
   field of responseValue of the End Transaction Response.

   The Pre- and Post-Read Entry controls are inappropriate for use in
   the LDAPMessage.controls field of the Transaction Start and End
   Request and Response messages.

5.  Distributed Directory Considerations

   The LDAP/X.500 models provide for distributed directory operations,
   including server-side chaining and client-side chasing of referrals.

   This document does not preclude servers from chaining operations that
   are part of a transaction.  However, if a server does attempt such
   chaining, it MUST ensure that transaction semantics are provided.

   The mechanism defined by this document does not support client-side
   chasing.  Transaction identifiers are specific to a particular LDAP
   association (as established via the LDAP Bind operation).



Zeilenga                      Experimental                      [Page 7]

RFC 5805                    LDAP Transactions                 March 2010


   The LDAP/X.500 models provide for a single-master/multiple-shadow
   replication architecture.  There is no requirement that changes made
   to the directory based upon processing a transaction be replicated as
   one atomic action.  Hence, clients SHOULD NOT assume tight data
   consistency nor fast data convergence of shadow copies unless they
   have prior knowledge that these properties are provided.  Note that
   DontUseCopy control [DONTUSECOPY] may be used in conjunction with the
   LDAP search request to ask for the return of the authoritative copy
   of the entry.

6.  Security Considerations

   Transaction mechanisms may be the target of denial-of-service
   attacks, especially where implementations lock shared resources for
   the duration of a transaction.

   General security considerations [RFC4510], especially those
   associated with update operations [RFC4511], apply to this extension.

7.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has made the following
   assignments.

7.1.  Object Identifier

   IANA has assigned an LDAP Object Identifier (21) [RFC4520] to
   identify the protocol elements specified in this document.

      Subject: Request for LDAP Object Identifier Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Specification: RFC 5805
      Author/Change Controller: Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Comments: Identifies protocol elements for LDAP Transactions
















Zeilenga                      Experimental                      [Page 8]

RFC 5805                    LDAP Transactions                 March 2010


7.2.  LDAP Protocol Mechanism

   IANA has registered the protocol mechanisms [RFC4520] specified in
   this document.

      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: see table
      Description: see table
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Specification: RFC 5805
      Author/Change Controller: Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Comments:

      Object Identifier   Type  Description
      ------------------- ----  ----------------------------------
      1.3.6.1.1.21.1      E     Start Transaction Extended Request
      1.3.6.1.1.21.2      C     Transaction Specification Control
      1.3.6.1.1.21.3      E     End Transaction Extended Request
      1.3.6.1.1.21.4      N     Aborted Transaction Notice

      Legend
      ------------------------
      C => supportedControl
      E => supportedExtension
      N => Unsolicited Notice

8.  Acknowledgments

   The author gratefully acknowledges the contributions made by Internet
   Engineering Task Force participants.

9.  References

9.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3062]     Zeilenga, K., "LDAP Password Modify Extended
                 Operation", RFC 3062, February 2001.

   [RFC3296]     Zeilenga, K., "Named Subordinate References in
                 Lightweight Directory Access Protocol (LDAP)
                 Directories", RFC 3296, July 2002.






Zeilenga                      Experimental                      [Page 9]

RFC 5805                    LDAP Transactions                 March 2010


   [RFC4370]     Weltman, R., "Lightweight Directory Access Protocol
                 (LDAP) Proxied Authorization Control", RFC 4370,
                 February 2006.

   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Directory Information Models", RFC
                 4512, June 2006.

   [RFC4527]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP) Read Entry Controls", RFC 4527, June 2006.

   [RFC4528]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP) Assertion Control", RFC 4528, June 2006.

   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(2002) (also ISO/IEC 8824-1:2002).

   [X.690]       International Telecommunication Union -
                 Telecommunication Standardization Sector,
                 "Specification of ASN.1 encoding rules: Basic Encoding
                 Rules (BER), Canonical Encoding Rules (CER), and
                 Distinguished Encoding Rules (DER)", X.690(2002) (also
                 ISO/IEC 8825-1:2002).

9.2.  Informative References

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [ACID]        "Information technology -- Open Systems Interconnection
                 -- Distributed Transaction Processing -- Part 1: OSI TP
                 Model", Section 4, ISO/IEC 10026-1:1992.

   [DONTUSECOPY] Zeilenga, K., "The LDAP Don't Use Copy Control", Work
                 in Progress, December 2009.






Zeilenga                      Experimental                     [Page 10]

RFC 5805                    LDAP Transactions                 March 2010


Author's Address

   Kurt D. Zeilenga
   Isode Limited

   EMail: Kurt.Zeilenga@Isode.COM













































Zeilenga                      Experimental                     [Page 11]

alt-openldap11-devel/rfc/rfc4529.txt000064400000026734150410163240013004 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4529                           OpenLDAP Foundation
Category: Informational                                        June 2006


              Requesting Attributes by Object Class in the
              Lightweight Directory Access Protocol (LDAP)

Status of This Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   The Lightweight Directory Access Protocol (LDAP) search operation
   provides mechanisms for clients to request all user application
   attributes, all operational attributes, and/or attributes selected by
   their description.  This document extends LDAP to support a mechanism
   that LDAP clients may use to request the return of all attributes of
   an object class.

Table of Contents

   1. Background and Intended Use .....................................1
   2. Terminology .....................................................2
   3. Return of all Attributes of an Object Class .....................2
   4. Security Considerations .........................................3
   5. IANA Considerations .............................................3
   6. References ......................................................4
      6.1. Normative References .......................................4
      6.2. Informative References .....................................4

1.  Background and Intended Use

   In the Lightweight Directory Access Protocol (LDAP) [RFC4510], the
   search operation [RFC4511] supports requesting the return of a set of
   attributes.  This set is determined by a list of attribute
   descriptions.  Two special descriptors are defined to request all
   user attributes ("*") [RFC4511] and all operational attributes ("+")
   [RFC3673].  However, there is no convenient mechanism for requesting
   pre-defined sets of attributes such as the set of attributes used to
   represent a particular class of object.



Zeilenga                     Informational                      [Page 1]

RFC 4529         Requesting Attributes by Object Class         June 2006


   This document extends LDAP to allow an object class identifier to be
   specified in attributes lists, such as in Search requests, to request
   the return of all attributes belonging to an object class.  The
   COMMERCIAL AT ("@", U+0040) character is used to distinguish an
   object class identifier from an attribute descriptions.

   For example, the attribute list of "@country" is equivalent to the
   attribute list of 'c', 'searchGuide', 'description', and
   'objectClass'.  This object class is described in [RFC4519].

   This extension is intended primarily to be used where the user is in
   direct control of the parameters of the LDAP search operation, for
   instance when entering an LDAP URL [RFC4516] into a web browser, such
   as <ldap:///dc=example,dc=com?@organization?base>.

2.  Terminology

   In this document, the key words "MUST", "MUST NOT", "REQUIRED",
   "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY",
   and "OPTIONAL" are to be interpreted as described in BCP 14
   [RFC2119].

   DSA stands for Directory System Agent (or server).
   DSE stands for DSA-specific Entry.

3.  Return of All Attributes of an Object Class

   This extension allows object class identifiers to be provided in the
   attributes field of the LDAP SearchRequest [RFC4511] or other request
   values of the AttributeSelection data type (e.g., attributes field in
   pre/post read controls [ReadEntry]) and/or <attributeSelector>
   production (e.g., attributes of an LDAP URL [RFC4516]).  For each
   object class identified in the attributes field, the request is to be
   treated as if each attribute allowed by that class (by "MUST" or
   "MAY", directly or by "SUP"erior) [RFC4512] were itself listed.

   This extension extends the <attributeSelector> [RFC4511] production
   as indicated by the following ABNF [RFC4234]:

        attributeSelector =/ objectclassdescription
        objectclassdescription = ATSIGN oid options
        ATSIGN = %x40 ; COMMERCIAL AT ("@" U+0040)

   where <oid> and <options> productions are as defined in [RFC4512].







Zeilenga                     Informational                      [Page 2]

RFC 4529         Requesting Attributes by Object Class         June 2006


   The <oid> component of an <objectclassdescription> production
   identifies the object class by short name (descr) or object
   identifier (numericoid).  If the value of the <oid> component is
   unrecognized or does not refer to an object class, the object class
   description is to be treated as an unrecognized attribute
   description.

   The <options> production is included in the grammar for extensibility
   purposes.  An object class description with an unrecognized or
   inappropriate option is to be treated as unrecognized.

   Although object class description options and attribute description
   options share the same syntax, they are not semantically related.
   This document does not define any object description option.

   Servers supporting this feature SHOULD publish the object identifier
   (OID) 1.3.6.1.4.1.4203.1.5.2 as a value of the 'supportedFeatures'
   [RFC4512] attribute in the root DSE.  Clients supporting this feature
   SHOULD NOT use the feature unless they know that the server supports
   it.

4.  Security Considerations

   This extension provides a shorthand for requesting all attributes of
   an object class.  Because these attributes could have been listed
   individually, introduction of this shorthand is not believed to raise
   additional security considerations.

   Implementors of this LDAP extension should be familiar with security
   considerations applicable to the LDAP search operation [RFC4511], as
   well as with general LDAP security considerations [RFC4510].

5.  IANA Considerations

   Registration of the LDAP Protocol Mechanism [RFC4520] defined in this
   document has been completed.

       Subject: Request for LDAP Protocol Mechanism Registration
       Object Identifier: 1.3.6.1.4.1.4203.1.5.2
       Description: OC AD Lists
       Person & email address to contact for further information:
            Kurt Zeilenga <kurt@openldap.org>
       Usage: Feature
       Specification: RFC 4529
       Author/Change Controller: Kurt Zeilenga <kurt@openldap.org>
       Comments: none





Zeilenga                     Informational                      [Page 3]

RFC 4529         Requesting Attributes by Object Class         June 2006


   This OID was assigned [ASSIGN] by OpenLDAP Foundation, under its
   IANA-assigned private enterprise allocation [PRIVATE], for use in
   this specification.

6.  References

6.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4234]     Crocker, D., Ed. and P. Overell, "Augmented BNF for
                 Syntax Specifications: ABNF", RFC 4234, October 2005.

   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Directory Information Models", RFC 4512, June
                 2006.

   [RFC4516]     Smith, M., Ed. and T. Howes, "Lightweight Directory
                 Access Protocol (LDAP): Uniform Resource Locator", RFC
                 4516, June 2006.

   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(2002) (also ISO/IEC 8824-1:2002).

6.2.  Informative References

   [RFC3673]     Zeilenga, K., "Lightweight Directory Access Protocol
                 version 3 (LDAPv3): All Operational Attributes", RFC
                 3673, December 2003.

   [RFC4519]     Sciberras, A., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Schema for User Applications", RFC
                 4519, June 2006.

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.




Zeilenga                     Informational                      [Page 4]

RFC 4529         Requesting Attributes by Object Class         June 2006


   [ReadEntry]   Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP) Read Entry Controls", RFC 4527, June 2006.

   [ASSIGN]      OpenLDAP Foundation, "OpenLDAP OID Delegations",
                 http://www.openldap.org/foundation/oid-delegate.txt.

   [PRIVATE]     IANA, "Private Enterprise Numbers",
                 http://www.iana.org/assignments/enterprise-numbers.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org




































Zeilenga                     Informational                      [Page 5]

RFC 4529         Requesting Attributes by Object Class         June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                     Informational                      [Page 6]

alt-openldap11-devel/rfc/rfc4516.txt000064400000073542150410163240012777 0ustar00





Network Working Group                                      M. Smith, Ed.
Request for Comments: 4516                           Pearl Crescent, LLC
Obsoletes: 2255                                                 T. Howes
Category: Standards Track                                  Opsware, Inc.
                                                               June 2006


             Lightweight Directory Access Protocol (LDAP):
                        Uniform Resource Locator

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document describes a format for a Lightweight Directory Access
   Protocol (LDAP) Uniform Resource Locator (URL).  An LDAP URL
   describes an LDAP search operation that is used to retrieve
   information from an LDAP directory, or, in the context of an LDAP
   referral or reference, an LDAP URL describes a service where an LDAP
   operation may be progressed.

Table of Contents

   1. Introduction ....................................................2
   2. URL Definition ..................................................2
      2.1. Percent-Encoding ...........................................4
   3. Defaults for Fields of the LDAP URL .............................5
   4. Examples ........................................................6
   5. Security Considerations .........................................8
   6. Normative References ............................................9
   7. Informative References .........................................10
   8. Acknowledgements ...............................................10
   Appendix A: Changes Since RFC 2255 ................................11
      A.1. Technical Changes .........................................11
      A.2. Editorial Changes .........................................11






Smith & Howes               Standards Track                     [Page 1]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


1.  Introduction

   LDAP is the Lightweight Directory Access Protocol [RFC4510].  This
   document specifies the LDAP URL format for version 3 of LDAP and
   clarifies how LDAP URLs are resolved.  This document also defines an
   extension mechanism for LDAP URLs.  This mechanism may be used to
   provide access to new LDAP extensions.

   Note that not all the parameters of the LDAP search operation
   described in [RFC4511] can be expressed using the format defined in
   this document.  Note also that URLs may be used to represent
   reference knowledge, including that for non-search operations.

   This document is an integral part of the LDAP technical specification
   [RFC4510], which obsoletes the previously defined LDAP technical
   specification, RFC 3377, in its entirety.

   This document replaces RFC 2255.  See Appendix A for a list of
   changes relative to RFC 2255.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

2.  URL Definition

   An LDAP URL begins with the protocol prefix "ldap" and is defined by
   the following grammar, following the ABNF notation defined in
   [RFC4234].

      ldapurl     = scheme COLON SLASH SLASH [host [COLON port]]
                       [SLASH dn [QUESTION [attributes]
                       [QUESTION [scope] [QUESTION [filter]
                       [QUESTION extensions]]]]]
                                      ; <host> and <port> are defined
                                      ;   in Sections 3.2.2 and 3.2.3
                                      ;   of [RFC3986].
                                      ; <filter> is from Section 3 of
                                      ;   [RFC4515], subject to the
                                      ;   provisions of the
                                      ;   "Percent-Encoding" section
                                      ;   below.

      scheme      = "ldap"







Smith & Howes               Standards Track                     [Page 2]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


      dn          = distinguishedName ; From Section 3 of [RFC4514],
                                      ; subject to the provisions of
                                      ; the "Percent-Encoding"
                                      ; section below.

      attributes  = attrdesc *(COMMA attrdesc)
      attrdesc    = selector *(COMMA selector)
      selector    = attributeSelector ; From Section 4.5.1 of
                                      ; [RFC4511], subject to the
                                      ; provisions of the
                                      ; "Percent-Encoding" section
                                      ; below.

      scope       = "base" / "one" / "sub"
      extensions  = extension *(COMMA extension)
      extension   = [EXCLAMATION] extype [EQUALS exvalue]
      extype      = oid               ; From section 1.4 of [RFC4512].

      exvalue     = LDAPString        ; From section 4.1.2 of
                                      ; [RFC4511], subject to the
                                      ; provisions of the
                                      ; "Percent-Encoding" section
                                      ; below.

      EXCLAMATION = %x21              ; exclamation mark ("!")
      SLASH       = %x2F              ; forward slash ("/")
      COLON       = %x3A              ; colon (":")
      QUESTION    = %x3F              ; question mark ("?")

   The "ldap" prefix indicates an entry or entries accessible from the
   LDAP server running on the given hostname at the given portnumber.
   Note that the <host> may contain literal IPv6 addresses as specified
   in Section 3.2.2 of [RFC3986].

   The <dn> is an LDAP Distinguished Name using the string format
   described in [RFC4514].  It identifies the base object of the LDAP
   search or the target of a non-search operation.

   The <attributes> construct is used to indicate which attributes
   should be returned from the entry or entries.

   The <scope> construct is used to specify the scope of the search to
   perform in the given LDAP server.  The allowable scopes are "base"
   for a base object search, "one" for a one-level search, or "sub" for
   a subtree search.






Smith & Howes               Standards Track                     [Page 3]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


   The <filter> is used to specify the search filter to apply to entries
   within the specified scope during the search.  It has the format
   specified in [RFC4515].

   The <extensions> construct provides the LDAP URL with an
   extensibility mechanism, allowing the capabilities of the URL to be
   extended in the future.  Extensions are a simple comma-separated list
   of type=value pairs, where the =value portion MAY be omitted for
   options not requiring it.  Each type=value pair is a separate
   extension.  These LDAP URL extensions are not necessarily related to
   any of the LDAP extension mechanisms.  Extensions may be supported or
   unsupported by the client resolving the URL.  An extension prefixed
   with a '!' character (ASCII 0x21) is critical.  An extension not
   prefixed with a '!' character is non-critical.

   If an LDAP URL extension is implemented (that is, if the
   implementation understands it and is able to use it), the
   implementation MUST make use of it.  If an extension is not
   implemented and is marked critical, the implementation MUST NOT
   process the URL.  If an extension is not implemented and is not
   marked critical, the implementation MUST ignore the extension.

   The extension type (<extype>) MAY be specified using the numeric OID
   <numericoid> form (e.g., 1.2.3.4) or the descriptor <descr> form
   (e.g., myLDAPURLExtension).  Use of the <descr> form SHOULD be
   restricted to registered object identifier descriptive names.  See
   [RFC4520] for registration details and usage guidelines for
   descriptive names.

   No LDAP URL extensions are defined in this document.  Other documents
   or a future version of this document MAY define one or more
   extensions.

2.1.  Percent-Encoding

   A generated LDAP URL MUST consist only of the restricted set of
   characters included in one of the following three productions defined
   in [RFC3986]:

         <reserved>
         <unreserved>
         <pct-encoded>

   Implementations SHOULD accept other valid UTF-8 strings [RFC3629] as
   input.  An octet MUST be encoded using the percent-encoding mechanism
   described in section 2.1 of [RFC3986] in any of these situations:





Smith & Howes               Standards Track                     [Page 4]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


      The octet is not in the reserved set defined in section 2.2 of
      [RFC3986] or in the unreserved set defined in section 2.3 of
      [RFC3986].

      It is the single Reserved character '?' and occurs inside a <dn>,
      <filter>, or other element of an LDAP URL.

      It is a comma character ',' that occurs inside an <exvalue>.

   Note that before the percent-encoding mechanism is applied, the
   extensions component of the LDAP URL may contain one or more null
   (zero) bytes.  No other component may.

3.  Defaults for Fields of the LDAP URL

   Some fields of the LDAP URL are optional, as described above.  In the
   absence of any other specification, the following general defaults
   SHOULD be used when a field is absent.  Note that other documents MAY
   specify different defaulting rules; for example, section 4.1.10 of
   [RFC4511] specifies a different rule for determining the correct DN
   to use when it is absent in an LDAP URL that is returned as a
   referral.

   <host>
      If no <host> is given, the client must have some a priori
      knowledge of an appropriate LDAP server to contact.

   <port>
      The default LDAP port is TCP port 389.

   <dn>
      If no <dn> is given, the default is the zero-length DN, "".

   <attributes>
      If the <attributes> part is omitted, all user attributes of the
      entry or entries should be requested (e.g., by setting the
      attributes field AttributeDescriptionList in the LDAP search
      request to a NULL list, or by using the special <alluserattrs>
      selector "*").

   <scope>
      If <scope> is omitted, a <scope> of "base" is assumed.

   <filter>
      If <filter> is omitted, a filter of "(objectClass=*)" is assumed.

   <extensions>
      If <extensions> is omitted, no extensions are assumed.



Smith & Howes               Standards Track                     [Page 5]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


4.  Examples

   The following are some example LDAP URLs that use the format defined
   above.  The first example is an LDAP URL referring to the University
   of Michigan entry, available from an LDAP server of the client's
   choosing:

      ldap:///o=University%20of%20Michigan,c=US

   The next example is an LDAP URL referring to the University of
   Michigan entry in a particular ldap server:

      ldap://ldap1.example.net/o=University%20of%20Michigan,c=US

   Both of these URLs correspond to a base object search of the
   "o=University of Michigan,c=US" entry using a filter of
   "(objectclass=*)", requesting all attributes.

   The next example is an LDAP URL referring to only the postalAddress
   attribute of the University of Michigan entry:

      ldap://ldap1.example.net/o=University%20of%20Michigan,
             c=US?postalAddress

   The corresponding LDAP search operation is the same as in the
   previous example, except that only the postalAddress attribute is
   requested.

   The next example is an LDAP URL referring to the set of entries found
   by querying the given LDAP server on port 6666 and doing a subtree
   search of the University of Michigan for any entry with a common name
   of "Babs Jensen", retrieving all attributes:

      ldap://ldap1.example.net:6666/o=University%20of%20Michigan,
             c=US??sub?(cn=Babs%20Jensen)

   The next example is an LDAP URL referring to all children of the c=GB
   entry:

      LDAP://ldap1.example.com/c=GB?objectClass?ONE

   The objectClass attribute is requested to be returned along with the
   entries, and the default filter of "(objectclass=*)" is used.

   The next example is an LDAP URL to retrieve the mail attribute for
   the LDAP entry named "o=Question?,c=US", illustrating the use of the
   percent-encoding mechanism on the reserved character '?'.




Smith & Howes               Standards Track                     [Page 6]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


      ldap://ldap2.example.com/o=Question%3f,c=US?mail

   The next example (which is broken into two lines for readability)
   illustrates the interaction between the LDAP string representation of
   the filters-quoting mechanism and the URL-quoting mechanisms.

      ldap://ldap3.example.com/o=Babsco,c=US
              ???(four-octet=%5c00%5c00%5c00%5c04)

   The filter in this example uses the LDAP escaping mechanism of \ to
   encode three zero or null bytes in the value.  In LDAP, the filter
   would be written as (four-octet=\00\00\00\04).  Because the \
   character must be escaped in a URL, the \s are percent-encoded as %5c
   (or %5C) in the URL encoding.

   The next example illustrates the interaction between the LDAP string
   representation of the DNs-quoting mechanism and URL-quoting
   mechanisms.

      ldap://ldap.example.com/o=An%20Example%5C2C%20Inc.,c=US

   The DN encoded in the above URL is:

      o=An Example\2C Inc.,c=US

   That is, the left-most RDN value is:

      An Example, Inc.

   The following three URLs are equivalent, assuming that the defaulting
   rules specified in Section 3 of this document are used:

      ldap://ldap.example.net
      ldap://ldap.example.net/
      ldap://ldap.example.net/?

   These three URLs point to the root DSE on the ldap.example.net
   server.

   The final two examples show use of a hypothetical, experimental bind
   name extension (the value associated with the extension is an LDAP
   DN).

      ldap:///??sub??e-bindname=cn=Manager%2cdc=example%2cdc=com
      ldap:///??sub??!e-bindname=cn=Manager%2cdc=example%2cdc=com






Smith & Howes               Standards Track                     [Page 7]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


   The two URLs are the same, except that the second one marks the
   e-bindname extension as critical.  Notice the use of the percent-
   encoding mechanism to encode the commas within the distinguished name
   value in the e-bindname extension.

5.  Security Considerations

   The general URL security considerations discussed in [RFC3986] are
   relevant for LDAP URLs.

   The use of security mechanisms when processing LDAP URLs requires
   particular care, since clients may encounter many different servers
   via URLs, and since URLs are likely to be processed automatically,
   without user intervention.  A client SHOULD have a user-configurable
   policy that controls which servers the client will establish LDAP
   sessions with and with which security mechanisms, and SHOULD NOT
   establish LDAP sessions that are inconsistent with this policy.  If a
   client chooses to reuse an existing LDAP session when resolving one
   or more LDAP URLs, it MUST ensure that the session is compatible with
   the URL and that no security policies are violated.

   Sending authentication information, no matter the mechanism, may
   violate a user's privacy requirements.  In the absence of specific
   policy permitting authentication information to be sent to a server,
   a client should use an anonymous LDAP session.  (Note that clients
   conforming to previous LDAP URL specifications, where all LDAP
   sessions are anonymous and unprotected, are consistent with this
   specification; they simply have the default security policy.)  Simply
   opening a transport connection to another server may violate some
   users' privacy requirements, so clients should provide the user with
   a way to control URL processing.

   Some authentication methods, in particular, reusable passwords sent
   to the server, may reveal easily-abused information to the remote
   server or to eavesdroppers in transit and should not be used in URL
   processing unless they are explicitly permitted by policy.
   Confirmation by the human user of the use of authentication
   information is appropriate in many circumstances.  Use of strong
   authentication methods that do not reveal sensitive information is
   much preferred.  If the URL represents a referral for an update
   operation, strong authentication methods SHOULD be used.  Please
   refer to the Security Considerations section of [RFC4513] for more
   information.

   The LDAP URL format allows the specification of an arbitrary LDAP
   search operation to be performed when evaluating the LDAP URL.
   Following an LDAP URL may cause unexpected results, for example, the
   retrieval of large amounts of data or the initiation of a long-lived



Smith & Howes               Standards Track                     [Page 8]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


   search.  The security implications of resolving an LDAP URL are the
   same as those of resolving an LDAP search query.

6.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3629]  Yergeau, F., "UTF-8, a transformation format of ISO
              10646", STD 63, RFC 3629, November 2003.

   [RFC3986]  Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
              Resource Identifier (URI): Generic Syntax", STD 66, RFC
              3986, January 2005.

   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", RFC 4234, October 2005.

   [RFC4510]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC 4510, June
              2006.

   [RFC4511]  Sermersheim, J., Ed., "Lightweight Directory Access
              Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512, June
              2006.

   [RFC4513]  Harrison, R., Ed., "Lightweight Directory Access Protocol
              (LDAP): Authentication Methods and Security Mechanisms",
              RFC 4513, June 2006.

   [RFC4514]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): String Representation of Distinguished Names", RFC
              4514, June 2006.

   [RFC4515]  Smith, M. Ed. and T. Howes, "Lightweight Directory Access
              Protocol (LDAP): String Representation of Search Filters",
              RFC 4515, June 2006.











Smith & Howes               Standards Track                     [Page 9]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


7.  Informative References

   [RFC2396]  Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
              Resource Identifiers (URI): Generic Syntax", RFC 2396,
              August 1998.

   [RFC4520]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

8.  Acknowledgements

   The LDAP URL format was originally defined at the University of
   Michigan.  This material is based upon work supported by the National
   Science Foundation under Grant No. NCR-9416667.  The support of both
   the University of Michigan and the National Science Foundation is
   gratefully acknowledged.

   This document obsoletes RFC 2255 by Tim Howes and Mark Smith.
   Changes included in this revised specification are based upon
   discussions among the authors, discussions within the LDAP (v3)
   Revision Working Group (ldapbis), and discussions within other IETF
   Working Groups.  The contributions of individuals in these working
   groups is gratefully acknowledged.  Several people in particular have
   made valuable comments on this document: RL "Bob" Morgan, Mark Wahl,
   Kurt Zeilenga, Jim Sermersheim, and Hallvard Furuseth deserve special
   thanks for their contributions.
























Smith & Howes               Standards Track                    [Page 10]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


Appendix A: Changes Since RFC 2255

A.1.  Technical Changes

   The following technical changes were made to the contents of the "URL
   Definition" section:

   Revised all of the ABNF to use common productions from [RFC4512].

   Replaced references to [RFC2396] with a reference to [RFC3986] (this
   allows literal IPv6 addresses to be used inside the <host> portion of
   the URL, and a note was added to remind the reader of this
   enhancement).  Referencing [RFC3986] required changes to the ABNF and
   text so that productions that are no longer defined by [RFC3986] are
   not used.  For example, <hostport> is not defined by [RFC3986] so it
   has been replaced with host [COLON port].  Note that [RFC3986]
   includes new definitions for the "Reserved" and "Unreserved" sets of
   characters, and the net result is that the following two additional
   characters should be percent-encoded when they appear anywhere in the
   data used to construct an LDAP URL: "[" and "]" (these two characters
   were first added to the Reserved set by RFC 2732).

   Changed the definition of <attrdesc> to refer to <attributeSelector>
   from [RFC4511].  This allows the use of "*" in the <attrdesc> part of
   the URL.  It is believed that existing implementations of RFC 2255
   already support this.

   Avoided use of <prose-val> (bracketed-string) productions in the
   <dn>, <host>, <attrdesc>, and <exvalue> rules.

   Changed the ABNF for <ldapurl> to group the <dn> component with the
   preceding <SLASH>.

   Changed the <extype> rule to be an <oid> from [RFC4512].

   Changed the text about extension types so it references [RFC4520].
   Reordered rules to more closely follow the order in which the
   elements appear in the URL.

   "Bindname Extension": removed due to lack of known implementations.

A.2.  Editorial Changes

   Changed document title to include "LDAP:" prefix.

   IESG Note: removed note about lack of satisfactory mandatory
   authentication mechanisms.




Smith & Howes               Standards Track                    [Page 11]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


   "Status of this Memo" section: updated boilerplate to match current
   I-D guidelines.

   "Abstract" section: separated from introductory material.

   "Table of Contents" and "Intellectual Property" sections: added.

   "Introduction" section: new section; separated from the Abstract.
   Changed the text indicate that RFC 2255 is replaced by this document
   (instead of RFC 1959).  Added text to indicate that LDAP URLs are
   used for references and referrals.  Fixed typo (replaced the nonsense
   phrase "to perform to retrieve" with "used to retrieve").  Added a
   note to let the reader know that not all of the parameters of the
   LDAP search operation described in [RFC4511] can be expressed using
   this format.

   "URL Definition" section: removed second copy of <ldapurl> grammar
   and following two paragraphs (editorial error in RFC 2255).  Fixed
   line break within '!' sequence.  Reformatted the ABNF to improve
   readability by aligning comments and adding some blank lines.
   Replaced "residing in the LDAP server" with "accessible from the LDAP
   server" in the sentence immediately following the ABNF.  Removed the
   sentence "Individual attrdesc names are as defined for
   AttributeDescription in [RFC4511]."  because [RFC4511]'s
   <attributeSelector> is now used directly in the ABNF.  Reworded last
   paragraph to clarify which characters must be percent-encoded.  Added
   text to indicate that LDAP URLs are used for references and
   referrals.  Added text that refers to the ABNF from RFC 4234.
   Clarified and strengthened the requirements with respect to
   processing of URLs that contain implemented and not implemented
   extensions (the approach now closely matches that specified in
   [RFC4511] for LDAP controls).

   "Defaults for Fields of the LDAP URL" section: added; formed by
   moving text about defaults out of the "URL Definition" section.
   Replaced direct reference to the attribute name "*" with a reference
   to the special <alluserattrs> selector "*" defined in [RFC4511].

   "URL Processing" section: removed.

   "Examples" section: Modified examples to use example.com and
   example.net hostnames.  Added missing '?' to the LDAP URL example
   whose filter contains three null bytes.  Removed space after one
   comma within a DN.  Revised the bindname example to use e-bindname.
   Changed the name of an attribute used in one example from "int" to
   "four-octet" to avoid potential confusion.  Added an example that
   demonstrates the interaction between DN escaping and URL percent-
   encoding.  Added some examples to show URL equivalence with respect



Smith & Howes               Standards Track                    [Page 12]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


   to the <dn> portion of the URL.  Used uppercase in some examples to
   remind the reader that some tokens are case-insensitive.

   "Security Considerations" section: Added a note about connection
   reuse.  Added a note about using strong authentication methods for
   updates.  Added a reference to [RFC4513].  Added note that simply
   opening a connection may violate some users' privacy requirements.
   Adopted the working group's revised LDAP terminology specification by
   replacing the word "connection" with "LDAP session" or "LDAP
   connection" as appropriate.

   "Acknowledgements" section: added statement that this document
   obsoletes RFC 2255.  Added Kurt Zeilenga, Jim Sermersheim, and
   Hallvard Furuseth.

   "Normative References" section: renamed from "References" per new RFC
   guidelines.  Changed from [1] style to [RFC4511] style throughout the
   document.  Added references to RFC 4234 and RFC 3629.  Updated all
   RFC 1738 references to point to the appropriate sections within
   [RFC3986].  Updated the LDAP references to refer to LDAPBis WG
   documents.  Removed the reference to the LDAP Attribute Syntaxes
   document and added references to the [RFC4513], [RFC4520], and
   [RFC4510] documents.

   "Informative References" section: added.

   Header and "Authors' Addresses" sections: added "editor" next to Mark
   Smith's name.  Updated affiliation and contact information.

   Copyright: updated the year.

   Throughout the document: surrounded the names of all ABNF productions
   with "<" and ">" where they are used in descriptive text.


















Smith & Howes               Standards Track                    [Page 13]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


Authors' Addresses

   Mark Smith, Editor
   Pearl Crescent, LLC
   447 Marlpool Dr.
   Saline, MI 48176
   USA

   Phone: +1 734 944-2856
   EMail: mcs@pearlcrescent.com


   Tim Howes
   Opsware, Inc.
   599 N. Mathilda Ave.
   Sunnyvale, CA 94085
   USA

   Phone: +1 408 744-7509
   EMail: howes@opsware.com































Smith & Howes               Standards Track                    [Page 14]

RFC 4516             LDAP: Uniform Resource Locator            June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Smith & Howes               Standards Track                    [Page 15]

alt-openldap11-devel/rfc/rfc2377.txt000064400000112602150410163240012771 0ustar00





Network Working Group                                        A. Grimstad
Request for Comments: 2377                                      R. Huber
Category: Informational                                             AT&T
                                                             S. Sataluri
                                                     Lucent Technologies
                                                                 M. Wahl
                                                     Critical Angle Inc.
                                                          September 1998


        Naming Plan for Internet Directory-Enabled Applications

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

Abstract

   Application of the conventional X.500 approach to naming has
   heretofore, in the experience of the authors, proven to be an
   obstacle to the wide deployment of directory-enabled applications on
   the Internet.  We propose a new directory naming plan that leverages
   the strengths of the most popular and successful Internet naming
   schemes for naming objects in a hierarchical directory.  This plan
   can, we believe, by extending the X.500 approach to naming,
   facilitate the creation of an Internet White Pages Service (IWPS) and
   other directory-enabled applications by overcoming the problems
   encountered by those using the conventional X.500 approach.

1.0 Executive Summary

   Application of the conventional X.500 approach to naming has
   heretofore, in the experience of the authors, proven to be an
   obstacle to the wide deployment of directory-enabled applications on
   the Internet.  The required registration infrastructure is either
   non-existent or largely ignored.  The infrastructure that does exist
   is cumbersome to use and tends to produce counterproductive results.
   The attributes used for naming have been confusing for users and
   inflexible to managers and operators of directory servers.






Grimstad, et. al.            Informational                      [Page 1]

RFC 2377                A Directory Naming Plan           September 1998


   This paper describes a directory naming plan for the construction of
   an Internet directory infrastructure to support directory-enabled
   applications that can serve as an alternative (or extension) to the
   conventional X.500 approach.

   The plan has the following two main features.  First, it bases the
   root and upper portions of the name hierarchy on the existing
   infrastructure of names from the Domain Name System (DNS). This
   component of the plan makes use of the ideas described in the
   companion paper to this plan, "Using Domains in LDAP Distinguished
   Names" [1].  And second, it provides a number of options for the
   assignment of names to directory leaf objects such as person objects,
   including an option that allows the reuse of existing Internet
   identifiers for people.

   Just as the conventional X.500 style of naming is not a formal
   standard, use of the naming plan described here is not obligatory for
   directory-enabled applications on the Internet. Other approaches are
   permissible. However, we believe widespread use of this plan will
   largely eliminate naming as a typically thorny issue when
   administrators set up an LDAP-based directory service.  Further, we
   strongly encourage developers of directory-enabled products,
   especially LDAP clients and user interfaces, to assume that this
   naming plan will see widespread use and design their products
   accordingly.

   Here, in summary, is our proposal.

   The upper portions of the hierarchical directory tree should be
   constructed using the components of registered DNS names using the
   domain component attribute "dc".  The directory name for the
   organization having the domain name "acme.com" will then be, e.g.,

      dc=acme, dc=com

   Organizations can add additional directory structure, for example to
   support implementation of access control lists or partitioning of
   their directory information, by using registered subdomains of DNS
   names, e.g., the subdomain "corporate.acme.com" can be used as the
   basis for the directory name

      dc=corporate, dc=acme, dc=com

   For naming directory leaf objects such as persons, groups, server
   applications and certification authorities in a hierarchical
   directory, we propose the use of either the "uid" (user identifier)
   or the "cn" (common name) attribute for the relative distinguished
   name. This plan does not constrain how these two attributes are used.



Grimstad, et. al.            Informational                      [Page 2]

RFC 2377                A Directory Naming Plan           September 1998


   One approach to their use, for example, is to employ the uid
   attribute as the RDN when reusing an existing store of identifiers
   and the cn attribute as the RDN when creating new identifiers
   specifically for the directory.  A convenient existing identification
   scheme for person objects is the RFC822 mailbox identifier. So an RDN
   for person employing this store of identifiers would be, e.g.,

      uid=John.Smith@acme.com

   For leaf objects not conveniently identified with such a scheme, the
   "cn" attribute is used, e.g.,

      cn=Reading Room

   Directory distinguished names will thus have the following structure,
   e.g.,

      uid=John.Smith@acme.com, dc=acme, dc=com
      uid=Mary.Jones@acme.com, dc=corporate, dc=acme, dc=com
      uid=J.Smith@worldnet.att.net, dc=legal, dc=acme, dc=com
      cn=Reading Room, dc=physics, dc=national-lab, dc=edu

2.0 The Problem

   The X.500 Directory model [2] can be used to create a world-wide
   distributed directory. The Internet X.500 Directory Pilot has been
   operational for several years and has grown to a size of about 1.5
   million entries of varying quality.  The rate of growth of the pilot
   is far lower than the rate of growth of the Internet during the pilot
   period.

   There are a substantial number of contributing factors that have
   inhibited the growth of this pilot.  The common X.500 approach to
   naming, while not the preponderant problem, has contributed in
   several ways to limit the growth of an Internet White Pages Service
   based on X.500.

   The conventional way to construct names in the X.500 community is
   documented as an informative (i.e., not officially standardized)
   Annex B to X.521. The relative distinguished name (RDN) of a user
   consists of a common name (cn) attribute. This is meant to be what --
   in the user's particular society -- is customarily understood to be
   the name of that user. The distinguished name of a user is the
   combination of the name of some general object, such as an
   organization or a geographical unit, with the common name. There are
   two main problems with this style of name construction.





Grimstad, et. al.            Informational                      [Page 3]

RFC 2377                A Directory Naming Plan           September 1998


   First, the common name attribute, while seeming to be user-friendly,
   cannot be used generally as an RDN in practice.  In any significant
   set of users to be named under the same Directory Information Tree
   (DIT) node there will be collisions on common name.  There is no way
   to overcome this other than either by forcing uniqueness on common
   names, something they do not possess, or by using an additional
   attribute to prevent collisions.  This additional attribute normally
   needs to be unique in a much larger context to have any practical
   value.  The end result is a RDN that is very long and unpopular with
   users.

   Second, and more serious, X.500 has not been able to use any
   significant number of pre-existing names.  Since X.500 naming models
   typically use organization names as part of the hierarchy [2, 3],
   organization names must be registered.  As organization names are
   frequently tied to trademarks and are used in sales and promotions,
   registration can be a difficult and acrimonious process.

   The North American Directory Forum (NADF, now the North Atlantic
   Directory Forum but still the NADF) proposed to avoid the problem of
   registration by using names that were already registered in the
   "civil naming infrastructure" [4][5].  Directory distinguished names
   would be based on an organization's legal name as recognized by some
   governmental agency (county clerk, state secretary of state, etc.) or
   other registering entity such as ANSI.

   This scheme has the significant advantage of keeping directory
   service providers out of disputes about the right to use a particular
   name, but it leads to rather obscure names.  Among these obscurities,
   the legal name almost invariably takes a form that is less familiar
   and longer than what users typically associate with the organization.
   For example, in the US a large proportion of legal organization names
   end with the text ", Inc." as in "Acme, Inc."  Moreover, in the case
   of the US, the civil naming infrastructure does not operate
   nationally, so the organization names it provides must be located
   under state and regional DIT nodes, making them difficult to find
   while browsing the directory.  NADF proposes a way to algorithmically
   derive multi-attribute RDNs which would allow placement of entries or
   aliases in more convenient places in the DIT, but these derived names
   are cumbersome and unpopular.  For example, suppose Nadir is an
   organization that is registered in New Jersey civil naming
   infrastructure under the name "Nadir Networks, Inc."  Its civil
   distinguished name (DN) would then be

      o="Nadir Networks, Inc.", st=New Jersey, c=US






Grimstad, et. al.            Informational                      [Page 4]

RFC 2377                A Directory Naming Plan           September 1998


   while its derived name which is unambiguous under c=US directly is

      o="Nadir Networks, Inc." + st=New Jersey, c=US

   More generally, the requirement for registration of organizations in
   X.500 naming has led to the establishment of national registration
   authorities whose function is mainly limited to assignment of X.500
   organization names.  Because of the very limited attraction of X.500,
   interest in registering an organization with one of these national
   authorities has been minimal.  Finally, multi-national organizations
   are frustrated by a lack of an international registration authority.

3.0 Requirements

   A directory naming plan must provide a guide for the construction of
   names (identifiers, labels) for directory objects that are
   unambiguous (identify only one directory object) within some context
   (namespace), at a minimum within one isolated directory server.

   A directory object is simply a set of attribute values. The
   association between a real-world object and a directory object is
   made by directory-enabled applications and is, in the general case,
   one to many.

   The following additional naming characteristics are requirements that
   this naming plan seeks to satisfy:

   a) hierarchical

   The Internet, consisting of a very large number of objects and
   management domains, requires hierarchical names.  Such names permit
   delegation in the name assignment process and partitioning of
   directory information among directory servers.

   b) friendly to loose coupling of directory servers

   One purpose of this naming plan is to define a naming pattern that
   will facilitate one form or another of loose coupling of potentially
   autonomous directory servers into a larger system.

   A name in such a loosely-coupled system should unambiguously identify
   one real-world object.  The real-world object may, however, be
   represented differently (i.e. by different directory objects having
   different attributes but the same DN) in different (e.g.
   independently managed) servers in the loosely-coupled system.  The
   plan does not attempt to produce names to overcome this likely
   scenario.  That is, it does not attempt to produce a single namespace
   for all directory objects. (This issue is considered in more detail



Grimstad, et. al.            Informational                      [Page 5]

RFC 2377                A Directory Naming Plan           September 1998


   in Section 5.1.)

   c) readily usable by LDAP clients and servers

   As of this writing, a substantial number of the Lightweight Directory
   Access Protocol (LDAP) [6][7] implementations are currently available
   or soon will be.  The names specified by this naming plan should be
   readily usable by these implementations and applications based on
   them.

   d) friendly to re-use of existing Internet name registries

   As described in Section 2 above, creation of new global name
   registries has been highly problematic.  Therefore, a fundamental
   requirement this plan addresses is to enable the reuse of existing
   Internet name registries such as DNS names and RFC822 mailbox
   identifiers when constructing directory names.

   e) minimally user-friendly

   Although we expect that user interfaces of directory-enabled
   applications will avoid exposing users to DNs, it is unlikely that
   users can be totally insulated from them.  For this reason, the
   naming plan should permit use of familiar information in name
   construction.  Minimally, a user should be capable of recognizing the
   information encoded in his/her own DN.  Names that are totally opaque
   to users cannot meet this requirement.

4.0 Name Construction

   The paper assumes familiarity with the terminology and concepts
   behind the terms distinguished name (DN) and relative distinguished
   name (RDN) [2][8][9].

   We describe how DNs can be constructed using three attribute types,
   domainComponent (dc), userID (uid) and commonName (cn).  They are
   each described in turn.

4.1 Domain Component (dc)

   The domain component attribute is defined and registered in RFC1274
   [3][10].  It is used in the construction of a DN from a domain name.
   Details of the construction algorithm is described in "Using Domains
   in LDAP Distinguished Names" [1].

   An organization wishing to deploy a directory following this naming
   plan would proceed as follows.  Consider an organization, for example
   "Acme, Inc.", having the registered domain name "acme.com".  It would



Grimstad, et. al.            Informational                      [Page 6]

RFC 2377                A Directory Naming Plan           September 1998


   construct the DN

      dc=acme, dc=com

   from its domain name.  It would then use this DN as the root of its
   subtree of directory information.

   The DN itself can be used to identify a directory organization object
   that represents information about the organization. The directory
   schema required to enable this is described below in section 5.2.

   The subordinates of the DN will be directory objects related to the
   organization.  The domain component attribute can be used to name
   subdivisions of the organization such as organizational units and
   localities.  Acme, for example, might use the domain names
   "corporate.acme.com" and "richmond.acme.com" to construct the names

      dc=corporate, dc=acme, dc=com
      dc=richmond, dc=acme, dc=com

   under which to place its directory objects.  The directory schema
   required to name organizationalUnit and locality objects in this way
   is described below in section 5.2.

   Note that subdivisions of the organization such as organizational
   units and localities could also be assigned RDNs using the
   conventional X.500 naming attributes, e.g.

      ou=corporate, dc=acme, dc=com
      l=richmond, dc=acme, dc=com.

   Use of the dc attribute for the RDN of directory objects of class
   "domain" is also possible [1].

4.2 User ID (uid)

   The userid (uid) attribute is defined and registered in RFC1274
   [3][10].

   This attribute may be used to construct the RDN for directory objects
   subordinate to objects named according to the procedure described in
   Section 4.1.  This plan does not constrain how this attribute is
   used.

4.3 Common Name (cn)

   The commonName (cn) attribute is defined and registered in X.500
   [3][11].



Grimstad, et. al.            Informational                      [Page 7]

RFC 2377                A Directory Naming Plan           September 1998


   This attribute may be used to construct the RDN for directory objects
   subordinate to objects named according to the procedure described in
   Section 4.1.  This plan does not constrain how this attribute is
   used.

4.4 Examples of uid and cn Usage

   Although this plan places no constraints on the use of the uid and cn
   attributes for name construction, we would like to offer some
   suggestions by way of examples.

   In practice, we have used uid for the RDN for person objects were we
   could make use of an existing registry of names and cn for other
   objects.

   Examples of existing registries of identifiers for person objects are
   RFC822 mailbox identifiers, employee numbers and employee "handles".
   Aside from the convenience to administrators of re-use of an existing
   store of identifiers, if it is ever necessary to display to a user
   his/her DN, there is some hope that it will be recognizable when such
   identifiers are used.

   We have found RFC822 mailbox identifiers a particularly convenient
   source for name construction.  When a person has several e-mail
   addresses, one will be selected for the purpose of user
   identification.  We call this the "distinguished" e-mail address or
   the "distinguished" RFC822 mailbox identifier for the user.

   For example, if there is a user affiliated with the organization Acme
   having distinguished e-mail address J.Smith@acme.com, the uid
   attribute will be:

      uid=J.Smith@acme.com

   The domain component attributes of a user's DN will normally be
   constructed from the domain name of his/her distinguished e-mail
   address.  That is, for the user uid=J.Smith@acme.com the domain
   component attributes would typically be:

      dc=acme, dc=com

   The full LDAP DN for this user would then be:

      uid=J.Smith@acme.com, dc=acme, dc=com

   Directory administrators having several RFC822 identifiers to choose
   from when constructing a DN for a user should consider the following
   factors:



Grimstad, et. al.            Informational                      [Page 8]

RFC 2377                A Directory Naming Plan           September 1998


      o Machine-independent addresses are likely to be more stable,
        resulting in directory names that change less. Thus an
        identifier such as:

            js@acme.com

        may well be preferable to one such as:

            js@blaster.third-floor.acme.com.

      o Use of some form of "handle" for the "local" part that is
        distinct from a user's real name may result in fewer collisions
        and thereby lessen user pain and suffering.  Thus the
        identifier:

            js@acme.com

        may well be preferable to one such as:

            J.Smith@acme.com

   Practical experience with use of the RFC822 mailbox identifier scheme
   described here has shown that there are situations where it is
   convenient to use such identifies for all users in a particular
   population, although a few users do not, in fact, possess working
   mailboxes.  For example, an organization may have a existing unique
   identification scheme for all employees that is used as a alias to
   the employees' real mailboxes -- which may be quite heterogeneous in
   structure.  The identification scheme works for all employees to
   identify unambiguously each employee; it only works as an e-mail
   alias for those employees having real mailboxes.  For this reason it
   would be a bad assumption for directory-enabled applications to
   assume the uid to be a valid mailbox; the value(s) of the mail
   attribute should always be checked.

   It is important to emphasize that the elements of the domain name of
   an RFC822 identifier may, BUT NEED NOT, be the same as the domain
   components of the DN.  This means that the domain components provide
   a degree of freedom to support access control or other directory
   structuring requirements that need not be mechanically reflected in
   the user's e-mail address.  We do not want under any condition to
   force the user's e-mail address to change just to facilitate a new
   system requirement such as a modification in an access control
   structure.  It should also be noted that while we do not require that
   the domain components match the RFC822 identifier, we DO require that
   the concatenated domain components form a registered domain name,
   that is, one that is represented in the DNS. This automatically
   avoids name conflicts in the directory hierarchy.



Grimstad, et. al.            Informational                      [Page 9]

RFC 2377                A Directory Naming Plan           September 1998


   To provide an example of a DN which deviates from what might be
   considered the default structure, consider the following scenario.

   Suppose that J.Smith needs to be granted special permissions to
   information in the dc=acme, dc=com part of the LDAP DIT.  Since it
   will be, in general, easier to organize special users by their name
   structure than via groups (an arbitrary collection of DNs), we use
   subdomains for this purpose.  Suppose the special permissions were
   required by users in the MIS organizational unit.  A subdomain
   "mis.acme.com" is established, if it does not already exist,
   according to normal DNS procedures.  The special permissions will be
   granted to users with the name structure:

      uid=*, dc=mis, dc=acme, dc=com

   The DN of J.Smith in this case will be:

      uid=J.Smith@acme.com, dc=mis, dc=acme, dc=com

   In principal, there is nothing to prevent the domain name elements of
   the RFC822 identifier from being completely different from the domain
   components of the DN.  For instance, the DN for a J.Smith could be:

      uid=J.Smith@worldnet.att.net, dc=mis, dc=acme, dc=com

   While we do not REQUIRE that the domain name part of the uid match
   the dc components of the directory distinguished name, we suggest
   that this be done where possible. At a minimum, if the most
   significant pieces of the DN and the uid are the same (i.e.,
   "dc=acme, dc=com" and "acme.com") the likelihood, based on a
   knowledge of a user's e-mail address, of discovering an appropriate
   directory system to contact to find information about the user is
   greatly enhanced.

   The example above represents a situation where this suggestion isn't
   possible because some of the users in a population have mailbox
   identifiers that differ from the pattern of the rest of the users,
   e.g., most mailboxes are of the form local@acme.com, but a
   subpopulation have mailboxes from an ISP and therefore mailboxes of
   the form local@worldnet.att.net.

5.0 Naming Plan and Directories

5.1 Directory Services Considerations

   We envision the deployment of LDAP-based directory services on the
   Internet to take the form of loosely coupled LDAP servers. This
   coupling will occur at two levels.



Grimstad, et. al.            Informational                     [Page 10]

RFC 2377                A Directory Naming Plan           September 1998


   Firstly, LDAP servers will be loosely connected into islands (i.e. a
   set of servers sharing a single DN namespace). The glue connecting
   the islands will be LDAP referral [12] information configured into
   the LDAP servers. An LDAP search directed to any server in such an
   island can be answered, if the information is not available to that
   server, by an LDAP referral to another, more appropriate server
   within the same island.

   Secondly, various techniques will be used span LDAP islands. The
   concept that enables such techniques is the LDAP URL [13]. By
   combining a DNS host name and port (corresponding to one or more LDAP
   servers) with a DN, the LDAP URL provides unified high-level
   identification scheme (an LDAP URL namespace) for directory objects.

   Because an LDAP referral is expressed as one or more LDAP URL, these
   two levels of coupling may not sharply distinguished in practice.

   We do not envision the X.500 model of a single DIT (i.e. a single DN
   namespace) to be viable in an environment of competing service
   providers.  This naming plan does not attempt to produce DNs to hide
   the possibility that a given real-world object may have independently
   managed directory objects with the same DN associated with it.

5.2 Directory Schema Implications of the Naming Plan

   The traditional directory schema(s) developed for the X.500 standard
   and its application to the Internet [4] require extension to be used
   with the naming plan developed here. The extensions described below
   attempt to reuse existing schema elements as much as possible. The
   directory objects for which extensions are required are:
   organization, organizational unit, and various classes of leaf
   objects. We describe the schema modifications below for organization,
   organizationalUnit and selected leaf classes.

   So as to continue to use existing structural object classes to the
   extent possible, we propose supplementing entries based on these
   classes with additional information from two new auxiliary object
   classes, dcObject and uidObject. They are specified using the
   notation in Section 4 of [14].

   The auxiliary object class dcObject is defined in "Using Domains in
   LDAP Distinguished Names" [1].









Grimstad, et. al.            Informational                     [Page 11]

RFC 2377                A Directory Naming Plan           September 1998


   The auxiliary object class uidObject is defined as:

   ( 1.3.6.1.1.3.1
     NAME uidObject
     SUP top
     AUXILIARY
     MUST uid )

5.2.1 Organization Schema

   The dc attribute is employed to construct the RDN of an organization
   object.  This is enabled by adding the auxiliary class dcObject to
   the organization's objectClass attribute.

5.2.2 Organizational Unit Schema

   The dc attribute is employed to construct the RDN of an
   organizationalUnit object (which is subordinate in the DIT to either
   an organization or an organizationalUnit object).  This is enabled by
   adding the auxiliary class dcObject to the organizational unit's
   objectClass attribute.

5.2.3 Person Schema

   No schema extensions are required for person objects if either the
   inetOrgPerson [15] (preferred) or the newPilotPerson object classes
   are used. The attribute uid is permissible in each class. For
   consistency, the uidObject could be added to person entry objectClass
   attributes to assist applications filtering on this object class
   attribute value. Use of other classes for person objects with RDN
   constructed with the uid attribute such as organizationalPerson
   requires the use of the uidObject class.

   It has been traditional in X.500 and LDAP directory services to
   employ the common name (cn) attribute in naming.  While this naming
   plan doesn't require use of the cn attribute in naming, it should be
   stressed that it is a required attribute in any class derived from
   the person class and is still quite important.  It will play a
   significant role in enabling searches to find user entries of
   interest.

5.2.4 Certification Authority Schema

   The certification authority (CA) object class is an auxiliary class,
   meaning it is essentially a set of additional attributes for a base
   class such as organizationalRole, organization, organizationalUnit or
   person.  Except in the case where the base structural class is
   inetOrgPerson, use of the uid attribute to construct the RDN of a CA



Grimstad, et. al.            Informational                     [Page 12]

RFC 2377                A Directory Naming Plan           September 1998


   will require the auxiliary class uidObject to permit the uid
   attribute to be used. In the cases where organizationalUnit or
   organization is the base class for a CA, use of the auxiliary class
   dcObject will permit the RDN of the CA to be a domain component.

5.2.5 Server and Server Application Schema

   Servers and server applications are typically represented, for want
   of anything better, by entries of the object class applicationProcess
   (or a class derived from it).  Sometimes the class applicationEntity
   is used.  In either case, the uid attribute should probably not be
   employed to construct the RDN of a server or server application
   object.  The standard schema uses the attribute cn for such RDNs.

   Suppose one wants to use this naming plan both in the construction of
   DNs for SSL server certificates and for their storage in a directory.
   It is customary for clients connecting via SSL to compare the
   server's domain name (e.g. from the URL used to contact the server)
   with the value of the cn attribute in the subject field (i.e.
   subject's DN) of the server's certificate. For this reason, it is
   common practice to set the cn attribute to the server's domain name.

   The naming and schema to handle this situation is best explained by
   an example. Consider the server "host.acme.com". Following the
   algorithm in "Using Domains in LDAP Distinguished Names" [1], the DN
   dc=host, dc=acme, dc=com is constructed. To conform to the existing
   practices just described, the server's subject DN for the SSL server
   certificate should be cn=host.acme.com, dc=host, dc=acme, dc=com and
   the server's certificate should be stored in a directory entry with
   this name. This entry should use application process or application
   entity as its structural object class and strong authentication user
   as is auxiliary class.

5.2.6 Name Forms

   For X.500 servers or LDAP servers following the X.500 model, our
   schema requires the definition of new name forms, structure rules,
   and DIT content rules.  Structure rules and DIT content rules are
   locally defined, and do not involve a globally significant object
   identifier.

   The following name forms are defined using the syntax of section 6.22
   of [14] for the convenience of those using such servers.

   Note that since the structural object classes organization,
   organizationalUnit, locality and organizationalPerson do not permit
   inclusion of the dc attribute, an auxiliary object class such as
   dcObject [1] must be used for instances of these classes.)



Grimstad, et. al.            Informational                     [Page 13]

RFC 2377                A Directory Naming Plan           September 1998


5.2.6.1 Name Form for Domain Objects

   The OIDs in this group are under the
   iso.org.dod.internet.directory.NameForm branch of the OID tree
   (1.3.6.1.1.2).

   ( 1.3.6.1.1.2.1
     NAME domainNameForm
     OC domain
     MUST dc )

   The domainNameForm name form indicates that objects of structural
   object class domain have their RDN constructed from a value of the
   attribute dc.

5.2.6.2 Name Form for Organization Objects

   ( 1.3.6.1.1.2.2
     NAME dcOrganizationNameForm
     OC organization
     MUST dc )

   The dcOrganizationNameForm name form indicates that objects of
   structural object class organization have their RDN constructed from
   a value of the attribute dc.

5.2.6.3 Name Form for Organizational Unit Objects

   ( 1.3.6.1.1.2.3
     NAME dcOrganizationalUnitNameForm
     OC organizationalUnit
     MUST dc )

   The dcOrganizationalUnitNameForm name form indicates that objects of
   structural object class organizationalUnit have their RDN constructed
   from a value of the attribute dc.

5.2.6.4 Name Form for Locality Objects

   ( 1.3.6.1.1.2.4
     NAME dcLocalityNameForm
     OC locality
     MUST dc )

   The dcLocalityNameForm name form indicates that objects of structural
   object class locality have their RDN constructed from a value of the
   attribute dc.




Grimstad, et. al.            Informational                     [Page 14]

RFC 2377                A Directory Naming Plan           September 1998


5.2.6.5 Name Form for Organizational Person Objects

   ( 1.3.6.1.1.2.5
     NAME uidOrganizationalPersonNameForm
     OC organizationalPerson
     MUST uid )

   The uidOrganizationalPersonNameForm name form indicates that objects
   of structural object class organizationalPerson have their RDN
   constructed from a value of the attribute uid.

6.0 Security Considerations

   Although access controls may be placed on portions of the DIT to deny
   browse access to unauthorized clients, it may be possible to infer
   directory names and DIT structure in such sensitive portions of the
   DIT from the results of DNS queries. Providing public visibility to
   some portions of the DIT may assist those make such inferences.

7.0 Acknowledgments

   This plan has emerged in the course of a number of fruitful
   discussions, especially with David Chadwick, John Dale, Joe Gajewski,
   Mark Jackson, Ryan Moats, Tom Spencer and Chris Tzu.

8.0 References

   [1]     Kille, S., Wahl, M., Grimstad, A., Huber, R., and S.
           Sataluri, "Using Domains in LDAP Distinguished Names", RFC
           2247, January 1998.

   [2]     X.500: The Directory -- Overview of Concepts, Models, and
           Service, CCITT Recommendation X.500, December, 1988.

   [3]     Barker, P., and S. Kille, "The COSINE and Internet X.500
           Schema", RFC 1274, November 1991.

   [4]     The North American Directory Forum, "A Naming Scheme for
           c=US", RFC 1255, September 1991.

   [5]     The North American Directory Forum, "NADF Standing Documents:
           A Brief Overview", RFC 1417, February 1993.

   [6]     Yeong, W., Howes, T., and S. Kille, "Lightweight Directory
           Access Protocol", RFC 1777, March 1995.

   [7]     Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
           Access Protocol (v3)", RFC 2251, December 1997.



Grimstad, et. al.            Informational                     [Page 15]

RFC 2377                A Directory Naming Plan           September 1998


   [8]     Kille, S., "A String Representation of Distinguished Names",
           RFC 1779, March 1995.

   [9]     Wahl, M., Kille, S., and T. Howes, "Lightweight Directory
           Access Protocol (v3): UTF-8 String Representation of
           Distinguished Names", RFC 2253, December 1997.

   [10]    Wahl, M., "A Summary of the Pilot X.500 Schema for use
           in LDAPv3", Work in Progress.

   [11]    Wahl, M., "A Summary of the X.500 User Schema for use with
           LDAPv3", RFC 2256, December 1997.

   [12]    Howes, T., and M. Wahl, "Referrals and Knowledge References
           in LDAP Directories", Work in Progress.

   [13]    Howes, T., and M. Smith, "The LDAP URL Format", RFC 2255,
           December 1997.

   [14]    Wahl, M., Coulbeck, A., Howes, T., and S. Kille,
           "Lightweight Directory Access Protocol (v3): Attribute Syntax
           Definitions", RFC 2252, December 1997.

   [15]    Smith, M., "Definition of the inetOrgPerson Object Class",
           Work in Progress.


























Grimstad, et. al.            Informational                     [Page 16]

RFC 2377                A Directory Naming Plan           September 1998


12.  Authors' Addresses

   Al Grimstad
   AT&T
   Room 1C-429, 101 Crawfords Corner Road
   Holmdel, NJ 07733-3030
   USA

   EMail:  alg@att.com


   Rick Huber
   AT&T
   Room 1B-433, 101 Crawfords Corner Road
   Holmdel, NJ 07733-3030
   USA

   EMail:  rvh@att.com


   Sri Sataluri
   Lucent Technologies
   Room 4D-335, 101 Crawfords Corner Road
   Holmdel, NJ 07733-3030
   USA

   EMail:  srs@lucent.com


   Mark Wahl
   Critical Angle Inc.
   4815 W Braker Lane #502-385
   Austin, TX 78759
   USA

   EMail:  M.Wahl@critical-angle.com















Grimstad, et. al.            Informational                     [Page 17]

RFC 2377                A Directory Naming Plan           September 1998


13.  Full Copyright Statement

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
























Grimstad, et. al.            Informational                     [Page 18]

alt-openldap11-devel/rfc/rfc3045.txt000064400000024426150410163240012770 0ustar00





Network Working Group                                        M. Meredith
Request for Comments: 3045                                   Novell Inc.
Category: Informational                                     January 2001


            Storing Vendor Information in the LDAP root DSE

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2001).  All Rights Reserved.

Abstract

   This document specifies two Lightweight Directory Access Protocol
   (LDAP) attributes, vendorName and vendorVersion that MAY be included
   in the root DSA-specific Entry (DSE) to advertise vendor-specific
   information.  These two attributes supplement the attributes defined
   in section 3.4 of RFC 2251.

   The information held in these attributes MAY be used for display and
   informational purposes and MUST NOT be used for feature advertisement
   or discovery.

Conventions used in this document

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in [RFC2219]

1. Overview

   LDAP clients discover server-specific data--such as available
   controls, extensions, etc.--by reading the root DSE.  See section 3.4
   of [RFC2251] for details.

   For display, information, and limited function discovery, it is
   desirable to be able to query an LDAP server to determine the vendor
   name of that server and also to see what version of that vendor's
   code is currently installed.






Meredith                     Informational                      [Page 1]

RFC 3045      LDAP Root DSE to Display Vendor Information   January 2001


1.1 Function discovery

   There are many ways in which a particular version of a vendor's LDAP
   server implementation may be functionally incomplete, or may contain
   software anomalies.  It is impossible to identify every known
   shortcoming of an LDAP server with the given set of server data
   advertisement attributes.  Furthermore, often times, the anomalies of
   an implementation are not found until after the implementation has
   been distributed, deployed, and is in use.

   The attributes defined in this document MAY be used by client
   implementations in order to identify a particular server
   implementation so that it can 'work around' such anomalies.

   The attributes defined in this document MUST NOT be used to gather
   information related to supported features of an LDAP implementation.
   All LDAP features, mechanisms, and capabilities--if advertised--MUST
   be advertised through other mechanisms, preferably advertisement
   mechanisms defined in concert with said features, mechanisms, and
   capabilities.

2. Attribute Types

   These attributes are an addition to the Server-specific Data
   Requirements defined in section 3.4 of [RFC2251].  The associated
   syntaxes are defined in section 4 of [RFC2252].

   Servers MAY restrict access to vendorName or vendorVersion and
   clients MUST NOT expect these attributes to be available.

2.1 vendorName

   This attribute contains a single string, which represents the name of
   the LDAP server implementer.

   All LDAP server implementations SHOULD maintain a vendorName, which
   is generally the name of the company that wrote the LDAP Server code
   like "Novell, Inc."

      ( 1.3.6.1.1.4 NAME 'vendorName' EQUALITY
        1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )

2.2 vendorVersion

   This attribute contains a string which represents the version of the
   LDAP server implementation.




Meredith                     Informational                      [Page 2]

RFC 3045      LDAP Root DSE to Display Vendor Information   January 2001


   All LDAP server implementations SHOULD maintain a vendorVersion.
   Note that this value is typically a release value--comprised of a
   string and/or a string of numbers--used by the developer of the LDAP
   server product (as opposed to the supportedLDAPVersion, which
   specifies the version of the LDAP protocol supported by this server).
   This is single-valued so that it will only have one version value.
   This string MUST be unique between two versions, but there are no
   other syntactic restrictions on the value or the way it is formatted.

      ( 1.3.6.1.1.5 NAME 'vendorVersion' EQUALITY
        1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )

   The intent behind the equality match on vendorVersion is to not allow
   a less than or greater than type of query.  Say release "LDAPv3 8.0"
   has a problem that is fixed in the next release "LDAPv3 8.5", but in
   the mean time there is also an update release say version "LDAPv3
   8.01" that fixes the problem.  This will hopefully stop the client
   from saying it will not work with a version less than "LDAPv3 8.5"
   when it would also work with "LDAPv3 8.01".  With the equality match
   the client would have to exactly match what it is looking for.

3. Notes to Server Implementers

   Server implementers may consider tying the vendorVersion attribute
   value to the build mechanism so that it is automatically updated when
   the version value changes.

4. Notes to Client Developers

   As mentioned in section 2.1, the use of vendorName and vendorVersion
   MUST NOT be used to discover features.

   It should be noted that an anomalies often on affect subset of
   implementations reporting the same version information.  Most
   implementations support multiple platforms, have numerous
   configuration options, and often support plug-ins.

   Client implementations SHOULD be written in such a way as to accept
   any value in the vendorName and vendorVersion attributes.  If a
   client implementation does not recognize the specific vendorName or
   vendorVersion as one it recognizes, then for the purposes of 'working
   around' anomalies, the client MUST assume that the server is complete
   and correct.  The client MUST work with implementations that do not
   publish these attributes.






Meredith                     Informational                      [Page 3]

RFC 3045      LDAP Root DSE to Display Vendor Information   January 2001


5. Security Considerations

   The vendorName and vendorVersion attributes are provided only as
   display or informational mechanisms, or as anomaly identifying
   mechanisms.  Client and application implementers must consider that
   the existence of a given value in the vendorName or vendorVersion
   attribute is no guarantee that the server was actually built by the
   asserted vendor or that its version is the asserted version and
   should act accordingly.

   Server implementers should be aware that this information could be
   used to exploit a security hole a server provides either by feature
   or flaw.

6. IANA Considerations

   This document seeks to create two attributes, vendorName and
   vendorVersion, which the IANA will primarily be responsible.  This is
   a one time effort; there is no need for any recurring assignment
   after this stage.

7. References

   [RFC2219]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2026]  Bradner, S., "The Internet Standards Process -- Revision
              3", BCP 9, RFC 2026, October 1996.

   [RFC2251]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252]  Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
              "Lightweight Directory Access Protocol (v3): Attribute
              Syntax Definitions", RFC 2252, December 1997.

8. Acknowledgments

   The author would like to thank the generous input and review by
   individuals at Novell including but not limited to Jim Sermersheim,
   Mark Hinckley, Renea Campbell, and Roger Harrison.  Also IETF
   contributors Kurt Zeilenga, Mark Smith, Mark Wahl, Peter Strong,
   Thomas Salter, Gordon Good, Paul Leach, Helmut Volpers.








Meredith                     Informational                      [Page 4]

RFC 3045      LDAP Root DSE to Display Vendor Information   January 2001


9. Author's Address

   Mark Meredith
   Novell Inc.
   1800 S. Novell Place
   Provo, UT 84606

   Phone: 801-861-2645
   EMail: mark_meredith@novell.com










































Meredith                     Informational                      [Page 5]

RFC 3045      LDAP Root DSE to Display Vendor Information   January 2001


10. Full Copyright Statement

   Copyright (C) The Internet Society (2001).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Meredith                     Informational                      [Page 6]

alt-openldap11-devel/rfc/rfc2307.txt000064400000120664150410163240012771 0ustar00





Network Working Group                                          L. Howard
Request for Comments: 2307                        Independent Consultant
Category: Experimental                                        March 1998


      An Approach for Using LDAP as a Network Information Service

Status of this Memo

   This memo defines an Experimental Protocol for the Internet
   community.  It does not specify an Internet standard of any kind.
   Discussion and suggestions for improvement are requested.
   Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

Abstract

   This document describes an experimental mechanism for mapping
   entities related to TCP/IP and the UNIX system into X.500 [X500]
   entries so that they may be resolved with the Lightweight Directory
   Access Protocol [RFC2251]. A set of attribute types and object
   classes are proposed, along with specific guidelines for interpreting
   them.

   The intention is to assist the deployment of LDAP as an
   organizational nameservice. No proposed solutions are intended as
   standards for the Internet. Rather, it is hoped that a general
   consensus will emerge as to the appropriate solution to such
   problems, leading eventually to the adoption of standards. The
   proposed mechanism has already been implemented with some success.

1. Background and Motivation

   The UNIX (R) operating system, and its derivatives (specifically,
   those which support TCP/IP and conform to the X/Open Single UNIX
   specification [XOPEN]) require a means of looking up entities, by
   matching them against search criteria or by enumeration. (Other
   operating systems that support TCP/IP may provide some means of
   resolving some of these entities. This schema is applicable to those
   environments also.)

   These entities include users, groups, IP services (which map names to
   IP ports and protocols, and vice versa), IP protocols (which map
   names to IP protocol numbers and vice versa), RPCs (which map names
   to ONC Remote Procedure Call [RFC1057] numbers and vice versa), NIS



Howard                        Experimental                      [Page 1]

RFC 2307      Using LDAP as a Network Information Service     March 1998


   netgroups, booting information (boot parameters and MAC address
   mappings), filesystem mounts, IP hosts and networks, and RFC822 mail
   aliases.

   Resolution requests are made through a set of C functions, provided
   in the UNIX system's C library. For example, the UNIX system utility
   "ls", which enumerates the contents of a filesystem directory, uses
   the C library function getpwuid() in order to map user IDs to login
   names. Once the request is made, it is resolved using a "nameservice"
   which is supported by the client library. The nameservice may be, at
   its simplest, a collection of files in the local filesystem which are
   opened and searched by the C library. Other common nameservices
   include the Network Information Service (NIS) and the Domain Name
   System (DNS). (The latter is typically used for resolving hosts,
   services and networks.) Both these nameservices have the advantage of
   being distributed and thus permitting a common set of entities to be
   shared amongst many clients.

   LDAP is a distributed, hierarchical directory service access protocol
   which is used to access repositories of users and other network-
   related entities. Because LDAP is often not tightly integrated with
   the host operating system, information such as users may need to be
   kept both in LDAP and in an operating system supported nameservice
   such as NIS. By using LDAP as the the primary means of resolving
   these entities, these redundancy issues are minimized and the
   scalability of LDAP can be exploited. (By comparison, NIS services
   based on flat files do not have the scalability or extensibility of
   LDAP or X.500.)

   The object classes and attributes defined below are suitable for
   representing the aforementioned entities in a form compatible with
   LDAP and X.500 directory services.

2. General Issues

2.1. Terminology

   The key words "MUST", "SHOULD", and "MAY" used in this document are
   to be interpreted as described in [RFC2119].

   For the purposes of this document, the term "nameservice" refers to a
   service, such as NIS or flat files, that is used by the operating
   system to resolve entities within a single, local naming context.
   Contrast this with a "directory service" such as LDAP, which supports
   extensible schema and multiple naming contexts.






Howard                        Experimental                      [Page 2]

RFC 2307      Using LDAP as a Network Information Service     March 1998


   The term "NIS-related entities" broadly refers to entities which are
   typically resolved using the Network Information Service. (NIS was
   previously known as YP.) Deploying LDAP for resolving these entities
   does not imply that NIS be used, as a gateway or otherwise. In
   particular, the host and network classes are generically applicable,
   and may be implemented on any system that wishes to use LDAP or X.500
   for host and network resolution.

   The "DUA" (directory user agent) refers to the LDAP client querying
   these entities, such as an LDAP to NIS gateway or the C library.  The
   "client" refers to the application which ultimately makes use of the
   information returned by the resolution. It is irrelevant whether the
   DUA and the client reside within the same address space. The act of
   the DUA making this information to the client is termed
   "republishing".

   To avoid confusion, the term "login name" refers to the user's login
   name (being the value of the uid attribute) and the term "user ID"
   refers to he user's integer identification number (being the value of
   the uidNumber attribute).

   The phrases "resolving an entity" and "resolution of entities" refer
   respectively to enumerating NIS-related entities of a given type, and
   matching them against a given search criterion. One or more entities
   are returned as a result of successful "resolutions" (a "match"
   operation will only return one entity).

   The use of the term UNIX does not confer upon this schema the
   endorsement of owners of the UNIX trademark. Where necessary, the
   term "TCP/IP entity" is used to refer to protocols, services, hosts,
   and networks, and the term "UNIX entity" to its complement. (The
   former category does not mandate the host operating system supporting
   the interfaces required for resolving UNIX entities.)

   The OIDs defined below are derived from iso(1) org(3) dod(6)
   internet(1) directory(1) nisSchema(1).

2.2. Attributes

   The attributes and classes defined in this document are summarized
   below.

   The following attributes are defined in this document:

           uidNumber
           gidNumber
           gecos
           homeDirectory



Howard                        Experimental                      [Page 3]

RFC 2307      Using LDAP as a Network Information Service     March 1998


           loginShell
           shadowLastChange
           shadowMin
           shadowMax
           shadowWarning
           shadowInactive
           shadowExpire
           shadowFlag
           memberUid
           memberNisNetgroup
           nisNetgroupTriple
           ipServicePort
           ipServiceProtocol
           ipProtocolNumber
           oncRpcNumber
           ipHostNumber
           ipNetworkNumber
           ipNetmaskNumber
           macAddress
           bootParameter
           bootFile
           nisMapName
           nisMapEntry

   Additionally, some of the attributes defined in [RFC2256] are
   required.

2.3. Object classes

   The following object classes are defined in this document:

           posixAccount
           shadowAccount
           posixGroup
           ipService
           ipProtocol
           oncRpc
           ipHost
           ipNetwork
           nisNetgroup
           nisMap
           nisObject
           ieee802Device
           bootableDevice

   Additionally, some of the classes defined in [RFC2256] are required.





Howard                        Experimental                      [Page 4]

RFC 2307      Using LDAP as a Network Information Service     March 1998


2.4. Syntax definitions

   The following syntax definitions [RFC2252] are used by this schema.
   The nisNetgroupTripleSyntax represents NIS netgroup triples:

           ( nisSchema.0.0 NAME 'nisNetgroupTripleSyntax'
             DESC 'NIS netgroup triple' )

   Values in this syntax are represented by the following:

        nisnetgrouptriple = "(" hostname "," username "," domainname ")"
        hostname          = "" / "-" / keystring
        username          = "" / "-" / keystring
        domainname        = "" / "-" / keystring

   X.500 servers may use the following representation of the above
   syntax:

        nisNetgroupTripleSyntax ::= SEQUENCE {
         hostname  [0] IA5String OPTIONAL,
         username  [1] IA5String OPTIONAL,
         domainname  [2] IA5String OPTIONAL
        }

   The bootParameterSyntax syntax represents boot parameters:

           ( nisSchema.0.1 NAME 'bootParameterSyntax'
             DESC 'Boot parameter' )

   where:

        bootparameter     = key "=" server ":" path
        key               = keystring
        server            = keystring
        path              = keystring

   X.500 servers may use the following representation of the above
   syntax:

        bootParameterSyntax ::= SEQUENCE {
         key     IA5String,
         server  IA5String,
         path    IA5String
        }

   Values adhering to these syntaxes are encoded as strings by LDAP
   servers.




Howard                        Experimental                      [Page 5]

RFC 2307      Using LDAP as a Network Information Service     March 1998


3. Attribute definitions

   This section contains attribute definitions to be implemented by DUAs
   supporting this schema.

        ( nisSchema.1.0 NAME 'uidNumber'
          DESC 'An integer uniquely identifying a user in an
                administrative domain'
          EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.1 NAME 'gidNumber'
          DESC 'An integer uniquely identifying a group in an
                administrative domain'
          EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.2 NAME 'gecos'
          DESC 'The GECOS field; the common name'
          EQUALITY caseIgnoreIA5Match
          SUBSTRINGS caseIgnoreIA5SubstringsMatch
          SYNTAX 'IA5String' SINGLE-VALUE )

        ( nisSchema.1.3 NAME 'homeDirectory'
          DESC 'The absolute path to the home directory'
          EQUALITY caseExactIA5Match
          SYNTAX 'IA5String' SINGLE-VALUE )

        ( nisSchema.1.4 NAME 'loginShell'
          DESC 'The path to the login shell'
          EQUALITY caseExactIA5Match
          SYNTAX 'IA5String' SINGLE-VALUE )

        ( nisSchema.1.5 NAME 'shadowLastChange'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.6 NAME 'shadowMin'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.7 NAME 'shadowMax'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.8 NAME 'shadowWarning'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.9 NAME 'shadowInactive'



Howard                        Experimental                      [Page 6]

RFC 2307      Using LDAP as a Network Information Service     March 1998


          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.10 NAME 'shadowExpire'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.11 NAME 'shadowFlag'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.12 NAME 'memberUid'
          EQUALITY caseExactIA5Match
          SUBSTRINGS caseExactIA5SubstringsMatch
          SYNTAX 'IA5String' )

        ( nisSchema.1.13 NAME 'memberNisNetgroup'
          EQUALITY caseExactIA5Match
          SUBSTRINGS caseExactIA5SubstringsMatch
          SYNTAX 'IA5String' )

        ( nisSchema.1.14 NAME 'nisNetgroupTriple'
          DESC 'Netgroup triple'
          SYNTAX 'nisNetgroupTripleSyntax' )

        ( nisSchema.1.15 NAME 'ipServicePort'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.16 NAME 'ipServiceProtocol'
          SUP name )

        ( nisSchema.1.17 NAME 'ipProtocolNumber'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.18 NAME 'oncRpcNumber'
          EQUALITY integerMatch
          SYNTAX 'INTEGER' SINGLE-VALUE )

        ( nisSchema.1.19 NAME 'ipHostNumber'
          DESC 'IP address as a dotted decimal, eg. 192.168.1.1,
                omitting leading zeros'
          EQUALITY caseIgnoreIA5Match
          SYNTAX 'IA5String{128}' )

        ( nisSchema.1.20 NAME 'ipNetworkNumber'
          DESC 'IP network as a dotted decimal, eg. 192.168,



Howard                        Experimental                      [Page 7]

RFC 2307      Using LDAP as a Network Information Service     March 1998


                omitting leading zeros'
          EQUALITY caseIgnoreIA5Match
          SYNTAX 'IA5String{128}' SINGLE-VALUE )

        ( nisSchema.1.21 NAME 'ipNetmaskNumber'
          DESC 'IP netmask as a dotted decimal, eg. 255.255.255.0,
                omitting leading zeros'
          EQUALITY caseIgnoreIA5Match
          SYNTAX 'IA5String{128}' SINGLE-VALUE )

        ( nisSchema.1.22 NAME 'macAddress'
          DESC 'MAC address in maximal, colon separated hex
                notation, eg. 00:00:92:90:ee:e2'
          EQUALITY caseIgnoreIA5Match
          SYNTAX 'IA5String{128}' )

        ( nisSchema.1.23 NAME 'bootParameter'
          DESC 'rpc.bootparamd parameter'
          SYNTAX 'bootParameterSyntax' )

        ( nisSchema.1.24 NAME 'bootFile'
          DESC 'Boot image name'
          EQUALITY caseExactIA5Match
          SYNTAX 'IA5String' )

        ( nisSchema.1.26 NAME 'nisMapName'
          SUP name )

        ( nisSchema.1.27 NAME 'nisMapEntry'
          EQUALITY caseExactIA5Match
          SUBSTRINGS caseExactIA5SubstringsMatch
          SYNTAX 'IA5String{1024}' SINGLE-VALUE )

4. Class definitions

   This section contains class definitions to be implemented by DUAs
   supporting the schema.

   The rfc822MailGroup object class MAY be used to represent a mail
   group for the purpose of alias expansion. Several alternative schemes
   for mail routing and delivery using LDAP directories, which are
   outside the scope of this document.

        ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY
          DESC 'Abstraction of an account with POSIX attributes'
          MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
          MAY ( userPassword $ loginShell $ gecos $ description ) )




Howard                        Experimental                      [Page 8]

RFC 2307      Using LDAP as a Network Information Service     March 1998


        ( nisSchema.2.1 NAME 'shadowAccount' SUP top AUXILIARY
          DESC 'Additional attributes for shadow passwords'
          MUST uid
          MAY ( userPassword $ shadowLastChange $ shadowMin
                shadowMax $ shadowWarning $ shadowInactive $
                shadowExpire $ shadowFlag $ description ) )

        ( nisSchema.2.2 NAME 'posixGroup' SUP top STRUCTURAL
          DESC 'Abstraction of a group of accounts'
          MUST ( cn $ gidNumber )
          MAY ( userPassword $ memberUid $ description ) )

        ( nisSchema.2.3 NAME 'ipService' SUP top STRUCTURAL
          DESC 'Abstraction an Internet Protocol service.
                Maps an IP port and protocol (such as tcp or udp)
                to one or more names; the distinguished value of
                the cn attribute denotes the service's canonical
                name'
          MUST ( cn $ ipServicePort $ ipServiceProtocol )
          MAY ( description ) )

        ( nisSchema.2.4 NAME 'ipProtocol' SUP top STRUCTURAL
          DESC 'Abstraction of an IP protocol. Maps a protocol number
                to one or more names. The distinguished value of the cn
                attribute denotes the protocol's canonical name'
          MUST ( cn $ ipProtocolNumber $ description )
          MAY description )

        ( nisSchema.2.5 NAME 'oncRpc' SUP top STRUCTURAL
          DESC 'Abstraction of an Open Network Computing (ONC)
               [RFC1057] Remote Procedure Call (RPC) binding.
               This class maps an ONC RPC number to a name.
               The distinguished value of the cn attribute denotes
               the RPC service's canonical name'
          MUST ( cn $ oncRpcNumber $ description )
          MAY description )

        ( nisSchema.2.6 NAME 'ipHost' SUP top AUXILIARY

          DESC 'Abstraction of a host, an IP device. The distinguished
                value of the cn attribute denotes the host's canonical
                name. Device SHOULD be used as a structural class'
          MUST ( cn $ ipHostNumber )
          MAY ( l $ description $ manager ) )

        ( nisSchema.2.7 NAME 'ipNetwork' SUP top STRUCTURAL
          DESC 'Abstraction of a network. The distinguished value of
                the cn attribute denotes the network's canonical name'



Howard                        Experimental                      [Page 9]

RFC 2307      Using LDAP as a Network Information Service     March 1998


          MUST ( cn $ ipNetworkNumber )
          MAY ( ipNetmaskNumber $ l $ description $ manager ) )

        ( nisSchema.2.8 NAME 'nisNetgroup' SUP top STRUCTURAL
          DESC 'Abstraction of a netgroup. May refer to other netgroups'
          MUST cn
          MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )

        ( nisSchema.2.09 NAME 'nisMap' SUP top STRUCTURAL
          DESC 'A generic abstraction of a NIS map'
          MUST nisMapName
          MAY description )

        ( nisSchema.2.10 NAME 'nisObject' SUP top STRUCTURAL
          DESC 'An entry in a NIS map'
          MUST ( cn $ nisMapEntry $ nisMapName )
          MAY description )

        ( nisSchema.2.11 NAME 'ieee802Device' SUP top AUXILIARY
          DESC 'A device with a MAC address; device SHOULD be
                used as a structural class'
          MAY macAddress )

        ( nisSchema.2.12 NAME 'bootableDevice' SUP top AUXILIARY
          DESC 'A device with boot parameters; device SHOULD be
                used as a structural class'
          MAY ( bootFile $ bootParameter ) )

5. Implementation details

5.1. Suggested resolution methods

   The preferred means of directing a client application (one using the
   shared services of the C library) to use LDAP as its information
   source for the functions listed in 5.2 is to modify the source code
   to directly query LDAP. As the source to commercial C libraries and
   applications is rarely available to the end-user, one could emulate a
   supported nameservice (such as NIS). (This is also an appropriate
   opportunity to perform caching of entries across process address
   spaces.) In the case of NIS, reference implementations are widely
   available and the RPC interface is well known.

   The means by which the operating system is directed to use LDAP is
   implementation dependent. For example, some operating systems and C
   libraries support end-user extensible resolvers using dynamically
   loadable libraries and a nameservice "switch". The means in which the
   DUA locates LDAP servers is also implementation dependent.




Howard                        Experimental                     [Page 10]

RFC 2307      Using LDAP as a Network Information Service     March 1998


5.2. Affected library functions

   The following functions are typically found in the C libraries of
   most UNIX and POSIX compliant systems. An LDAP search filter
   [RFC2254] which may be used to satisfy the function call is included
   alongside each function name. Parameters are denoted by %s and %d for
   string and integer arguments, respectively. Long lines are broken.

        getpwnam()              (&(objectClass=posixAccount)(uid=%s))
        getpwuid()              (&(objectClass=posixAccount)
                                (uidNumber=%d))
        getpwent()              (objectClass=posixAccount)

        getspnam()              (&(objectClass=shadowAccount)(uid=%s))
        getspent()              (objectClass=shadowAccount)

        getgrnam()              (&(objectClass=posixGroup)(cn=%s))
        getgrgid()              (&(objectClass=posixGroup)
                                (gidNumber=%d))
        getgrent()              (objectClass=posixGroup)

        getservbyname()         (&(objectClass=ipService)
                                (cn=%s)(ipServiceProtocol=%s))
        getservbyport()         (&(objectClass=ipService)
                                (ipServicePort=%d)
                                (ipServiceProtocol=%s))
        getservent()            (objectClass=ipService)

        getrpcbyname()          (&(objectClass=oncRpc)(cn=%s))
        getrpcbynumber()        (&(objectClass=oncRpc)(oncRpcNumber=%d))
        getrpcent()             (objectClass=oncRpc)

        getprotobyname()        (&(objectClass=ipProtocol)(cn=%s))
        getprotobynumber()      (&(objectClass=ipProtocol)
                                (ipProtocolNumber=%d))
        getprotoent()           (objectClass=ipProtocol)

        gethostbyname()         (&(objectClass=ipHost)(cn=%s))
        gethostbyaddr()         (&(objectClass=ipHost)(ipHostNumber=%s))
        gethostent()            (objectClass=ipHost)

        getnetbyname()          (&(objectClass=ipNetwork)(cn=%s))
        getnetbyaddr()          (&(objectClass=ipNetwork)
                                (ipNetworkNumber=%s))
        getnetent()             (objectClass=ipNetwork)

        setnetgrent()           (&(objectClass=nisNetgroup)(cn=%s))




Howard                        Experimental                     [Page 11]

RFC 2307      Using LDAP as a Network Information Service     March 1998


5.3. Interpreting user and group entries

   User and group resolution is initiated by the functions prefixed by
   getpw and getgr respectively. The uid attribute contains the user's
   login name. The cn attribute, in posixGroup entries, contains the
   group's name.

   The account object class provides a convenient structural class for
   posixAccount, and SHOULD be used where additional attributes are not
   required.

   It is suggested that uid and cn are used as the RDN attribute type
   for posixAccount and posixGroup entries, respectively.

   An account's GECOS field is preferably determined by a value of the
   gecos attribute. If no gecos attribute exists, the value of the cn
   attribute MUST be used. (The existence of the gecos attribute allows
   information embedded in the GECOS field, such as a user's telephone
   number, to be returned to the client without overloading the cn
   attribute. It also accommodates directories where the common name
   does not contain the user's full name.)

   An entry of class posixAccount, posixGroup, or shadowAccount without
   a userPassword attribute MUST NOT be used for authentication. The
   client should be returned a non-matchable password such as "x".

   userPassword values MUST be represented by following syntax:

        passwordvalue          = schemeprefix encryptedpassword
        schemeprefix           = "{" scheme "}"
        scheme                 = "crypt" / "md5" / "sha" / altscheme
        altscheme              = "x-" keystring
        encryptedpassword      = encrypted password

   The encrypted password contains of a plaintext key hashed using the
   algorithm scheme.

   userPassword values which do not adhere to this syntax MUST NOT be
   used for authentication. The DUA MUST iterate through the values of
   the attribute until a value matching the above syntax is found. Only
   if encryptedpassword is an empty string does the user have no
   password. DUAs are not required to consider encryption schemes which
   the client will not recognize; in most cases, it may be sufficient to
   consider only "crypt".

   Below is an example of a userPassword attribute:

                    userPassword: {crypt}X5/DBrWPOQQaI



Howard                        Experimental                     [Page 12]

RFC 2307      Using LDAP as a Network Information Service     March 1998


   A future standard may specify LDAP v3 attribute descriptions to
   represent hashed userPasswords, as noted below. This schema MUST NOT
   be used with LDAP v2 DUAs and DSAs.

        attributetype           = attributename sep attributeoption
        attributename           = "userPassword"
        sep                     = ";"
        attributeoption         = schemeclass "-" scheme
        schemeclass             = "hash" / altschemeclass
        scheme                  = "crypt" / "md5" / "sha" / altscheme
        altschemeclass          = "x-" keystring
        altscheme               = keystring


   Below is an example of a userPassword attribute, represented with an
   LDAP v3 attribute description:

           userPassword;hash-crypt: X5/DBrWPOQQaI


   A DUA MAY utilise the attributes in the shadowAccount class to
   provide shadow password service (getspnam() and getspent()). In such
   cases, the DUA MUST NOT make use of the userPassword attribute for
   getpwnam() et al, and MUST return a non-matchable password (such as
   "x") to the client instead.

5.4. Interpreting hosts and networks

   The ipHostNumber and ipNetworkNumber attributes are defined in
   preference to dNSRecord (defined in [RFC1279]), in order to simplify
   the DUA's role in interpreting entries in the directory. A dNSRecord
   expresses a complete resource record, including time to live and
   class data, which is extraneous to this schema.

   Additionally, the ipHost and ipNetwork classes permit a host or
   network (respectively) and all its aliases to be represented by a
   single entry in the directory. This is not necessarily possible if a
   DNS resource record is mapped directly to an LDAP entry.
   Implementations that wish to use LDAP to master DNS zone information
   are not precluded from doing so, and may simply avoid the ipHost and
   ipNetwork classes.

   This document redefines, although not exclusively, the ipNetwork
   class defined in [RFC1279], in order to achieve consistent naming
   with ipHost. The ipNetworkNumber attribute is also used in the
   siteContact object class [ROSE].





Howard                        Experimental                     [Page 13]

RFC 2307      Using LDAP as a Network Information Service     March 1998


   The trailing zeros in a network address MUST be omitted. CIDR-style
   network addresses (eg. 192.168.1/24) MAY be used.

   Hosts with IPv6 addresses MUST be written in their "preferred" form
   as defined in section 2.2.1 of [RFC1884], such that all components of
   the address are indicated and leading zeros are omitted. This
   provides a consistent means of resolving ipHosts by address.

5.5. Interpreting other entities

   In general, a one-to-one mapping between entities and LDAP entries is
   proposed, in that each entity has exactly one representation in the
   DIT. In some cases this is not feasible; for example, a service which
   is represented in more than one protocol domain. Consider the
   following entry:

           dn: cn=domain, dc=aja, dc=com
           cn: domain
           cn: nameserver
           objectClass: top
           objectClass: ipService
           ipServicePort: 53
           ipServiceProtocol: tcp
           ipServiceProtocol: udp

   This entry MUST map to the following two (2) services entities:

           domain  53/tcp  nameserver
           domain  53/udp  nameserver

   While the above two entities may be represented as separate LDAP
   entities, with different distinguished names (such as
   cn=domain+ipServiceProtocol=tcp, ... and
   cn=domain+ipServiceProtocol=udp, ...) it is convenient to represent
   them as a single entry. (If a service is represented in multiple
   protocol domains with different ports, then multiple entries are
   required; multivalued RDNs may be used to distinguish them.)

   With the exception of userPassword values, which are parsed according
   to the syntax considered in section 5.2, any empty values (consisting
   of a zero length string) are returned by the DUA to the client. The
   DUA MUST reject any entries which do not conform to the schema
   (missing mandatory attributes). Non-conforming entries SHOULD be
   ignored while enumerating entries.

   The nisObject object class MAY be used as a generic means of
   representing NIS entities. Its use is not encouraged; where support
   for entities not described in this schema is desired, an appropriate



Howard                        Experimental                     [Page 14]

RFC 2307      Using LDAP as a Network Information Service     March 1998


   schema should be devised. Implementors are strongly advised to
   support end-user extensible mappings between NIS entities and object
   classes. (Where the nisObject class is used, the nisMapName attribute
   may be used as a RDN.)

5.6. Canonicalizing entries with multi-valued naming attributes

   For entities such as hosts, services, networks, protocols, and RPCs,
   where there may be one or more aliases, the respective entry's
   relative distinguished name SHOULD be used to determine the canonical
   name.  Any other values for the same attribute are used as aliases.
   For example, the service described in section 5.5 has the canonical
   name "domain" and exactly one alias, "nameserver".

   The schema in this document generally only defines one attribute per
   class which is suitable for distinguishing an entity (excluding any
   attributes with integer syntax; it is assumed that entries will be
   distinguished on name). Usually, this is the common name (cn)
   attribute.  This aids the DUA in determining the canonical name of an
   entity, as it can examine the value of the relative distinguished
   name. Aliases are thus any values of the distinguishing attribute
   (such as cn) which do not match the canonical name of the entity.

   In the event that a different attribute is used to distinguish the
   entry, as may be the case where these object classes are used as
   auxiliary classes, the entry's canonical name may not be present in
   the RDN. In this case, the DUA MUST choose one of the non-
   distinguished values to represent the entity's canonical name. As the
   directory server guarantees no ordering of attribute values, it may
   not be possible to distinguish an entry deterministically. This
   ambiguity SHOULD NOT be resolved by mapping one directory entry into
   multiple entities.

6. Implementation focus

   A NIS server which uses LDAP instead of local files has been
   developed which supports the schema defined in this document.

   A reference implementation of the C library resolution code has been
   written for the Free Software Foundation. It may support other C
   libraries which support the Name Service Switch (NSS) or the
   Information Retrieval Service (IRS).

   The author has made available a freely distributable set of scripts
   which parses local databases such as /etc/passwd and /etc/hosts into
   a form suitable for loading into an LDAP server.





Howard                        Experimental                     [Page 15]

RFC 2307      Using LDAP as a Network Information Service     March 1998


7. Security Considerations

   The entirety of related security considerations are outside the scope
   of this document. It is noted that making passwords encrypted with a
   widely understood hash function (such as crypt()) available to non-
   privileged users is dangerous because it exposes them to dictionary
   and brute-force attacks.  This is proposed only for compatibility
   with existing UNIX system implementations. Sites where security is
   critical SHOULD consider using a strong authentication service for
   user authentication.

   Alternatively, the encrypted password could be made available only to
   a subset of privileged DUAs, which would provide "shadow" password
   service to client applications. This may be difficult to enforce.

   Because the schema represents operating system-level entities, access
   to these entities SHOULD be granted on a discretionary basis. (There
   is little point in restricting access to data which will be
   republished without restriction, however.) It is particularly
   important that only administrators can modify entries defined in this
   schema, with the exception of allowing a principal to change their
   password (which may be done on behalf of the user by a client bound
   as a superior principal, such that password restrictions may be
   enforced). For example, if a user were allowed to change the value of
   their uidNumber attribute, they could subvert security by
   equivalencing their account with the superuser account.

   A subtree of the DIT which is to be republished by a DUA (such as a
   NIS gateway) SHOULD be within the same administrative domain that the
   republishing DUA represents. (For example, principals outside an
   organization, while conceivably part of the DIT, should not be
   considered with the same degree of authority as those within the
   organization.)

   Finally, care should be exercised with integer attributes of a
   sensitive nature (particularly the uidNumber and gidNumber
   attributes) which contain zero-length values. DUAs MAY treat such
   values as corresponding to the "nobody" or "nogroup" user and group,
   respectively.

8. Acknowledgements

   Thanks to Leif Hedstrom of Netscape Communications Corporation,
   Michael Grant and Rosanna Lee of Sun Microsystems Inc., Ed Reed of
   Novell Inc., and Mark Wahl of Critical Angle Inc. for their valuable
   contributions to the development of this schema. Thanks to Andrew
   Josey of The Open Group for clarifying the use of the UNIX trademark,
   and to Tim Howes and Peter J. Cherny for their support.



Howard                        Experimental                     [Page 16]

RFC 2307      Using LDAP as a Network Information Service     March 1998


   UNIX is a registered trademark of The Open Group.

9. References

   [RFC1057]
        Sun Microsystems, Inc., "RPC: Remote Procedure Call: Protocol
        Specification Version 2", RFC 1057, June 1988.

   [RFC1279]
        Kille, S., "X.500 and Domains", RFC 1279, November 1991.

   [RFC1884]
        Hinden, R., and S. Deering, "IP Version 6 Addressing
        Architecture", RFC 1884, December 1995.

   [RFC2119]
        Bradner, S., "Key Words for use in RFCs to Indicate Requirement
        Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251]
        Wahl, M., Howes, T., and S. Kille, "Lightweight Directory Access
        Protocol (v3)", RFC 2251, December 1997.

   [RFC2252]
        Wahl, M., Coulbeck, A., Howes, T., and S. Kille, "Lightweight
        Directory Access Protocol (v3): Attribute Syntax Definitions",
        RFC 2252, December 1997.

   [RFC2254]
        Howes, T., "The String Representation of LDAP Search Filters",
        RFC 2254, December 1997.

   [RFC2256]
        Wahl, M., "A Summary of the X.500(96) User Schema for use with
        LDAPv3", RFC 2256, December 1997.

   [ROSE]
        M. T. Rose, "The Little Black Book: Mail Bonding with OSI
        Directory Services", ISBN 0-13-683210-5, Prentice-Hall, Inc.,
        1992.

   [X500]
        "Information Processing Systems - Open Systems Interconnection -
        The Directory: Overview of Concepts, Models and Service",
        ISO/IEC JTC 1/SC21, International Standard 9594-1, 1988.






Howard                        Experimental                     [Page 17]

RFC 2307      Using LDAP as a Network Information Service     March 1998


   [XOPEN]
        ISO/IEC 9945-1:1990, Information Technology - Portable Operating
        Systems Interface (POSIX) - Part 1: Systems Application
        Programming Interface (API) [C Language]

10. Author's Address

   Luke Howard
   PO Box 59
   Central Park Vic 3145
   Australia

   EMail: lukeh@xedoc.com






































Howard                        Experimental                     [Page 18]

RFC 2307      Using LDAP as a Network Information Service     March 1998


A. Example entries

   The examples described in this section are provided to illustrate the
   schema described in this memo. They are not meant to be exhaustive.

   The following entry is an example of the posixAccount class:

           dn: uid=lester, dc=aja, dc=com
           objectClass: top
           objectClass: account
           objectClass: posixAccount
           uid: lester
           cn: Lester the Nightfly
           userPassword: {crypt}X5/DBrWPOQQaI
           gecos: Lester
           loginShell: /bin/csh
           uidNumber: 10
           gidNumber: 10
           homeDirectory: /home/lester


   This corresponds the UNIX system password file entry:

        lester:X5/DBrWPOQQaI:10:10:Lester:/home/lester:/bin/sh

   The following entry is an example of the ipHost class:

           dn: cn=peg.aja.com, dc=aja, dc=com
           objectClass: top
           objectClass: device
           objectClass: ipHost
           objectClass: bootableDevice
           objectClass: ieee802Device
           cn: peg.aja.com
           cn: www.aja.com
           ipHostNumber: 10.0.0.1
           macAddress: 00:00:92:90:ee:e2
           bootFile: mach
           bootParameter: root=fs:/nfsroot/peg
           bootParameter: swap=fs:/nfsswap/peg
           bootParameter: dump=fs:/nfsdump/peg

   This entry represents the host canonically peg.aja.com, also known as
   www.aja.com. The Ethernet address and four boot parameters are also
   specified.






Howard                        Experimental                     [Page 19]

RFC 2307      Using LDAP as a Network Information Service     March 1998


   An example of the nisNetgroup class:

           dn: cn=nightfly, dc=aja, dc=com
           objectClass: top
           objectClass: nisNetgroup
           cn: nightfly
           nisNetgroupTriple: (charlemagne,peg,dunes.aja.com)
           nisNetgroupTriple: (lester,-,)
           memberNisNetgroup: kamakiriad

   This entry represents the netgroup nightfly, which contains two
   triples (the user charlemagne, the host peg, and the domain
   dunes.aja.com; and, the user lester, no host, and any domain) and one
   netgroup (kamakiriad).

   Finally, an example of the nisObject class:

           dn: nisMapName=tracks, dc=dunes, dc=aja, dc=com
           objectClass: top
           objectClass: nisMap
           nisMapName: tracks

           dn: cn=Maxine, nisMapName=tracks, dc=dunes, dc=aja, dc=com
           objectClass: top
           objectClass: nisObject
           cn: Maxine
           nisMapName: tracks
           nisMapEntry: Nightfly$4

   This entry represents the NIS map tracks, and a single map entry.





















Howard                        Experimental                     [Page 20]

RFC 2307      Using LDAP as a Network Information Service     March 1998


Full Copyright Statement

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
























Howard                        Experimental                     [Page 21]

alt-openldap11-devel/rfc/rfc4520.txt000064400000102772150410163240012770 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4520                           OpenLDAP Foundation
BCP: 64                                                        June 2006
Obsoletes: 3383
Category: Best Current Practice


     Internet Assigned Numbers Authority (IANA) Considerations for
            the Lightweight Directory Access Protocol (LDAP)

Status of This Memo

   This document specifies an Internet Best Current Practices for the
   Internet Community, and requests discussion and suggestions for
   improvements.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document provides procedures for registering extensible elements
   of the Lightweight Directory Access Protocol (LDAP).  The document
   also provides guidelines to the Internet Assigned Numbers Authority
   (IANA) describing conditions under which new values can be assigned.

1.  Introduction

   The Lightweight Directory Access Protocol [RFC4510] (LDAP) is an
   extensible protocol.  LDAP supports:

      -  the addition of new operations,
      -  the extension of existing operations, and
      -  the extensible schema.

   This document details procedures for registering values used to
   unambiguously identify extensible elements of the protocol, including
   the following:

      - LDAP message types
      - LDAP extended operations and controls
      - LDAP result codes
      - LDAP authentication methods
      - LDAP attribute description options
      - Object Identifier descriptors





Zeilenga                 Best Current Practice                  [Page 1]

RFC 4520              IANA Considerations for LDAP             June 2006


   These registries are maintained by the Internet Assigned Numbers
   Authority (IANA).

   In addition, this document provides guidelines to IANA describing the
   conditions under which new values can be assigned.

   This document replaces RFC 3383.

2.  Terminology and Conventions

   This section details terms and conventions used in this document.

2.1.  Policy Terminology

   The terms "IESG Approval", "Standards Action", "IETF Consensus",
   "Specification Required", "First Come First Served", "Expert Review",
   and "Private Use" are used as defined in BCP 26 [RFC2434].

   The term "registration owner" (or "owner") refers to the party
   authorized to change a value's registration.

2.2.  Requirement Terminology

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].  In
   this case, "the specification", as used by BCP 14, refers to the
   processing of protocols being submitted to the IETF standards
   process.

2.3.  Common ABNF Productions

   A number of syntaxes in this document are described using ABNF
   [RFC4234].  These syntaxes rely on the following common productions:

         ALPHA = %x41-5A / %x61-7A    ; "A"-"Z" / "a"-"z"
         LDIGIT = %x31-39             ; "1"-"9"
         DIGIT = %x30 / LDIGIT        ; "0"-"9"
         HYPHEN = %x2D                ; "-"
         DOT = %x2E                   ; "."
         number = DIGIT / ( LDIGIT 1*DIGIT )
         keychar = ALPHA / DIGIT / HYPHEN
         leadkeychar = ALPHA
         keystring = leadkeychar *keychar
         keyword = keystring

   Keywords are case insensitive.




Zeilenga                 Best Current Practice                  [Page 2]

RFC 4520              IANA Considerations for LDAP             June 2006


3.  IANA Considerations for LDAP

   This section details each kind of protocol value that can be
   registered and provides IANA guidelines on how to assign new values.

   IANA may reject obviously bogus registrations.

   LDAP values specified in RFCs MUST be registered.  Other LDAP values,
   except those in private-use name spaces, SHOULD be registered.  RFCs
   SHOULD NOT reference, use, or otherwise recognize unregistered LDAP
   values.

3.1.  Object Identifiers

   Numerous LDAP schema and protocol elements are identified by Object
   Identifiers (OIDs) [X.680].  Specifications that assign OIDs to
   elements SHOULD state who delegated the OIDs for their use.

   For IETF-developed elements, specifications SHOULD use OIDs under
   "Internet Directory Numbers" (1.3.6.1.1.x).  For elements developed
   by others, any properly delegated OID can be used, including those
   under "Internet Directory Numbers" (1.3.6.1.1.x) or "Internet Private
   Enterprise Numbers" (1.3.6.1.4.1.x).

   Internet Directory Numbers (1.3.6.1.1.x) will be assigned upon Expert
   Review with Specification Required.  Only one OID per specification
   will be assigned.  The specification MAY then assign any number of
   OIDs within this arc without further coordination with IANA.

   Internet Private Enterprise Numbers (1.3.6.1.4.1.x) are assigned by
   IANA <http://www.iana.org/cgi-bin/enterprise.pl>.  Practices for IANA
   assignment of Internet Private Enterprise Numbers are detailed in RFC
   2578 [RFC2578].

   To avoid interoperability problems between early implementations of a
   "work in progress" and implementations of the published specification
   (e.g., the RFC), experimental OIDs SHOULD be used in "works in
   progress" and early implementations.  OIDs under the Internet
   Experimental OID arc (1.3.6.1.3.x) may be used for this purpose.
   Practices for IANA assignment of these Internet Experimental numbers
   are detailed in RFC 2578 [RFC2578].

3.2.  Protocol Mechanisms

   LDAP provides a number of Root DSA-Specific Entry (DSE) attributes
   for discovery of protocol mechanisms identified by OIDs, including
   the supportedControl, supportedExtension, and supportedFeatures
   attributes [RFC4512].



Zeilenga                 Best Current Practice                  [Page 3]

RFC 4520              IANA Considerations for LDAP             June 2006


   A registry of OIDs used for discovery of protocol mechanisms is
   provided to allow implementors and others to locate the technical
   specification for these protocol mechanisms.  Future specifications
   of additional Root DSE attributes holding values identifying protocol
   mechanisms MAY extend this registry for their values.

   Protocol mechanisms are registered on a First Come First Served
   basis.

3.3.  LDAP Syntaxes

   This registry provides a listing of LDAP syntaxes [RFC4512].  Each
   LDAP syntax is identified by an OID.  This registry is provided to
   allow implementors and others to locate the technical specification
   describing a particular LDAP Syntax.

   LDAP Syntaxes are registered on a First Come First Served with
   Specification Required basis.

   Note: Unlike object classes, attribute types, and various other kinds
         of schema elements, descriptors are not used in LDAP to
         identify LDAP Syntaxes.

3.4.  Object Identifier Descriptors

   LDAP allows short descriptive names (or descriptors) to be used
   instead of a numeric Object Identifier to identify select protocol
   extensions [RFC4511], schema elements [RFC4512], LDAP URL [RFC4516]
   extensions, and other objects.

   Although the protocol allows the same descriptor to refer to
   different object identifiers in certain cases and the registry
   supports multiple registrations of the same descriptor (each
   indicating a different kind of schema element and different object
   identifier), multiple registrations of the same descriptor are to be
   avoided.  All such multiple registration requests require Expert
   Review.

   Descriptors are restricted to strings of UTF-8 [RFC3629] encoded
   Unicode characters restricted by the following ABNF:

      name = keystring

   Descriptors are case insensitive.

   Multiple names may be assigned to a given OID.  For purposes of
   registration, an OID is to be represented in numeric OID form (e.g.,
   1.1.0.23.40) conforming to the following ABNF:



Zeilenga                 Best Current Practice                  [Page 4]

RFC 4520              IANA Considerations for LDAP             June 2006


      numericoid = number 1*( DOT number )

   While the protocol places no maximum length restriction upon
   descriptors, they should be short.  Descriptors longer than 48
   characters may be viewed as too long to register.

   A value ending with a hyphen ("-") reserves all descriptors that
   start with that value.  For example, the registration of the option
   "descrFamily-" reserves all options that start with "descrFamily-"
   for some related purpose.

   Descriptors beginning with "x-" are for Private Use and cannot be
   registered.

   Descriptors beginning with "e-" are reserved for experiments and will
   be registered on a First Come First Served basis.

   All other descriptors require Expert Review to be registered.

   The registrant need not "own" the OID being named.

   The OID name space is managed by the ISO/IEC Joint Technical
   Committee 1 - Subcommittee 6.

3.5.  AttributeDescription Options

   An AttributeDescription [RFC4512] can contain zero or more options
   specifying additional semantics.  An option SHALL be restricted to a
   string of UTF-8 encoded Unicode characters limited by the following
   ABNF:

      option = keystring

   Options are case insensitive.

   While the protocol places no maximum length restriction upon option
   strings, they should be short.  Options longer than 24 characters may
   be viewed as too long to register.

   Values ending with a hyphen ("-") reserve all option names that start
   with the name.  For example, the registration of the option
   "optionFamily-" reserves all options that start with "optionFamily-"
   for some related purpose.

   Options beginning with "x-" are for Private Use and cannot be
   registered.





Zeilenga                 Best Current Practice                  [Page 5]

RFC 4520              IANA Considerations for LDAP             June 2006


   Options beginning with "e-" are reserved for experiments and will be
   registered on a First Come First Served basis.

   All other options require Standards Action or Expert Review with
   Specification Required to be registered.

3.6.  LDAP Message Types

   Each protocol message is encapsulated in an LDAPMessage envelope
   [RFC4511.  The protocolOp CHOICE indicates the type of message
   encapsulated.  Each message type consists of an ASN.1 identifier in
   the form of a keyword and a non-negative choice number.  The choice
   number is combined with the class (APPLICATION) and data type
   (CONSTRUCTED or PRIMITIVE) to construct the BER tag in the message's
   encoding.  The choice numbers for existing protocol messages are
   implicit in the protocol's ASN.1 defined in [RFC4511].

   New values will be registered upon Standards Action.

   Note: LDAP provides extensible messages that reduce but do not
         eliminate the need to add new message types.

3.7.  LDAP Authentication Method

   The LDAP Bind operation supports multiple authentication methods
   [RFC4511].  Each authentication choice consists of an ASN.1
   identifier in the form of a keyword and a non-negative integer.

   The registrant SHALL classify the authentication method usage using
   one of the following terms:

         COMMON      - method is appropriate for common use on the
                       Internet.
         LIMITED USE - method is appropriate for limited use.
         OBSOLETE    - method has been deprecated or otherwise found to
                       be inappropriate for any use.

   Methods without publicly available specifications SHALL NOT be
   classified as COMMON.  New registrations of the class OBSOLETE cannot
   be registered.

   New authentication method integers in the range 0-1023 require
   Standards Action to be registered.  New authentication method
   integers in the range 1024-4095 require Expert Review with
   Specification Required.  New authentication method integers in the
   range 4096-16383 will be registered on a First Come First Served
   basis.  Keywords associated with integers in the range 0-4095 SHALL
   NOT start with "e-" or "x-".  Keywords associated with integers in



Zeilenga                 Best Current Practice                  [Page 6]

RFC 4520              IANA Considerations for LDAP             June 2006


   the range 4096-16383 SHALL start with "e-".  Values greater than or
   equal to 16384 and keywords starting with "x-" are for Private Use
   and cannot be registered.

   Note: LDAP supports Simple Authentication and Security Layers
         [RFC4422] as an authentication choice.  SASL is an extensible
         authentication framework.

3.8.  LDAP Result Codes

   LDAP result messages carry a resultCode enumerated value to indicate
   the outcome of the operation [RFC4511].  Each result code consists of
   an ASN.1 identifier in the form of a keyword and a non-negative
   integer.

   New resultCodes integers in the range 0-1023 require Standards Action
   to be registered.  New resultCode integers in the range 1024-4095
   require Expert Review with Specification Required.  New resultCode
   integers in the range 4096-16383 will be registered on a First Come
   First Served basis.  Keywords associated with integers in the range
   0-4095 SHALL NOT start with "e-" or "x-".  Keywords associated with
   integers in the range 4096-16383 SHALL start with "e-".  Values
   greater than or equal to 16384 and keywords starting with "x-" are
   for Private Use and cannot be registered.

3.9.  LDAP Search Scope

   LDAP SearchRequest messages carry a scope-enumerated value to
   indicate the extent of search within the DIT [RFC4511].  Each search
   value consists of an ASN.1 identifier in the form of a keyword and a
   non-negative integer.

   New scope integers in the range 0-1023 require Standards Action to be
   registered.  New scope integers in the range 1024-4095 require Expert
   Review with Specification Required.  New scope integers in the range
   4096-16383 will be registered on a First Come First Served basis.
   Keywords associated with integers in the range 0-4095 SHALL NOT start
   with "e-" or "x-".  Keywords associated with integers in the range
   4096-16383 SHALL start with "e-".  Values greater than or equal to
   16384 and keywords starting with "x-" are for Private Use and cannot
   be registered.

3.10.  LDAP Filter Choice

   LDAP filters are used in making assertions against an object
   represented in the directory [RFC4511].  The Filter CHOICE indicates
   a type of assertion.  Each Filter CHOICE consists of an ASN.1
   identifier in the form of a keyword and a non-negative choice number.



Zeilenga                 Best Current Practice                  [Page 7]

RFC 4520              IANA Considerations for LDAP             June 2006


   The choice number is combined with the class (APPLICATION) and data
   type (CONSTRUCTED or PRIMITIVE) to construct the BER tag in the
   message's encoding.

   Note: LDAP provides the extensibleMatching choice, which reduces but
         does not eliminate the need to add new filter choices.

3.11.  LDAP ModifyRequest Operation Type

   The LDAP ModifyRequest carries a sequence of modification operations
   [RFC4511].  Each kind (e.g., add, delete, replace) of operation
   consists of an ASN.1 identifier in the form of a keyword and a non-
   negative integer.

   New operation type integers in the range 0-1023 require Standards
   Action to be registered.  New operation type integers in the range
   1024-4095 require Expert Review with Specification Required.  New
   operation type integers in the range 4096-16383 will be registered on
   a First Come First Served basis.  Keywords associated with integers
   in the range 0-4095 SHALL NOT start with "e-" or "x-".  Keywords
   associated with integers in the range 4096-16383 SHALL start with
   "e-".  Values greater than or equal to 16384 and keywords starting
   with "x-" are for Private Use and cannot be registered.

3.12.  LDAP authzId Prefixes

   Authorization Identities in LDAP are strings conforming to the
   <authzId> production [RFC4513].  This production is extensible.  Each
   new specific authorization form is identified by a prefix string
   conforming to the following ABNF:

         prefix = keystring COLON
         COLON = %x3A ; COLON (":" U+003A)

   Prefixes are case insensitive.

   While the protocol places no maximum length restriction upon prefix
   strings, they should be short.  Prefixes longer than 12 characters
   may be viewed as too long to register.

   Prefixes beginning with "x-" are for Private Use and cannot be
   registered.

   Prefixes beginning with "e-" are reserved for experiments and will be
   registered on a First Come First Served basis.

   All other prefixes require Standards Action or Expert Review with
   Specification Required to be registered.



Zeilenga                 Best Current Practice                  [Page 8]

RFC 4520              IANA Considerations for LDAP             June 2006


3.13.  Directory Systems Names

   The IANA-maintained "Directory Systems Names" registry [IANADSN] of
   valid keywords for well-known attributes was used in the LDAPv2
   string representation of a distinguished name [RFC1779].  LDAPv2 is
   now Historic [RFC3494].

   Directory systems names are not known to be used in any other
   context.  LDAPv3 [RFC4514] uses Object Identifier Descriptors
   [Section 3.2] (which have a different syntax than directory system
   names).

   New Directory System Names will no longer be accepted.  For
   historical purposes, the current list of registered names should
   remain publicly available.

4.  Registration Procedure

   The procedure given here MUST be used by anyone who wishes to use a
   new value of a type described in Section 3 of this document.

   The first step is for the requester to fill out the appropriate form.
   Templates are provided in Appendix A.

   If the policy is Standards Action, the completed form SHOULD be
   provided to the IESG with the request for Standards Action.  Upon
   approval of the Standards Action, the IESG SHALL forward the request
   (possibly revised) to IANA.  The IESG SHALL be regarded as the
   registration owner of all values requiring Standards Action.

   If the policy is Expert Review, the requester SHALL post the
   completed form to the <directory@apps.ietf.org> mailing list for
   public review.  The review period is two (2) weeks.  If a revised
   form is later submitted, the review period is restarted.  Anyone may
   subscribe to this list by sending a request to <directory-
   request@apps.ietf.org>.  During the review, objections may be raised
   by anyone (including the Expert) on the list.  After completion of
   the review, the Expert, based on public comments, SHALL either
   approve the request and forward it to the IANA OR deny the request.
   In either case, the Expert SHALL promptly notify the requester of the
   action.  Actions of the Expert may be appealed [RFC2026].  The Expert
   is appointed by Applications Area Directors.  The requester is viewed
   as the registration owner of values registered under Expert Review.

   If the policy is First Come First Served, the requester SHALL submit
   the completed form directly to the IANA: <iana@iana.org>.  The
   requester is viewed as the registration owner of values registered
   under First Come First Served.



Zeilenga                 Best Current Practice                  [Page 9]

RFC 4520              IANA Considerations for LDAP             June 2006


   Neither the Expert nor IANA will take position on the claims of
   copyright or trademark issues regarding completed forms.

   Prior to submission of the Internet Draft (I-D) to the RFC Editor but
   after IESG review and tentative approval, the document editor SHOULD
   revise the I-D to use registered values.

5.  Registration Maintenance

   This section discusses maintenance of registrations.

5.1.  Lists of Registered Values

   IANA makes lists of registered values readily available to the
   Internet community on its web site: <http://www.iana.org/>.

5.2.  Change Control

   The registration owner MAY update the registration subject to the
   same constraints and review as with new registrations.  In cases
   where the registration owner is unable or is unwilling to make
   necessary updates, the IESG MAY assume ownership of the registration
   in order to update the registration.

5.3.  Comments

   For cases where others (anyone other than the registration owner)
   have significant objections to the claims in a registration and the
   registration owner does not agree to change the registration,
   comments MAY be attached to a registration upon Expert Review.  For
   registrations owned by the IESG, the objections SHOULD be addressed
   by initiating a request for Expert Review.

   The form of these requests is ad hoc, but MUST include the specific
   objections to be reviewed and SHOULD contain (directly or by
   reference) materials supporting the objections.

6.  Security Considerations

   The security considerations detailed in BCP 26 [RFC2434] are
   generally applicable to this document.  Additional security
   considerations specific to each name space are discussed in Section
   3, where appropriate.

   Security considerations for LDAP are discussed in documents
   comprising the technical specification [RFC4510].





Zeilenga                 Best Current Practice                 [Page 10]

RFC 4520              IANA Considerations for LDAP             June 2006


7.  Acknowledgement

   This document is a product of the IETF LDAP Revision (LDAPBIS)
   Working Group (WG).  This document is a revision of RFC 3383, also a
   product of the LDAPBIS WG.

   This document includes text borrowed from "Guidelines for Writing an
   IANA Considerations Section in RFCs" [RFC2434] by Thomas Narten and
   Harald Alvestrand.

8.  References

8.1.  Normative References

   [RFC2026]  Bradner, S., "The Internet Standards Process -- Revision
              3", BCP 9, RFC 2026, October 1996.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2434]  Narten, T. and H. Alvestrand, "Guidelines for Writing an
              IANA Considerations Section in RFCs", BCP 26, RFC 2434,
              October 1998.

   [RFC2578]  McCloghrie, K., Perkins, D., and J. Schoenwaelder,
              "Structure of Management Information Version 2 (SMIv2)",
              STD 58, RFC 2578, April 1999.

   [RFC3629]  Yergeau, F., "UTF-8, a transformation format of ISO
              10646", STD 63, RFC 3629, November 2003.

   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", RFC 4234, October 2005.

   [RFC4510]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC 4510, June
              2006.

   [RFC4511]  Sermersheim, J., Ed., "Lightweight Directory Access
              Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512, June
              2006.

   [RFC4513]  Harrison, R., Ed., "Lightweight Directory Access Protocol
              (LDAP): Authentication Methods and Security Mechanisms",
              RFC 4513, June 2006.



Zeilenga                 Best Current Practice                 [Page 11]

RFC 4520              IANA Considerations for LDAP             June 2006


   [RFC4516]  Smith, M., Ed. and T. Howes, "Lightweight Directory Access
              Protocol (LDAP): Uniform Resource Locator", RFC 4516, June
              2006.

   [Unicode]  The Unicode Consortium, "The Unicode Standard, Version
              3.2.0" is defined by "The Unicode Standard, Version 3.0"
              (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-61633-5),
              as amended by the "Unicode Standard Annex #27: Unicode
              3.1" (http://www.unicode.org/reports/tr27/) and by the
              "Unicode Standard Annex #28: Unicode 3.2"
              (http://www.unicode.org/reports/tr28/).

   [X.680]    International Telecommunication Union - Telecommunication
              Standardization Sector, "Abstract Syntax Notation One
              (ASN.1) - Specification of Basic Notation", X.680(2002)
              (also ISO/IEC 8824-1:2002).

8.2.  Informative References

   [RFC1779]  Kille, S., "A String Representation of Distinguished
              Names", RFC 1779, March 1995.

   [RFC3494]  Zeilenga, K.,"Lightweight Directory Access Protocol
              version 2 (LDAPv2) to Historic Status", RFC 3494, March
              2003.

   [RFC4514]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): String Representation of Distinguished Names", RFC
              4514, June 2006.

   [RFC4422]  Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
              Authentication and Security Layer (SASL)", RFC 4422, June
              2006.

   [IANADSN]  IANA, "Directory Systems Names",
              http://www.iana.org/assignments/directory-system-names.















Zeilenga                 Best Current Practice                 [Page 12]

RFC 4520              IANA Considerations for LDAP             June 2006


Appendix A.  Registration Templates

   This appendix provides registration templates for registering new
   LDAP values.  Note that more than one value may be requested by
   extending the template by listing multiple values, or through use of
   tables.

A.1.  LDAP Object Identifier Registration Template

   Subject: Request for LDAP OID Registration

   Person & email address to contact for further information:

   Specification: (I-D)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)

A.2.  LDAP Protocol Mechanism Registration Template

   Subject: Request for LDAP Protocol Mechanism Registration

   Object Identifier:

   Description:

   Person & email address to contact for further information:

   Usage: (One of Control or Extension or Feature or other)

   Specification: (RFC, I-D, URI)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)











Zeilenga                 Best Current Practice                 [Page 13]

RFC 4520              IANA Considerations for LDAP             June 2006


A.3.  LDAP Syntax Registration Template

   Subject: Request for LDAP Syntax Registration

   Object Identifier:

   Description:

   Person & email address to contact for further information:

   Specification: (RFC, I-D, URI)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)

A.4.  LDAP Descriptor Registration Template

   Subject: Request for LDAP Descriptor Registration

   Descriptor (short name):

   Object Identifier:

   Person & email address to contact for further information:

   Usage: (One of administrative role, attribute type, matching rule,
     name form, object class, URL extension, or other)

   Specification: (RFC, I-D, URI)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)













Zeilenga                 Best Current Practice                 [Page 14]

RFC 4520              IANA Considerations for LDAP             June 2006


A.5.  LDAP Attribute Description Option Registration Template

   Subject: Request for LDAP Attribute Description Option Registration
   Option Name:

   Family of Options: (YES or NO)

   Person & email address to contact for further information:

   Specification: (RFC, I-D, URI)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)

A.6.  LDAP Message Type Registration Template

   Subject: Request for LDAP Message Type Registration

   LDAP Message Name:

   Person & email address to contact for further information:

   Specification: (Approved I-D)

   Comments:

   (Any comments that the requester deems relevant to the request.)

A.7.  LDAP Authentication Method Registration Template

   Subject: Request for LDAP Authentication Method Registration

   Authentication Method Name:

   Person & email address to contact for further information:

   Specification: (RFC, I-D, URI)

   Intended Usage: (One of COMMON, LIMITED-USE, OBSOLETE)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)



Zeilenga                 Best Current Practice                 [Page 15]

RFC 4520              IANA Considerations for LDAP             June 2006


A.8.  LDAP Result Code Registration Template

   Subject: Request for LDAP Result Code Registration

   Result Code Name:

   Person & email address to contact for further information:

   Specification: (RFC, I-D, URI)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)

A.8.  LDAP Search Scope Registration Template

   Subject: Request for LDAP Search Scope Registration

   Search Scope Name:

   Filter Scope String:

   Person & email address to contact for further information:

   Specification: (RFC, I-D, URI)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)


















Zeilenga                 Best Current Practice                 [Page 16]

RFC 4520              IANA Considerations for LDAP             June 2006


A.9.  LDAP Filter Choice Registration Template

   Subject: Request for LDAP Filter Choice Registration

   Filter Choice Name:

   Person & email address to contact for further information:

   Specification: (RFC, I-D, URI)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)

A.10.  LDAP ModifyRequest Operation Registration Template

   Subject: Request for LDAP ModifyRequest Operation Registration

   ModifyRequest Operation Name:

   Person & email address to contact for further information:

   Specification: (RFC, I-D, URI)

   Author/Change Controller:

   Comments:

   (Any comments that the requester deems relevant to the request.)

Appendix B.  Changes since RFC 3383

   This informative appendix provides a summary of changes made since
   RFC 3383.

      -  Object Identifier Descriptors practices were updated to require
         all descriptors defined in RFCs to be registered and
         recommending all other descriptors (excepting those in
         private-use name space) be registered.  Additionally, all
         requests for multiple registrations of the same descriptor are
         now subject to Expert Review.

      -  Protocol Mechanisms practices were updated to include values of
         the 'supportedFeatures' attribute type.





Zeilenga                 Best Current Practice                 [Page 17]

RFC 4520              IANA Considerations for LDAP             June 2006


      -  LDAP Syntax, Search Scope, Filter Choice, ModifyRequest
         operation, and authzId prefixes registries were added.

      -  References to RFCs comprising the LDAP technical specifications
         have been updated to latest revisions.

      -  References to ISO 10646 have been replaced with [Unicode].

      -  The "Assigned Values" appendix providing initial registry
         values was removed.

      -  Numerous editorial changes were made.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org
































Zeilenga                 Best Current Practice                 [Page 18]

RFC 4520              IANA Considerations for LDAP             June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                 Best Current Practice                 [Page 19]

alt-openldap11-devel/rfc/rfc4533.txt000064400000220247150410163250012773 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4533                           OpenLDAP Foundation
Category: Experimental                                         J.H. Choi
                                                         IBM Corporation
                                                               June 2006


           The Lightweight Directory Access Protocol (LDAP)
                   Content Synchronization Operation

Status of This Memo

   This memo defines an Experimental Protocol for the Internet
   community.  It does not specify an Internet standard of any kind.
   Discussion and suggestions for improvement are requested.
   Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

IESG Note

   The IESG notes that this work was originally discussed in the LDUP
   working group.  The group came to consensus on a different approach,
   documented in RFC 3928; that document is on the standards track and
   should be reviewed by those considering implementation of this
   proposal.

Abstract

   This specification describes the Lightweight Directory Access
   Protocol (LDAP) Content Synchronization Operation.  The operation
   allows a client to maintain a copy of a fragment of the Directory
   Information Tree (DIT).  It supports both polling for changes and
   listening for changes.  The operation is defined as an extension of
   the LDAP Search Operation.














Zeilenga & Choi               Experimental                      [Page 1]

RFC 4533         LDAP Content Synchronization Operation        June 2006


Table of Contents

   1. Introduction ....................................................3
      1.1. Background .................................................3
      1.2. Intended Usage .............................................4
      1.3. Overview ...................................................5
      1.4. Conventions ................................................8
   2. Elements of the Sync Operation ..................................8
      2.1. Common ASN.1 Elements ......................................9
      2.2. Sync Request Control .......................................9
      2.3. Sync State Control ........................................10
      2.4. Sync Done Control .........................................10
      2.5. Sync Info Message .........................................11
      2.6. Sync Result Codes .........................................11
   3. Content Synchronization ........................................11
      3.1. Synchronization Session ...................................12
      3.2. Content Determination .....................................12
      3.3. refreshOnly Mode ..........................................13
      3.4. refreshAndPersist Mode ....................................16
      3.5. Search Request Parameters .................................17
      3.6. objectName ................................................18
      3.7. Canceling the Sync Operation ..............................19
      3.8. Refresh Required ..........................................19
      3.9. Chattiness Considerations .................................20
      3.10. Operation Multiplexing ...................................21
   4. Meta Information Considerations ................................22
      4.1. Entry DN ..................................................22
      4.2. Operational Attributes ....................................22
      4.3. Collective Attributes .....................................23
      4.4. Access and Other Administrative Controls ..................23
   5. Interaction with Other Controls ................................23
      5.1. ManageDsaIT Control .......................................24
      5.2. Subentries Control ........................................24
   6. Shadowing Considerations .......................................24
   7. Security Considerations ........................................25
   8. IANA Considerations ............................................26
      8.1. Object Identifier .........................................26
      8.2. LDAP Protocol Mechanism ...................................26
      8.3. LDAP Result Codes .........................................26
   9. Acknowledgements ...............................................26
   10. Normative References ..........................................27
   11. Informative References ........................................28
   Appendix A.  CSN-based Implementation Considerations ..............29








Zeilenga & Choi               Experimental                      [Page 2]

RFC 4533         LDAP Content Synchronization Operation        June 2006


1.  Introduction

   The Lightweight Directory Access Protocol (LDAP) [RFC4510] provides a
   mechanism, the search operation [RFC4511], that allows a client to
   request directory content matching a complex set of assertions and to
   request that the server return this content, subject to access
   control and other restrictions, to the client.  However, LDAP does
   not provide (despite the introduction of numerous extensions in this
   area) an effective and efficient mechanism for maintaining
   synchronized copies of directory content.  This document introduces a
   new mechanism specifically designed to meet the content
   synchronization requirements of sophisticated directory applications.

   This document defines the LDAP Content Synchronization Operation, or
   Sync Operation for short, which allows a client to maintain a
   synchronized copy of a fragment of a Directory Information Tree
   (DIT).  The Sync Operation is defined as a set of controls and other
   protocol elements that extend the Search Operation.

1.1.  Background

   Over the years, a number of content synchronization approaches have
   been suggested for use in LDAP directory services.  These approaches
   are inadequate for one or more of the following reasons:

      -  failure to ensure a reasonable level of convergence;

      -  failure to detect that convergence cannot be achieved (without
         reload);

      -  require pre-arranged synchronization agreements;

      -  require the server to maintain histories of past changes to DIT
         content and/or meta information;

      -  require the server to maintain synchronization state on a per-
         client basis; and/or

      -  are overly chatty.

   The Sync Operation provides eventual convergence of synchronized
   content when possible and, when not, notification that a full reload
   is required.

   The Sync Operation does not require pre-arranged synchronization
   agreements.





Zeilenga & Choi               Experimental                      [Page 3]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   The Sync Operation does not require that servers maintain or use any
   history of past changes to the DIT or to meta information.  However,
   servers may maintain and use histories (e.g., change logs,
   tombstones, DIT snapshots) to reduce the number of messages generated
   and to reduce their size.  As it is not always feasible to maintain
   and use histories, the operation may be implemented using purely
   (current) state-based approaches.  The Sync Operation allows use of
   either the state-based approach or the history-based approach on an
   operation-by-operation basis to balance the size of history and the
   amount of traffic.  The Sync Operation also allows the combined use
   of the state-based and the history-based approaches.

   The Sync Operation does not require that servers maintain
   synchronization state on a per-client basis.  However, servers may
   maintain and use per-client state information to reduce the number of
   messages generated and the size of such messages.

   A synchronization mechanism can be considered overly chatty when
   synchronization traffic is not reasonably bounded.  The Sync
   Operation traffic is bounded by the size of updated (or new) entries
   and the number of unchanged entries in the content.  The operation is
   designed to avoid full content exchanges, even when the history
   information available to the server is insufficient to determine the
   client's state.  The operation is also designed to avoid transmission
   of out-of-content history information, as its size is not bounded by
   the content and it is not always feasible to transmit such history
   information due to security reasons.

   This document includes a number of non-normative appendices providing
   additional information to server implementors.

1.2.  Intended Usage

   The Sync Operation is intended to be used in applications requiring
   eventually-convergent content synchronization.  Upon completion of
   each synchronization stage of the operation, all information to
   construct a synchronized client copy of the content has been provided
   to the client or the client has been notified that a complete content
   reload is necessary.  Except for transient inconsistencies due to
   concurrent operation (or other) processing at the server, the client
   copy is an accurate reflection of the content held by the server.
   Transient inconsistencies will be resolved by subsequent
   synchronization operations.








Zeilenga & Choi               Experimental                      [Page 4]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   Possible uses include the following:

      -  White page service applications may use the Sync Operation to
         maintain a current copy of a DIT fragment, for example, a mail
         user agent that uses the sync operation to maintain a local
         copy of an enterprise address book.

      -  Meta-information engines may use the Sync Operation to maintain
         a copy of a DIT fragment.

      -  Caching proxy services may use the Sync Operation to maintain a
         coherent content cache.

      -  Lightweight master-slave replication between heterogeneous
         directory servers.  For example, the Sync Operation can be used
         by a slave server to maintain a shadow copy of a DIT fragment.
         (Note: The International Telephone Union (ITU) has defined the
         X.500 Directory [X.500] Information Shadowing Protocol (DISP)
         [X.525], which may be used for master-slave replication between
         directory servers.  Other experimental LDAP replication
         protocols also exist.)

   This protocol is not intended to be used in applications requiring
   transactional data consistency.

   As this protocol transfers all visible values of entries belonging to
   the content upon change instead of change deltas, this protocol is
   not appropriate for bandwidth-challenged applications or deployments.

1.3.  Overview

   This section provides an overview of basic ways the Sync Operation
   can be used to maintain a synchronized client copy of a DIT fragment.

      -  Polling for changes: refreshOnly mode

      -  Listening for changes: refreshAndPersist mode

1.3.1.  Polling for Changes (refreshOnly)

   To obtain its initial client copy, the client issues a Sync request:
   a search request with the Sync Request Control with mode set to
   refreshOnly.  The server, much like it would with a normal search
   operation, returns (subject to access controls and other
   restrictions) the content matching the search criteria (baseObject,
   scope, filter, attributes).  Additionally, with each entry returned,
   the server provides a Sync State Control indicating state add.  This
   control contains the Universally Unique Identifier (UUID) [UUID] of



Zeilenga & Choi               Experimental                      [Page 5]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   the entry [RFC4530].  Unlike the Distinguished Name (DN), which may
   change over time, an entry's UUID is stable.  The initial content is
   followed by a SearchResultDone with a Sync Done Control.  The Sync
   Done Control provides a syncCookie.  The syncCookie represents
   session state.

   To poll for updates to the client copy, the client reissues the Sync
   Operation with the syncCookie previously returned.  The server, much
   as it would with a normal search operation, determines which content
   would be returned as if the operation were a normal search operation.
   However, using the syncCookie as an indicator of what content the
   client was sent previously, the server sends copies of entries that
   have changed with a Sync State Control indicating state add.  For
   each changed entry, all (modified or unmodified) attributes belonging
   to the content are sent.

   The server may perform either or both of the two distinct
   synchronization phases that are distinguished by how to synchronize
   entries deleted from the content: the present and the delete phases.
   When the server uses a single phase for the refresh stage, each phase
   is marked as ended by a SearchResultDone with a Sync Done Control.  A
   present phase is identified by a FALSE refreshDeletes value in the
   Sync Done Control.  A delete phase is identified by a TRUE
   refreshDeletes value.  The present phase may be followed by a delete
   phase.  The two phases are delimited by a refreshPresent Sync Info
   Message having a FALSE refreshDone value.  In the case that both the
   phases are used, the present phase is used to bring the client copy
   up to the state at which the subsequent delete phase can begin.

   In the present phase, the server sends an empty entry (i.e., no
   attributes) with a Sync State Control indicating state present for
   each unchanged entry.

   The delete phase may be used when the server can reliably determine
   which entries in the prior client copy are no longer present in the
   content and the number of such entries is less than or equal to the
   number of unchanged entries.  In the delete mode, the server sends an
   empty entry with a Sync State Control indicating state delete for
   each entry that is no longer in the content, instead of returning an
   empty entry with state present for each present entry.

   The server may send syncIdSet Sync Info Messages containing the set
   of UUIDs of either unchanged present entries or deleted entries,
   instead of sending multiple individual messages.  If refreshDeletes
   of syncIdSet is set to FALSE, the UUIDs of unchanged present entries
   are contained in the syncUUIDs set; if refreshDeletes of syncIdSet is
   set to TRUE, the UUIDs of the entries no longer present in the
   content are contained in the syncUUIDs set.  An optional cookie can



Zeilenga & Choi               Experimental                      [Page 6]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   be included in the syncIdSet to represent the state of the content
   after synchronizing the presence or the absence of the entries
   contained in the syncUUIDs set.

   The synchronized copy of the DIT fragment is constructed by the
   client.

   If refreshDeletes of syncDoneValue is FALSE, the new copy includes
   all changed entries returned by the reissued Sync Operation, as well
   as all unchanged entries identified as being present by the reissued
   Sync Operation, but whose content is provided by the previous Sync
   Operation.  The unchanged entries not identified as being present are
   deleted from the client content.  They had been either deleted,
   moved, or otherwise scoped-out from the content.

   If refreshDeletes of syncDoneValue is TRUE, the new copy includes all
   changed entries returned by the reissued Sync Operation, as well as
   all other entries of the previous copy except for those that are
   identified as having been deleted from the content.

   The client can, at some later time, re-poll for changes to this
   synchronized client copy.

1.3.2.  Listening for Changes (refreshAndPersist)

   Polling for changes can be expensive in terms of server, client, and
   network resources.  The refreshAndPersist mode allows for active
   updates of changed entries in the content.

   By selecting the refreshAndPersist mode, the client requests that the
   server send updates of entries that are changed after the initial
   refresh content is determined.  Instead of sending a SearchResultDone
   Message as in polling, the server sends a Sync Info Message to the
   client indicating that the refresh stage is complete and then enters
   the persist stage.  After receipt of this Sync Info Message, the
   client will construct a synchronized copy as described in Section
   1.3.1.

   The server may then send change notifications as the result of the
   original Sync search request, which now remains persistent in the
   server.  For entries to be added to the returned content, the server
   sends a SearchResultEntry (with attributes) with a Sync State Control
   indicating state add.  For entries to be deleted from the content,
   the server sends a SearchResultEntry containing no attributes and a
   Sync State Control indicating state delete.  For entries to be
   modified in the return content, the server sends a SearchResultEntry
   (with attributes) with a Sync State Control indicating state modify.




Zeilenga & Choi               Experimental                      [Page 7]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   Upon modification of an entry, all (modified or unmodified)
   attributes belonging to the content are sent.

   Note that renaming an entry of the DIT may cause an add state change
   where the entry is renamed into the content, a delete state change
   where the entry is renamed out of the content, and a modify state
   change where the entry remains in the content.  Also note that a
   modification of an entry of the DIT may cause an add, delete, or
   modify state change to the content.

   Upon receipt of a change notification, the client updates its copy of
   the content.

   If the server desires to update the syncCookie during the persist
   stage, it may include the syncCookie in any Sync State Control or
   Sync Info Message returned.

   The operation persists until canceled [RFC3909] by the client or
   terminated by the server.  A Sync Done Control shall be attached to
   SearchResultDone Message to provide a new syncCookie.

1.4.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

   Protocol elements are described using ASN.1 [X.680] with implicit
   tags.  The term "BER-encoded" means the element is to be encoded
   using the Basic Encoding Rules [X.690] under the restrictions
   detailed in Section 5.1 of [RFC4511].

2.  Elements of the Sync Operation

   The Sync Operation is defined as an extension to the LDAP Search
   Operation [RFC4511] where the directory user agent (DUA or client)
   submits a SearchRequest Message with a Sync Request Control and the
   directory system agent (DSA or server) responds with zero or more
   SearchResultEntry Messages, each with a Sync State Control; zero or
   more SearchResultReference Messages, each with a Sync State Control;
   zero or more Sync Info Intermediate Response Messages; and a
   SearchResultDone Message with a Sync Done Control.

   To allow clients to discover support for this operation, servers
   implementing this operation SHOULD publish 1.3.6.1.4.1.4203.1.9.1.1
   as a value of the 'supportedControl' attribute [RFC4512] of the root
   DSA-specific entry (DSE).  A server MAY choose to advertise this
   extension only when the client is authorized to use it.



Zeilenga & Choi               Experimental                      [Page 8]

RFC 4533         LDAP Content Synchronization Operation        June 2006


2.1.  Common ASN.1 Elements

2.1.1.  syncUUID

   The syncUUID data type is an OCTET STRING holding a 128-bit
   (16-octet) Universally Unique Identifier (UUID) [UUID].

      syncUUID ::= OCTET STRING (SIZE(16))
           -- constrained to UUID

2.1.2.  syncCookie

   The syncCookie is a notational convenience to indicate that, while
   the syncCookie type is encoded as an OCTET STRING, its value is an
   opaque value containing information about the synchronization session
   and its state.  Generally, the session information would include a
   hash of the operation parameters that the server requires not be
   changed and the synchronization state information would include a
   commit (log) sequence number, a change sequence number, or a time
   stamp.  For convenience of description, the term "no cookie" refers
   either to a null cookie or to a cookie with pre-initialized
   synchronization state.

      syncCookie ::= OCTET STRING

2.2.  Sync Request Control

   The Sync Request Control is an LDAP Control [RFC4511] where the
   controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.1 and the
   controlValue, an OCTET STRING, contains a BER-encoded
   syncRequestValue.  The criticality field is either TRUE or FALSE.

      syncRequestValue ::= SEQUENCE {
          mode ENUMERATED {
              -- 0 unused
              refreshOnly       (1),
              -- 2 reserved
              refreshAndPersist (3)
          },
          cookie     syncCookie OPTIONAL,
          reloadHint BOOLEAN DEFAULT FALSE
      }

   The Sync Request Control is only applicable to the SearchRequest
   Message.






Zeilenga & Choi               Experimental                      [Page 9]

RFC 4533         LDAP Content Synchronization Operation        June 2006


2.3.  Sync State Control

   The Sync State Control is an LDAP Control [RFC4511] where the
   controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.2 and the
   controlValue, an OCTET STRING, contains a BER-encoded syncStateValue.
   The criticality is FALSE.

      syncStateValue ::= SEQUENCE {
          state ENUMERATED {
              present (0),
              add (1),
              modify (2),
              delete (3)
          },
          entryUUID syncUUID,
          cookie    syncCookie OPTIONAL
      }

   The Sync State Control is only applicable to SearchResultEntry and
   SearchResultReference Messages.

2.4.  Sync Done Control

   The Sync Done Control is an LDAP Control [RFC4511] where the
   controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.3 and the
   controlValue contains a BER-encoded syncDoneValue.  The criticality
   is FALSE (and hence absent).

      syncDoneValue ::= SEQUENCE {
          cookie          syncCookie OPTIONAL,
          refreshDeletes  BOOLEAN DEFAULT FALSE
      }

   The Sync Done Control is only applicable to the SearchResultDone
   Message.
















Zeilenga & Choi               Experimental                     [Page 10]

RFC 4533         LDAP Content Synchronization Operation        June 2006


2.5.  Sync Info Message

   The Sync Info Message is an LDAP Intermediate Response Message
   [RFC4511] where responseName is the object identifier
   1.3.6.1.4.1.4203.1.9.1.4 and responseValue contains a BER-encoded
   syncInfoValue.  The criticality is FALSE (and hence absent).

      syncInfoValue ::= CHOICE {
          newcookie      [0] syncCookie,
          refreshDelete  [1] SEQUENCE {
              cookie         syncCookie OPTIONAL,
              refreshDone    BOOLEAN DEFAULT TRUE
          },
          refreshPresent [2] SEQUENCE {
              cookie         syncCookie OPTIONAL,
              refreshDone    BOOLEAN DEFAULT TRUE
          },
          syncIdSet      [3] SEQUENCE {
              cookie         syncCookie OPTIONAL,
              refreshDeletes BOOLEAN DEFAULT FALSE,
              syncUUIDs      SET OF syncUUID
          }
      }

2.6.  Sync Result Codes

   The following LDAP resultCode [RFC4511] is defined:

      e-syncRefreshRequired (4096)

3.  Content Synchronization

   The Sync Operation is invoked when the client sends a SearchRequest
   Message with a Sync Request Control.

   The absence of a cookie or an initialized synchronization state in a
   cookie indicates a request for initial content, while the presence of
   a cookie representing a state of a client copy indicates a request
   for a content update.  Synchronization Sessions are discussed in
   Section 3.1.  Content Determination is discussed in Section 3.2.

   The mode is either refreshOnly or refreshAndPersist.  The refreshOnly
   and refreshAndPersist modes are discussed in Sections 3.3 and 3.4,
   respectively.  The refreshOnly mode consists only of a refresh stage,
   while the refreshAndPersist mode consists of a refresh stage and a
   subsequent persist stage.





Zeilenga & Choi               Experimental                     [Page 11]

RFC 4533         LDAP Content Synchronization Operation        June 2006


3.1.  Synchronization Session

   A sequence of Sync Operations where the last cookie returned by the
   server for one operation is provided by the client in the next
   operation is said to belong to the same Synchronization Session.

   The client MUST specify the same content-controlling parameters (see
   Section 3.5) in each Search Request of the session.  The client
   SHOULD also issue each Sync request of a session under the same
   authentication and authorization associations with equivalent
   integrity and protections.  If the server does not recognize the
   request cookie or the request is made under different associations or
   non-equivalent protections, the server SHALL return the initial
   content as if no cookie had been provided or return an empty content
   with the e-syncRefreshRequired LDAP result code.  The decision
   between the return of the initial content and the return of the empty
   content with the e-syncRefreshRequired result code MAY be based on
   reloadHint in the Sync Request Control from the client.  If the
   server recognizes the request cookie as representing empty or initial
   synchronization state of the client copy, the server SHALL return the
   initial content.

   A Synchronization Session may span multiple LDAP sessions between the
   client and the server.  The client SHOULD issue each Sync request of
   a session to the same server.  (Note: Shadowing considerations are
   discussed in Section 6.)

3.2.  Content Determination

   The content to be provided is determined by parameters of the Search
   Request, as described in [RFC4511], and possibly other controls.  The
   same content parameters SHOULD be used in each Sync request of a
   session.  If different content is requested and the server is
   unwilling or unable to process the request, the server SHALL return
   the initial content as if no cookie had been provided or return an
   empty content with the e-syncRefreshRequired LDAP result code.  The
   decision between the return of the initial content and the return of
   the empty content with the e-syncRefreshRequired result code MAY be
   based on reloadHint in the Sync Request Control from the client.

   The content may not necessarily include all entries or references
   that would be returned by a normal search operation, nor, for those
   entries included, all attributes returned by a normal search.  When
   the server is unwilling or unable to provide synchronization for any
   attribute for a set of entries, the server MUST treat all filter
   components matching against these attributes as Undefined and MUST
   NOT return these attributes in SearchResultEntry responses.




Zeilenga & Choi               Experimental                     [Page 12]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   Servers SHOULD support synchronization for all non-collective user-
   application attributes for all entries.

   The server may also return continuation references to other servers
   or to itself.  The latter is allowed as the server may partition the
   entries it holds into separate synchronization contexts.

   The client may chase all or some of these continuations, each as a
   separate content synchronization session.

3.3.  refreshOnly Mode

   A Sync request with mode refreshOnly and with no cookie is a poll for
   initial content.  A Sync request with mode refreshOnly and with a
   cookie representing a synchronization state is a poll for content
   update.

3.3.1.  Initial Content Poll

   Upon receipt of the request, the server provides the initial content
   using a set of zero or more SearchResultEntry and
   SearchResultReference Messages followed by a SearchResultDone
   Message.

   Each SearchResultEntry Message SHALL include a Sync State Control of
   state add, an entryUUID containing the entry's UUID, and no cookie.
   Each SearchResultReference Message SHALL include a Sync State Control
   of state add, an entryUUID containing the UUID associated with the
   reference (normally the UUID of the associated named referral
   [RFC3296] object), and no cookie.  The SearchResultDone Message SHALL
   include a Sync Done Control having refreshDeletes set to FALSE.

   A resultCode value of success indicates that the operation
   successfully completed.  Otherwise, the result code indicates the
   nature of the failure.  The server may return e-syncRefreshRequired
   result code on the initial content poll if it is safe to do so when
   it is unable to perform the operation due to various reasons.
   reloadHint is set to FALSE in the SearchRequest Message requesting
   the initial content poll.

   If the operation is successful, a cookie representing the
   synchronization state of the current client copy SHOULD be returned
   for use in subsequent Sync Operations.

3.3.2.  Content Update Poll

   Upon receipt of the request, the server provides the content refresh
   using a set of zero or more SearchResultEntry and



Zeilenga & Choi               Experimental                     [Page 13]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   SearchResultReference Messages followed by a SearchResultDone
   Message.

   The server is REQUIRED to:

      a) provide the sequence of messages necessary for eventual
         convergence of the client's copy of the content to the server's
         copy,

      b) treat the request as an initial content request (e.g., ignore
         the cookie or the synchronization state represented in the
         cookie),

      c) indicate that the incremental convergence is not possible by
         returning e-syncRefreshRequired,

      d) return a resultCode other than success or e-
         syncRefreshRequired.

   A Sync Operation may consist of a single present phase, a single
   delete phase, or a present phase followed by a delete phase.

   In each phase, for each entry or reference that has been added to the
   content or been changed since the previous Sync Operation indicated
   by the cookie, the server returns a SearchResultEntry or
   SearchResultReference Message, respectively, each with a Sync State
   Control consisting of state add, an entryUUID containing the UUID of
   the entry or reference, and no cookie.  Each SearchResultEntry
   Message represents the current state of a changed entry.  Each
   SearchResultReference Message represents the current state of a
   changed reference.

   In the present phase, for each entry that has not been changed since
   the previous Sync Operation, an empty SearchResultEntry is returned
   whose objectName reflects the entry's current DN, whose attributes
   field is empty, and whose Sync State Control consists of state
   present, an entryUUID containing the UUID of the entry, and no
   cookie.  For each reference that has not been changed since the
   previous Sync Operation, an empty SearchResultReference containing an
   empty SEQUENCE OF LDAPURL is returned with a Sync State Control
   consisting of state present, an entryUUID containing the UUID of the
   entry, and no cookie.  No messages are sent for entries or references
   that are no longer in the content.

   Multiple empty entries with a Sync State Control of state present
   SHOULD be coalesced into one or more Sync Info Messages of syncIdSet
   value with refreshDeletes set to FALSE.  syncUUIDs contain a set of
   UUIDs of the entries and references unchanged since the last Sync



Zeilenga & Choi               Experimental                     [Page 14]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   Operation.  syncUUIDs may be empty.  The Sync Info Message of
   syncIdSet may contain a cookie to represent the state of the content
   after performing the synchronization of the entries in the set.

   In the delete phase, for each entry no longer in the content, the
   server returns a SearchResultEntry whose objectName reflects a past
   DN of the entry or is empty, whose attributes field is empty, and
   whose Sync State Control consists of state delete, an entryUUID
   containing the UUID of the deleted entry, and no cookie.  For each
   reference no longer in the content, a SearchResultReference
   containing an empty SEQUENCE OF LDAPURL is returned with a Sync State
   Control consisting of state delete, an entryUUID containing the UUID
   of the deleted reference, and no cookie.

   Multiple empty entries with a Sync State Control of state delete
   SHOULD be coalesced into one or more Sync Info Messages of syncIdSet
   value with refreshDeletes set to TRUE.  syncUUIDs contain a set of
   UUIDs of the entries and references that have been deleted from the
   content since the last Sync Operation.  syncUUIDs may be empty.  The
   Sync Info Message of syncIdSet may contain a cookie to represent the
   state of the content after performing the synchronization of the
   entries in the set.

   When a present phase is followed by a delete phase, the two phases
   are delimited by a Sync Info Message containing syncInfoValue of
   refreshPresent, which may contain a cookie representing the state
   after completing the present phase.  The refreshPresent contains
   refreshDone, which is always FALSE in the refreshOnly mode of Sync
   Operation because it is followed by a delete phase.

   If a Sync Operation consists of a single phase, each phase and hence
   the Sync Operation are marked as ended by a SearchResultDone Message
   with Sync Done Control, which SHOULD contain a cookie representing
   the state of the content after completing the Sync Operation.  The
   Sync Done Control contains refreshDeletes, which is set to FALSE for
   the present phase and set to TRUE for the delete phase.

   If a Sync Operation consists of a present phase followed by a delete
   phase, the Sync Operation is marked as ended at the end of the delete
   phase by a SearchResultDone Message with Sync Done Control, which
   SHOULD contain a cookie representing the state of the content after
   completing the Sync Operation.  The Sync Done Control contains
   refreshDeletes, which is set to TRUE.

   The client can specify whether it prefers to receive an initial
   content by supplying reloadHint of TRUE or to receive a e-
   syncRefreshRequired resultCode by supplying reloadHint of FALSE
   (hence absent), in the case that the server determines that it is



Zeilenga & Choi               Experimental                     [Page 15]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   impossible or inefficient to achieve the eventual convergence by
   continuing the current incremental synchronization thread.

   A resultCode value of success indicates that the operation is
   successfully completed.  A resultCode value of e-syncRefreshRequired
   indicates that a full or partial refresh is needed.  Otherwise, the
   result code indicates the nature of failure.  A cookie is provided in
   the Sync Done Control for use in subsequent Sync Operations for
   incremental synchronization.

3.4.  refreshAndPersist Mode

   A Sync request with mode refreshAndPersist asks for initial content
   or content update (during the refresh stage) followed by change
   notifications (during the persist stage).

3.4.1.  refresh Stage

   The content refresh is provided as described in Section 3.3, except
   that the successful completion of content refresh is indicated by
   sending a Sync Info Message of refreshDelete or refreshPresent with a
   refreshDone value set to TRUE instead of a SearchResultDone Message
   with resultCode success.  A cookie SHOULD be returned in the Sync
   Info Message to represent the state of the content after finishing
   the refresh stage of the Sync Operation.

3.4.2.  persist Stage

   Change notifications are provided during the persist stage.

   As updates are made to the DIT, the server notifies the client of
   changes to the content.  DIT updates may cause entries and references
   to be added to the content, deleted from the content, or modified
   within the content.  DIT updates may also cause references to be
   added, deleted, or modified within the content.

   Where DIT updates cause an entry to be added to the content, the
   server provides a SearchResultEntry Message that represents the entry
   as it appears in the content.  The message SHALL include a Sync State
   Control with state of add, an entryUUID containing the entry's UUID,
   and an optional cookie.

   Where DIT updates cause a reference to be added to the content, the
   server provides a SearchResultReference Message that represents the
   reference in the content.  The message SHALL include a Sync State
   Control with state of add, an entryUUID containing the UUID
   associated with the reference, and an optional cookie.




Zeilenga & Choi               Experimental                     [Page 16]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   Where DIT updates cause an entry to be modified within the content,
   the server provides a SearchResultEntry Message that represents the
   entry as it appears in the content.  The message SHALL include a Sync
   State Control with state of modify, an entryUUID containing the
   entry's UUID, and an optional cookie.

   Where DIT updates cause a reference to be modified within the
   content, the server provides a SearchResultReference Message that
   represents the reference in the content.  The message SHALL include a
   Sync State Control with state of modify, an entryUUID containing the
   UUID associated with the reference, and an optional cookie.

   Where DIT updates cause an entry to be deleted from the content, the
   server provides a SearchResultEntry Message with no attributes.  The
   message SHALL include a Sync State Control with state of delete, an
   entryUUID containing the entry's UUID, and an optional cookie.

   Where DIT updates cause a reference to be deleted from the content,
   the server provides a SearchResultReference Message with an empty
   SEQUENCE OF LDAPURL.  The message SHALL include a Sync State Control
   with state of delete, an entryUUID containing the UUID associated
   with the reference, and an optional cookie.

   Multiple empty entries with a Sync State Control of state delete
   SHOULD be coalesced into one or more Sync Info Messages of syncIdSet
   value with refreshDeletes set to TRUE. syncUUIDs contain a set of
   UUIDs of the entries and references that have been deleted from the
   content.  The Sync Info Message of syncIdSet may contain a cookie to
   represent the state of the content after performing the
   synchronization of the entries in the set.

   With each of these messages, the server may provide a new cookie to
   be used in subsequent Sync Operations.  Additionally, the server may
   also return Sync Info Messages of choice newCookie to provide a new
   cookie.  The client SHOULD use the newest (last) cookie it received
   from the server in subsequent Sync Operations.

3.5.  Search Request Parameters

   As stated in Section 3.1, the client SHOULD specify the same
   content-controlling parameters in each Search Request of the session.
   All fields of the SearchRequest Message are considered content-
   controlling parameters except for sizeLimit and timeLimit.








Zeilenga & Choi               Experimental                     [Page 17]

RFC 4533         LDAP Content Synchronization Operation        June 2006


3.5.1.  baseObject

   As with the normal search operation, the refresh and persist stages
   are not isolated from DIT changes.  It is possible that the entry
   referred to by the baseObject is deleted, renamed, or moved.  It is
   also possible that the alias object used in finding the entry
   referred to by the baseObject is changed such that the baseObject
   refers to a different entry.

   If the DIT is updated during processing of the Sync Operation in a
   manner that causes the baseObject no longer to refer to any entry or
   in a manner that changes the entry the baseObject refers to, the
   server SHALL return an appropriate non-success result code, such as
   noSuchObject, aliasProblem, aliasDereferencingProblem, referral, or
   e-syncRefreshRequired.

3.5.2.  derefAliases

   This operation does not support alias dereferencing during searching.
   The client SHALL specify neverDerefAliases or derefFindingBaseObj for
   the SearchRequest derefAliases parameter.  The server SHALL treat
   other values (e.g., derefInSearching, derefAlways) as protocol
   errors.

3.5.3.  sizeLimit

   The sizeLimit applies only to entries (regardless of their state in
   Sync State Control) returned during the refreshOnly operation or the
   refresh stage of the refreshAndPersist operation.

3.5.4.  timeLimit

   For a refreshOnly Sync Operation, the timeLimit applies to the whole
   operation.  For a refreshAndPersist operation, the timeLimit applies
   only to the refresh stage including the generation of the Sync Info
   Message with a refreshDone value of TRUE.

3.5.5.  filter

   The client SHOULD avoid filter assertions that apply to the values of
   the attributes likely to be considered by the server as ones holding
   meta-information.  See Section 4.

3.6.  objectName

   The Sync Operation uses entryUUID values provided in the Sync State
   Control as the primary keys to entries.  The client MUST use these
   entryUUIDs to correlate synchronization messages.



Zeilenga & Choi               Experimental                     [Page 18]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   In some circumstances, the DN returned may not reflect the entry's
   current DN.  In particular, when the entry is being deleted from the
   content, the server may provide an empty DN if the server does not
   wish to disclose the entry's current DN (or, if deleted from the DIT,
   the entry's last DN).

   Also note that the entry's DN may be viewed as meta information (see
   Section 4.1).

3.7.  Canceling the Sync Operation

   Servers MUST implement the LDAP Cancel [RFC3909] Operation and
   support cancellation of outstanding Sync Operations as described
   here.

   To cancel an outstanding Sync Operation, the client issues an LDAP
   Cancel [RFC3909] Operation.

   If at any time the server becomes unwilling or unable to continue
   processing a Sync Operation, the server SHALL return a
   SearchResultDone with a non-success resultCode indicating the reason
   for the termination of the operation.

   Whether the client or the server initiated the termination, the
   server may provide a cookie in the Sync Done Control for use in
   subsequent Sync Operations.

3.8.  Refresh Required

   In order to achieve the eventually-convergent synchronization, the
   server may terminate the Sync Operation in the refresh or persist
   stages by returning an e-syncRefreshRequired resultCode to the
   client.  If no cookie is provided, a full refresh is needed.  If a
   cookie representing a synchronization state is provided in this
   response, an incremental refresh is needed.

   To obtain a full refresh, the client then issues a new
   synchronization request with no cookie.  To obtain an incremental
   reload, the client issues a new synchronization with the provided
   cookie.

   The server may choose to provide a full copy in the refresh stage
   (e.g., ignore the cookie or the synchronization state represented in
   the cookie) instead of providing an incremental refresh in order to
   achieve the eventual convergence.






Zeilenga & Choi               Experimental                     [Page 19]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   The decision between the return of the initial content and the return
   of the e-syncRefreshRequired result code may be based on reloadHint
   in the Sync Request Control from the client.

   In the case of persist stage Sync, the server returns the resultCode
   of e-syncRefreshRequired to the client to indicate that the client
   needs to issue a new Sync Operation in order to obtain a synchronized
   copy of the content.  If no cookie is provided, a full refresh is
   needed.  If a cookie representing a synchronization state is
   provided, an incremental refresh is needed.

   The server may also return e-syncRefreshRequired if it determines
   that a refresh would be more efficient than sending all the messages
   required for convergence.

   Note that the client may receive one or more of SearchResultEntry,
   SearchResultReference, and/or Sync Info Messages before it receives a
   SearchResultDone Message with the e-syncRefreshRequired result code.

3.9.  Chattiness Considerations

   The server MUST ensure that the number of entry messages generated to
   refresh the client content does not exceed the number of entries
   presently in the content.  While there is no requirement for servers
   to maintain history information, if the server has sufficient history
   to allow it to reliably determine which entries in the prior client
   copy are no longer present in the content and the number of such
   entries is less than or equal to the number of unchanged entries, the
   server SHOULD generate delete entry messages instead of present entry
   messages (see Section 3.3.2).

   When the amount of history information maintained in the server is
   not enough for the clients to perform infrequent refreshOnly Sync
   Operations, it is likely that the server has incomplete history
   information (e.g., due to truncation) by the time those clients
   connect again.

   The server SHOULD NOT resort to full reload when the history
   information is not enough to generate delete entry messages.  The
   server SHOULD generate either present entry messages only or present
   entry messages followed by delete entry messages to bring the client
   copy to the current state.  In the latter case, the present entry
   messages bring the client copy to a state covered by the history
   information maintained in the server.

   The server SHOULD maintain enough (current or historical) state
   information (such as a context-wide last modify time stamp) to
   determine if no changes were made in the context since the content



Zeilenga & Choi               Experimental                     [Page 20]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   refresh was provided and, when no changes were made, generate zero
   delete entry messages instead of present messages.

   The server SHOULD NOT use the history information when its use does
   not reduce the synchronization traffic or when its use can expose
   sensitive information not allowed to be received by the client.

   The server implementor should also consider chattiness issues that
   span multiple Sync Operations of a session.  As noted in Section 3.8,
   the server may return e-syncRefreshRequired if it determines that a
   reload would be more efficient than continuing under the current
   operation.  If reloadHint in the Sync Request is TRUE, the server may
   initiate a reload without directing the client to request a reload.

   The server SHOULD transfer a new cookie frequently to avoid having to
   transfer information already provided to the client.  Even where DIT
   changes do not cause content synchronization changes to be
   transferred, it may be advantageous to provide a new cookie using a
   Sync Info Message.  However, the server SHOULD avoid overloading the
   client or network with Sync Info Messages.

   During persist mode, the server SHOULD coalesce multiple outstanding
   messages updating the same entry.  The server MAY delay generation of
   an entry update in anticipation of subsequent changes to that entry
   that could be coalesced.  The length of the delay should be long
   enough to allow coalescing of update requests issued back to back but
   short enough that the transient inconsistency induced by the delay is
   corrected in a timely manner.

   The server SHOULD use the syncIdSet Sync Info Message when there are
   multiple delete or present messages to reduce the amount of
   synchronization traffic.

   Also note that there may be many clients interested in a particular
   directory change, and that servers attempting to service all of these
   at once may cause congestion on the network.  The congestion issues
   are magnified when the change requires a large transfer to each
   interested client.  Implementors and deployers of servers should take
   steps to prevent and manage network congestion.

3.10.  Operation Multiplexing

   The LDAP protocol model [RFC4511] allows operations to be multiplexed
   over a single LDAP session.  Clients SHOULD NOT maintain multiple
   LDAP sessions with the same server.  Servers SHOULD ensure that
   responses from concurrently processed operations are interleaved
   fairly.




Zeilenga & Choi               Experimental                     [Page 21]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   Clients SHOULD combine Sync Operations whose result set is largely
   overlapping.  This avoids having to return multiple messages, once
   for each overlapping session, for changes to entries in the overlap.

   Clients SHOULD NOT combine Sync Operations whose result sets are
   largely non-overlapping.  This ensures that an event requiring an
   e-syncRefreshRequired response can be limited to as few result sets
   as possible.

4.  Meta Information Considerations

4.1.  Entry DN

   As an entry's DN is constructed from its relative DN (RDN) and the
   entry's parent's DN, it is often viewed as meta information.

   While renaming or moving to a new superior causes the entry's DN to
   change, that change SHOULD NOT, by itself, cause synchronization
   messages to be sent for that entry.  However, if the renaming or the
   moving could cause the entry to be added or deleted from the content,
   appropriate synchronization messages should be generated to indicate
   this to the client.

   When a server treats the entry's DN as meta information, the server
   SHALL either

      -  evaluate all MatchingRuleAssertions [RFC4511] to TRUE if
         matching a value of an attribute of the entry, otherwise
         Undefined, or

      -  evaluate all MatchingRuleAssertion with dnAttributes of TRUE as
         Undefined.

   The latter choice is offered for ease of server implementation.

4.2.  Operational Attributes

   Where values of an operational attribute are determined by values not
   held as part of the entry it appears in, the operational attribute
   SHOULD NOT support synchronization of that operational attribute.

   For example, in servers that implement the X.501 subschema model
   [X.501], servers should not support synchronization of the
   subschemaSubentry attribute as its value is determined by values held
   and administrated in subschema subentries.






Zeilenga & Choi               Experimental                     [Page 22]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   As a counter example, servers that implement aliases [RFC4512][X.501]
   can support synchronization of the aliasedObjectName attribute as its
   values are held and administrated as part of the alias entries.

   Servers SHOULD support synchronization of the following operational
   attributes: createTimestamp, modifyTimestamp, creatorsName,
   modifiersName [RFC4512].  Servers MAY support synchronization of
   other operational attributes.

4.3.  Collective Attributes

   A collective attribute is "a user attribute whose values are the same
   for each member of an entry collection" [X.501].  Use of collective
   attributes in LDAP is discussed in [RFC3671].

   Modification of a collective attribute generally affects the content
   of multiple entries, which are the members of the collection.  It is
   inefficient to include values of collective attributes visible in
   entries of the collection, as a single modification of a collective
   attribute requires transmission of multiple SearchResultEntry (one
   for each entry of the collection that the modification affected).

   Servers SHOULD NOT synchronize collective attributes appearing in
   entries of any collection.  Servers MAY support synchronization of
   collective attributes appearing in collective attribute subentries.

4.4.  Access and Other Administrative Controls

   Entries are commonly subject to access and other administrative
   Controls.  While portions of the policy information governing a
   particular entry may be held in the entry, policy information is
   often held elsewhere (in superior entries, in subentries, in the root
   DSE, in configuration files, etc.).  Because of this, changes to
   policy information make it difficult to ensure eventual convergence
   during incremental synchronization.

   Where it is impractical or infeasible to generate content changes
   resulting from a change to policy information, servers may opt to
   return e-syncRefreshRequired or to treat the Sync Operation as an
   initial content request (e.g., ignore the cookie or the
   synchronization state represented in the cookie).

5.  Interaction with Other Controls

   The Sync Operation may be used with:

      - ManageDsaIT Control [RFC3296]




Zeilenga & Choi               Experimental                     [Page 23]

RFC 4533         LDAP Content Synchronization Operation        June 2006


      - Subentries Control [RFC3672]

   as described below.  The Sync Operation may be used with other LDAP
   extensions as detailed in other documents.

5.1.  ManageDsaIT Control

   The ManageDsaIT Control [RFC3296] indicates that the operation acts
   upon the DSA Information Tree and causes referral and other special
   entries to be treated as object entries with respect to the
   operation.

5.2.  Subentries Control

   The Subentries Control is used with the search operation "to control
   the visibility of entries and subentries which are within scope"
   [RFC3672].  When used with the Sync Operation, the subentries control
   and other factors (search scope, filter, etc.) are used to determine
   whether an entry or subentry appears in the content.

6.  Shadowing Considerations

   As noted in [RFC4511], some servers may hold shadow copies of entries
   that can be used to answer search and comparison queries.  Such
   servers may also support content synchronization requests.  This
   section discusses considerations for implementors and deployers for
   the implementation and deployment of the Sync operation in shadowed
   directories.

   While a client may know of multiple servers that are equally capable
   of being used to obtain particular directory content from, a client
   SHOULD NOT assume that each of these servers is equally capable of
   continuing a content synchronization session.  As stated in Section
   3.1, the client SHOULD issue each Sync request of a Sync session to
   the same server.

   However, through domain naming or IP address redirection or other
   techniques, multiple physical servers can be made to appear as one
   logical server to a client.  Only servers that are equally capable in
   regards to their support for the Sync operation and that hold equally
   complete copies of the entries should be made to appear as one
   logical server.  In particular, each physical server acting as one
   logical server SHOULD be equally capable of continuing a content
   synchronization based upon cookies provided by any of the other
   physical servers without requiring a full reload.  Because there is
   no standard LDAP shadowing mechanism, the specification of how to
   independently implement equally capable servers (as well as the
   precise definition of "equally capable") is left to future documents.



Zeilenga & Choi               Experimental                     [Page 24]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   Note that it may be difficult for the server to reliably determine
   what content was provided to the client by another server, especially
   in the shadowing environments that allow shadowing events to be
   coalesced.  For these servers, the use of the delete phase discussed
   in Section 3.3.2 may not be applicable.

7.  Security Considerations

   In order to maintain a synchronized copy of the content, a client is
   to delete information from its copy of the content as described
   above.  However, the client may maintain knowledge of information
   disclosed to it by the server separate from its copy of the content
   used for synchronization.  Management of this knowledge is beyond the
   scope of this document.  Servers should be careful not to disclose
   information for content the client is not authorized to have
   knowledge of and/or about.

   While the information provided by a series of refreshOnly Sync
   Operations is similar to that provided by a series of Search
   Operations, persist stage may disclose additional information.  A
   client may be able to discern information about the particular
   sequence of update operations that caused content change.

   Implementors should take precautions against malicious cookie
   content, including malformed cookies or valid cookies used with
   different security associations and/or protections in an attempt to
   obtain unauthorized access to information.  Servers may include a
   digital signature in the cookie to detect tampering.

   The operation may be the target of direct denial-of-service attacks.
   Implementors should provide safeguards to ensure the operation is not
   abused.  Servers may place access control or other restrictions upon
   the use of this operation.

   Note that even small updates to the directory may cause a significant
   amount of traffic to be generated to clients using this operation.  A
   user could abuse its update privileges to mount an indirect denial of
   service to these clients, other clients, and/or portions of the
   network.  Servers should provide safeguards to ensure that update
   operations are not abused.

   Implementors of this (or any) LDAP extension should be familiar with
   general LDAP security considerations [RFC4510].








Zeilenga & Choi               Experimental                     [Page 25]

RFC 4533         LDAP Content Synchronization Operation        June 2006


8.  IANA Considerations

   Registration of the following values have been completed by the IANA
   [RFC4520].

8.1.  Object Identifier

   The OID arc 1.3.6.1.4.1.4203.1.9.1 was assigned [ASSIGN] by the
   OpenLDAP Foundation, under its IANA-assigned private enterprise
   allocation [PRIVATE], for use in this specification.

8.2.  LDAP Protocol Mechanism

   The IANA has registered the LDAP Protocol Mechanism described in this
   document.

      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: 1.3.6.1.4.1.4203.1.9.1.1
      Description: LDAP Content Synchronization Control
      Person & email address to contact for further information:
          Kurt Zeilenga <kurt@openldap.org>
      Usage: Control
      Specification: RFC 4533
      Author/Change Controller: Kurt D. Zeilenga, Jong Hyuk Choi
      Comments: none

8.3.  LDAP Result Codes

   The IANA has registered the LDAP Result Code described in this
   document.

      Subject: LDAP Result Code Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <kurt@OpenLDAP.org>
      Result Code Name: e-syncRefreshRequired (4096)
      Specification: RFC 4533
      Author/Change Controller: Kurt D. Zeilenga, Jong Hyuk Choi
      Comments:  none

9.  Acknowledgements

   This document borrows significantly from the LDAP Client Update
   Protocol [RFC3928], a product of the IETF LDUP working group.  This
   document also benefited from Persistent Search [PSEARCH], Triggered
   Search [TSEARCH], and Directory Synchronization [DIRSYNC] works.
   This document also borrows from "Lightweight Directory Access
   Protocol (v3)" [RFC2251].




Zeilenga & Choi               Experimental                     [Page 26]

RFC 4533         LDAP Content Synchronization Operation        June 2006


10.  Normative References

   [RFC2119]   Bradner, S., "Key words for use in RFCs to Indicate
               Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3296]   Zeilenga, K., "Named Subordinate References in
               Lightweight Directory Access Protocol (LDAP)
               Directories", RFC 3296, July 2002.

   [RFC3671]   Zeilenga, K., "Collective Attributes in the Lightweight
               Directory Access Protocol (LDAP)", RFC 3671, December
               2003.

   [RFC3672]   Zeilenga, K., "Subentries in the Lightweight Directory
               Access Protocol (LDAP)", RFC 3672, December 2003.

   [RFC3909]   Zeilenga, K., "Lightweight Directory Access Protocol
               (LDAP) Cancel Operation", RFC 3909, October 2004.

   [RFC4510]   Zeilenga, K., Ed., "Lightweight Directory Access Protocol
               (LDAP): Technical Specification Road Map", RFC 4510, June
               2006.

   [RFC4511]   Sermersheim, J., Ed., "Lightweight Directory Access
               Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]   Zeilenga, K., "Lightweight Directory Access Protocol
               (LDAP): Directory Information Models", RFC 4512, June
               2006.

   [RFC4530]   Zeilenga, K., "Lightweight Directory Access Protocol
               (LDAP) entryUUID Operational Attribute", RFC 4530, June
               2006.

   [UUID]      International Organization for Standardization (ISO),
               "Information technology - Open Systems Interconnection -
               Remote Procedure Call", ISO/IEC 11578:1996

   [X.501]     International Telecommunication Union - Telecommunication
               Standardization Sector, "The Directory -- Models,"
               X.501(1993) (also ISO/IEC 9594-2:1994).

   [X.680]     International Telecommunication Union - Telecommunication
               Standardization Sector, "Abstract Syntax Notation One
               (ASN.1) - Specification of Basic Notation", X.680(1997)
               (also ISO/IEC 8824-1:1998).





Zeilenga & Choi               Experimental                     [Page 27]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   [X.690]     International Telecommunication Union - Telecommunication
               Standardization Sector, "Specification of ASN.1 encoding
               rules: Basic Encoding Rules (BER), Canonical Encoding
               Rules (CER), and Distinguished Encoding Rules (DER)",
               X.690(1997) (also ISO/IEC 8825-1:1998).

11.  Informative References

   [RFC2251]   Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
               Access Protocol (v3)", RFC 2251, December 1997.

   [RFC3928]   Megginson, R., Ed., Smith, M., Natkovich, O., and J.
               Parham, "Lightweight Directory Access Protocol (LDAP)
               Client Update Protocol (LCUP)", RFC 3928, October 2004.

   [RFC4520]   Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
               Considerations for the Lightweight Directory Access
               Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [PRIVATE]   IANA, "Private Enterprise Numbers",
               http://www.iana.org/assignments/enterprise-numbers.

   [ASSIGN]    OpenLDAP Foundation, "OpenLDAP OID Delegations",
               http://www.openldap.org/foundation/oid-delegate.txt.

   [X.500]     International Telecommunication Union - Telecommunication
               Standardization Sector, "The Directory -- Overview of
               concepts, models and services," X.500(1993) (also ISO/IEC
               9594-1:1994).

   [X.525]     International Telecommunication Union - Telecommunication
               Standardization Sector, "The Directory: Replication",
               X.525(1993).

   [DIRSYNC]   Armijo, M., "Microsoft LDAP Control for Directory
               Synchronization", Work in Progress.

   [PSEARCH]   Smith, M., et al., "Persistent Search: A Simple LDAP
               Change Notification Mechanism", Work in Progress.

   [TSEARCH]   Wahl, M., "LDAPv3 Triggered Search Control", Work in
               Progress.









Zeilenga & Choi               Experimental                     [Page 28]

RFC 4533         LDAP Content Synchronization Operation        June 2006


Appendix A.  CSN-based Implementation Considerations

   This appendix is provided for informational purposes only; it is not
   a normative part of the LDAP Content Synchronization Operation's
   technical specification.

   This appendix discusses LDAP Content Synchronization Operation server
   implementation considerations associated with Change Sequence Number
   based approaches.

   Change Sequence Number based approaches are targeted for use in
   servers that do not maintain history information (e.g., change logs,
   state snapshots) about changes made to the Directory and hence, must
   rely on current directory state and minimal synchronization state
   information embedded in Sync Cookie.  Servers that maintain history
   information should consider other approaches that exploit the history
   information.

   A Change Sequence Number is effectively a time stamp that has
   sufficient granularity to ensure that the precedence relationship in
   time of two updates to the same object can be determined.  Change
   Sequence Numbers are not to be confused with Commit Sequence Numbers
   or Commit Log Record Numbers.  A Commit Sequence Number allows one to
   determine how two commits (to the same object or different objects)
   relate to each other in time.  A Change Sequence Number associated
   with different entries may be committed out of order.  In the
   remainder of this Appendix, the term CSN refers to a Change Sequence
   Number.

   In these approaches, the server not only maintains a CSN for each
   directory entry (the entry CSN) but also maintains a value that we
   will call the context CSN.  The context CSN is the greatest committed
   entry CSN that is not greater than any outstanding (uncommitted)
   entry CSNs for all entries in a directory context.  The values of
   context CSN are used in syncCookie values as synchronization state
   indicators.

   As search operations are not isolated from individual directory
   update operations and individual update operations cannot be assumed
   to be serialized, one cannot assume that the returned content
   incorporates each relevant change whose change sequence number is
   less than or equal to the greatest entry CSN in the content.  The
   content incorporates all the relevant changes whose change sequence
   numbers are less than or equal to context CSN before search
   processing.  The content may also incorporate any subset of the
   changes whose change sequence number is greater than context CSN
   before search processing but less than or equal to the context CSN
   after search processing.  The content does not incorporate any of the



Zeilenga & Choi               Experimental                     [Page 29]

RFC 4533         LDAP Content Synchronization Operation        June 2006


   changes whose CSN is greater than the context CSN after search
   processing.

   A simple server implementation could use the value of the context CSN
   before search processing to indicate state.  Such an implementation
   would embed this value into each SyncCookie returned.  We'll call
   this the cookie CSN.  When a refresh was requested, the server would
   simply generate "update" messages for all entries in the content
   whose CSN is greater than the supplied cookie CSN and generate
   "present" messages for all other entries in the content.  However, if
   the current context CSN is the same as the cookie CSN, the server
   should instead generate zero "updates" and zero "delete" messages and
   indicate a refreshDeletes of TRUE, as the directory has not changed.

   The implementation should also consider the impact of changes to meta
   information, such as access controls, that affect content
   determination.  One approach is for the server to maintain a
   context-wide meta information CSN or meta CSN.  This meta CSN would
   be updated whenever meta information affecting content determination
   was changed.  If the value of the meta CSN is greater than the cookie
   CSN, the server should ignore the cookie and treat the request as an
   initial request for content.

   Additionally, servers may want to consider maintaining some per-
   session history information to reduce the number of messages needed
   to be transferred during incremental refreshes.  Specifically, a
   server could record information about entries as they leave the scope
   of a disconnected sync session and later use this information to
   generate delete messages instead of present messages.

   When the history information is truncated, the CSN of the latest
   truncated history information entry may be recorded as the truncated
   CSN of the history information.  The truncated CSN may be used to
   determine whether a client copy can be covered by the history
   information by comparing it to the synchronization state contained in
   the cookie supplied by the client.

   When there is a large number of sessions, it may make sense to
   maintain such history only for the selected clients.  Also, servers
   taking this approach need to consider resource consumption issues to
   ensure reasonable server operation and to protect against abuse.  It
   may be appropriate to restrict this mode of operation by policy.









Zeilenga & Choi               Experimental                     [Page 30]

RFC 4533         LDAP Content Synchronization Operation        June 2006


Authors' Addresses

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org


   Jong Hyuk Choi
   IBM Corporation

   EMail: jongchoi@us.ibm.com







































Zeilenga & Choi               Experimental                     [Page 31]

RFC 4533         LDAP Content Synchronization Operation        June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78 and at www.rfc-editor.org/copyright.html, and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga & Choi               Experimental                     [Page 32]

alt-openldap11-devel/rfc/rfc3703.txt000064400000427207150410163250012776 0ustar00





Network Working Group                                       J. Strassner
Request for Comments: 3703                        Intelliden Corporation
Category: Standards Track                                       B. Moore
                                                         IBM Corporation
                                                                R. Moats
                                                    Lemur Networks, Inc.
                                                             E. Ellesson
                                                           February 2004


    Policy Core Lightweight Directory Access Protocol (LDAP) Schema

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).  All Rights Reserved.

Abstract

   This document defines a mapping of the Policy Core Information Model
   to a form that can be implemented in a directory that uses
   Lightweight Directory Access Protocol (LDAP) as its access protocol.
   This model defines two hierarchies of object classes: structural
   classes representing information for representing and controlling
   policy data as specified in RFC 3060, and relationship classes that
   indicate how instances of the structural classes are related to each
   other.  Classes are also added to the LDAP schema to improve the
   performance of a client's interactions with an LDAP server when the
   client is retrieving large amounts of policy-related information.
   These classes exist only to optimize LDAP retrievals: there are no
   classes in the information model that correspond to them.

Table of Contents

   1.  Introduction .................................................  2
   2.  The Policy Core Information Model ............................  4
   3.  Inheritance Hierarchy for the PCLS ...........................  5
   4.  General Discussion of Mapping the Information Model to LDAP ..  6
       4.1.  Summary of Class and Association Mappings ..............  7
       4.2.  Usage of DIT Content and Structure Rules and Name Forms.  9
       4.3.  Naming Attributes in the PCLS .......................... 10



Strassner, et al.           Standards Track                     [Page 1]

RFC 3703                Policy Core LDAP Schema            February 2004


       4.4.  Rule-Specific and Reusable Conditions and Actions ...... 11
       4.5.  Location and Retrieval of Policy Objects in the
             Directory .............................................. 16
             4.5.1.  Aliases and Other DIT-Optimization Techniques .. 19
   5.  Class Definitions ............................................ 19
       5.1.  The Abstract Class "pcimPolicy" ........................ 21
       5.2.  The Three Policy Group Classes ......................... 22
       5.3.  The Three Policy Rule Classes .......................... 23
       5.4.  The Class pcimRuleConditionAssociation ................. 30
       5.5.  The Class pcimRuleValidityAssociation .................. 32
       5.6.  The Class pcimRuleActionAssociation .................... 34
       5.7.  The Auxiliary Class pcimConditionAuxClass .............. 36
       5.8.  The Auxiliary Class pcimTPCAuxClass .................... 36
       5.9.  The Auxiliary Class pcimConditionVendorAuxClass ........ 40
       5.10. The Auxiliary Class pcimActionAuxClass ................. 41
       5.11. The Auxiliary Class pcimActionVendorAuxClass ........... 42
       5.12. The Class pcimPolicyInstance ........................... 43
       5.13. The Auxiliary Class pcimElementAuxClass ................ 44
       5.14. The Three Policy Repository Classes .................... 45
       5.15. The Auxiliary Class pcimSubtreesPtrAuxClass ............ 46
       5.16. The Auxiliary Class pcimGroupContainmentAuxClass ....... 48
       5.17. The Auxiliary Class pcimRuleContainmentAuxClass ........ 49
   6.  Extending the Classes Defined in This Document ............... 50
       6.1.  Subclassing pcimConditionAuxClass and pcimActionAuxClass 50
       6.2.  Using the Vendor Policy Attributes ..................... 50
       6.3.  Using Time Validity Periods ............................ 51
   7.  Security Considerations ...................................... 51
   8.  IANA Considerations .......................................... 53
       8.1.  Object Identifiers ..................................... 53
       8.2.  Object Identifier Descriptors .......................... 53
   9.  Acknowledgments .............................................. 56
   10. Appendix:  Constructing the Value of orderedCIMKeys .......... 57
   11. References ................................................... 58
       11.1. Normative References ................................... 58
       11.2. Informative References ................................. 59
   12. Authors' Addresses ........................................... 60
   13. Full Copyright Statement ..................................... 61

1.  Introduction

   This document takes as its starting point the object-oriented
   information model for representing information for representing and
   controlling policy data as specified in [1].  Lightweight Directory
   Access Protocol (LDAP) [2] implementers, please note that the use of
   the term "policy" in this document does not refer to the use of the
   term "policy" as defined in X.501 [4].  Rather, the use of the term
   "policy" throughout this document is defined as follows:




Strassner, et al.           Standards Track                     [Page 2]

RFC 3703                Policy Core LDAP Schema            February 2004


      Policy is defined as a set of rules to administer, manage, and
      control access to network resources.

   This work is currently under joint development in the IETF's Policy
   Framework working group and in the Policy working group of the
   Distributed Management Task Force (DMTF).  This model defines two
   hierarchies of object classes: structural classes representing policy
   information and control of policies, and relationship classes that
   indicate how instances of the structural classes are related to each
   other.  In general, both of these class hierarchies will need to be
   mapped to a particular data store.

   This document defines the mapping of these information model classes
   to a directory that uses LDAP as its access protocol.  Two types of
   mappings are involved:

      -  For the structural classes in the information model, the
         mapping is basically one-for-one: information model classes map
         to LDAP classes, information model properties map to LDAP
         attributes.

      -  For the relationship classes in the information model,
         different mappings are possible.  In this document, the Policy
         Core Information Model's (PCIM's) relationship classes and
         their properties are mapped in three ways: to LDAP auxiliary
         classes, to attributes representing distinguished name (DN)
         references, and to superior-subordinate relationships in the
         Directory Information Tree (DIT).

   Implementations that use an LDAP directory as their policy repository
   and want to implement policy information according to RFC 3060 [1]
   SHALL use the LDAP schema defined in this document, or a schema that
   subclasses from the schema defined in this document.  The use of the
   information model defined in reference [1] as the starting point
   enables the inheritance and the relationship class hierarchies to be
   extensible, such that other types of policy repositories, such as
   relational databases, can also use this information.

   This document fits into the overall framework for representing,
   deploying, and managing policies being developed by the Policy
   Framework Working Group.

   The LDAP schema described in this document uses the prefix "pcim" to
   identify its classes and attributes.  It consists of ten very general
   classes: pcimPolicy (an abstract class), three policy group classes
   (pcimGroup, pcimGroupAuxClass, and pcimGroupInstance), three policy
   rule classes (pcimRule, pcimRuleAuxClass, and pcimRuleInstance), and
   three special auxiliary classes (pcimConditionAuxClass,



Strassner, et al.           Standards Track                     [Page 3]

RFC 3703                Policy Core LDAP Schema            February 2004


   pcimTPCAuxClass, and pcimActionAuxClass).  (Note that the
   PolicyTimePeriodCondition auxiliary class defined in [1] would
   normally have been named pcimTimePeriodConditionAuxClass, but this
   name is too long for some directories.  Therefore, we have
   abbreviated this name to be pcimTPCAuxClass).

   The mapping for the PCIM classes pcimGroup and pcimRule is designed
   to be as flexible as possible.  Three classes are defined for these
   two PCIM classes.  First, an abstract superclass is defined that
   contains all required properties of each PCIM class.  Then, both an
   auxiliary class as well as a structural class are derived from the
   abstract superclass.  This provides maximum flexibility for the
   developer.

   The schema also contains two less general classes:
   pcimConditionVendorAuxClass and pcimActionVendorAuxClass.  To achieve
   the mapping of the information model's relationships, the schema also
   contains two auxiliary classes: pcimGroupContainmentAuxClass and
   pcimRuleContainmentAuxClass.  Capturing the distinction between
   rule-specific and reusable policy conditions and policy actions
   introduces seven other classes: pcimRuleConditionAssociation,
   pcimRuleValidityAssociation, pcimRuleActionAssociation,
   pcimPolicyInstance, and three policy repository classes
   (pcimRepository, pcimRepositoryAuxClass, and pcimRepositoryInstance).
   Finally, the schema includes two classes (pcimSubtreesPtrAuxClass and
   pcimElementAuxClass) for optimizing LDAP retrievals.  In all, the
   schema contains 23 classes.

   Within the context of this document, the term "PCLS" (Policy Core
   LDAP Schema) is used to refer to the LDAP class definitions that this
   document contains.  The term "PCIM" refers to classes defined in [1].

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in RFC 2119 [10].

2.  The Policy Core Information Model

   This document contains an LDAP schema representing the classes
   defined in the companion document "Policy Core Information
   Model -- Version 1 Specification" [1].  Other documents may
   subsequently be produced, with mappings of this same PCIM to other
   storage technologies.  Since the detailed semantics of the PCIM
   classes appear only in [1], that document is a prerequisite for
   reading and understanding this document.






Strassner, et al.           Standards Track                     [Page 4]

RFC 3703                Policy Core LDAP Schema            February 2004


3.  Inheritance Hierarchy for the PCLS

   The following diagram illustrates the class hierarchy for the LDAP
   Classes defined in this document:

        top
         |
         +--dlm1ManagedElement (abstract)
         |   |
         |   +--pcimPolicy (abstract)
         |   |   |
         |   |   +--pcimGroup (abstract)
         |   |   |  |
         |   |   |  +--pcimGroupAuxClass (auxiliary)
         |   |   |  |
         |   |   |  +--pcimGroupInstance (structural)
         |   |   |
         |   |   +--pcimRule (abstract)
         |   |   |  |
         |   |   |  +--pcimRuleAuxClass (auxiliary)
         |   |   |  |
         |   |   |  +--pcimRuleInstance (structural)
         |   |   |
         |   |   +--pcimRuleConditionAssociation (structural)
         |   |   |
         |   |   +--pcimRuleValidityAssociation (structural)
         |   |   |
         |   |   +--pcimRuleActionAssociation (structural)
         |   |   |
         |   |   +--pcimPolicyInstance (structural)
         |   |   |
         |   |   +--pcimElementAuxClass (auxiliary)
         |   |
         |   +--dlm1ManagedSystemElement (abstract)
         |       |
         |       +--dlm1LogicalElement (abstract)
         |           |
         |           +--dlm1System (abstract)
         |               |
         |               +--dlm1AdminDomain (abstract)
         |                   |
         |                   +--pcimRepository (abstract)
         |                      |
         |                      +--pcimRepositoryAuxClass (auxiliary)







Strassner, et al.           Standards Track                     [Page 5]

RFC 3703                Policy Core LDAP Schema            February 2004


        top
         |                      |
         |                      +--pcimRepositoryInstance
         |                         (structural)
         |
         +--pcimConditionAuxClass (auxiliary)
         |   |
         |   +---pcimTPCAuxClass (auxiliary)
         |   |
         |   +---pcimConditionVendorAuxClass (auxiliary)
         |
         +--pcimActionAuxClass (auxiliary)
         |   |
         |   +---pcimActionVendorAuxClass (auxiliary)
         |
         +--pcimSubtreesPtrAuxClass (auxiliary)
         |
         +--pcimGroupContainmentAuxClass (auxiliary)
         |
         +--pcimRuleContainmentAuxClass (auxiliary)

         Figure 1.  LDAP Class Inheritance Hierarchy for the PCLS

4.  General Discussion of Mapping the Information Model to LDAP

   The classes described in Section 5 below contain certain
   optimizations for a directory that uses LDAP as its access protocol.
   One example of this is the use of auxiliary classes to represent some
   of the associations defined in the information model.  Other data
   stores might need to implement these associations differently.  A
   second example is the introduction of classes specifically designed
   to optimize retrieval of large amounts of policy-related data from a
   directory.  This section discusses some general topics related to the
   mapping from the information model to LDAP.

   The remainder of this section will discuss the following topics.
   Section 4.1 will discuss the strategy used in mapping the classes and
   associations defined in [1] to a form that can be represented in a
   directory that uses LDAP as its access protocol.  Section 4.2
   discusses DIT content and structure rules, as well as name forms.
   Section 4.3 describes the strategy used in defining naming attributes
   for the schema described in Section 5 of this document.  Section 4.4
   defines the strategy recommended for locating and retrieving
   PCIM-derived objects in the directory.







Strassner, et al.           Standards Track                     [Page 6]

RFC 3703                Policy Core LDAP Schema            February 2004


4.1.  Summary of Class and Association Mappings

   Fifteen of the classes in the PCLS come directly from the nine
   corresponding classes in the information model.  Note that names of
   classes begin with an upper case character in the information model
   (although for CIM in particular, case is not significant in class and
   property names), but with a lower case character in LDAP.  This is
   because although LDAP doesn't care, X.500 doesn't allow class names
   to begin with an uppercase character.  Note also that the prefix
   "pcim" is used to identify these LDAP classes.

      +---------------------------+-------------------------------+
      | Information Model         | LDAP Class(es)                |
      +---------------------------+-------------------------------+
      +---------------------------+-------------------------------+
      | Policy                    | pcimPolicy                    |
      +---------------------------+-------------------------------+
      | PolicyGroup               | pcimGroup                     |
      |                           |   pcimGroupAuxClass           |
      |                           |   pcimGroupInstance           |
      +---------------------------+-------------------------------+
      | PolicyRule                | pcimRule                      |
      |                           |   pcimRuleAuxClass            |
      |                           |   pcimRuleInstance            |
      +---------------------------+-------------------------------+
      | PolicyCondition           | pcimConditionAuxClass         |
      +---------------------------+-------------------------------+
      | PolicyAction              | pcimActionAuxClass            |
      +---------------------------+-------------------------------+
      | VendorPolicyCondition     | pcimConditionVendorAuxClass   |
      +---------------------------+-------------------------------+
      | VendorPolicyAction        | pcimActionVendorAuxClass      |
      +---------------------------+-------------------------------+
      | PolicyTimePeriodCondition | pcimTPCAuxClass               |
      +---------------------------+-------------------------------+
      | PolicyRepository          | pcimRepository                |
      |                           |   pcimRepositoryAuxClass      |
      |                           |   pcimRepositoryInstance      |
      +---------------------------+-------------------------------+

          Figure 2.  Mapping of Information Model Classes to LDAP

   The associations in the information model map to attributes that
   reference DNs (Distinguished Names) or to Directory Information Tree
   (DIT) containment (i.e., superior-subordinate relationships) in LDAP.
   Two of the attributes that reference DNs appear in auxiliary classes,
   which allow each of them to represent several relationships from the
   information model.



Strassner, et al.           Standards Track                     [Page 7]

RFC 3703                Policy Core LDAP Schema            February 2004


+----------------------------------+----------------------------------+
| Information Model Association     | LDAP Attribute / Class          |
+-----------------------------------+---------------------------------+
+-----------------------------------+---------------------------------+
| PolicyGroupInPolicyGroup          | pcimGroupsAuxContainedSet in    |
|                                   |  pcimGroupContainmentAuxClass   |
+-----------------------------------+---------------------------------+
| PolicyRuleInPolicyGroup           | pcimRulesAuxContainedSet in     |
|                                   |  pcimRuleContainmentAuxClass    |
+-----------------------------------+---------------------------------+
| PolicyConditionInPolicyRule       | DIT containment or              |
|                                   | pcimRuleConditionList in        |
|                                   |  pcimRule or                    |
|                                   | pcimConditionDN in              |
|                                   |  pcimRuleConditionAssociation   |
+-----------------------------------+---------------------------------+
| PolicyActionInPolicyRule          | DIT containment or              |
|                                   | pcimRuleActionList in           |
|                                   |  pcimRule or                    |
|                                   | pcimActionDN in                 |
|                                   |  pcimRuleActionAssociation      |
+-----------------------------------+---------------------------------+
| PolicyRuleValidityPeriod          | pcimRuleValidityPeriodList      |
|                                   |  in pcimRule or (if reusable)   |
|                                   |  referenced through the         |
|                                   | pcimTimePeriodConditionDN in    |
|                                   |  pcimRuleValidityAssociation    |
+-----------------------------------+---------------------------------+
| PolicyConditionInPolicyRepository | DIT containment                 |
+-----------------------------------+---------------------------------+
| PolicyActionInPolicyRepository    | DIT containment                 |
+-----------------------------------+---------------------------------+
| PolicyRepositoryInPolicyRepository| DIT containment                 |
+-----------------------------------+---------------------------------+

      Figure 3.  Mapping of Information Model Associations to LDAP

   Of the remaining classes in the PCLS, two (pcimElementAuxClass and
   pcimSubtreesPtrAuxClass) are included to make navigation through the
   DIT and retrieval of the entries found there more efficient.  This
   topic is discussed below in Section 4.5.

   The remaining four classes in the PCLS, pcimRuleConditionAssociation,
   pcimRuleValidityAssociation, pcimRuleActionAssociation, and
   pcimPolicyInstance, are all involved with the representation of
   policy conditions and policy actions in an LDAP directory.  This
   topic is discussed below in Section 4.4.




Strassner, et al.           Standards Track                     [Page 8]

RFC 3703                Policy Core LDAP Schema            February 2004


4.2.  Usage of DIT Content and Structure Rules and Name Forms

   There are three powerful tools that can be used to help define
   schemata. The first, DIT content rules, is a way of defining the
   content of an entry for a structural object class.  It can be used to
   specify the following characteristics of the entry:

      -  additional mandatory attributes that the entries are required
         to contain
      -  additional optional attributes the entries are allowed to
         contain
      -  the set of additional auxiliary object classes that these
         entries are allowed to be members of
      -  any optional attributes from the structural and auxiliary
         object class definitions that the entries are required to
         preclude

   DIT content rules are NOT mandatory for any structural object class.

   A DIT structure rule, together with a name form, controls the
   placement and naming of an entry within the scope of a subschema.
   Name forms define which attribute type(s) are required and are
   allowed to be used in forming the Relative Distinguished Names (RDNs)
   of entries.  DIT structure rules specify which entries are allowed to
   be superior to other entries, and hence control the way that RDNs are
   added together to make DNs.

   A name form specifies the following:

      -  the structural object class of the entries named by this name
         form
      -  attributes that are required to be used in forming the RDNs of
         these entries
      -  attributes that are allowed to be used in forming the RDNs of
         these entries
      -  an object identifier to uniquely identify this name form

   Note that name forms can only be specified for structural object
   classes.  However, every entry in the DIT must have a name form
   controlling it.

   Unfortunately, current LDAP servers vary quite a lot in their support
   of these features.  There are also three crucial implementation
   points that must be followed.  First, X.500 use of structure rules
   requires that a structural object class with no superior structure
   rule be a subschema administrative point.  This is exactly NOT what
   we want for policy information.  Second, when an auxiliary class is
   subclassed, if a content rule exists for the structural class that



Strassner, et al.           Standards Track                     [Page 9]

RFC 3703                Policy Core LDAP Schema            February 2004


   the auxiliary class refers to, then that content rule needs to be
   augmented.  Finally, most LDAP servers unfortunately do not support
   inheritance of structure and content rules.

   Given these concerns, DIT structure and content rules have been
   removed from the PCLS.  This is because, if included, they would be
   normative references and would require OIDs.  However, we don't want
   to lose the insight gained in building the structure and content
   rules of the previous version of the schema.  Therefore, we describe
   where such rules could be used in this schema, what they would
   control, and what their effect would be.

4.3.  Naming Attributes in the PCLS

   Instances in a directory are identified by distinguished names (DNs),
   which provide the same type of hierarchical organization that a file
   system provides in a computer system.  A distinguished name is a
   sequence of RDNs.  An RDN provides a unique identifier for an
   instance within the context of its immediate superior, in the same
   way that a filename provides a unique identifier for a file within
   the context of the folder in which it resides.

   To preserve maximum naming flexibility for policy administrators,
   three optional (i.e., "MAY") naming attributes have been defined.
   They are:

      -  Each of the structural classes defined in this schema has its
         own unique ("MAY") naming attribute.  Since the naming
         attributes are different, a policy administrator can, by using
         these attributes, guarantee that there will be no name
         collisions between instances of different classes, even if the
         same value is assigned to the instances' respective naming
         attributes.

      -  The LDAP attribute cn (corresponding to X.500's commonName) is
         included as a MAY attribute in the abstract class pcimPolicy,
         and thus by inheritance in all of its subclasses.  In X.500,
         commonName typically functions as an RDN attribute, for naming
         instances of many classes (e.g., X.500's person class).

      -  A special attribute is provided for implementations that expect
         to map between native CIM and LDAP representations of policy
         information.  This attribute, called orderedCimKeys, is defined
         in the class dlm1ManagedElement [6].  The value of this
         attribute is derived algorithmically from values that are
         already present in a CIM policy instance.  The normative
         reference for this algorithm is contained in [6].  See the
         appendix of this document for a description of the algorithm.



Strassner, et al.           Standards Track                    [Page 10]

RFC 3703                Policy Core LDAP Schema            February 2004


   Since any of these naming attributes MAY be used for naming an
   instance of a PCLS class, implementations MUST be able to accommodate
   instances named in any of these ways.

   Note that it is recommended that two or more of these attributes
   SHOULD NOT be used together to form a multi-part RDN, since support
   for multi-part RDNs is limited among existing directory
   implementations.

4.4.  Rule-Specific and Reusable Conditions and Actions

   The PCIM [1] distinguishes between two types of policy conditions and
   policy actions:  those associated with a single policy rule, and
   those that are reusable, in the sense that they may be associated
   with more than one policy rule.  While there is no inherent
   functional difference between a rule-specific condition or action and
   a reusable one, there is both a usage, as well as, an implementation
   difference between them.

   Defining a condition or action as reusable vs. rule-specific reflects
   a conscious decision on the part of the administrator in defining how
   they are used.  In addition, there are variations that reflect
   implementing rule-specific vs. reusable policy conditions and actions
   and how they are treated in a policy repository.  The major
   implementation differences between a rule-specific and a reusable
   condition or action are delineated below:

   1.  It is natural for a rule-specific condition or action to be
       removed from the policy repository at the same time the rule is.
       It is just the opposite for reusable conditions and actions.
       This is because the condition or action is conceptually attached
       to the rule in the rule-specific case, whereas it is referenced
       (e.g., pointed at) in the reusable case.  The persistence of a
       pcimRepository instance is independent of the persistence of a
       pcimRule instance.
   2.  Access permissions for a rule-specific condition or action are
       usually identical to those for the rule itself.  On the other
       hand, access permissions of reusable conditions and actions must
       be expressible without reference to a policy rule.
   3.  Rule-specific conditions and actions require fewer accesses,
       because the conditions and actions are "attached" to the rule.
       In contrast, reusable conditions and actions require more
       accesses, because each condition or action that is reusable
       requires a separate access.
   4.  Rule-specific conditions and actions are designed for use by a
       single rule.  As the number of rules that use the same
       rule-specific condition increase, subtle problems are created
       (the most obvious being how to keep the rule-specific conditions



Strassner, et al.           Standards Track                    [Page 11]

RFC 3703                Policy Core LDAP Schema            February 2004


       and actions updated to reflect the same value).  Reusable
       conditions and actions lend themselves for use by multiple
       independent rules.
   5.  Reusable conditions and actions offer an optimization when
       multiple rules are using the same condition or action.  This is
       because the reusable condition or action only needs be updated
       once, and by virtue of DN reference, the policy rules will be
       automatically updated.

   The preceding paragraph does not contain an exhaustive list of the
   ways in which reusable and rule-specific conditions should be treated
   differently.  Its purpose is merely to justify making a semantic
   distinction between rule-specific and reusable, and then reflecting
   this distinction in the policy repository itself.

   When the policy repository is realized in an LDAP-accessible
   directory, the distinction between rule-specific and reusable
   conditions and actions is realized via placement of auxiliary classes
   and via DIT containment.  Figure 4 illustrates a policy rule Rule1
   with one rule-specific condition CA and one rule-specific action AB.

                    +-----+
                    |Rule1|
                    |     |
              +-----|-   -|-----+
              |     +-----+     |
              |       * *       |
              |       * *       |
              |    **** ****    |
              |    *       *    |
              v    *       *    v
            +--------+   +--------+
            | CA+ca  |   | AB+ab  |
            +--------+   +--------+


                          +------------------------------+
                          |LEGEND:                       |
                          |  ***** DIT containment       |
                          |    +   auxiliary attachment  |
                          |  ----> DN reference          |
                          +------------------------------+

           Figure 4  Rule-Specific Policy Conditions and Actions







Strassner, et al.           Standards Track                    [Page 12]

RFC 3703                Policy Core LDAP Schema            February 2004


   Because the condition and action are specific to Rule1, the auxiliary
   classes ca and ab that represent them are attached, respectively, to
   the structural classes CA and AB.  These structural classes represent
   not the condition ca and action ab themselves, but rather the
   associations between Rule1 and ca, and between Rule1 and ab.

   As Figure 4 illustrates, Rule1 contains DN references to the
   structural classes CA and AB that appear below it in the DIT.  At
   first glance it might appear that these DN references are
   unnecessary, since a subtree search below Rule1 would find all of the
   structural classes representing the associations between Rule1 and
   its conditions and actions.  Relying only on a subtree search,
   though, runs the risk of missing conditions or actions that should
   have appeared in the subtree, but for some reason did not, or of
   finding conditions or actions that were inadvertently placed in the
   subtree, or that should have been removed from the subtree, but for
   some reason were not.  Implementation experience has suggested that
   many (but not all) of these risks are eliminated.

   However, it must be noted that this comes at a price.  The use of DN
   references, as shown in Figure 4 above, thwarts inheritance of access
   control information as well as existence dependency information.  It
   also is subject to referential integrity considerations.  Therefore,
   it is being included as an option for the designer.

   Figure 5 illustrates a second way of representing rule-specific
   conditions and actions in an LDAP-accessible directory: attachment of
   the auxiliary classes directly to the instance representing the
   policy rule.  When all of the conditions and actions are attached to
   a policy rule in this way, the rule is termed a "simple" policy rule.
   When conditions and actions are not attached directly to a policy
   rule, the rule is termed a "complex" policy rule.

                    +-----------+
                    |Rule1+ca+ab|
                    |           |
                    +-----------+

                          +------------------------------+
                          |LEGEND:                       |
                          |    +   auxiliary attachment  |
                          +------------------------------+

                      Figure 5.  A Simple Policy Rule







Strassner, et al.           Standards Track                    [Page 13]

RFC 3703                Policy Core LDAP Schema            February 2004


   The simple/complex distinction for a policy rule is not all or
   nothing.  A policy rule may have its conditions attached to itself
   and its actions attached to other entries, or it may have its actions
   attached to itself and its conditions attached to other entries.
   However, it SHALL NOT have either its conditions or its actions
   attached both to itself and to other entries, with one exception:  a
   policy rule may reference its validity periods with the
   pcimRuleValidityPeriodList attribute, but have its other conditions
   attached to itself.

   The tradeoffs between simple and complex policy rules are between the
   efficiency of simple rules and the flexibility and greater potential
   for reuse of complex rules.  With a simple policy rule, the semantic
   options are limited:

   -   All conditions are ANDed together.  This combination can be
       represented in two ways in the Disjunctive Normal Form (DNF)/
       Conjunctive Normal Form (CNF) (please see [1] for definitions of
       these terms) expressions characteristic of policy conditions:  as
       a DNF expression with a single AND group, or as a CNF expression
       with multiple single-condition OR groups.  The first of these is
       arbitrarily chosen as the representation for the ANDed conditions
       in a simple policy rule.

   -   If multiple actions are included, no order can be specified for
       them.

   If a policy administrator needs to combine conditions in some other
   way, or if there is a set of actions that must be ordered, then the
   only option is to use a complex policy rule.

   Finally, Figure 6 illustrates the same policy rule Rule1, but this
   time its condition and action are reusable.  The association classes
   CA and AB are still present, and they are still DIT contained under
   Rule1.  But rather than having the auxiliary classes ca and ab
   attached directly to the association classes CA and AB, each now
   contains DN references to other entries to which these auxiliary
   classes are attached.  These other entries, CIA and AIB, are DIT
   contained under RepositoryX, which is an instance of the class
   pcimRepository.  Because they are named under an instance of
   pcimRepository, ca and ab are clearly identified as reusable.










Strassner, et al.           Standards Track                    [Page 14]

RFC 3703                Policy Core LDAP Schema            February 2004


                   +-----+             +-------------+
                   |Rule1|             | RepositoryX |
                 +-|-   -|--+          |             |
                 | +-----+  |          +-------------+
                 |   * *    |             *       *
                 |   * *    |             *       *
                 | *** **** |             *       *
                 | *      * v             *       *
                 | *     +---+            *       *
                 | *     |AB |         +------+   *
                 v *     |  -|-------->|AIB+ab|   *
                +---+    +---+         +------+   *
                |CA |                         +------+
                |  -|------------------------>|CIA+ca|
                +---+                         +------+

                          +------------------------------+
                          |LEGEND:                       |
                          |  ***** DIT containment       |
                          |    +   auxiliary attachment  |
                          |  ----> DN reference          |
                          +------------------------------+

             Figure 6.  Reusable Policy Conditions and Actions

   The classes pcimConditionAuxClass and pcimActionAuxClass do not
   themselves represent actual conditions and actions:  these are
   introduced in their subclasses.  What pcimConditionAuxClass and
   pcimActionAuxClass do introduce are the semantics of being a policy
   condition or a policy action.  These are the semantics that all the
   subclasses of pcimConditionAuxClass and pcimActionAuxClass inherit.
   Among these semantics are those of representing either a
   rule-specific or a reusable policy condition or policy action.

   In order to preserve the ability to represent a rule-specific or a
   reusable condition or action, as well as a simple policy rule, all
   the subclasses of pcimConditionAuxClass and pcimActionAuxClass MUST
   also be auxiliary classes.













Strassner, et al.           Standards Track                    [Page 15]

RFC 3703                Policy Core LDAP Schema            February 2004


4.5.  Location and Retrieval of Policy Objects in the Directory

   When a Policy Decision Point (PDP) goes to an LDAP directory to
   retrieve the policy object instances relevant to the Policy
   Enforcement Points (PEPs) it serves, it is faced with two related
   problems:

   -   How does it locate and retrieve the directory entries that apply
       to its PEPs?  These entries may include instances of the PCLS
       classes, instances of domain-specific subclasses of these
       classes, and instances of other classes modeling such resources
       as user groups, interfaces, and address ranges.

   -   How does it retrieve the directory entries it needs in an
       efficient manner, so that retrieval of policy information from
       the directory does not become a roadblock to scalability?  There
       are two facets to this efficiency:  retrieving only the relevant
       directory entries, and retrieving these entries using as few LDAP
       calls as possible.

   The placement of objects in the Directory Information Tree (DIT)
   involves considerations other than how the policy-related objects
   will be retrieved by a PDP.  Consequently, all that the PCLS can do
   is to provide a "toolkit" of classes to assist the policy
   administrator as the DIT is being designed and built.  A PDP SHOULD
   be able to take advantage of any tools that the policy administrator
   is able to build into the DIT, but it MUST be able to use a less
   efficient means of retrieval if that is all it has available to it.

   The basic idea behind the LDAP optimization classes is a simple one:
   make it possible for a PDP to retrieve all the policy-related objects
   it needs, and only those objects, using as few LDAP calls as
   possible.  An important assumption underlying this approach is that
   the policy administrator has sufficient control over the underlying
   DIT structure to define subtrees for storing policy information.  If
   the policy administrator does not have this level of control over DIT
   structure, a PDP can still retrieve the policy-related objects it
   needs individually.  But it will require more LDAP access operations
   to do the retrieval in this way.  Figure 7 illustrates how LDAP
   optimization is accomplished.











Strassner, et al.           Standards Track                    [Page 16]

RFC 3703                Policy Core LDAP Schema            February 2004


                       +-----+
      ---------------->|  A  |
      DN reference to  |     |    DN references to subtrees   +---+
      starting object  +-----+    +-------------------------->| C |
                       |  o--+----+         +---+             +---+
                       |  o--+------------->| B |            /     \
                       +-----+              +---+           /       \
                      /       \            /     \         /   ...   \
                     /         \          /       \
                    /           \        /   ...   \

      Figure 7.  Using the pcimSubtreesPtrAuxClass to Locate Policies

   The PDP is configured initially with a DN reference to some entry in
   the DIT.  The structural class of this entry is not important; the
   PDP is interested only in the pcimSubtreesPtrAuxClass attached to it.
   This auxiliary class contains a multi-valued attribute with DN
   references to objects that anchor subtrees containing policy-related
   objects of interest to the PDP.  Since pcimSubtreesPtrAuxClass is an
   auxiliary class, it can be attached to an entry that the PDP would
   need to access anyway - perhaps an entry containing initial
   configuration settings for the PDP, or for a PEP that uses the PDP.

   Once it has retrieved the DN references, the PDP will direct to each
   of the objects identified by them an LDAP request that all entries in
   its subtree be evaluated against the selection criteria specified in
   the request.  The LDAP-enabled directory then returns all entries in
   that subtree that satisfy the specified criteria.

   The selection criteria always specify that object class="pcimPolicy".
   Since all classes representing policy rules, policy conditions, and
   policy actions, both in the PCLS and in any domain-specific schema
   derived from it, are subclasses of the abstract class policy, this
   criterion evaluates to TRUE for all instances of these classes.  To
   accommodate special cases where a PDP needs to retrieve objects that
   are not inherently policy-related (for example, an IP address range
   object referenced by a subclass of pcimActionAuxClass representing
   the DHCP action "assign from this address range"), the auxiliary
   class pcimElementAuxClass can be used to "tag" an entry, so that it
   will be found by the selection criterion "object class=pcimPolicy".

   The approach described in the preceding paragraph will not work for
   certain directory implementations, because these implementations do
   not support matching of auxiliary classes in the objectClass
   attribute.  For environments where these implementations are expected
   to be present, the "tagging" of entries as relevant to policy can be





Strassner, et al.           Standards Track                    [Page 17]

RFC 3703                Policy Core LDAP Schema            February 2004


   accomplished by inserting the special value "POLICY" into the list of
   values contained in the pcimKeywords attribute (provided by the
   pcimPolicy class).

   If a PDP needs only a subset of the policy-related objects in the
   indicated subtrees, then it can be configured with additional
   selection criteria based on the pcimKeywords attribute defined in the
   pcimPolicy class.  This attribute supports both standardized and
   administrator- defined values.  For example, a PDP could be
   configured to request only those policy-related objects containing
   the keywords "DHCP" and "Eastern US".

   To optimize what is expected to be a typical case, the initial
   request from the client includes not only the object to which its
   "seed" DN references, but also the subtree contained under this
   object.  The filter for searching this subtree is whatever the client
   is going to use later to search the other subtrees:  object
   class="pcimPolicy" or the presence of the keyword "POLICY", and/or
   presence of a more specific value of pcimKeywords (e.g., "QoS Edge
   Policy").

   Returning to the example in Figure 7, we see that in the best case, a
   PDP can get all the policy-related objects it needs, and only those
   objects, with exactly three LDAP requests:  one to its starting
   object A to get the references to B and C, as well as the
   policy-related objects it needs from the subtree under A, and then
   one each to B and C to get all the policy-related objects that pass
   the selection criteria with which it was configured.  Once it has
   retrieved all of these objects, the PDP can then traverse their
   various DN references locally to understand the semantic
   relationships among them.  The PDP should also be prepared to find a
   reference to another subtree attached to any of the objects it
   retrieves, and to follow this reference first, before it follows any
   of the semantically significant references it has received.  This
   recursion permits a structured approach to identifying related
   policies.  In Figure 7, for example, if the subtree under B includes
   departmental policies and the one under C includes divisional
   policies, then there might be a reference from the subtree under C to
   an object D that roots the subtree of corporate-level policies.

   A PDP SHOULD understand the pcimSubtreesPtrAuxClass class, SHOULD be
   capable of retrieving and processing the entries in the subtrees it
   references, and SHOULD be capable of doing all of this recursively.
   The same requirements apply to any other entity needing to retrieve
   policy information from the directory.  Thus, a Policy Management
   Tool that retrieves policy entries from the directory in order to
   perform validation and conflict detection SHOULD also understand and
   be capable of using the pcimSubtreesPtrAuxClass.  All of these



Strassner, et al.           Standards Track                    [Page 18]

RFC 3703                Policy Core LDAP Schema            February 2004


   requirements are "SHOULD"s rather than "MUST"s because an LDAP client
   that doesn't implement them can still access and retrieve the
   directory entries it needs.  The process of doing so will just be
   less efficient than it would have been if the client had implemented
   these optimizations.

   When it is serving as a tool for creating policy entries in the
   directory, a Policy Management Tool SHOULD support creation of
   pcimSubtreesPtrAuxClass entries and their references to object
   instances.

4.5.1.  Aliases and Other DIT-Optimization Techniques

   Additional flexibility in DIT structure is available to the policy
   administrator via LDAP aliasing and other techniques.  Previous
   versions of this document have used aliases.  However, because
   aliases are experimental, the use of aliases has been removed from
   this version of this document.  This is because the IETF has yet to
   produce a specification on how aliases are represented in the
   directory or how server implementations are to process aliases.

5.  Class Definitions

   The semantics for the policy information classes that are to be
   mapped directly from the information model to an LDAP representation
   are detailed in [1].  Consequently, all that this document presents
   for these classes is the specification for how to do the mapping from
   the information model (which is independent of repository type and
   access protocol) to a form that can be accessed using LDAP.  Remember
   that some new classes needed to be created (that were not part of
   [1]) to implement the LDAP mapping.  These new LDAP-only classes are
   fully documented in this document.

   The formal language for specifying the classes, attributes, and DIT
   structure and content rules is that defined in reference [3].  If
   your implementation does not support auxiliary class inheritance, you
   will have to list auxiliary classes in content rules explicitly or
   define them in another (implementation-specific) way.

   The following notes apply to this section in its entirety.

   Note 1: in the following definitions, the class and attribute
   definitions follow RFC 2252 [3] but they are line-wrapped to enhance
   human readability.

   Note 2: where applicable, the possibilities for specifying DIT
   structure and content rules are noted.  However, care must be taken
   in specifying DIT structure rules.  This is because X.501 [4] states



Strassner, et al.           Standards Track                    [Page 19]

RFC 3703                Policy Core LDAP Schema            February 2004


   that an entry may only exist in the DIT as a subordinate to another
   superior entry (the superior) if a DIT structure rule exists in the
   governing subschema which:

   1)  indicates a name form for the structural object class of the
       subordinate entry, and
   2)  either includes the entry's superior structure rule as a possible
       superior structure rule, or
   3)  does not specify a superior structure rule.

   If this last case (3) applies, then the entry is defined to be a
   subschema administrative point.  This is not what is desired.
   Therefore, care must be taken in defining structure rules, and in
   particular, they must be locally augmented.

   Note 3: Wherever possible, both an equality and a substring matching
   rule are defined for a particular attribute (as well as an ordering
   match rule to enable sorting of matching results).  This provides two
   different choices for the developer for maximum flexibility.

   For example, consider the pcimRoles attribute (section 5.3).  Suppose
   that a PEP has reported that it is interested in pcimRules for three
   roles R1, R2, and R3.  If the goal is to minimize queries, then the
   PDP can supply three substring filters containing the three role
   names.

   These queries will return all of the pcimRules that apply to the PEP,
   but they may also get some that do not apply (e.g., ones that contain
   one of the roles R1, R2, or R3 and one or more other roles present in
   a role-combination [1]).

   Another strategy would be for the PDP to use only equality filters.
   This approach eliminates the extraneous replies, but it requires the
   PDP to explicitly build the desired role-combinations itself.  It
   also requires extra queries.  Note that this approach is practical
   only because the role names in a role combination are required to
   appear in alphabetical order.

   Note 4: in the following definitions, note that all LDAP matching
   rules are defined in [3] and in [9].  The corresponding X.500
   matching rules are defined in [8].

   Note 5: some of the following attribute definitions specify
   additional constraints on various data types (e.g., this integer has
   values that are valid  from 1..10).  Text has been added to instruct
   servers and applications what to do if a value outside of this range





Strassner, et al.           Standards Track                    [Page 20]

RFC 3703                Policy Core LDAP Schema            February 2004


   is encountered.  In all cases, if a constraint is violated, then the
   policy rule SHOULD be treated as being disabled, meaning that
   execution of the policy rule SHOULD be stopped.

5.1.  The Abstract Class pcimPolicy

   The abstract class pcimPolicy is a direct mapping of the abstract
   class Policy from the PCIM.  The class value "pcimPolicy" is also
   used as the mechanism for identifying policy-related instances in the
   Directory Information Tree.  An instance of any class may be "tagged"
   with this class value by attaching to it the auxiliary class
   pcimElementAuxClass.  Since pcimPolicy is derived from the class
   dlm1ManagedElement defined in reference [6], this specification has a
   normative dependency on that element of reference [6].

   The class definition is as follows:

       ( 1.3.6.1.1.6.1.1 NAME 'pcimPolicy'
         DESC 'An abstract class that is the base class for all classes
               that describe policy-related instances.'
         SUP dlm1ManagedElement
         ABSTRACT
         MAY ( cn $ dlmCaption $ dlmDescription $ orderedCimKeys $
               pcimKeywords )
       )

   The attribute cn is defined in RFC 2256 [7].  The dlmCaption,
   dlmDescription, and orderedCimKeys attributes are defined in [6].

   The pcimKeywords attribute is a multi-valued attribute that contains
   a set of keywords to assist directory clients in locating the policy
   objects identified by these keywords.  It is defined as follows:

       ( 1.3.6.1.1.6.2.3 NAME 'pcimKeywords'
              DESC 'A set of keywords to assist directory clients in
                    locating the policy objects applicable to them.'
              EQUALITY caseIgnoreMatch
              ORDERING caseIgnoreOrderingMatch
              SUBSTR caseIgnoreSubstringsMatch
              SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
       )










Strassner, et al.           Standards Track                    [Page 21]

RFC 3703                Policy Core LDAP Schema            February 2004


5.2.  The Three Policy Group Classes

   PCIM [1] defines the PolicyGroup class to serve as a generalized
   aggregation mechanism, enabling PolicyRules and/or PolicyGroups to be
   aggregated together.  PCLS maps this class into three LDAP classes,
   called pcimGroup, pcimGroupAuxClass, and pcimGroupInstance.  This is
   done in order to provide maximum flexibility for the DIT designer.

   The class definitions for the three policy group classes are listed
   below.  These class definitions do not include attributes to realize
   the PolicyRuleInPolicyGroup and PolicyGroupInPolicyGroup associations
   from the PCIM.  This is because a pcimGroup object refers to
   instances of pcimGroup and pcimRule via, respectively, the attribute
   pcimGroupsAuxContainedSet in the pcimGroupContainmentAuxClass object
   class and the attribute pcimRulesAuxContainedSet in the
   pcimRuleContainmentAuxClass object class.

   To maximize flexibility, the pcimGroup class is defined as abstract.
   The subclass pcimGroupAuxClass provides for auxiliary attachment to
   another entry, while the structural subclass pcimGroupInstance is
   available to represent a policy group as a standalone entry.

   The class definitions are as follows.  First, the definition of the
   abstract class pcimGroup:

       ( 1.3.6.1.1.6.1.2 NAME 'pcimGroup'
              DESC 'A container for a set of related pcimRules and/or
                    a set of related pcimGroups.'
              SUP pcimPolicy
              ABSTRACT
              MAY ( pcimGroupName )
       )

   The one attribute of pcimGroup is pcimGroupName.  This attribute is
   used to define a user-friendly name of this policy group, and may be
   used as a naming attribute if desired.  It is defined as follows:

       ( 1.3.6.1.1.6.2.4 NAME 'pcimGroupName'
              DESC 'The user-friendly name of this policy group.'
              EQUALITY caseIgnoreMatch
              ORDERING caseIgnoreOrderingMatch
              SUBSTR caseIgnoreSubstringsMatch
              SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
              SINGLE-VALUE
       )






Strassner, et al.           Standards Track                    [Page 22]

RFC 3703                Policy Core LDAP Schema            February 2004


   The two subclasses of pcimGroup are defined as follows.  The class
   pcimGroupAuxClass is an auxiliary class that can be used to collect a
   set of related pcimRule and/or pcimGroup classes.  It is defined as
   follows:

       ( 1.3.6.1.1.6.1.3 NAME 'pcimGroupAuxClass'
              DESC 'An auxiliary class that collects a set of related
                    pcimRule and/or pcimGroup entries.'
              SUP pcimGroup
              AUXILIARY
       )

   The class pcimGroupInstance is a structural class that can be used to
   collect a set of related pcimRule and/or pcimGroup classes.  It is
   defined as follows:

       ( 1.3.6.1.1.6.1.4 NAME 'pcimGroupInstance'
              DESC 'A structural class that collects a set of related
                    pcimRule and/or pcimGroup entries.'
              SUP pcimGroup
              STRUCTURAL
       )

   A DIT content rule could be written to enable an instance of
   pcimGroupInstance to have attached to it either references to one or
   more policy groups (using pcimGroupContainmentAuxClass) or references
   to one or more policy rules (using pcimRuleContainmentAuxClass).
   This would be used to formalize the semantics of the PolicyGroup
   class [1].  Since these semantics do not include specifying any
   properties of the PolicyGroup class, the content rule would not need
   to specify any attributes.

   Similarly, three separate DIT structure rules could be written, each
   of which would refer to a specific name form that identified one of
   the three possible naming attributes (i.e., pcimGroupName, cn, and
   orderedCIMKeys) for the pcimGroup object class.  This structure rule
   SHOULD include a superiorStructureRule (see Note 2 at the beginning
   of section 5).  The three name forms referenced by the three
   structure rules would each define one of the three naming attributes.

5.3.  The Three Policy Rule Classes

   The information model defines a PolicyRule class to represent the "If
   Condition then Action" semantics associated with processing policy
   information.  For maximum flexibility, the PCLS maps this class into
   three LDAP classes.





Strassner, et al.           Standards Track                    [Page 23]

RFC 3703                Policy Core LDAP Schema            February 2004


   To maximize flexibility, the pcimRule class is defined as abstract.
   The subclass pcimRuleAuxClass provides for auxiliary attachment to
   another entry, while the structural subclass pcimRuleInstance is
   available to represent a policy rule as a standalone entry.

   The conditions and actions associated with a policy rule are modeled,
   respectively, with auxiliary subclasses of the auxiliary classes
   pcimConditionAuxClass and pcimActionAuxClass.  Each of these
   auxiliary subclasses is attached to an instance of one of three
   structural classes.  A subclass of pcimConditionAuxClass is attached
   to an instance of pcimRuleInstance, to an instance of
   pcimRuleConditionAssociation, or to an instance of
   pcimPolicyInstance.  Similarly, a subclass of pcimActionAuxClass is
   attached to an instance of pcimRuleInstance, to an instance of
   pcimRuleActionAssociation, or to an instance of pcimPolicyInstance.

   The pcimRuleValidityPeriodList attribute (defined below) realizes the
   PolicyRuleValidityPeriod association defined in the PCIM.  Since this
   association has no additional properties besides those that tie the
   association to its associated objects, this association can be
   realized by simply using an attribute.  Thus, the
   pcimRuleValidityPeriodList attribute is simply a multi-valued
   attribute that provides an unordered set of DN references to one or
   more instances of the pcimTPCAuxClass, indicating when the policy
   rule is scheduled to be active and when it is scheduled to be
   inactive.  A policy rule is scheduled to be active if it is active
   according to AT LEAST ONE of the pcimTPCAuxClass instances referenced
   by this attribute.

   The PolicyConditionInPolicyRule and PolicyActionInPolicyRule
   associations, however, do have additional attributes.  The
   association PolicyActionInPolicyRule defines an integer attribute to
   sequence the actions, and the association PolicyConditionInPolicyRule
   has both an integer attribute to group the condition terms as well as
   a Boolean property to specify whether a condition is to be negated.

   In the PCLS, these additional association attributes are represented
   as attributes of two classes introduced specifically to model these
   associations.  These classes are the pcimRuleConditionAssociation
   class and the pcimRuleActionAssociation class, which are defined in
   Sections 5.4 and 5.5, respectively.  Thus, they do not appear as
   attributes of the class pcimRule.  Instead, the pcimRuleConditionList
   and pcimRuleActionList attributes can be used to reference these
   classes.







Strassner, et al.           Standards Track                    [Page 24]

RFC 3703                Policy Core LDAP Schema            February 2004


   The class definitions for the three pcimRule classes are as follows.

   The abstract class pcimRule is a base class for representing the "If
   Condition then Action" semantics associated with a policy rule.  It
   is defined as follows:

     ( 1.3.6.1.1.6.1.5 NAME 'pcimRule'
            DESC 'The base class for representing the "If Condition
                  then Action" semantics associated with a policy rule.'
            SUP pcimPolicy
            ABSTRACT
            MAY ( pcimRuleName $ pcimRuleEnabled $
                  pcimRuleConditionListType $ pcimRuleConditionList $
                  pcimRuleActionList $ pcimRuleValidityPeriodList $
                  pcimRuleUsage $ pcimRulePriority $
                  pcimRuleMandatory $ pcimRuleSequencedActions $
                  pcimRoles )
     )

   The PCIM [1] defines seven properties for the PolicyRule class.  The
   PCLS defines eleven attributes for the pcimRule class, which is the
   LDAP equivalent of the PolicyRule class.  Of these eleven attributes,
   seven are mapped directly from corresponding properties in PCIM's
   PolicyRule class.  The remaining four attributes are a class-specific
   optional naming attribute, and three attributes used to realize the
   three associations that the pcimRule class participates in.

   The pcimRuleName attribute is used as a user-friendly name of this
   policy rule, and can also serve as the class-specific optional naming
   attribute.  It is defined as follows:

        ( 1.3.6.1.1.6.2.5 NAME 'pcimRuleName'
               DESC 'The user-friendly name of this policy rule.'
               EQUALITY caseIgnoreMatch
               ORDERING caseIgnoreOrderingMatch
               SUBSTR caseIgnoreSubstringsMatch
               SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
               SINGLE-VALUE
        )

   The pcimRuleEnabled attribute is an integer enumeration indicating
   whether a policy rule is administratively enabled (value=1),
   administratively disabled (value=2), or enabled for debug (value=3).
   It is defined as follows:

        ( 1.3.6.1.1.6.2.6 NAME 'pcimRuleEnabled'
               DESC 'An integer indicating whether a policy rule is
                     administratively enabled (value=1), disabled



Strassner, et al.           Standards Track                    [Page 25]

RFC 3703                Policy Core LDAP Schema            February 2004


                     (value=2), or enabled for debug (value=3).'
               EQUALITY integerMatch
               ORDERING integerOrderingMatch
               SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
               SINGLE-VALUE
        )

   Note: All other values for the pcimRuleEnabled attribute are
   considered errors, and the administrator SHOULD treat this rule as
   being disabled if an invalid value is found.

   The pcimRuleConditionListType attribute is used to indicate whether
   the list of policy conditions associated with this policy rule is in
   disjunctive normal form (DNF, value=1) or conjunctive normal form
   (CNF, value=2).  It is defined as follows:

     ( 1.3.6.1.1.6.2.7 NAME 'pcimRuleConditionListType'
            DESC 'A value of 1 means that this policy rule is in
                  disjunctive normal form; a value of 2 means that this
                  policy rule is in conjunctive normal form.'
            EQUALITY integerMatch
            ORDERING integerOrderingMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE
     )

   Note: any value other than 1 or 2 for the pcimRuleConditionListType
   attribute is considered an error.  Administrators SHOULD treat this
   rule as being disabled if an invalid value is found, since it is
   unclear how to structure the condition list.

   The pcimRuleConditionList attribute is a multi-valued attribute that
   is used to realize the policyRuleInPolicyCondition association
   defined in [1].  It contains a set of DNs of
   pcimRuleConditionAssociation entries representing associations
   between this policy rule and its conditions.  No order is implied.
   It is defined as follows:

     ( 1.3.6.1.1.6.2.8 NAME 'pcimRuleConditionList'
            DESC 'Unordered set of DNs of pcimRuleConditionAssociation
                  entries representing associations between this policy
                  rule and its conditions.'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
     )






Strassner, et al.           Standards Track                    [Page 26]

RFC 3703                Policy Core LDAP Schema            February 2004


   The pcimRuleActionList attribute is a multi-valued attribute that is
   used to realize the policyRuleInPolicyAction association defined in
   [1].  It contains a set of DNs of pcimRuleActionAssociation entries
   representing associations between this policy rule and its actions.
   No order is implied.  It is defined as follows:

     ( 1.3.6.1.1.6.2.9 NAME 'pcimRuleActionList'
            DESC 'Unordered set of DNs of pcimRuleActionAssociation
                  entries representing associations between this policy
                  rule and its actions.'
           EQUALITY distinguishedNameMatch
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
     )

   The pcimRuleValidityPeriodList attribute is a multi-valued attribute
   that is used to realize the pcimRuleValidityPeriod association that
   is defined in [1].  It contains a set of DNs of
   pcimRuleValidityAssociation entries that determine when the pcimRule
   is scheduled to be active or inactive.  No order is implied.  It is
   defined as follows:

     ( 1.3.6.1.1.6.2.10 NAME 'pcimRuleValidityPeriodList'
            DESC 'Unordered set of DNs of pcimRuleValidityAssociation
                  entries that determine when the pcimRule is scheduled
                  to be active or inactive.'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
     )

   The pcimRuleUsage attribute is a free-form string providing
   guidelines on how this policy should be used.  It is defined as
   follows:

     ( 1.3.6.1.1.6.2.11 NAME 'pcimRuleUsage'
            DESC 'This attribute is a free-form sting providing
                  guidelines on how this policy should be used.'
            EQUALITY caseIgnoreMatch
            ORDERING caseIgnoreOrderingMatch
            SUBSTR caseIgnoreSubstringsMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE
     )









Strassner, et al.           Standards Track                    [Page 27]

RFC 3703                Policy Core LDAP Schema            February 2004


   The pcimRulePriority attribute is a non-negative integer that is used
   to prioritize this pcimRule relative to other pcimRules.  A larger
   value indicates a higher priority.  It is defined as follows:

     ( 1.3.6.1.1.6.2.12 NAME 'pcimRulePriority'
            DESC 'A non-negative integer for prioritizing this
                  pcimRule relative to other pcimRules.  A larger
                  value indicates a higher priority.'
            EQUALITY integerMatch
            ORDERING integerOrderingMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE
     )

   Note: if the value of the pcimRulePriority field is 0, then it SHOULD
   be treated as "don't care".  On the other hand, if the value is
   negative, then it SHOULD be treated as an error and Administrators
   SHOULD treat this rule as being disabled.

   The pcimRuleMandatory attribute is a Boolean attribute that, if TRUE,
   indicates that for this policy rule, the evaluation of its conditions
   and execution of its actions (if the condition is satisfied) is
   required.  If it is FALSE, then the evaluation of its conditions and
   execution of its actions (if the condition is satisfied) is not
   required.  This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.13 NAME 'pcimRuleMandatory'
            DESC 'If TRUE, indicates that for this policy rule, the
                  evaluation of its conditions and execution of its
                  actions (if the condition is satisfied) is required.'
            EQUALITY booleanMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
            SINGLE-VALUE
     )

   The pcimRuleSequencedActions attribute is an integer enumeration that
   is used to indicate that the ordering of actions defined by the
   pcimActionOrder attribute is either  mandatory(value=1),
   recommended(value=2), or dontCare(value=3).  It is defined as
   follows:

     ( 1.3.6.1.1.6.2.14 NAME 'pcimRuleSequencedActions'
            DESC 'An integer enumeration indicating that the ordering of
                  actions defined by the pcimActionOrder attribute is
                  mandatory(1), recommended(2), or dontCare(3).'
            EQUALITY integerMatch
            ORDERING integerOrderingMatch




Strassner, et al.           Standards Track                    [Page 28]

RFC 3703                Policy Core LDAP Schema            February 2004


            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE
     )

   Note: if the value of pcimRulesSequencedActions field is not one of
   these three values, then Administrators SHOULD treat this rule as
   being disabled.

   The pcimRoles attribute represents the policyRoles property of [1].
   Each value of this attribute represents a role-combination, which is
   a string of the form:
       <RoleName>[&&<RoleName>]* where the individual role names appear
   in alphabetical order according to the collating sequence for UCS-2.
   This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.15 NAME 'pcimRoles'
            DESC 'Each value of this attribute represents a role-
                  combination.'
            EQUALITY caseIgnoreMatch
            ORDERING caseIgnoreOrderingMatch
            SUBSTR caseIgnoreSubstringsMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
     )

   Note: if the value of the pcimRoles attribute does not conform to the
   format "<RoleName>[&&<RoleName>]*" (see Section 6.3.7 of [1]), then
   this attribute is malformed and its policy rule SHOULD be treated as
   being disabled.

   The two subclasses of the pcimRule class are defined as follows.
   First, the pcimRuleAuxClass is an auxiliary class for representing
   the "If Condition then Action" semantics associated with a policy
   rule.  Its class definition is as follows:

     ( 1.3.6.1.1.6.1.6 NAME 'pcimRuleAuxClass'
            DESC 'An auxiliary class for representing the "If Condition
                 then Action" semantics associated with a policy rule.'
            SUP pcimRule
            AUXILIARY
     )

   The pcimRuleInstance is a structural class for representing the "If
   Condition then Action" semantics associated with a policy rule.  Its
   class definition is as follows:

     ( 1.3.6.1.1.6.1.7 NAME 'pcimRuleInstance'
            DESC 'A structural class for representing the "If Condition
                 then Action" semantics associated with a policy rule.'



Strassner, et al.           Standards Track                    [Page 29]

RFC 3703                Policy Core LDAP Schema            February 2004


            SUP pcimRule
            STRUCTURAL
     )

   A DIT content rule could be written to enable an instance of
   pcimRuleInstance to have attached to it either references to one or
   more policy conditions (using pcimConditionAuxClass) or references to
   one or more policy actions (using pcimActionAuxClass).  This would be
   used to formalize the semantics of the PolicyRule class [1].  Since
   these semantics do not include specifying any properties of the
   PolicyRule class, the content rule would not need to specify any
   attributes.

   Similarly, three separate DIT structure rules could be written, each
   of which would refer to a specific name form that identified one of
   its three possible naming attributes (i.e., pcimRuleName, cn, and
   orderedCIMKeys).  This structure rule SHOULD include a
   superiorStructureRule (see Note 2 at the beginning of section 5).
   The three name forms referenced by the three structure rules would
   each define one of the three naming attributes.

5.4.  The Class pcimRuleConditionAssociation

   This class contains attributes to represent the properties of the
   PCIM's PolicyConditionInPolicyRule association.  Instances of this
   class are related to an instance of pcimRule via DIT containment.
   The policy conditions themselves are represented by auxiliary
   subclasses of the auxiliary class pcimConditionAuxClass.  These
   auxiliary classes are attached directly to instances of
   pcimRuleConditionAssociation for rule-specific policy conditions.
   For a reusable policy condition, the policyCondition auxiliary
   subclass is attached to an instance of the class pcimPolicyInstance
   (which is presumably associated with a pcimRepository by DIT
   containment), and the policyConditionDN attribute (of this class) is
   used to reference the reusable policyCondition instance.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.8 NAME 'pcimRuleConditionAssociation'
            DESC 'This class contains attributes characterizing the
                  relationship between a policy rule and one of its
                  policy conditions.'
            SUP pcimPolicy
            MUST ( pcimConditionGroupNumber $ pcimConditionNegated )
            MAY ( pcimConditionName $ pcimConditionDN )
     )





Strassner, et al.           Standards Track                    [Page 30]

RFC 3703                Policy Core LDAP Schema            February 2004


   The attributes of this class are defined as follows.

   The pcimConditionGroupNumber attribute is a non-negative integer.  It
   is used to identify the group to which the condition referenced by
   this association is assigned.  This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.16
            NAME 'pcimConditionGroupNumber'
            DESC 'The number of the group to which a policy condition
                  belongs.  This is used to form the DNF or CNF
                  expression associated with a policy rule.'
            EQUALITY integerMatch
            ORDERING integerOrderingMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE
     )

   Note that this number is non-negative.  A negative value for this
   attribute is invalid, and any policy rule that refers to an invalid
   entry SHOULD be treated as being disabled.

   The pcimConditionNegated attribute is a Boolean attribute that
   indicates whether this policy condition is to be negated or not.  If
   it is TRUE (FALSE), it indicates that a policy condition IS (IS NOT)
   negated in the DNF or CNF expression associated with a policy rule.
   This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.17
            NAME 'pcimConditionNegated'
            DESC 'If TRUE (FALSE), it indicates that a policy condition
                  IS (IS NOT) negated in the DNF or CNF expression
                  associated with a policy rule.'
            EQUALITY booleanMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
            SINGLE-VALUE
     )

   The pcimConditionName is a user-friendly name for identifying this
   policy condition, and may be used as a naming attribute if desired.
   This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.18
            NAME 'pcimConditionName'
            DESC 'A user-friendly name for a policy condition.'
            EQUALITY caseIgnoreMatch
            ORDERING caseIgnoreOrderingMatch
            SUBSTR caseIgnoreSubstringsMatch




Strassner, et al.           Standards Track                    [Page 31]

RFC 3703                Policy Core LDAP Schema            February 2004


            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE
     )

   The pcimConditionDN attribute is a DN that references an instance of
   a reusable policy condition.  This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.19
            NAME 'pcimConditionDN'
            DESC 'A DN that references an instance of a reusable policy
                  condition.'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
            SINGLE-VALUE
     )

   A DIT content rule could be written to enable an instance of
   pcimRuleConditionAssociation to have attached to it an instance of
   the auxiliary class pcimConditionAuxClass, or one of its subclasses.
   This would be used to formalize the semantics of the
   PolicyConditionInPolicyRule association.  Specifically, this would be
   used to represent a rule-specific policy condition [1].
   Similarly, three separate DIT structure rules could be written.  Each
   of these DIT structure rules would refer to a specific name form that
   defined two important semantics.  First, each name form would
   identify one of the three possible naming attributes (i.e.,
   pcimConditionName, cn, and orderedCIMKeys) for the
   pcimRuleConditionAssociation object class.  Second, each name form
   would require that an instance of the pcimRuleConditionAssociation
   class have as its superior an instance of the pcimRule class.  This
   structure rule SHOULD also include a superiorStructureRule (see Note
   2 at the beginning of section 5).

5.5.  The Class pcimRuleValidityAssociation

   The policyRuleValidityPeriod aggregation is mapped to the PCLS
   pcimRuleValidityAssociation class.  This class represents the
   scheduled activation and deactivation of a policy rule by binding the
   definition of times that the policy is active to the policy rule
   itself.  The "scheduled" times are either identified through an
   attached auxiliary class pcimTPCAuxClass, or are referenced through
   its pcimTimePeriodConditionDN attribute.

   This class is defined as follows:

     ( 1.3.6.1.1.6.1.9 NAME 'pcimRuleValidityAssociation'
           DESC 'This defines the scheduled activation or deactivation
                 of a policy rule.'



Strassner, et al.           Standards Track                    [Page 32]

RFC 3703                Policy Core LDAP Schema            February 2004


           SUP pcimPolicy
           STRUCTURAL
           MAY ( pcimValidityConditionName $ pcimTimePeriodConditionDN )
     )

   The attributes of this class are defined as follows:

   The pcimValidityConditionName attribute is used to define a
   user-friendly name of this condition, and may be used as a naming
   attribute if desired.  This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.20
            NAME 'pcimValidityConditionName'
            DESC 'A user-friendly name for identifying an instance of
                  a pcimRuleValidityAssociation entry.'
            EQUALITY caseIgnoreMatch
            ORDERING caseIgnoreOrderingMatch
            SUBSTR caseIgnoreSubstringsMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE
     )

   The pcimTimePeriodConditionDN attribute is a DN that references a
   reusable time period condition.  It is defined as follows:

     ( 1.3.6.1.1.6.2.21
            NAME 'pcimTimePeriodConditionDN'
             DESC 'A reference to a reusable policy time period
                   condition.'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
            SINGLE-VALUE
     )

   A DIT content rule could be written to enable an instance of
   pcimRuleValidityAssociation to have attached to it an instance of the
   auxiliary class pcimTPCAuxClass, or one of its subclasses.  This
   would be used to formalize the semantics of the
   PolicyRuleValidityPeriod aggregation [1].

   Similarly, three separate DIT structure rules could be written.  Each
   of these DIT structure rules would refer to a specific name form that
   defined two important semantics.  First, each name form would
   identify one of the three possible naming attributes (i.e.,
   pcimValidityConditionName, cn, and orderedCIMKeys) for the
   pcimRuleValidityAssociation object class.  Second, each name form
   would require that an instance of the pcimRuleValidityAssociation
   class have as its superior an instance of the pcimRule class.  This



Strassner, et al.           Standards Track                    [Page 33]

RFC 3703                Policy Core LDAP Schema            February 2004


   structure rule SHOULD also include a superiorStructureRule (see Note
   2 at the beginning of section 5).

5.6.  The Class pcimRuleActionAssociation

   This class contains an attribute to represent the one property of the
   PCIM PolicyActionInPolicyRule association, ActionOrder.  This
   property is used to specify an order for executing the actions
   associated with a policy rule.  Instances of this class are related
   to an instance of pcimRule via DIT containment.  The actions
   themselves are represented by auxiliary subclasses of the auxiliary
   class pcimActionAuxClass.

   These auxiliary classes are attached directly to instances of
   pcimRuleActionAssociation for rule-specific policy actions.  For a
   reusable policy action, the pcimAction auxiliary subclass is attached
   to an instance of the class pcimPolicyInstance (which is presumably
   associated with a pcimRepository by DIT containment), and the
   pcimActionDN attribute (of this class) is used to reference the
   reusable pcimCondition instance.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.10 NAME 'pcimRuleActionAssociation'
            DESC 'This class contains attributes characterizing the
                  relationship between a policy rule and one of its
                  policy actions.'
            SUP pcimPolicy
            MUST ( pcimActionOrder )
            MAY ( pcimActionName $ pcimActionDN )
     )

   The pcimActionName attribute is used to define a user-friendly name
   of this action, and may be used as a naming attribute if desired.
   This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.22
            NAME 'pcimActionName'
            DESC 'A user-friendly name for a policy action.'
            EQUALITY caseIgnoreMatch
            ORDERING caseIgnoreOrderingMatch
            SUBSTR caseIgnoreSubstringsMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE
     )






Strassner, et al.           Standards Track                    [Page 34]

RFC 3703                Policy Core LDAP Schema            February 2004


   The pcimActionOrder attribute is an unsigned integer that is used to
   indicate the relative position of an action in a sequence of actions
   that are associated with a given policy rule.  When this number is
   positive, it indicates a place in the sequence of actions to be
   performed, with smaller values indicating earlier positions in the
   sequence.  If the value is zero, then this indicates that the order
   is irrelevant.  Note that if two or more actions have the same
   non-zero value, they may be performed in any order as long as they
   are each performed in the correct place in the overall sequence of
   actions.  This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.23
            NAME 'pcimActionOrder'
            DESC 'An integer indicating the relative order of an action
                  in the context of a policy rule.'
            EQUALITY integerMatch
            ORDERING integerOrderingMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE
     )

   Note: if the value of the pcimActionOrder field is negative, then it
   SHOULD be treated as an error and any policy rule that refers to such
   an entry SHOULD be treated as being disabled.

   The pcimActionDN attribute is a DN that references a reusable policy
   action.  It is defined as follows:

     ( 1.3.6.1.1.6.2.24
            NAME 'pcimActionDN'
            DESC 'A DN that references a reusable policy action.'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
            SINGLE-VALUE
     )

   A DIT content rule could be written to enable an instance of
   pcimRuleActionAssociation to have attached to it an instance of the
   auxiliary class pcimActionAuxClass, or one of its subclasses.  This
   would be used to formalize the semantics of the
   PolicyActionInPolicyRule association.  Specifically, this would be
   used to represent a rule-specific policy action [1].

   Similarly, three separate DIT structure rules could be written.  Each
   of these DIT structure rules would refer to a specific name form that
   defined two important semantics.  First, each name form would
   identify one of the three possible naming attributes (i.e.,
   pcimActionName, cn, and orderedCIMKeys) for the



Strassner, et al.           Standards Track                    [Page 35]

RFC 3703                Policy Core LDAP Schema            February 2004


   pcimRuleActionAssociation object class.  Second, each name form would
   require that an instance of the pcimRuleActionAssociation class have
   as its superior an instance of the pcimRule class.  This structure
   rule should also include a superiorStructureRule (see Note 2 at the
   beginning of section 5).

5.7.  The Auxiliary Class pcimConditionAuxClass

   The purpose of a policy condition is to determine whether or not the
   set of actions (contained in the pcimRule that the condition applies
   to) should be executed or not.  This class defines the basic
   organizational semantics of a policy condition, as specified in [1].
   Subclasses of this auxiliary class can be attached to instances of
   three other classes in the PCLS.  When a subclass of this class is
   attached to an instance of pcimRuleConditionAssociation, or to an
   instance of pcimRule, it represents a rule-specific policy condition.
   When a subclass of this class is attached to an instance of
   pcimPolicyInstance, it represents a reusable policy condition.

   Since all of the classes to which subclasses of this auxiliary class
   may be attached are derived from the pcimPolicy class, the attributes
   of pcimPolicy will already be defined for the entries to which these
   subclasses attach.  Thus, this class is derived directly from "top".

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.11 NAME 'pcimConditionAuxClass'
            DESC 'A class representing a condition to be evaluated in
                  conjunction with a policy rule.'
            SUP top
            AUXILIARY
     )

5.8.  The Auxiliary Class pcimTPCAuxClass

   The PCIM defines a time period class, PolicyTimePeriodCondition, to
   provide a means of representing the time periods during which a
   policy rule is valid, i.e., active.  It also defines an aggregation,
   PolicyRuleValidityPeriod, so that time periods can be associated with
   a PolicyRule.  The LDAP mapping also provides two classes, one for
   the time condition itself, and one for the aggregation.

   In the PCIM, the time period class is named
   PolicyTimePeriodCondition. However, the resulting name of the
   auxiliary class in this mapping (pcimTimePeriodConditionAuxClass)
   exceeds the length of a name that some directories can store.
   Therefore, the name has been shortened to pcimTPCAuxClass.




Strassner, et al.           Standards Track                    [Page 36]

RFC 3703                Policy Core LDAP Schema            February 2004


   The class definition is as follows:

     ( 1.3.6.1.1.6.1.12 NAME 'pcimTPCAuxClass'
            DESC 'This provides the capability of enabling or disabling
                  a policy rule according to a predetermined schedule.'
            SUP pcimConditionAuxClass
            AUXILIARY
            MAY ( pcimTPCTime $ pcimTPCMonthOfYearMask $
                  pcimTPCDayOfMonthMask $ pcimTPCDayOfWeekMask $
                  pcimTPCTimeOfDayMask $ pcimTPCLocalOrUtcTime )
     )

   The attributes of the pcimTPCAuxClass are defined as follows.

   The pcimTPCTime attribute represents the time period that a policy
   rule is enabled for.  This attribute is defined as a string in [1]
   with a special format which defines a time period with a starting
   date and an ending date separated by a forward slash ("/"), as
   follows:

       yyyymmddThhmmss/yyyymmddThhmmss

   where the first date and time may be replaced with the string
   "THISANDPRIOR" or the second date and time may be replaced with the
   string "THISANDFUTURE".  This attribute is defined as follows:

        ( 1.3.6.1.1.6.2.25
               NAME 'pcimTPCTime'
               DESC 'The start and end times on which a policy rule is
                     valid.'
               EQUALITY caseIgnoreMatch
               ORDERING caseIgnoreOrderingMatch
               SUBSTR caseIgnoreSubstringsMatch
               SYNTAX 1.3.6.1.4.1.1466.115.121.1.44
               SINGLE-VALUE
        )

   The value of this attribute SHOULD be checked against its defined
   format ("yyyymmddThhmmss/yyyymmddThhmmss", where the first and second
   date strings may be replaced with the strings "THISANDPRIOR" and
   "THISANDFUTURE").  If the value of this attribute does not conform to
   this syntax, then this SHOULD be considered an error and the policy
   rule SHOULD be treated as being disabled.

   The next four attributes (pcimTPCMonthOfYearMask,
   pcimTPCDayOfMonthMask, pcimTPCDayOfWeekMask, and
   pcimTPCTimeOfDayMask) are all defined as octet strings in [1].
   However, the semantics of each of these attributes are contained in



Strassner, et al.           Standards Track                    [Page 37]

RFC 3703                Policy Core LDAP Schema            February 2004


   bit strings of various fixed lengths.  Therefore, the PCLS uses a
   syntax of Bit String to represent each of them.  The definition of
   these four attributes are as follows.

   The pcimTPCMonthOfYearMask attribute defines a 12-bit mask
   identifying the months of the year in which a policy rule is valid.
   The format is a bit string of length 12, representing the months of
   the year from January through December.  The definition of this
   attribute is as follows:

     ( 1.3.6.1.1.6.2.26
            NAME 'pcimTPCMonthOfYearMask'
            DESC 'This identifies the valid months of the year for a
                  policy rule using a 12-bit string that represents the
                  months of the year from January through December.'
            EQUALITY bitStringMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.6
            SINGLE-VALUE
     )

   The value of this attribute SHOULD be checked against its defined
   format.  If the value of this attribute does not conform to this
   syntax, then this SHOULD be considered an error and the policy rule
   SHOULD be treated as being disabled.

   The pcimTPCMonthOfDayMask attribute defines a mask identifying the
   days of the month on which a policy rule is valid.  The format is a
   bit string of length 62.  The first 31 positions represent the days
   of the month in ascending order, from day 1 to day 31.  The next 31
   positions represent the days of the month in descending order, from
   the last day to the day 31 days from the end.  The definition of this
   attribute is as follows:

     ( 1.3.6.1.1.6.2.27
            NAME 'pcimTPCDayOfMonthMask'
            DESC 'This identifies the valid days of the month for a
                  policy rule using a 62-bit string. The first 31
                  positions represent the days of the month in ascending
                  order, and the next 31 positions represent the days of
                  the month in descending order.'
            EQUALITY bitStringMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.6
            SINGLE-VALUE
     )







Strassner, et al.           Standards Track                    [Page 38]

RFC 3703                Policy Core LDAP Schema            February 2004


   The value of this attribute SHOULD be checked against its defined
   format.  If the value of this attribute does not conform to this
   syntax, then this SHOULD be considered an error and the policy rule
   SHOULD be treated as being disabled.

   The pcimTPCDayOfWeekMask attribute defines a mask identifying the
   days of the week on which a policy rule is valid.  The format is a
   bit string of length 7, representing the days of the week from Sunday
   through Saturday.  The definition of this attribute is as follows:

     ( 1.3.6.1.1.6.2.28
            NAME 'pcimTPCDayOfWeekMask'
            DESC 'This identifies the valid days of the week for a
                  policy rule using a 7-bit string. This represents
                  the days of the week from Sunday through Saturday.'
            EQUALITY bitStringMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.6
            SINGLE-VALUE
     )

   The value of this attribute SHOULD be checked against its defined
   format.  If the value of this attribute does not conform to this
   syntax, then this SHOULD be considered an error and the policy rule
   SHOULD be treated as being disabled.

   The pcimTPCTimeOfDayMask attribute defines the range of times at
   which a policy rule is valid.  If the second time is earlier than the
   first, then the interval spans midnight.  The format of the string is
   Thhmmss/Thhmmss.  The definition of this attribute is as follows:

     ( 1.3.6.1.1.6.2.29
            NAME 'pcimTPCTimeOfDayMask'
            DESC 'This identifies the valid range of times for a policy
                  using the format Thhmmss/Thhmmss.'
            EQUALITY caseIgnoreMatch
            ORDERING caseIgnoreOrderingMatch
            SUBSTR caseIgnoreSubstringsMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.44
            SINGLE-VALUE
     )

   The value of this attribute SHOULD be checked against its defined
   format.  If the value of this attribute does not conform to this
   syntax, then this SHOULD be considered an error and the policy rule
   SHOULD be treated as being disabled.






Strassner, et al.           Standards Track                    [Page 39]

RFC 3703                Policy Core LDAP Schema            February 2004


   Finally, the pcimTPCLocalOrUtcTime attribute is used to choose
   between local or UTC time representation.  This is mapped as a simple
   integer syntax, with the value of 1 representing local time and the
   value of 2 representing UTC time.  The definition of this attribute
   is as follows:

     ( 1.3.6.1.1.6.2.30
            NAME 'pcimTPCLocalOrUtcTime'
            DESC 'This defines whether the times in this instance
                  represent local (value=1) times or UTC (value=2)
                  times.'
            EQUALITY integerMatch
            ORDERING integerOrderingMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE
     )

   Note: if the value of the pcimTPCLocalOrUtcTime is not 1 or 2, then
   this SHOULD be considered an error and the policy rule SHOULD be
   disabled. If the attribute is not present at all, then all times are
   interpreted as if it were present with the value 2, that is, UTC
   time.

5.9.  The Auxiliary Class pcimConditionVendorAuxClass

   This class provides a general extension mechanism for representing
   policy conditions that have not been modeled with specific
   properties. Instead, its two properties are used to define the
   content and format of the condition, as explained below.  This class
   is intended for vendor-specific extensions that are not amenable to
   using pcimCondition; standardized extensions SHOULD NOT use this
   class.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.13 NAME 'pcimConditionVendorAuxClass'
            DESC 'A class that defines a registered means to describe a
                  policy condition.'
            SUP pcimConditionAuxClass
            AUXILIARY
            MAY ( pcimVendorConstraintData $
                 pcimVendorConstraintEncoding )
     )

   The pcimVendorConstraintData attribute is a multi-valued attribute.
   It provides a general mechanism for representing policy conditions
   that have not been modeled as specific attributes.  This information
   is encoded in a set of octet strings.  The format of the octet



Strassner, et al.           Standards Track                    [Page 40]

RFC 3703                Policy Core LDAP Schema            February 2004


   strings is identified by the OID stored in the
   pcimVendorConstraintEncoding attribute.  This attribute is defined as
   follows:

     ( 1.3.6.1.1.6.2.31
            NAME 'pcimVendorConstraintData'
            DESC 'Mechanism for representing constraints that have not
                  been modeled as specific attributes.  Their format is
                  identified by the OID stored in the attribute
                  pcimVendorConstraintEncoding.'
            EQUALITY octetStringMatch
            ORDERING octetStringOrderingMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
     )

   The pcimVendorConstraintEncoding attribute is used to identify the
   format and semantics for the pcimVendorConstraintData attribute.
   This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.32
            NAME 'pcimVendorConstraintEncoding'
            DESC 'An OID identifying the format and semantics for the
                  pcimVendorConstraintData for this instance.'
            EQUALITY objectIdentifierMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
            SINGLE-VALUE
     )

5.10.  The Auxiliary Class pcimActionAuxClass

   The purpose of a policy action is to execute one or more operations
   that will affect network traffic and/or systems, devices, etc. in
   order to achieve a desired policy state.  This class is used to
   represent an action to be performed as a result of a policy rule
   whose condition clause was satisfied.

   Subclasses of this auxiliary class can be attached to instances of
   three other classes in the PCLS.  When a subclass of this class is
   attached to an instance of pcimRuleActionAssociation, or to an
   instance of pcimRule, it represents a rule-specific policy action.
   When a subclass of this class is attached to an instance of
   pcimPolicyInstance, it represents a reusable policy action.

   Since all of the classes to which subclasses of this auxiliary class
   may be attached are derived from the pcimPolicy class, the attributes
   of the pcimPolicy class will already be defined for the entries to
   which these subclasses attach.  Thus, this class is derived directly
   from "top".



Strassner, et al.           Standards Track                    [Page 41]

RFC 3703                Policy Core LDAP Schema            February 2004


   The class definition is as follows:

     ( 1.3.6.1.1.6.1.14 NAME 'pcimActionAuxClass'
            DESC 'A class representing an action to be performed as a
                  result of a policy rule.'
            SUP top
            AUXILIARY
     )

5.11.  The Auxiliary Class pcimActionVendorAuxClass

   The purpose of this class is to provide a general extension mechanism
   for representing policy actions that have not been modeled with
   specific properties.  Instead, its two properties are used to define
   the content and format of the action, as explained below.

   As its name suggests, this class is intended for vendor-specific
   extensions that are not amenable to using the standard pcimAction
   class.  Standardized extensions SHOULD NOT use this class.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.15 NAME 'pcimActionVendorAuxClass'
            DESC 'A class that defines a registered means to describe a
                  policy action.'
            SUP pcimActionAuxClass
            AUXILIARY
            MAY ( pcimVendorActionData $ pcimVendorActionEncoding )
     )

   The pcimVendorActionData attribute is a multi-valued attribute.  It
   provides a general mechanism for representing policy actions that
   have not been modeled as specific attributes.  This information is
   encoded in a set of octet strings.  The format of the octet strings
   is identified by the OID stored in the pcimVendorActionEncoding
   attribute.  This attribute is defined as follows:

     ( 1.3.6.1.1.6.2.33
            NAME 'pcimVendorActionData'
            DESC ' Mechanism for representing policy actions that have
                   not been modeled as specific attributes.  Their
                   format is identified by the OID stored in the
                   attribute pcimVendorActionEncoding.'
            EQUALITY octetStringMatch
            ORDERING octetStringOrderingMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
     )




Strassner, et al.           Standards Track                    [Page 42]

RFC 3703                Policy Core LDAP Schema            February 2004


   The pcimVendorActionEncoding attribute is used to identify the format
   and semantics for the pcimVendorActionData attribute.  This attribute
   is defined as follows:

     ( 1.3.6.1.1.6.2.34
            NAME 'pcimVendorActionEncoding'
            DESC 'An OID identifying the format and semantics for the
                  pcimVendorActionData attribute of this instance.'
            EQUALITY objectIdentifierMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
            SINGLE-VALUE
     )

5.12.  The Class pcimPolicyInstance

   This class is not defined in the PCIM.  Its role is to serve as a
   structural class to which auxiliary classes representing policy
   information are attached when the information is reusable.  For
   auxiliary classes representing policy conditions and policy actions,
   there are alternative structural classes that may be used.  See
   Section 4.4 for a complete discussion of reusable policy conditions
   and actions, and of the role that this class plays in how they are
   represented.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.16 NAME 'pcimPolicyInstance'
            DESC 'A structural class to which aux classes containing
                  reusable policy information can be attached.'
            SUP pcimPolicy
            MAY ( pcimPolicyInstanceName )
     )

   The pcimPolicyInstanceName attribute is used to define a
   user-friendly name of this class, and may be used as a naming
   attribute if desired.  It is defined as follows:

     ( 1.3.6.1.1.6.2.35 NAME 'pcimPolicyInstanceName'
            DESC 'The user-friendly name of this policy instance.'
            EQUALITY caseIgnoreMatch
            ORDERING caseIgnoreOrderingMatch
            SUBSTR caseIgnoreSubstringsMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE
     )






Strassner, et al.           Standards Track                    [Page 43]

RFC 3703                Policy Core LDAP Schema            February 2004


   A DIT content rule could be written to enable an instance of
   pcimPolicyInstance to have attached to it either instances of one or
   more of the auxiliary object classes pcimConditionAuxClass and
   pcimActionAuxClass.  Since these semantics do not include specifying
   any properties, the content rule would not need to specify any
   attributes.  Note that other content rules could be defined to enable
   other policy-related auxiliary classes to be attached to
   pcimPolicyInstance.

   Similarly, three separate DIT structure rules could be written.  Each
   of these DIT structure rules would refer to a specific name form that
   defined two important semantics.  First, each name form would
   identify one of the three possible naming attributes (i.e.,
   pcimPolicyInstanceName, cn, and orderedCIMKeys) for this object
   class.  Second, each name form would require that an instance of the
   pcimPolicyInstance class have as its superior an instance of the
   pcimRepository class.  This structure rule SHOULD also include a
   superiorStructureRule (see Note 2 at the beginning of section 5).

5.13.  The Auxiliary Class pcimElementAuxClass

   This class introduces no additional attributes, beyond those defined
   in the class pcimPolicy from which it is derived.  Its role is to
   "tag" an instance of a class defined outside the realm of policy
   information as represented by PCIM as being nevertheless relevant to
   a policy specification.  This tagging can potentially take place at
   two levels:

   -   Every instance to which pcimElementAuxClass is attached becomes
       an instance of the class pcimPolicy, since pcimElementAuxClass is
       a subclass of pcimPolicy.  Searching for object
       class="pcimPolicy" will return the instance.  (As noted earlier,
       this approach does NOT work for some directory implementations.
       To accommodate these implementations, policy-related entries
       SHOULD be tagged with the pcimKeyword "POLICY".)

   -   With the pcimKeywords attribute that it inherits from pcimPolicy,
       an instance to which pcimElementAuxClass is attached can be
       tagged as being relevant to a particular type or category of
       policy information, using standard keywords,
       administrator-defined keywords, or both.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.17 NAME 'pcimElementAuxClass'
            DESC 'An auxiliary class used to tag instances of classes
                  defined outside the realm of policy as relevant to a
                  particular policy specification.'



Strassner, et al.           Standards Track                    [Page 44]

RFC 3703                Policy Core LDAP Schema            February 2004


            SUP pcimPolicy
            AUXILIARY
     )

5.14.  The Three Policy Repository Classes

   These classes provide a container for reusable policy information,
   such as reusable policy conditions and/or reusable policy actions.
   This document is concerned with mapping just the properties that
   appear in these classes.  Conceptually, this may be thought of as a
   special location in the DIT where policy information may reside.
   Since pcimRepository is derived from the class dlm1AdminDomain
   defined in reference [6], this specification has a normative
   dependency on that element of reference [6] (as well as on its entire
   derivation hierarchy, which also appears in reference [6]).  To
   maximize flexibility, the pcimRepository class is defined as
   abstract.  A subclass pcimRepositoryAuxClass provides for auxiliary
   attachment to another entry, while a structural subclass
   pcimRepositoryInstance is available to represent a policy repository
   as a standalone entry.

   The definition for the pcimRepository class is as follows:

     ( 1.3.6.1.1.6.1.18 NAME 'pcimRepository'
            DESC 'A container for reusable policy information.'
            SUP dlm1AdminDomain
            ABSTRACT
            MAY ( pcimRepositoryName )
     )

   The pcimRepositoryName attribute is used to define a user-friendly
   name of this class, and may be used as a naming attribute if desired.
   It is defined as follows:

     ( 1.3.6.1.1.6.2.36 NAME 'pcimRepositoryName'
            DESC 'The user-friendly name of this policy repository.'
            EQUALITY caseIgnoreMatch
            ORDERING caseIgnoreOrderingMatch
            SUBSTR caseIgnoreSubstringsMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE
     )









Strassner, et al.           Standards Track                    [Page 45]

RFC 3703                Policy Core LDAP Schema            February 2004


   The two subclasses of pcimRepository are defined as follows.  First,
   the pcimRepositoryAuxClass is an auxiliary class that can be used to
   aggregate reusable policy information.  It is defined as follows:

     ( 1.3.6.1.1.6.1.19 NAME 'pcimRepositoryAuxClass'
            DESC 'An auxiliary class that can be used to aggregate
                  reusable policy information.'
            SUP pcimRepository
            AUXILIARY
     )

   In cases where structural classes are needed instead of an auxiliary
   class, the pcimRepositoryInstance class is a structural class that
   can be used to aggregate reusable policy information.  It is defined
   as follows:

     ( 1.3.6.1.1.6.1.20 NAME 'pcimRepositoryInstance'
            DESC 'A structural class that can be used to aggregate
                  reusable policy information.'
            SUP pcimRepository
            STRUCTURAL
     )

   Three separate DIT structure rules could be written for this class.
   Each of these DIT structure rules would refer to a specific name form
   that enabled an instance of the pcimRepository class to be named
   under any superior using one of the three possible naming attributes
   (i.e., pcimRepositoryName, cn, and orderedCIMKeys).  This structure
   rule SHOULD also include a superiorStructureRule (see Note 2 at the
   beginning of section 5).

5.15.  The Auxiliary Class pcimSubtreesPtrAuxClass

   This auxiliary class provides a single, multi-valued attribute that
   references a set of objects that are at the root of DIT subtrees
   containing policy-related information.  By attaching this attribute
   to instances of various other classes, a policy administrator has a
   flexible way of providing an entry point into the directory that
   allows a client to locate and retrieve the policy information
   relevant to it.

   It is intended that these entries are placed in the DIT such that
   well-known DNs can be used to reference a well-known structural entry
   that has the pcimSubtreesPtrAuxClass attached to it.  In effect, this
   defines a set of entry points.  Each of these entry points can
   contain and/or reference all related policy entries for





Strassner, et al.           Standards Track                    [Page 46]

RFC 3703                Policy Core LDAP Schema            February 2004


   any well-known policy domains.  The pcimSubtreesPtrAuxClass functions
   as a tag to identify portions of the DIT that contain policy
   information.

   This object does not provide the semantic linkages between individual
   policy objects, such as those between a policy group and the policy
   rules that belong to it.  Its only role is to enable efficient bulk
   retrieval of policy-related objects, as described in Section 4.5.

   Once the objects have been retrieved, a directory client can
   determine the semantic linkages by following references contained in
   multi-valued attributes, such as pcimRulesAuxContainedSet.

   Since policy-related objects will often be included in the DIT
   subtree beneath an object to which this auxiliary class is attached,
   a client SHOULD request the policy-related objects from the subtree
   under the object with these references at the same time that it
   requests the references themselves.

   Since clients are expected to behave in this way, the policy
   administrator SHOULD make sure that this subtree does not contain so
   many objects unrelated to policy that an initial search done in this
   way results in a performance problem.  The pcimSubtreesPtrAuxClass
   SHOULD NOT be attached to the partition root for a large directory
   partition containing a relatively few number of policy-related
   objects along with a large number of objects unrelated to policy
   (again, "policy" here refers to the PCIM, not the X.501, definition
   and use of "policy").  A better approach would be to introduce a
   container object immediately below the partition root, attach
   pcimSubtreesPtrAuxClass to this container object, and then place all
   of the policy-related objects in that subtree.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.21 NAME 'pcimSubtreesPtrAuxClass'
            DESC 'An auxiliary class providing DN references to roots of
                  DIT subtrees containing policy-related objects.'
            SUP top
            AUXILIARY
            MAY ( pcimSubtreesAuxContainedSet )
     )










Strassner, et al.           Standards Track                    [Page 47]

RFC 3703                Policy Core LDAP Schema            February 2004


   The attribute pcimSubtreesAuxContainedSet provides an unordered set
   of DN references to instances of one or more objects under which
   policy-related information is present.  The objects referenced may or
   may not themselves contain policy-related information.  The attribute
   definition is as follows:

     ( 1.3.6.1.1.6.2.37
            NAME 'pcimSubtreesAuxContainedSet'
            DESC 'DNs of objects that serve as roots for DIT subtrees
                  containing policy-related objects.'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
     )

   Note that the cn attribute does NOT need to be defined for this
   class. This is because an auxiliary class is used as a means to
   collect common attributes and treat them as properties of an object.
   A good analogy is a #include file, except that since an auxiliary
   class is a class, all the benefits of a class (e.g., inheritance) can
   be applied to an auxiliary class.

5.16.  The Auxiliary Class pcimGroupContainmentAuxClass

   This auxiliary class provides a single, multi-valued attribute that
   references a set of pcimGroups.  By attaching this attribute to
   instances of various other classes, a policy administrator has a
   flexible way of providing an entry point into the directory that
   allows a client to locate and retrieve the pcimGroups relevant to it.

   As is the case with pcimRules, a policy administrator might have
   several different references to a pcimGroup in the overall directory
   structure. The pcimGroupContainmentAuxClass is the mechanism that
   makes it possible for the policy administrator to define all these
   different references.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.22 NAME 'pcimGroupContainmentAuxClass'
            DESC 'An auxiliary class used to bind pcimGroups to an
                  appropriate container object.'
            SUP top
            AUXILIARY
            MAY ( pcimGroupsAuxContainedSet )
     )







Strassner, et al.           Standards Track                    [Page 48]

RFC 3703                Policy Core LDAP Schema            February 2004


   The attribute pcimGroupsAuxContainedSet provides an unordered set of
   references to instances of one or more pcimGroups associated with the
   instance of a structural class to which this attribute has been
   appended.

   The attribute definition is as follows:

     ( 1.3.6.1.1.6.2.38
            NAME 'pcimGroupsAuxContainedSet'
            DESC 'DNs of pcimGroups associated in some way with the
                  instance to which this attribute has been appended.'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
     )

   Note that the cn attribute does NOT have to be defined for this class
   for the same reasons as those given for the pcimSubtreesPtrAuxClass
   in section 5.15.

5.17.  The Auxiliary Class pcimRuleContainmentAuxClass

   This auxiliary class provides a single, multi-valued attribute that
   references a set of pcimRules.  By attaching this attribute to
   instances of various other classes, a policy administrator has a
   flexible way of providing an entry point into the directory that
   allows a client to locate and retrieve the pcimRules relevant to it.

   A policy administrator might have several different references to a
   pcimRule in the overall directory structure.  For example, there
   might be references to all pcimRules for traffic originating in a
   particular subnet from a directory entry that represents that subnet.
   At the same time, there might be references to all pcimRules related
   to a particular DiffServ setting from an instance of a pcimGroup
   explicitly introduced as a container for DiffServ-related pcimRules.
   The pcimRuleContainmentAuxClass is the mechanism that makes it
   possible for the policy administrator to define all these separate
   references.

   The class definition is as follows:

     ( 1.3.6.1.1.6.1.23 NAME 'pcimRuleContainmentAuxClass'
            DESC 'An auxiliary class used to bind pcimRules to an
                  appropriate container object.'
            SUP top
            AUXILIARY
            MAY ( pcimRulesAuxContainedSet )
     )




Strassner, et al.           Standards Track                    [Page 49]

RFC 3703                Policy Core LDAP Schema            February 2004


   The attribute pcimRulesAuxContainedSet provides an unordered set of
   references to one or more instances of pcimRules associated with the
   instance of a structural class to which this attribute has been
   appended.  The attribute definition is as follows:

     ( 1.3.6.1.1.6.2.39
            NAME 'pcimRulesAuxContainedSet'
            DESC 'DNs of pcimRules associated in some way with the
                  instance to which this attribute has been appended.'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
     )

   The cn attribute does NOT have to be defined for this class for the
   same reasons as those given for the pcimSubtreesPtrAuxClass in
   section 5.15.

6.  Extending the Classes Defined in This Document

   The following subsections provide general guidance on how to create a
   domain-specific schema derived from this document, discuss how the
   vendor classes in the PCLS should be used, and explain how
   policyTimePeriodConditions are related to other policy conditions.

6.1.  Subclassing pcimConditionAuxClass and pcimActionAuxClass

   In Section 4.4, there is a discussion of how, by representing policy
   conditions and policy actions as auxiliary classes in a schema, the
   flexibility is retained to instantiate a particular condition or
   action as either rule-specific or reusable.  This flexibility is lost
   if a condition or action class is defined as structural rather than
   auxiliary.  For standardized schemata, this document specifies that
   domain-specific information MUST be expressed in auxiliary subclasses
   of pcimConditionAuxClass and pcimActionAuxClass.  It is RECOMMENDED
   that non-standardized schemata follow this practice as well.

6.2.  Using the Vendor Policy Attributes

   As discussed Section 5.9, the attributes pcimVendorConstraintData and
   pcimVendorConstraintEncoding are included in the
   pcimConditionVendorAuxClass to provide a mechanism for representing
   vendor-specific policy conditions that are not amenable to being
   represented with the pcimCondition class (or its subclasses).  The
   attributes pcimVendorActionData and pcimVendorActionEncoding in the
   pcimActionVendorAuxClass class play the same role with respect to
   actions.  This enables interoperability between different vendors who
   could not otherwise interoperate.




Strassner, et al.           Standards Track                    [Page 50]

RFC 3703                Policy Core LDAP Schema            February 2004


   For example, imagine a network composed of access devices from vendor
   A, edge and core devices from vendor B, and a policy server from
   vendor C. It is desirable for this policy server to be able to
   configure and manage all of the devices from vendors A and B.
   Unfortunately, these devices will in general have little in common
   (e.g., different mechanisms, different ways for controlling those
   mechanisms, different operating systems, different commands, and so
   forth).  The extension conditions provide a way for vendor-specific
   commands to be encoded as octet strings, so that a single policy
   server can commonly manage devices from different vendors.

6.3.  Using Time Validity Periods

   Time validity periods are defined as an auxiliary subclass of
   pcimConditionAuxClass, called pcimTPCAuxClass.  This is to allow
   their inclusion in the AND/OR condition definitions for a pcimRule.
   Care should be taken not to subclass pcimTPCAuxClass to add
   domain-specific condition properties.

   For example, it would be incorrect to add IPsec- or QoS-specific
   condition properties to the pcimTPCAuxClass class, just because IPsec
   or QoS includes time in its condition definition.  The correct
   subclassing would be to create IPsec or QoS-specific subclasses of
   pcimConditionAuxClass and then combine instances of these
   domain-specific condition classes with the appropriate validity
   period criteria.  This is accomplished using the AND/OR association
   capabilities for policy conditions in pcimRules.

7.  Security Considerations

   The PCLS, presented in this document, provides a mapping of the
   object-oriented model for describing policy information (PCIM) into a
   data model that forms the basic framework for describing the
   structure of policy data, in the case where the policy repository
   takes the form of an LDAP-accessible directory.

   PCLS is not intended to represent any particular system design or
   implementation.  PCLS is not directly useable in a real world system,
   without the discipline-specific mappings that are works in progress
   in the Policy Framework Working Group of the IETF.

   These other derivative documents, which use PCIM and its
   discipline-specific extensions as a base, will need to convey more
   specific security considerations (refer to RFC 3060 for more
   information.)






Strassner, et al.           Standards Track                    [Page 51]

RFC 3703                Policy Core LDAP Schema            February 2004


   The reason that PCLS, as defined here, is not representative of any
   real-world system, is that its object classes were designed to be
   independent of any specific discipline, or policy domain.  For
   example, DiffServ and IPsec represent two different policy domains.
   Each document that extends PCIM to one of these domains will derive
   subclasses from the classes and relationships defined in PCIM, in
   order to represent extensions of a generic model to cover specific
   technical domains.

   PCIM-derived documents will thus subclass the PCIM classes into
   classes specific to each technical policy domain (QOS, IPsec, etc.),
   which will, in turn, be mapped, to directory-specific schemata
   consistent with the PCLS documented here.

   Even though discipline-specific security requirements are not
   appropriate for PCLS, specific security requirements MUST be defined
   for each operational real-world application of PCIM.  Just as there
   will be a wide range of operational, real-world systems using PCIM,
   there will also be a wide range of security requirements for these
   systems.  Some operational, real-world systems that are deployed
   using PCLS may have extensive security requirements that impact
   nearly all object classes utilized by such a system, while other
   systems' security requirements might have very little impact.

   The derivative documents, discussed above, will create the context
   for applying operational, real-world, system-level security
   requirements against the various models that derive from PCIM,
   consistent with PCLS.

   In some real-world scenarios, the values associated with certain
   properties, within certain instantiated object classes, may represent
   information associated with scarce, and/or costly (and therefore
   valuable) resources.  It may be the case that these values must not
   be disclosed to, or manipulated by, unauthorized parties.

   Since this document forms the basis for the representation of a
   policy data model in a specific format (an LDAP-accessible
   directory), it is herein appropriate to reference the data
   model-specific tools and mechanisms that are available for achieving
   the authentication and authorization implicit in a requirement that
   restricts read and/or read- write access to these values stored in a
   directory.









Strassner, et al.           Standards Track                    [Page 52]

RFC 3703                Policy Core LDAP Schema            February 2004


   General LDAP security considerations apply, as documented in RFC 3377
   [2]. LDAP-specific authentication and authorization tools and
   mechanisms are found in the following standards track documents,
   which are appropriate for application to the management of security
   applied to policy data models stored in an LDAP-accessible directory:

     -   RFC 2829 (Authentication Methods for LDAP)
     -   RFC 2830 (Lightweight Directory Access Protocol (v3): Extension
         for Transport Layer Security)

   Any identified security requirements that are not dealt with in the
   appropriate discipline-specific information model documents, or in
   this document, MUST be dealt with in the derivative data model
   documents which are specific to each discipline.

8.  IANA Considerations

   Refer to RFC 3383, "Internet Assigned Numbers Authority (IANA)
   Considerations for the Lightweight Directory Access Protocol (LDAP)"
   [16].

8.1.  Object Identifiers

   The IANA has registered an LDAP Object Identifier for use in this
   technical specification according to the following template:

   Subject: Request for LDAP OID Registration
   Person & email address to contact for further information:
      Bob Moore (remoore@us.ibm.com)
   Specification: RFC 3703
   Author/Change Controller: IESG
   Comments:
      The assigned OID will be used as a base for identifying
      a number of schema elements defined in this document.

   IANA has assigned an OID of 1.3.6.1.1.6 with the name of pcimSchema
   to this registration as recorded in the following registry:

      http://www.iana.org/assignments/smi-numbers

8.2.  Object Identifier Descriptors

   The IANA has registered the LDAP Descriptors used in this technical
   specification as detailed in the following template:

   Subject: Request for LDAP Descriptor Registration Update
   Descriptor (short name): see comment
   Object Identifier: see comment



Strassner, et al.           Standards Track                    [Page 53]

RFC 3703                Policy Core LDAP Schema            February 2004


   Person & email address to contact for further information:
      Bob Moore (remoore@us.ibm.com)
   Usage: see comment
   Specification: RFC 3703
   Author/Change Controller: IESG
   Comments:

   The following descriptors have been added:

   NAME                            Type    OID
   --------------                  ----    ------------
   pcimPolicy                      O       1.3.6.1.1.6.1.1
   pcimGroup                       O       1.3.6.1.1.6.1.2
   pcimGroupAuxClass               O       1.3.6.1.1.6.1.3
   pcimGroupInstance               O       1.3.6.1.1.6.1.4
   pcimRule                        O       1.3.6.1.1.6.1.5
   pcimRuleAuxClass                O       1.3.6.1.1.6.1.6
   pcimRuleInstance                O       1.3.6.1.1.6.1.7
   pcimRuleConditionAssociation    O       1.3.6.1.1.6.1.8
   pcimRuleValidityAssociation     O       1.3.6.1.1.6.1.9
   pcimRuleActionAssociation       O       1.3.6.1.1.6.1.10
   pcimConditionAuxClass           O       1.3.6.1.1.6.1.11
   pcimTPCAuxClass                 O       1.3.6.1.1.6.1.12
   pcimConditionVendorAuxClass     O       1.3.6.1.1.6.1.13
   pcimActionAuxClass              O       1.3.6.1.1.6.1.14
   pcimActionVendorAuxClass        O       1.3.6.1.1.6.1.15
   pcimPolicyInstance              O       1.3.6.1.1.6.1.16
   pcimElementAuxClass             O       1.3.6.1.1.6.1.17
   pcimRepository                  O       1.3.6.1.1.6.1.18
   pcimRepositoryAuxClass          O       1.3.6.1.1.6.1.19
   pcimRepositoryInstance          O       1.3.6.1.1.6.1.20
   pcimSubtreesPtrAuxClass         O       1.3.6.1.1.6.1.21
   pcimGroupContainmentAuxClass    O       1.3.6.1.1.6.1.22
   pcimRuleContainmentAuxClass     O       1.3.6.1.1.6.1.23
   pcimKeywords                    A       1.3.6.1.1.6.2.3
   pcimGroupName                   A       1.3.6.1.1.6.2.4
   pcimRuleName                    A       1.3.6.1.1.6.2.5
   pcimRuleEnabled                 A       1.3.6.1.1.6.2.6
   pcimRuleConditionListType       A       1.3.6.1.1.6.2.7
   pcimRuleConditionList           A       1.3.6.1.1.6.2.8
   pcimRuleActionList              A       1.3.6.1.1.6.2.9
   pcimRuleValidityPeriodList      A       1.3.6.1.1.6.2.10
   pcimRuleUsage                   A       1.3.6.1.1.6.2.11
   pcimRulePriority                A       1.3.6.1.1.6.2.12
   pcimRuleMandatory               A       1.3.6.1.1.6.2.13
   pcimRuleSequencedActions        A       1.3.6.1.1.6.2.14
   pcimRoles                       A       1.3.6.1.1.6.2.15
   pcimConditionGroupNumber        A       1.3.6.1.1.6.2.16



Strassner, et al.           Standards Track                    [Page 54]

RFC 3703                Policy Core LDAP Schema            February 2004


   NAME                            Type    OID
   --------------                  ----    ------------
   pcimConditionNegated            A       1.3.6.1.1.6.2.17
   pcimConditionName               A       1.3.6.1.1.6.2.18
   pcimConditionDN                 A       1.3.6.1.1.6.2.19
   pcimValidityConditionName       A       1.3.6.1.1.6.2.20
   pcimTimePeriodConditionDN       A       1.3.6.1.1.6.2.21
   pcimActionName                  A       1.3.6.1.1.6.2.22
   pcimActionOrder                 A       1.3.6.1.1.6.2.23
   pcimActionDN                    A       1.3.6.1.1.6.2.24
   pcimTPCTime                     A       1.3.6.1.1.6.2.25
   pcimTPCMonthOfYearMask          A       1.3.6.1.1.6.2.26
   pcimTPCDayOfMonthMask           A       1.3.6.1.1.6.2.27
   pcimTPCDayOfWeekMask            A       1.3.6.1.1.6.2.28
   pcimTPCTimeOfDayMask            A       1.3.6.1.1.6.2.29
   pcimTPCLocalOrUtcTime           A       1.3.6.1.1.6.2.30
   pcimVendorConstraintData        A       1.3.6.1.1.6.2.31
   pcimVendorConstraintEncoding    A       1.3.6.1.1.6.2.32
   pcimVendorActionData            A       1.3.6.1.1.6.2.33
   pcimVendorActionEncoding        A       1.3.6.1.1.6.2.34
   pcimPolicyInstanceName          A       1.3.6.1.1.6.2.35
   pcimRepositoryName              A       1.3.6.1.1.6.2.36
   pcimSubtreesAuxContainedSet     A       1.3.6.1.1.6.2.37
   pcimGroupsAuxContainedSet       A       1.3.6.1.1.6.2.38
   pcimRulesAuxContainedSet        A       1.3.6.1.1.6.2.39

   where Type A is Attribute, Type O is ObjectClass

   These assignments are recorded in the following registry:

      http://www.iana.org/assignments/ldap-parameters




















Strassner, et al.           Standards Track                    [Page 55]

RFC 3703                Policy Core LDAP Schema            February 2004


9.  Acknowledgments

   We would like to thank Kurt Zeilenga, Roland Hedburg, and Steven Legg
   for doing a review of this document and making many helpful
   suggestions and corrections.

   Several of the policy classes in this model first appeared in early
   IETF drafts on IPsec policy and QoS policy.  The authors of these
   drafts were Partha Bhattacharya, Rob Adams, William Dixon, Roy
   Pereira, Raju Rajan, Jean-Christophe Martin, Sanjay Kamat, Michael
   See, Rajiv Chaudhury, Dinesh Verma, George Powers, and Raj Yavatkar.

   This document is closely aligned with the work being done in the
   Distributed Management Task Force (DMTF) Policy and Networks working
   groups.  We would especially like to thank Lee Rafalow, Glenn Waters,
   David Black, Michael Richardson, Mark Stevens, David Jones, Hugh
   Mahon, Yoram Snir, and Yoram Ramberg for their helpful comments.


































Strassner, et al.           Standards Track                    [Page 56]

RFC 3703                Policy Core LDAP Schema            February 2004


10.  Appendix:  Constructing the Value of orderedCIMKeys

   This appendix is non-normative, and is included in this document as a
   guide to implementers that wish to exchange information between CIM
   schemata and LDAP schemata.

   Within a CIM name space, the naming is basically flat; all instances
   are identified by the values of their key properties, and each
   combination of key values must be unique.  A limited form of
   hierarchical naming is available in CIM, however, by using weak
   associations: since a weak association involves propagation of key
   properties and their values from the superior object to the
   subordinate one, the subordinate object can be thought of as being
   named "under" the superior object.  Once they have been propagated,
   however, propagated key properties and their values function in
   exactly the same way that native key properties and their values do
   in identifying a CIM instance.

   The CIM mapping document [6] introduces a special attribute,
   orderedCIMKeys, to help map from the CIM_ManagedElement class to the
   LDAP class dlm1ManagedElement.  This attribute SHOULD only be used in
   an environment where it is necessary to map between an
   LDAP-accessible directory and a CIM repository.  For an LDAP
   environment, other LDAP naming attributes are defined (i.e., cn and a
   class-specific naming attribute) that SHOULD be used instead.

   The role of orderedCIMKeys is to represent the information necessary
   to correlate an entry in an LDAP-accessible directory with an
   instance in a CIM name space.  Depending on how naming of CIM-related
   entries is handled in an LDAP directory, the value of orderedCIMKeys
   represents one of two things:

     - If the DIT hierarchy does not mirror the "weakness hierarchy" of
       the CIM name space, then orderedCIMKeys represents all the
       keys of the CIM instance, both native and propagated.
     - If the DIT hierarchy does mirror the "weakness hierarchy" of the
       CIM name space, then orderedCIMKeys may represent either all the
       keys of the instance, or only the native keys.

   Regardless of which of these alternatives is taken, the syntax of
   orderedCIMKeys is the same - a DirectoryString of the form

       <className>.<key>=<value>[,<key>=<value>]*

   where the <key>=<value> elements are ordered by the names of the key
   properties, according to the collating sequence for US ASCII.  The
   only spaces allowed in the DirectoryString are those that fall within
   a <value> element.  As with alphabetizing the key properties, the



Strassner, et al.           Standards Track                    [Page 57]

RFC 3703                Policy Core LDAP Schema            February 2004


   goal of suppressing the spaces is once again to make the results of
   string operations predictable.

   The values of the <value> elements are derived from the various CIM
   syntaxes according to a grammar specified in [5].

11.  References

11.1.  Normative References

   [1]   Moore, B., Ellesson,E., Strassner, J. and A. Westerinen "Policy
         Core Information Model -- Version 1 Specification", RFC 3060,
         February 2001.

   [2]   Hodges, J. and R. Morgan, "Lightweight Directory Access
         Protocol (v3): Technical Specification", RFC 3377, September
         2002.

   [3]   Wahl, M., Coulbeck, A., Howes,T. and S. Kille, "Lightweight
         Directory Access Protocol (v3): Attribute Syntax Definitions",
         RFC 2252, December 1997.

   [4]   The Directory: Models.  ITU-T Recommendation X.501, 2001.

   [5]   Distributed Management Task Force, Inc., "Common Information
         Model (CIM) Specification", Version 2.2, June 14, 1999.  This
         document is available on the following DMTF web page:
         http://www.dmtf.org/standards/documents/CIM/DSP0004.pdf

   [6]   Distributed Management Task Force, Inc., "DMTF LDAP Schema for
         the CIM v2.5 Core Information Model", April 15, 2002.  This
         document is available on the following DMTF web page:
         http://www.dmtf.org/standards/documents/DEN/DSP0123.pdf

   [7]   Wahl, M., "A Summary of the X.500(96) User Schema for use with
         LDAPv3", RFC 2256, December 1997.

   [8]   The Directory: Selected Attribute Types.  ITU-T Recommendation
         X.520, 2001.

   [9]   Zeilenga, K., Ed., "Lightweight Directory Access Protocol
         (LDAP): Additional Matching Rules", RFC 3698, February 2004.

   [10]  Bradner, S., "Key words for use in RFCs to Indicate Requirement
         Levels", BCP 14, RFC 2119, March 1997.






Strassner, et al.           Standards Track                    [Page 58]

RFC 3703                Policy Core LDAP Schema            February 2004


11.2.  Informative References

   [11]  Hovey, R. and S. Bradner, "The Organizations Involved in the
         IETF Standards Process", BCP 11, RFC 2028, October 1996.

   [12]  Strassner, J., policy architecture BOF presentation, 42nd IETF
         Meeting, Chicago, Illinois, October 1998.  Minutes of this BOF
         are available at the following location:
         http://www.ietf.org/proceedings/98aug/index.html.

   [13]  Yavatkar, R., Guerin, R. and D. Pendarakis, "A Framework for
         Policy-based Admission Control", RFC 2753, January 2000.

   [14]  Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
         "Authentication Methods for LDAP", RFC 2829, May 2000

   [15]  Hodges, J., Morgan, R. and M. Wahl, "Lightweight Directory
         Access Protocol (v3): Extension for Transport Layer Security",
         RFC 2830, May 2000.

   [16]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
         Considerations for the Lightweight Directory Access Protocol
         (LDAP)", BCP 64, RFC 3383, September 2002.




























Strassner, et al.           Standards Track                    [Page 59]

RFC 3703                Policy Core LDAP Schema            February 2004


12.  Authors' Addresses

   John Strassner
   Intelliden Corporation
   90 South Cascade Avenue
   Colorado Springs, CO  80903

   Phone: +1.719.785.0648
   Fax:   +1.719.785.0644
   EMail: john.strassner@intelliden.com


   Bob Moore
   IBM Corporation
   P. O. Box 12195, BRQA/B501/G206
   3039 Cornwallis Rd.
   Research Triangle Park, NC  27709-2195

   Phone: +1 919-254-4436
   Fax:   +1 919-254-6243
   EMail: remoore@us.ibm.com


   Ryan Moats
   Lemur Networks, Inc.
   15621 Drexel Circle
   Omaha, NE 68135

   Phone: +1-402-894-9456
   EMail: rmoats@lemurnetworks.net


   Ed Ellesson
   3026 Carriage Trail
   Hillsborough, NC 27278

   Phone: +1 919-644-3977
   EMail: ellesson@mindspring.com













Strassner, et al.           Standards Track                    [Page 60]

RFC 3703                Policy Core LDAP Schema            February 2004


13.  Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78 and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
   REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE
   INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed
   to pertain to the implementation or use of the technology
   described in this document or the extent to which any license
   under such rights might or might not be available; nor does it
   represent that it has made any independent effort to identify any
   such rights.  Information on the procedures with respect to
   rights in RFC documents can be found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use
   of such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository
   at http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention
   any copyrights, patents or patent applications, or other
   proprietary rights that may cover technology that may be required
   to implement this standard.  Please address the information to the
   IETF at ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.









Strassner, et al.           Standards Track                    [Page 61]

alt-openldap11-devel/rfc/rfc3112.txt000064400000041334150410163250012761 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 3112                           OpenLDAP Foundation
Category: Informational                                         May 2001


                  LDAP Authentication Password Schema

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2001).  All Rights Reserved.

Abstract

   This document describes schema in support of user/password
   authentication in a LDAP (Lightweight Directory Access Protocol)
   directory including the authPassword attribute type.  This attribute
   type holds values derived from the user's password(s) (commonly using
   cryptographic strength one-way hash).  authPassword is intended to
   used instead of userPassword.

1. Background and Intended Use

   The userPassword attribute type [RFC2256] is intended to be used to
   support the LDAP [RFC2251] "simple" bind operation.  However, values
   of userPassword must be clear text passwords.  It is often desirable
   to store values derived from the user's password(s) instead of actual
   passwords.

   The authPassword attribute type is intended to be used to store
   information used to implement simple password based authentication.
   The attribute type may be used by LDAP servers to implement the LDAP
   Bind operation's "simple" authentication method.

   The attribute type supports multiple storage schemes.  A matching
   rule is provided for use with extensible search filters to allow
   clients to assert that a clear text password "matches" one of the
   attribute's values.

   Storage schemes often use cryptographic strength one-way hashing.
   Though the use of one-way hashing reduces the potential that exposed
   values will allow unauthorized access to the Directory (unless the




Zeilenga                     Informational                      [Page 1]

RFC 3112          LDAP Authentication Password Schema           May 2001


   hash algorithm/implementation is flawed), the hashing of passwords is
   intended to be as an additional layer of protection.  It is
   RECOMMENDED that hashed values be protected as if they were clear
   text passwords.

   This attribute may be used in conjunction with server side password
   generation mechanisms (such as the LDAP Password Modify [RFC3062]
   extended operation).

   Access to this attribute may governed by administrative controls such
   as those which implement password change policies.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", and "MAY" in this document are
   to be interpreted as described in RFC 2119 [RFC2119].

2. Schema Definitions

   The following schema definitions are described in terms of LDAPv3
   Attribute Syntax Definitions [RFC2252] with specific syntax detailed
   using Augmented BNF [RFC2234].

2.1. authPasswordSyntax

      ( 1.3.6.1.4.1.4203.1.1.2
        DESC 'authentication password syntax' )

   Values of this syntax are encoded according to:

      authPasswordValue = w scheme s authInfo s authValue w
      scheme = %x30-39 / %x41-5A / %x2D-2F / %x5F
            ; 0-9, A-Z, "-", ".", "/", or "_"
      authInfo = schemeSpecificValue
      authValue = schemeSpecificValue
              schemeSpecificValue = *( %x21-23 / %x25-7E )
            ; printable ASCII less "$" and " "
      s = w SEP w
      w = *SP
      SEP = %x24 ; "$"
      SP = %x20 ; " " (space)

   where scheme describes the mechanism and authInfo and authValue are a
   scheme specific.  The authInfo field is often a base64 encoded salt.
   The authValue field is often a base64 encoded value derived from a
   user's password(s).  Values of this attribute are case sensitive.






Zeilenga                     Informational                      [Page 2]

RFC 3112          LDAP Authentication Password Schema           May 2001


   Transfer of values of this syntax is strongly discouraged where the
   underlying transport service cannot guarantee confidentiality and may
   result in disclosure of the values to unauthorized parties.

   This document describes a number of schemes, as well as requirements
   for the scheme naming, in section 3.

2.2. authPasswordExactMatch

      ( 1.3.6.1.4.1.4203.1.2.2
        NAME 'authPasswordExactMatch'
        DESC 'authentication password exact matching rule'
        SYNTAX 1.3.6.1.4.1.4203.1.1.2 )

   This matching rule allows a client to assert that an asserted
   authPasswordSyntax value matches authPasswordSyntax values.  It is
   meant to be used as the EQUALITY matching rule of attributes whose
   SYNTAX is authPasswordSyntax.

   The assertion is "TRUE" if there is an attribute value which has the
   same scheme, authInfo, and authValue components as the asserted
   value; "FALSE" if no attribute value has the same components as the
   asserted value; and "Undefined" otherwise.

2.3. authPasswordMatch

       ( 1.3.6.1.4.1.4203.1.2.3
         NAME 'authPasswordMatch'
         DESC 'authentication password matching rule'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )

   This matching rule allows a client to assert that a password matches
   values of authPasswordSyntax using an extensibleMatch filter
   component.  Each value is matched per its scheme.  The assertion is
   "TRUE" if one or more attribute values matches the asserted value,
   "FALSE" if all values do not matches, and "Undefined" otherwise.

   Servers which support use of this matching rule SHOULD publish
   appropriate matchingRuleUse values per [RFC2252], 4.4.

   Transfer of authPasswordMatch assertion values is strongly
   discouraged where the underlying transport service cannot guarantee
   confidentiality and may result in disclosure of the values to
   unauthorized parties.







Zeilenga                     Informational                      [Page 3]

RFC 3112          LDAP Authentication Password Schema           May 2001


2.4. supportedAuthPasswordSchemes

      ( 1.3.6.1.4.1.4203.1.3.3
        NAME 'supportedAuthPasswordSchemes'
        DESC 'supported password storage schemes'
        EQUALITY caseExactIA5Match
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32}
        USAGE dSAOperation )

   The values of this attribute are names of supported authentication
   password schemes which the server supports.  The syntax of a scheme
   name is described in section 2.1.  This attribute may only be present
   in the root DSE.  If the server does not support any password
   schemes, this attribute will not be present.

2.5. authPassword

      ( 1.3.6.1.4.1.4203.1.3.4 NAME 'authPassword'
        DESC 'password authentication information'
        EQUALITY 1.3.6.1.4.1.4203.1.2.2
        SYNTAX 1.3.6.1.4.1.4203.1.1.2 )

   The values of this attribute are representative of the user's
   password(s) and conform to the authPasswordSyntax described in 2.1.
   The values of this attribute may be used for authentication purposes.

   Transfer of authPassword values is strongly discouraged where the
   underlying transport service cannot guarantee confidentiality and may
   result in disclosure of the values to unauthorized parties.

2.6. authPasswordObject

      ( 1.3.6.1.4.1.4203.1.4.7 NAME 'authPasswordObject'
        DESC 'authentication password mix in class'
        MAY 'authPassword'
        AUXILIARY )

   Entries of this object class may contain authPassword attribute
   types.

3. Schemes

   This section describes the "MD5" and "SHA1" schemes.  Other schemes
   may be defined by other documents.  Schemes which are not described
   in an RFC SHOULD be named with a leading "X-" to indicate they are a
   private or implementation specific scheme, or may be named using the
   dotted-decimal representation [RFC2252] of an OID assigned to the
   scheme.



Zeilenga                     Informational                      [Page 4]

RFC 3112          LDAP Authentication Password Schema           May 2001


3.1. MD5 scheme

   The MD5 [RFC1321] scheme name is "MD5".

   The authValue is the base64 encoding of an MD5 digest of the
   concatenation the user password and salt.  The base64 encoding of the
   salt is provided in the authInfo field.  The salt MUST be at least 64
   bits long.  Implementations of this scheme MUST support salts up to
   128 bits in length.

   Example:
      Given a user "joe" who's password is "mary" and a salt of "salt",
      the authInfo field would be the base64 encoding of "salt" and the
      authValue field would be the base64 encoding of the MD5 digest of
      "marysalt".

   A match against an asserted password and an attribute value of this
   scheme SHALL be true if and only if the MD5 digest of concatenation
   of the asserted value and the salt is equal to the MD5 digest
   contained in AuthValue.  The match SHALL be undefined if the server
   is unable to complete the equality test for any reason.  Otherwise
   the match SHALL be false.

   Values of this scheme SHOULD only be used to implement simple
   user/password authentication.

3.2. SHA1 scheme

   The SHA1 [SHA1] scheme name is "SHA1".

   The authValue is the base64 encoding of a SHA1 digest of the
   concatenation the user password and the salt.  The base64 encoding of
   the salt is provided in the authInfo field.  The salt MUST be at
   least 64 bits long.  Implementations of this scheme MUST support
   salts up to 128 bits in length.

   Example:
      Given a user "joe" who's password is "mary" and a salt of "salt",
      the authInfo field would be the base64 encoding of "salt" and the
      authValue field would be the base64 encoding of the SHA1 digest of
      "marysalt".

   A match against an asserted password and an attribute value of this
   scheme SHALL be true if and only if the SHA1 digest of concatenation
   of the asserted value and the salt is equal to the SHA1 digest
   contained in AuthValue.  The match SHALL be undefined if the server
   is unable to complete the equality test for any reason.  Otherwise
   the match SHALL be false.



Zeilenga                     Informational                      [Page 5]

RFC 3112          LDAP Authentication Password Schema           May 2001


   Values of this scheme SHOULD only be used to implement simple
   user/password authentication.

4. Implementation Issues

   For all implementations of this specification:

      Servers MAY restrict which schemes are used in conjunction with a
      particular authentication process but SHOULD use all values of
      selected schemes.  If the asserted password matches any of the
      stored values, the asserted password SHOULD be considered valid.
      Servers MAY use other authentication storage mechanisms, such as
      userPassword or an external password store, in conjunction with
      authPassword to support the authentication process.

      Servers that support simple bind MUST support the SHA1 scheme and
      SHOULD support the MD5 scheme.

      Servers SHOULD NOT publish values of authPassword nor allow
      operations which expose authPassword values or AuthPasswordMatch
      assertions to unless confidentiality protection is in place.

      Clients SHOULD NOT initiate operations which provide or request
      values of authPassword or make authPasswordMatch assertions unless
      confidentiality protection is in place.

      Clients SHOULD NOT assume that a successful AuthPasswordMatch,
      whether by compare or search, is sufficient to gain directory
      access.  The bind operation MUST be used to authenticate to the
      directory.

5. Security Considerations

   This document describes how authentication information may be stored
   in a directory.  Authentication information MUST be adequately
   protected as unintended disclosure will allow attackers to gain
   immediate access to the directory as described by [RFC2829].

   As flaws may be discovered in the hashing algorithm or with a
   particular implementation of the algorithm or values could be subject
   to various attacks if exposed, values of AuthPassword SHOULD be
   protected as if they were clear text passwords.  When values are
   transferred, privacy protections, such as IPSEC or TLS, SHOULD be in
   place.

   Clients SHOULD use strong authentication mechanisms [RFC2829].





Zeilenga                     Informational                      [Page 6]

RFC 3112          LDAP Authentication Password Schema           May 2001


   AuthPasswordMatch matching rule allows applications to test the
   validity of a user password and, hence, may be used to mount an
   attack.  Servers SHOULD take appropriate measures to protect the
   directory from such attacks.

   Some password schemes may require CPU intensive operations.  Servers
   SHOULD take appropriate measures to protect against Denial of Service
   attacks.

   AuthPassword does not restrict an authentication identity to a single
   password.  An attacker who gains write access to this attribute may
   store additional values without disabling the user's true
   password(s).  Use of policy aware clients and servers is RECOMMENDED.

   The level of protection offered against various attacks differ from
   scheme to scheme.  It is RECOMMENDED that servers support scheme
   selection as a configuration item.  This allows for a scheme to be
   easily disabled if a significant security flaw is discovered.

6. Acknowledgment

   This document borrows from a number of IETF documents and is based
   upon input from the IETF LDAPext working group.

7. Bibliography

   [RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321,
             April 1992

   [RFC2219] Bradner, S., "Key words for use in RFCs to Indicate
             Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2234] Crocker, D., Editor, P. Overell, "Augmented BNF for Syntax
             Specifications: ABNF", RFC 2234, November 1997.

   [RFC2251] Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
             Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252] Wahl, M., Coulbeck, A., Howes, T., and S. Kille,
             "Lightweight Directory Access Protocol (v3): Attribute
             Syntax Definitions", RFC 2252, December 1997.

   [RFC2256] Wahl, A., "A Summary of the X.500(96) User Schema for use
             with LDAPv3", RFC 2256, December 1997.

   [RFC2307] Howard, L., "An Approach for Using LDAP as a Network
             Information Service", RFC 2307, March 1998.




Zeilenga                     Informational                      [Page 7]

RFC 3112          LDAP Authentication Password Schema           May 2001


   [RFC2829] Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
             "Authentication Methods for LDAP", RFC 2829, June 2000.

   [RFC3062] Zeilenga, K., "LDAP Password Modify Extended Operation",
             RFC 3062, February 2001.

   [SHA1]    NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.

8. Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org





































Zeilenga                     Informational                      [Page 8]

RFC 3112          LDAP Authentication Password Schema           May 2001


9.  Full Copyright Statement

   Copyright (C) The Internet Society (2001).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Zeilenga                     Informational                      [Page 9]

alt-openldap11-devel/rfc/rfc4512.txt000064400000323531150410163250012770 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4512                           OpenLDAP Foundation
Obsoletes: 2251, 2252, 2256, 3674                              June 2006
Category: Standards Track


             Lightweight Directory Access Protocol (LDAP):
                      Directory Information Models

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   The Lightweight Directory Access Protocol (LDAP) is an Internet
   protocol for accessing distributed directory services that act in
   accordance with X.500 data and service models.  This document
   describes the X.500 Directory Information Models, as used in LDAP.
























Zeilenga                    Standards Track                     [Page 1]

RFC 4512                      LDAP Models                      June 2006


Table of Contents

   1. Introduction ....................................................3
      1.1. Relationship to Other LDAP Specifications ..................3
      1.2. Relationship to X.501 ......................................4
      1.3. Conventions ................................................4
      1.4. Common ABNF Productions ....................................4
   2. Model of Directory User Information .............................6
      2.1. The Directory Information Tree .............................7
      2.2. Structure of an Entry ......................................7
      2.3. Naming of Entries ..........................................8
      2.4. Object Classes .............................................9
      2.5. Attribute Descriptions ....................................12
      2.6. Alias Entries .............................................16
   3. Directory Administrative and Operational Information ...........17
      3.1. Subtrees ..................................................17
      3.2. Subentries ................................................18
      3.3. The 'objectClass' attribute ...............................18
      3.4. Operational Attributes ....................................19
   4. Directory Schema ...............................................22
      4.1. Schema Definitions ........................................23
      4.2. Subschema Subentries ......................................32
      4.3. 'extensibleObject' object class ...........................35
      4.4. Subschema Discovery .......................................35
   5. DSA (Server) Informational Model ...............................36
      5.1. Server-Specific Data Requirements .........................36
   6. Other Considerations ...........................................40
      6.1. Preservation of User Information ..........................40
      6.2. Short Names ...............................................41
      6.3. Cache and Shadowing .......................................41
   7. Implementation Guidelines ......................................42
      7.1. Server Guidelines .........................................42
      7.2. Client Guidelines .........................................42
   8. Security Considerations ........................................43
   9. IANA Considerations ............................................43
   10. Acknowledgements ..............................................44
   11. Normative References ..........................................45
   Appendix A. Changes ...............................................47
      A.1. Changes to RFC 2251 .......................................47
      A.2. Changes to RFC 2252 .......................................49
      A.3. Changes to RFC 2256 .......................................50
      A.4. Changes to RFC 3674 .......................................51









Zeilenga                    Standards Track                     [Page 2]

RFC 4512                      LDAP Models                      June 2006


1.  Introduction

   This document discusses the X.500 Directory Information Models
   [X.501], as used by the Lightweight Directory Access Protocol (LDAP)
   [RFC4510].

   The Directory is "a collection of open systems cooperating to provide
   directory services" [X.500].  The information held in the Directory
   is collectively known as the Directory Information Base (DIB).  A
   Directory user, which may be a human or other entity, accesses the
   Directory through a client (or Directory User Agent (DUA)).  The
   client, on behalf of the directory user, interacts with one or more
   servers (or Directory System Agents (DSA)).  A server holds a
   fragment of the DIB.

   The DIB contains two classes of information:

      1) user information (e.g., information provided and administrated
         by users).  Section 2 describes the Model of User Information.

      2) administrative and operational information (e.g., information
         used to administer and/or operate the directory).  Section 3
         describes the model of Directory Administrative and Operational
         Information.

   These two models, referred to as the generic Directory Information
   Models, describe how information is represented in the Directory.
   These generic models provide a framework for other information
   models.  Section 4 discusses the subschema information model and
   subschema discovery.  Section 5 discusses the DSA (Server)
   Informational Model.

   Other X.500 information models (such as access control distribution
   knowledge and replication knowledge information models) may be
   adapted for use in LDAP.  Specification of how these models apply to
   LDAP is left to future documents.

1.1.  Relationship to Other LDAP Specifications

   This document is a integral part of the LDAP technical specification
   [RFC4510], which obsoletes the previously defined LDAP technical
   specification, RFC 3377, in its entirety.

   This document obsoletes RFC 2251, Sections 3.2 and 3.4, as well as
   portions of Sections 4 and 6.  Appendix A.1 summarizes changes to
   these sections.  The remainder of RFC 2251 is obsoleted by the
   [RFC4511], [RFC4513], and [RFC4510] documents.




Zeilenga                    Standards Track                     [Page 3]

RFC 4512                      LDAP Models                      June 2006


   This document obsoletes RFC 2252, Sections 4, 5, and 7.  Appendix A.2
   summarizes changes to these sections.  The remainder of RFC 2252 is
   obsoleted by [RFC4517].

   This document obsoletes RFC 2256, Sections 5.1, 5.2, 7.1, and 7.2.
   Appendix A.3 summarizes changes to these sections.  The remainder of
   RFC 2256 is obsoleted by [RFC4519] and [RFC4517].

   This document obsoletes RFC 3674 in its entirety.  Appendix A.4
   summarizes changes since RFC 3674.

1.2.  Relationship to X.501

   This document includes material, with and without adaptation, from
   [X.501] as necessary to describe this protocol.  These adaptations
   (and any other differences herein) apply to this protocol, and only
   this protocol.

1.3.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

   Schema definitions are provided using LDAP description formats (as
   defined in Section 4.1).  Definitions provided here are formatted
   (line wrapped) for readability.  Matching rules and LDAP syntaxes
   referenced in these definitions are specified in [RFC4517].

1.4.  Common ABNF Productions

   A number of syntaxes in this document are described using Augmented
   Backus-Naur Form (ABNF) [RFC4234].  These syntaxes (as well as a
   number of syntaxes defined in other documents) rely on the following
   common productions:

      keystring = leadkeychar *keychar
      leadkeychar = ALPHA
      keychar = ALPHA / DIGIT / HYPHEN
      number  = DIGIT / ( LDIGIT 1*DIGIT )

      ALPHA   = %x41-5A / %x61-7A   ; "A"-"Z" / "a"-"z"
      DIGIT   = %x30 / LDIGIT       ; "0"-"9"
      LDIGIT  = %x31-39             ; "1"-"9"
      HEX     = DIGIT / %x41-46 / %x61-66 ; "0"-"9" / "A"-"F" / "a"-"f"

      SP      = 1*SPACE  ; one or more " "
      WSP     = 0*SPACE  ; zero or more " "



Zeilenga                    Standards Track                     [Page 4]

RFC 4512                      LDAP Models                      June 2006


      NULL    = %x00 ; null (0)
      SPACE   = %x20 ; space (" ")
      DQUOTE  = %x22 ; quote (""")
      SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
      DOLLAR  = %x24 ; dollar sign ("$")
      SQUOTE  = %x27 ; single quote ("'")
      LPAREN  = %x28 ; left paren ("(")
      RPAREN  = %x29 ; right paren (")")
      PLUS    = %x2B ; plus sign ("+")
      COMMA   = %x2C ; comma (",")
      HYPHEN  = %x2D ; hyphen ("-")
      DOT     = %x2E ; period (".")
      SEMI    = %x3B ; semicolon (";")
      LANGLE  = %x3C ; left angle bracket ("<")
      EQUALS  = %x3D ; equals sign ("=")
      RANGLE  = %x3E ; right angle bracket (">")
      ESC     = %x5C ; backslash ("\")
      USCORE  = %x5F ; underscore ("_")
      LCURLY  = %x7B ; left curly brace "{"
      RCURLY  = %x7D ; right curly brace "}"

      ; Any UTF-8 [RFC3629] encoded Unicode [Unicode] character
      UTF8    = UTF1 / UTFMB
      UTFMB   = UTF2 / UTF3 / UTF4
      UTF0    = %x80-BF
      UTF1    = %x00-7F
      UTF2    = %xC2-DF UTF0
      UTF3    = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
                %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
      UTF4    = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
                %xF4 %x80-8F 2(UTF0)

      OCTET   = %x00-FF ; Any octet (8-bit data unit)

   Object identifiers (OIDs) [X.680] are represented in LDAP using a
   dot-decimal format conforming to the ABNF:

      numericoid = number 1*( DOT number )

   Short names, also known as descriptors, are used as more readable
   aliases for object identifiers.  Short names are case insensitive and
   conform to the ABNF:

      descr = keystring







Zeilenga                    Standards Track                     [Page 5]

RFC 4512                      LDAP Models                      June 2006


   Where either an object identifier or a short name may be specified,
   the following production is used:

      oid = descr / numericoid

   While the <descr> form is generally preferred when the usage is
   restricted to short names referring to object identifiers that
   identify like kinds of objects (e.g., attribute type descriptions,
   matching rule descriptions, object class descriptions), the
   <numericoid> form should be used when the object identifiers may
   identify multiple kinds of objects or when an unambiguous short name
   (descriptor) is not available.

   Implementations SHOULD treat short names (descriptors) used in an
   ambiguous manner (as discussed above) as unrecognized.

   Short Names (descriptors) are discussed further in Section 6.2.

2.  Model of Directory User Information

   As [X.501] states:

      The purpose of the Directory is to hold, and provide access to,
      information about objects of interest (objects) in some 'world'.
      An object can be anything which is identifiable (can be named).

      An object class is an identified family of objects, or conceivable
      objects, which share certain characteristics.  Every object
      belongs to at least one class.  An object class may be a subclass
      of other object classes, in which case the members of the former
      class, the subclass, are also considered to be members of the
      latter classes, the superclasses.  There may be subclasses of
      subclasses, etc., to an arbitrary depth.

   A directory entry, a named collection of information, is the basic
   unit of information held in the Directory.  There are multiple kinds
   of directory entries.

   An object entry represents a particular object.  An alias entry
   provides alternative naming.  A subentry holds administrative and/or
   operational information.

   The set of entries representing the DIB are organized hierarchically
   in a tree structure known as the Directory Information Tree (DIT).

   Section 2.1 describes the Directory Information Tree.
   Section 2.2 discusses the structure of entries.
   Section 2.3 discusses naming of entries.



Zeilenga                    Standards Track                     [Page 6]

RFC 4512                      LDAP Models                      June 2006


   Section 2.4 discusses object classes.
   Section 2.5 discusses attribute descriptions.
   Section 2.6 discusses alias entries.

2.1.  The Directory Information Tree

   As noted above, the DIB is composed of a set of entries organized
   hierarchically in a tree structure known as the Directory Information
   Tree (DIT); specifically, a tree where vertices are the entries.

   The arcs between vertices define relations between entries.  If an
   arc exists from X to Y, then the entry at X is the immediate superior
   of Y, and Y is the immediate subordinate of X.  An entry's superiors
   are the entry's immediate superior and its superiors.  An entry's
   subordinates are all of its immediate subordinates and their
   subordinates.

   Similarly, the superior/subordinate relationship between object
   entries can be used to derive a relation between the objects they
   represent.  DIT structure rules can be used to govern relationships
   between objects.

   Note: An entry's immediate superior is also known as the entry's
         parent, and an entry's immediate subordinate is also known as
         the entry's child.  Entries that have the same parent are known
         as siblings.

2.2.  Structure of an Entry

   An entry consists of a set of attributes that hold information about
   the object that the entry represents.  Some attributes represent user
   information and are called user attributes.  Other attributes
   represent operational and/or administrative information and are
   called operational attributes.

   An attribute is an attribute description (a type and zero or more
   options) with one or more associated values.  An attribute is often
   referred to by its attribute description.  For example, the
   'givenName' attribute is the attribute that consists of the attribute
   description 'givenName' (the 'givenName' attribute type [RFC4519] and
   zero options) and one or more associated values.

   The attribute type governs whether the attribute can have multiple
   values, the syntax and matching rules used to construct and compare
   values of that attribute, and other functions.  Options indicate
   subtypes and other functions.

   Attribute values conform to the defined syntax of the attribute type.



Zeilenga                    Standards Track                     [Page 7]

RFC 4512                      LDAP Models                      June 2006


   No two values of an attribute may be equivalent.  Two values are
   considered equivalent if and only if they would match according to
   the equality matching rule of the attribute type.  Or, if the
   attribute type is defined with no equality matching rule, two values
   are equivalent if and only if they are identical.  (See 2.5.1 for
   other restrictions.)

   For example, a 'givenName' attribute can have more than one value,
   they must be Directory Strings, and they are case insensitive.  A
   'givenName' attribute cannot hold both "John" and "JOHN", as these
   are equivalent values per the equality matching rule of the attribute
   type.

   Additionally, no attribute is to have a value that is not equivalent
   to itself.  For example, the 'givenName' attribute cannot have as a
   value a directory string that includes the REPLACEMENT CHARACTER
   (U+FFFD) code point, as matching involving that directory string is
   Undefined per this attribute's equality matching rule.

   When an attribute is used for naming of the entry, one and only one
   value of the attribute is used in forming the Relative Distinguished
   Name.  This value is known as a distinguished value.

2.3.  Naming of Entries

2.3.1.  Relative Distinguished Names

   Each entry is named relative to its immediate superior.  This
   relative name, known as its Relative Distinguished Name (RDN)
   [X.501], is composed of an unordered set of one or more attribute
   value assertions (AVA) consisting of an attribute description with
   zero options and an attribute value.  These AVAs are chosen to match
   attribute values (each a distinguished value) of the entry.

   An entry's relative distinguished name must be unique among all
   immediate subordinates of the entry's immediate superior (i.e., all
   siblings).

   The following are examples of string representations of RDNs
   [RFC4514]:

      UID=12345
      OU=Engineering
      CN=Kurt Zeilenga+L=Redwood Shores

   The last is an example of a multi-valued RDN; that is, an RDN
   composed of multiple AVAs.




Zeilenga                    Standards Track                     [Page 8]

RFC 4512                      LDAP Models                      June 2006


2.3.2.  Distinguished Names

   An entry's fully qualified name, known as its Distinguished Name (DN)
   [X.501], is the concatenation of its RDN and its immediate superior's
   DN.  A Distinguished Name unambiguously refers to an entry in the
   tree.  The following are examples of string representations of DNs
   [RFC4514]:

      UID=nobody@example.com,DC=example,DC=com
      CN=John Smith,OU=Sales,O=ACME Limited,L=Moab,ST=Utah,C=US

2.3.3.  Alias Names

   An alias, or alias name, is "an name for an object, provided by the
   use of alias entries" [X.501].  Alias entries are described in
   Section 2.6.

2.4.  Object Classes

   An object class is "an identified family of objects (or conceivable
   objects) that share certain characteristics" [X.501].

   As defined in [X.501]:

      Object classes are used in the Directory for a number of purposes:

        - describing and categorizing objects and the entries that
          correspond to these objects;

        - where appropriate, controlling the operation of the Directory;

        - regulating, in conjunction with DIT structure rule
          specifications, the position of entries in the DIT;

        - regulating, in conjunction with DIT content rule
          specifications, the attributes that are contained in entries;

        - identifying classes of entry that are to be associated with a
          particular policy by the appropriate administrative authority.

      An object class (a subclass) may be derived from an object class
      (its direct superclass) which is itself derived from an even more
      generic object class.  For structural object classes, this process
      stops at the most generic object class, 'top' (defined in Section
      2.4.1).  An ordered set of superclasses up to the most superior
      object class of an object class is its superclass chain.





Zeilenga                    Standards Track                     [Page 9]

RFC 4512                      LDAP Models                      June 2006


      An object class may be derived from two or more direct
      superclasses (superclasses not part of the same superclass chain).
      This feature of subclassing is termed multiple inheritance.

   Each object class identifies the set of attributes required to be
   present in entries belonging to the class and the set of attributes
   allowed to be present in entries belonging to the class.  As an entry
   of a class must meet the requirements of each class it belongs to, it
   can be said that an object class inherits the sets of allowed and
   required attributes from its superclasses.  A subclass can identify
   an attribute allowed by its superclass as being required.  If an
   attribute is a member of both sets, it is required to be present.

   Each object class is defined to be one of three kinds of object
   classes: Abstract, Structural, or Auxiliary.

   Each object class is identified by an object identifier (OID) and,
   optionally, one or more short names (descriptors).

2.4.1.  Abstract Object Classes

   An abstract object class, as the name implies, provides a base of
   characteristics from which other object classes can be defined to
   inherit from.  An entry cannot belong to an abstract object class
   unless it belongs to a structural or auxiliary class that inherits
   from that abstract class.

   Abstract object classes cannot derive from structural or auxiliary
   object classes.

   All structural object classes derive (directly or indirectly) from
   the 'top' abstract object class.  Auxiliary object classes do not
   necessarily derive from 'top'.

   The following is the object class definition (see Section 4.1.1) for
   the 'top' object class:

      ( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass )

   All entries belong to the 'top' abstract object class.











Zeilenga                    Standards Track                    [Page 10]

RFC 4512                      LDAP Models                      June 2006


2.4.2.  Structural Object Classes

   As stated in [X.501]:

      An object class defined for use in the structural specification of
      the DIT is termed a structural object class.  Structural object
      classes are used in the definition of the structure of the names
      of the objects for compliant entries.

      An object or alias entry is characterized by precisely one
      structural object class superclass chain which has a single
      structural object class as the most subordinate object class.
      This structural object class is referred to as the structural
      object class of the entry.

      Structural object classes are related to associated entries:

        - an entry conforming to a structural object class shall
          represent the real-world object constrained by the object
          class;

        - DIT structure rules only refer to structural object classes;
          the structural object class of an entry is used to specify the
          position of the entry in the DIT;

        - the structural object class of an entry is used, along with an
          associated DIT content rule, to control the content of an
          entry.

      The structural object class of an entry shall not be changed.

   Each structural object class is a (direct or indirect) subclass of
   the 'top' abstract object class.

   Structural object classes cannot subclass auxiliary object classes.

   Each entry is said to belong to its structural object class as well
   as all classes in its structural object class's superclass chain.

2.4.3.  Auxiliary Object Classes

   Auxiliary object classes are used to augment the characteristics of
   entries.  They are commonly used to augment the sets of attributes
   required and allowed to be present in an entry.  They can be used to
   describe entries or classes of entries.

   Auxiliary object classes cannot subclass structural object classes.




Zeilenga                    Standards Track                    [Page 11]

RFC 4512                      LDAP Models                      June 2006


   An entry can belong to any subset of the set of auxiliary object
   classes allowed by the DIT content rule associated with the
   structural object class of the entry.  If no DIT content rule is
   associated with the structural object class of the entry, the entry
   cannot belong to any auxiliary object class.

   The set of auxiliary object classes that an entry belongs to can
   change over time.

2.5.  Attribute Descriptions

   An attribute description is composed of an attribute type (see
   Section 2.5.1) and a set of zero or more attribute options (see
   Section 2.5.2).

   An attribute description is represented by the ABNF:

      attributedescription = attributetype options
      attributetype = oid
      options = *( SEMI option )
      option = 1*keychar

   where <attributetype> identifies the attribute type and each <option>
   identifies an attribute option.  Both <attributetype> and <option>
   productions are case insensitive.  The order in which <option>s
   appear is irrelevant.  That is, any two <attributedescription>s that
   consist of the same <attributetype> and same set of <option>s are
   equivalent.

   Examples of valid attribute descriptions:

      2.5.4.0
      cn;lang-de;lang-en
      owner

   An attribute description with an unrecognized attribute type is to be
   treated as unrecognized.  Servers SHALL treat an attribute
   description with an unrecognized attribute option as unrecognized.
   Clients MAY treat an unrecognized attribute option as a tagging
   option (see Section 2.5.2.1).

   All attributes of an entry must have distinct attribute descriptions.

2.5.1.  Attribute Types

   An attribute type governs whether the attribute can have multiple
   values, the syntax and matching rules used to construct and compare
   values of that attribute, and other functions.



Zeilenga                    Standards Track                    [Page 12]

RFC 4512                      LDAP Models                      June 2006


   If no equality matching is specified for the attribute type:

      - the attribute (of the type) cannot be used for naming;
      - when adding the attribute (or replacing all values), no two
        values may be equivalent (see 2.2);
      - individual values of a multi-valued attribute are not to be
        independently added or deleted;
      - attribute value assertions (such as matching in search filters
        and comparisons) using values of such a type cannot be
        performed.

   Otherwise, the specified equality matching rule is to be used to
   evaluate attribute value assertions concerning the attribute type.
   The specified equality rule is to be transitive and commutative.

   The attribute type indicates whether the attribute is a user
   attribute or an operational attribute.  If operational, the attribute
   type indicates the operational usage and whether or not the attribute
   is modifiable by users.  Operational attributes are discussed in
   Section 3.4.

   An attribute type (a subtype) may derive from a more generic
   attribute type (a direct supertype).  The following restrictions
   apply to subtyping:

      - a subtype must have the same usage as its direct supertype,
      - a subtype's syntax must be the same, or a refinement of, its
        supertype's syntax, and
      - a subtype must be collective [RFC3671] if its supertype is
        collective.

   An attribute description consisting of a subtype and no options is
   said to be the direct description subtype of the attribute
   description consisting of the subtype's direct supertype and no
   options.

   Each attribute type is identified by an object identifier (OID) and,
   optionally, one or more short names (descriptors).

2.5.2.  Attribute Options

   There are multiple kinds of attribute description options.  The LDAP
   technical specification details one kind: tagging options.

   Not all options can be associated with attributes held in the
   directory.  Tagging options can be.





Zeilenga                    Standards Track                    [Page 13]

RFC 4512                      LDAP Models                      June 2006


   Not all options can be used in conjunction with all attribute types.
   In such cases, the attribute description is to be treated as
   unrecognized.

   An attribute description that contains mutually exclusive options
   shall be treated as unrecognized.  That is, "cn;x-bar;x-foo", where
   "x-foo" and "x-bar" are mutually exclusive, is to be treated as
   unrecognized.

   Other kinds of options may be specified in future documents.  These
   documents must detail how new kinds of options they define relate to
   tagging options.  In particular, these documents must detail whether
   or not new kinds of options can be associated with attributes held in
   the directory, how new kinds of options affect transfer of attribute
   values, and how new kinds of options are treated in attribute
   description hierarchies.

   Options are represented as short, case-insensitive textual strings
   conforming to the <option> production defined in Section 2.5 of this
   document.

   Procedures for registering options are detailed in BCP 64, RFC 4520
   [RFC4520].

2.5.2.1.  Tagging Options

   Attributes held in the directory can have attribute descriptions with
   any number of tagging options.  Tagging options are never mutually
   exclusive.

   An attribute description with N tagging options is a direct
   (description) subtype of all attribute descriptions of the same
   attribute type and all but one of the N options.  If the attribute
   type has a supertype, then the attribute description is also a direct
   (description) subtype of the attribute description of the supertype
   and the N tagging options.  That is, 'cn;lang-de;lang-en' is a direct
   (description) subtype of 'cn;lang-de', 'cn;lang-en', and
   'name;lang-de;lang-en' ('cn' is a subtype of 'name'; both are defined
   in [RFC4519]).

2.5.3.  Attribute Description Hierarchies

   An attribute description can be the direct subtype of zero or more
   other attribute descriptions as indicated by attribute type subtyping
   (as described in Section 2.5.1) or attribute tagging option subtyping
   (as described in Section 2.5.2.1).  These subtyping relationships are
   used to form hierarchies of attribute descriptions and attributes.




Zeilenga                    Standards Track                    [Page 14]

RFC 4512                      LDAP Models                      June 2006


   As adapted from [X.501]:

      Attribute hierarchies allow access to the DIB with varying degrees
      of granularity.  This is achieved by allowing the value components
      of attributes to be accessed by using either their specific
      attribute description (a direct reference to the attribute) or a
      more generic attribute description (an indirect reference).

      Semantically related attributes may be placed in a hierarchical
      relationship, the more specialized being placed subordinate to the
      more generalized.  Searching for or retrieving attributes and
      their values is made easier by quoting the more generalized
      attribute description; a filter item so specified is evaluated for
      the more specialized descriptions as well as for the quoted
      description.

      Where subordinate specialized descriptions are selected to be
      returned as part of a search result these descriptions shall be
      returned if available.  Where the more general descriptions are
      selected to be returned as part of a search result both the
      general and the specialized descriptions shall be returned, if
      available.  An attribute value shall always be returned as a value
      of its own attribute description.

      All of the attribute descriptions in an attribute hierarchy are
      treated as distinct and unrelated descriptions for user
      modification of entry content.

      An attribute value stored in an object or alias entry is of
      precisely one attribute description.  The description is indicated
      when the value is originally added to the entry.

   For the purpose of subschema administration of the entry, a
   specification that an attribute is required is fulfilled if the entry
   contains a value of an attribute description belonging to an
   attribute hierarchy where the attribute type of that description is
   the same as the required attribute's type.  That is, a "MUST name"
   specification is fulfilled by 'name' or 'name;x-tag-option', but is
   not fulfilled by 'CN' or 'CN;x-tag-option' (even though 'CN' is a
   subtype of 'name').  Likewise, an entry may contain a value of an
   attribute description belonging to an attribute hierarchy where the
   attribute type of that description is either explicitly included in
   the definition of an object class to which the entry belongs or
   allowed by the DIT content rule applicable to that entry.  That is,
   'name' and 'name;x-tag-option' are allowed by "MAY name" (or by "MUST
   name"), but 'CN' and 'CN;x-tag-option' are not allowed by "MAY name"
   (or by "MUST name").




Zeilenga                    Standards Track                    [Page 15]

RFC 4512                      LDAP Models                      June 2006


   For the purposes of other policy administration, unless stated
   otherwise in the specification of the particular administrative
   model, all of the attribute descriptions in an attribute hierarchy
   are treated as distinct and unrelated descriptions.

2.6.  Alias Entries

   As adapted from [X.501]:

      An alias, or an alias name, for an object is an alternative name
      for an object or object entry which is provided by the use of
      alias entries.

      Each alias entry contains, within the 'aliasedObjectName'
      attribute (known as the 'aliasedEntryName' attribute in X.500), a
      name of some object.  The distinguished name of the alias entry is
      thus also a name for this object.

          NOTE - The name within the 'aliasedObjectName' is said to be
                 pointed to by the alias.  It does not have to be the
                 distinguished name of any entry.

      The conversion of an alias name to an object name is termed
      (alias) dereferencing and comprises the systematic replacement of
      alias names, where found within a purported name, by the value of
      the corresponding 'aliasedObjectName' attribute.  The process may
      require the examination of more than one alias entry.

      Any particular entry in the DIT may have zero or more alias names.
      It therefore follows that several alias entries may point to the
      same entry.  An alias entry may point to an entry that is not a
      leaf entry and may point to another alias entry.

      An alias entry shall have no subordinates, so that an alias entry
      is always a leaf entry.

      Every alias entry shall belong to the 'alias' object class.

   An entry with the 'alias' object class must also belong to an object
   class (or classes), or be governed by a DIT content rule, which
   allows suitable naming attributes to be present.

   Example:

      dn: cn=bar,dc=example,dc=com
      objectClass: top
      objectClass: alias
      objectClass: extensibleObject



Zeilenga                    Standards Track                    [Page 16]

RFC 4512                      LDAP Models                      June 2006


      cn: bar
      aliasedObjectName: cn=foo,dc=example,dc=com

2.6.1.  'alias' Object Class

   Alias entries belong to the 'alias' object class.

      ( 2.5.6.1 NAME 'alias'
        SUP top STRUCTURAL
        MUST aliasedObjectName )

2.6.2.  'aliasedObjectName' Attribute Type

   The 'aliasedObjectName' attribute holds the name of the entry an
   alias points to.  The 'aliasedObjectName' attribute is known as the
   'aliasedEntryName' attribute in X.500.

      ( 2.5.4.1 NAME 'aliasedObjectName'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
        SINGLE-VALUE )

   The 'distinguishedNameMatch' matching rule and the DistinguishedName
   (1.3.6.1.4.1.1466.115.121.1.12) syntax are defined in [RFC4517].

3.  Directory Administrative and Operational Information

   This section discusses select aspects of the X.500 Directory
   Administrative and Operational Information model [X.501].  LDAP
   implementations MAY support other aspects of this model.

3.1.  Subtrees

   As defined in [X.501]:

      A subtree is a collection of object and alias entries situated at
      the vertices of a tree.  Subtrees do not contain subentries.  The
      prefix sub, in subtree, emphasizes that the base (or root) vertex
      of this tree is usually subordinate to the root of the DIT.

      A subtree begins at some vertex and extends to some identifiable
      lower boundary, possibly extending to leaves.  A subtree is always
      defined within a context which implicitly bounds the subtree.  For
      example, the vertex and lower boundaries of a subtree defining a
      replicated area are bounded by a naming context.






Zeilenga                    Standards Track                    [Page 17]

RFC 4512                      LDAP Models                      June 2006


3.2.  Subentries

   A subentry is a "special sort of entry, known by the Directory, used
   to hold information associated with a subtree or subtree refinement"
   [X.501].  Subentries are used in Directory to hold for administrative
   and operational purposes as defined in [X.501].  Their use in LDAP is
   detailed in [RFC3672].

   The term "(sub)entry" in this specification indicates that servers
   implementing X.500(93) models are, in accordance with X.500(93) as
   described in [RFC3672], to use a subentry and that other servers are
   to use an object entry belonging to the appropriate auxiliary class
   normally used with the subentry (e.g., 'subschema' for subschema
   subentries) to mimic the subentry.  This object entry's RDN SHALL be
   formed from a value of the 'cn' (commonName) attribute [RFC4519] (as
   all subentries are named with 'cn').

3.3.  The 'objectClass' attribute

   Each entry in the DIT has an 'objectClass' attribute.

      ( 2.5.4.0 NAME 'objectClass'
        EQUALITY objectIdentifierMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )

   The 'objectIdentifierMatch' matching rule and the OBJECT IDENTIFIER
   (1.3.6.1.4.1.1466.115.121.1.38) syntax are defined in [RFC4517].

   The 'objectClass' attribute specifies the object classes of an entry,
   which (among other things) are used in conjunction with the
   controlling schema to determine the permitted attributes of an entry.
   Values of this attribute can be modified by clients, but the
   'objectClass' attribute cannot be removed.

   Servers that follow X.500(93) models SHALL restrict modifications of
   this attribute to prevent the basic structural class of the entry
   from being changed.  That is, one cannot change a 'person' into a
   'country'.

   When creating an entry or adding an 'objectClass' value to an entry,
   all superclasses of the named classes SHALL be implicitly added as
   well if not already present.  That is, if the auxiliary class 'x-a'
   is a subclass of the class 'x-b', adding 'x-a' to 'objectClass'
   causes 'x-b' to be implicitly added (if is not already present).

   Servers SHALL restrict modifications of this attribute to prevent
   superclasses of remaining 'objectClass' values from being deleted.
   That is, if the auxiliary class 'x-a' is a subclass of the auxiliary



Zeilenga                    Standards Track                    [Page 18]

RFC 4512                      LDAP Models                      June 2006


   class 'x-b' and the 'objectClass' attribute contains 'x-a' and 'x-b',
   an attempt to delete only 'x-b' from the 'objectClass' attribute is
   an error.

3.4.  Operational Attributes

   Some attributes, termed operational attributes, are used or
   maintained by servers for administrative and operational purposes.
   As stated in [X.501]: "There are three varieties of operational
   attributes:  Directory operational attributes, DSA-shared operational
   attributes, and DSA-specific operational attributes".

   A directory operational attribute is used to represent operational
   and/or administrative information in the Directory Information Model.
   This includes operational attributes maintained by the server (e.g.,
   'createTimestamp') as well as operational attributes that hold values
   administrated by the user (e.g., 'ditContentRules').

   A DSA-shared operational attribute is used to represent information
   of the DSA Information Model that is shared between DSAs.

   A DSA-specific operational attribute is used to represent information
   of the DSA Information Model that is specific to the DSA (though, in
   some cases, may be derived from information shared between DSAs;
   e.g., 'namingContexts').

   The DSA Information Model operational attributes are detailed in
   [X.501].

   Operational attributes are not normally visible.  They are not
   returned in search results unless explicitly requested by name.

   Not all operational attributes are user modifiable.

   Entries may contain, among others, the following operational
   attributes:

      - creatorsName: the Distinguished Name of the user who added this
          entry to the directory,

      - createTimestamp: the time this entry was added to the directory,

      - modifiersName: the Distinguished Name of the user who last
          modified this entry, and

      - modifyTimestamp: the time this entry was last modified.





Zeilenga                    Standards Track                    [Page 19]

RFC 4512                      LDAP Models                      June 2006


   Servers SHOULD maintain the 'creatorsName', 'createTimestamp',
   'modifiersName', and 'modifyTimestamp' attributes for all entries of
   the DIT.

3.4.1.  'creatorsName'

   This attribute appears in entries that were added using the protocol
   (e.g., using the Add operation).  The value is the distinguished name
   of the creator.

      ( 2.5.18.3 NAME 'creatorsName'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
        SINGLE-VALUE NO-USER-MODIFICATION
        USAGE directoryOperation )

   The 'distinguishedNameMatch' matching rule and the DistinguishedName
   (1.3.6.1.4.1.1466.115.121.1.12) syntax are defined in [RFC4517].

3.4.2.  'createTimestamp'

   This attribute appears in entries that were added using the protocol
   (e.g., using the Add operation).  The value is the time the entry was
   added.

      ( 2.5.18.1 NAME 'createTimestamp'
        EQUALITY generalizedTimeMatch
        ORDERING generalizedTimeOrderingMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
        SINGLE-VALUE NO-USER-MODIFICATION
        USAGE directoryOperation )

   The 'generalizedTimeMatch' and 'generalizedTimeOrderingMatch'
   matching rules and the GeneralizedTime
   (1.3.6.1.4.1.1466.115.121.1.24) syntax are defined in [RFC4517].

3.4.3.  'modifiersName'

   This attribute appears in entries that have been modified using the
   protocol (e.g., using the Modify operation).  The value is the
   distinguished name of the last modifier.

      ( 2.5.18.4 NAME 'modifiersName'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
        SINGLE-VALUE NO-USER-MODIFICATION
        USAGE directoryOperation )




Zeilenga                    Standards Track                    [Page 20]

RFC 4512                      LDAP Models                      June 2006


   The 'distinguishedNameMatch' matching rule and the DistinguishedName
   (1.3.6.1.4.1.1466.115.121.1.12) syntax are defined in [RFC4517].

3.4.4.  'modifyTimestamp'

   This attribute appears in entries that have been modified using the
   protocol (e.g., using the Modify operation).  The value is the time
   the entry was last modified.

      ( 2.5.18.2 NAME 'modifyTimestamp'
        EQUALITY generalizedTimeMatch
        ORDERING generalizedTimeOrderingMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
        SINGLE-VALUE NO-USER-MODIFICATION
        USAGE directoryOperation )

   The 'generalizedTimeMatch' and 'generalizedTimeOrderingMatch'
   matching rules and the GeneralizedTime
   (1.3.6.1.4.1.1466.115.121.1.24) syntax are defined in [RFC4517].

3.4.5.  'structuralObjectClass'

   This attribute indicates the structural object class of the entry.

      ( 2.5.21.9 NAME 'structuralObjectClass'
        EQUALITY objectIdentifierMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
        SINGLE-VALUE NO-USER-MODIFICATION
        USAGE directoryOperation )

   The 'objectIdentifierMatch' matching rule and OBJECT IDENTIFIER
   (1.3.6.1.4.1.1466.115.121.1.38) syntax is defined in [RFC4517].

3.4.6.  'governingStructureRule'

   This attribute indicates the structure rule governing the entry.

      ( 2.5.21.10 NAME 'governingStructureRule'
        EQUALITY integerMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
        SINGLE-VALUE NO-USER-MODIFICATION
        USAGE directoryOperation )

   The 'integerMatch' matching rule and INTEGER
   (1.3.6.1.4.1.1466.115.121.1.27) syntax is defined in [RFC4517].






Zeilenga                    Standards Track                    [Page 21]

RFC 4512                      LDAP Models                      June 2006


4.  Directory Schema

   As defined in [X.501]:

      The Directory Schema is a set of definitions and constraints
      concerning the structure of the DIT, the possible ways entries are
      named, the information that can be held in an entry, the
      attributes used to represent that information and their
      organization into hierarchies to facilitate search and retrieval
      of the information and the ways in which values of attributes may
      be matched in attribute value and matching rule assertions.

      NOTE 1 - The schema enables the Directory system to, for example:

      - prevent the creation of subordinate entries of the wrong
        object-class (e.g., a country as a subordinate of a person);

      - prevent the addition of attribute-types to an entry
        inappropriate to the object-class (e.g., a serial number to a
        person's entry);

      - prevent the addition of an attribute value of a syntax not
        matching that defined for the attribute-type (e.g., a printable
        string to a bit string).

      Formally, the Directory Schema comprises a set of:

      a) Name Form definitions that define primitive naming relations
         for structural object classes;

      b) DIT Structure Rule definitions that define the names that
         entries may have and the ways in which the entries may be
         related to one another in the DIT;

      c) DIT Content Rule definitions that extend the specification of
         allowable attributes for entries beyond those indicated by the
         structural object classes of the entries;

      d) Object Class definitions that define the basic set of mandatory
         and optional attributes that shall be present, and may be
         present, respectively, in an entry of a given class, and which
         indicate the kind of object class that is being defined;









Zeilenga                    Standards Track                    [Page 22]

RFC 4512                      LDAP Models                      June 2006


      e) Attribute Type definitions that identify the object identifier
         by which an attribute is known, its syntax, associated matching
         rules, whether it is an operational attribute and if so its
         type, whether it is a collective attribute, whether it is
         permitted to have multiple values and whether or not it is
         derived from another attribute type;

      f) Matching Rule definitions that define matching rules.

      And in LDAP:

      g) LDAP Syntax definitions that define encodings used in LDAP.

4.1.  Schema Definitions

   Schema definitions in this section are described using ABNF and rely
   on the common productions specified in Section 1.2 as well as these:

      noidlen = numericoid [ LCURLY len RCURLY ]
      len = number

      oids = oid / ( LPAREN WSP oidlist WSP RPAREN )
      oidlist = oid *( WSP DOLLAR WSP oid )

      extensions = *( SP xstring SP qdstrings )
      xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE )

      qdescrs = qdescr / ( LPAREN WSP qdescrlist WSP RPAREN )
      qdescrlist = [ qdescr *( SP qdescr ) ]
      qdescr = SQUOTE descr SQUOTE

      qdstrings = qdstring / ( LPAREN WSP qdstringlist WSP RPAREN )
      qdstringlist = [ qdstring *( SP qdstring ) ]
      qdstring = SQUOTE dstring SQUOTE
      dstring = 1*( QS / QQ / QUTF8 )   ; escaped UTF-8 string

      QQ =  ESC %x32 %x37 ; "\27"
      QS =  ESC %x35 ( %x43 / %x63 ) ; "\5C" / "\5c"

      ; Any UTF-8 encoded Unicode character
      ; except %x27 ("\'") and %x5C ("\")
      QUTF8    = QUTF1 / UTFMB

      ; Any ASCII character except %x27 ("\'") and %x5C ("\")
      QUTF1    = %x00-26 / %x28-5B / %x5D-7F

   Schema definitions in this section also share a number of common
   terms.



Zeilenga                    Standards Track                    [Page 23]

RFC 4512                      LDAP Models                      June 2006


   The NAME field provides a set of short names (descriptors) that are
   to be used as aliases for the OID.

   The DESC field optionally allows a descriptive string to be provided
   by the directory administrator and/or implementor.  While
   specifications may suggest a descriptive string, there is no
   requirement that the suggested (or any) descriptive string be used.

   The OBSOLETE field, if present, indicates the element is not active.

   Implementors should note that future versions of this document may
   expand these definitions to include additional terms.  Terms whose
   identifier begins with "X-" are reserved for private experiments and
   are followed by <SP> and <qdstrings> tokens.

4.1.1.  Object Class Definitions

   Object Class definitions are written according to the ABNF:

     ObjectClassDescription = LPAREN WSP
         numericoid                 ; object identifier
         [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
         [ SP "DESC" SP qdstring ]  ; description
         [ SP "OBSOLETE" ]          ; not active
         [ SP "SUP" SP oids ]       ; superior object classes
         [ SP kind ]                ; kind of class
         [ SP "MUST" SP oids ]      ; attribute types
         [ SP "MAY" SP oids ]       ; attribute types
         extensions WSP RPAREN

     kind = "ABSTRACT" / "STRUCTURAL" / "AUXILIARY"

   where:
     <numericoid> is object identifier assigned to this object class;
     NAME <qdescrs> are short names (descriptors) identifying this
         object class;
     DESC <qdstring> is a short descriptive string;
     OBSOLETE indicates this object class is not active;
     SUP <oids> specifies the direct superclasses of this object class;
     the kind of object class is indicated by one of ABSTRACT,
         STRUCTURAL, or AUXILIARY (the default is STRUCTURAL);
     MUST and MAY specify the sets of required and allowed attribute
         types, respectively; and
     <extensions> describe extensions.







Zeilenga                    Standards Track                    [Page 24]

RFC 4512                      LDAP Models                      June 2006


4.1.2.  Attribute Types

   Attribute Type definitions are written according to the ABNF:

     AttributeTypeDescription = LPAREN WSP
         numericoid                    ; object identifier
         [ SP "NAME" SP qdescrs ]      ; short names (descriptors)
         [ SP "DESC" SP qdstring ]     ; description
         [ SP "OBSOLETE" ]             ; not active
         [ SP "SUP" SP oid ]           ; supertype
         [ SP "EQUALITY" SP oid ]      ; equality matching rule
         [ SP "ORDERING" SP oid ]      ; ordering matching rule
         [ SP "SUBSTR" SP oid ]        ; substrings matching rule
         [ SP "SYNTAX" SP noidlen ]    ; value syntax
         [ SP "SINGLE-VALUE" ]         ; single-value
         [ SP "COLLECTIVE" ]           ; collective
         [ SP "NO-USER-MODIFICATION" ] ; not user modifiable
         [ SP "USAGE" SP usage ]       ; usage
         extensions WSP RPAREN         ; extensions

     usage = "userApplications"     /  ; user
             "directoryOperation"   /  ; directory operational
             "distributedOperation" /  ; DSA-shared operational
             "dSAOperation"            ; DSA-specific operational

   where:
     <numericoid> is object identifier assigned to this attribute type;
     NAME <qdescrs> are short names (descriptors) identifying this
         attribute type;
     DESC <qdstring> is a short descriptive string;
     OBSOLETE indicates this attribute type is not active;
     SUP oid specifies the direct supertype of this type;
     EQUALITY, ORDERING, and SUBSTR provide the oid of the equality,
         ordering, and substrings matching rules, respectively;
     SYNTAX identifies value syntax by object identifier and may suggest
         a minimum upper bound;
     SINGLE-VALUE indicates attributes of this type are restricted to a
         single value;
     COLLECTIVE indicates this attribute type is collective
         [X.501][RFC3671];
     NO-USER-MODIFICATION indicates this attribute type is not user
         modifiable;
     USAGE indicates the application of this attribute type; and
     <extensions> describe extensions.

   Each attribute type description must contain at least one of the SUP
   or SYNTAX fields.  If no SYNTAX field is provided, the attribute type
   description takes its value from the supertype.



Zeilenga                    Standards Track                    [Page 25]

RFC 4512                      LDAP Models                      June 2006


   If SUP field is provided, the EQUALITY, ORDERING, and SUBSTRING
   fields, if not specified, take their value from the supertype.

   Usage of userApplications, the default, indicates that attributes of
   this type represent user information.  That is, they are user
   attributes.

   A usage of directoryOperation, distributedOperation, or dSAOperation
   indicates that attributes of this type represent operational and/or
   administrative information.  That is, they are operational
   attributes.

   directoryOperation usage indicates that the attribute of this type is
   a directory operational attribute.  distributedOperation usage
   indicates that the attribute of this type is a DSA-shared usage
   operational attribute.  dSAOperation usage indicates that the
   attribute of this type is a DSA-specific operational attribute.

   COLLECTIVE requires usage userApplications.  Use of collective
   attribute types in LDAP is discussed in [RFC3671].

   NO-USER-MODIFICATION requires an operational usage.

   Note that the <AttributeTypeDescription> does not list the matching
   rules that can be used with that attribute type in an extensibleMatch
   search filter [RFC4511].  This is done using the 'matchingRuleUse'
   attribute described in Section 4.1.4.

   This document refines the schema description of X.501 by requiring
   that the SYNTAX field in an <AttributeTypeDescription> be a string
   representation of an object identifier for the LDAP string syntax
   definition, with an optional indication of the suggested minimum
   bound of a value of this attribute.

   A suggested minimum upper bound on the number of characters in a
   value with a string-based syntax, or the number of bytes in a value
   for all other syntaxes, may be indicated by appending this bound
   count inside of curly braces following the syntax's OBJECT IDENTIFIER
   in an Attribute Type Description.  This bound is not part of the
   syntax name itself.  For instance, "1.3.6.4.1.1466.0{64}" suggests
   that server implementations should allow a string to be 64 characters
   long, although they may allow longer strings.  Note that a single
   character of the Directory String syntax may be encoded in more than
   one octet since UTF-8 [RFC3629] is a variable-length encoding.







Zeilenga                    Standards Track                    [Page 26]

RFC 4512                      LDAP Models                      June 2006


4.1.3.  Matching Rules

   Matching rules are used in performance of attribute value assertions,
   such as in performance of a Compare operation.  They are also used in
   evaluating search filters, determining which individual values are to
   be added or deleted during performance of a Modify operation, and in
   comparing distinguished names.

   Each matching rule is identified by an object identifier (OID) and,
   optionally, one or more short names (descriptors).

   Matching rule definitions are written according to the ABNF:

     MatchingRuleDescription = LPAREN WSP
         numericoid                 ; object identifier
         [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
         [ SP "DESC" SP qdstring ]  ; description
         [ SP "OBSOLETE" ]          ; not active
         SP "SYNTAX" SP numericoid  ; assertion syntax
         extensions WSP RPAREN      ; extensions

   where:
     <numericoid> is object identifier assigned to this matching rule;
     NAME <qdescrs> are short names (descriptors) identifying this
         matching rule;
     DESC <qdstring> is a short descriptive string;
     OBSOLETE indicates this matching rule is not active;
     SYNTAX identifies the assertion syntax (the syntax of the assertion
         value) by object identifier; and
     <extensions> describe extensions.

4.1.4.  Matching Rule Uses

   A matching rule use lists the attribute types that are suitable for
   use with an extensibleMatch search filter.

   Matching rule use descriptions are written according to the following
   ABNF:

     MatchingRuleUseDescription = LPAREN WSP
         numericoid                 ; object identifier
         [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
         [ SP "DESC" SP qdstring ]  ; description
         [ SP "OBSOLETE" ]          ; not active
         SP "APPLIES" SP oids       ; attribute types
         extensions WSP RPAREN      ; extensions





Zeilenga                    Standards Track                    [Page 27]

RFC 4512                      LDAP Models                      June 2006


   where:
     <numericoid> is the object identifier of the matching rule
         associated with this matching rule use description;
     NAME <qdescrs> are short names (descriptors) identifying this
         matching rule use;
     DESC <qdstring> is a short descriptive string;
     OBSOLETE indicates this matching rule use is not active;
     APPLIES provides a list of attribute types the matching rule
         applies to; and
     <extensions> describe extensions.

4.1.5.  LDAP Syntaxes

   LDAP Syntaxes of (attribute and assertion) values are described in
   terms of ASN.1 [X.680] and, optionally, have an octet string encoding
   known as the LDAP-specific encoding.  Commonly, the LDAP-specific
   encoding is constrained to a string of Unicode [Unicode] characters
   in UTF-8 [RFC3629] form.

   Each LDAP syntax is identified by an object identifier (OID).

   LDAP syntax definitions are written according to the ABNF:

     SyntaxDescription = LPAREN WSP
         numericoid                 ; object identifier
         [ SP "DESC" SP qdstring ]  ; description
         extensions WSP RPAREN      ; extensions

   where:
     <numericoid> is the object identifier assigned to this LDAP syntax;
     DESC <qdstring> is a short descriptive string; and
     <extensions> describe extensions.

4.1.6.  DIT Content Rules

   A DIT content rule is a "rule governing the content of entries of a
   particular structural object class" [X.501].

   For DIT entries of a particular structural object class, a DIT
   content rule specifies which auxiliary object classes the entries are
   allowed to belong to and which additional attributes (by type) are
   required, allowed, or not allowed to appear in the entries.

   The list of precluded attributes cannot include any attribute listed
   as mandatory in the rule, the structural object class, or any of the
   allowed auxiliary object classes.





Zeilenga                    Standards Track                    [Page 28]

RFC 4512                      LDAP Models                      June 2006


   Each content rule is identified by the object identifier, as well as
   any short names (descriptors), of the structural object class it
   applies to.

   An entry may only belong to auxiliary object classes listed in the
   governing content rule.

   An entry must contain all attributes required by the object classes
   the entry belongs to as well as all attributes required by the
   governing content rule.

   An entry may contain any non-precluded attributes allowed by the
   object classes the entry belongs to as well as all attributes allowed
   by the governing content rule.

   An entry cannot include any attribute precluded by the governing
   content rule.

   An entry is governed by (if present and active in the subschema) the
   DIT content rule that applies to the structural object class of the
   entry (see Section 2.4.2).  If no active rule is present for the
   entry's structural object class, the entry's content is governed by
   the structural object class (and possibly other aspects of user and
   system schema).  DIT content rules for superclasses of the structural
   object class of an entry are not applicable to that entry.

   DIT content rule descriptions are written according to the ABNF:

     DITContentRuleDescription = LPAREN WSP
         numericoid                 ; object identifier
         [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
         [ SP "DESC" SP qdstring ]  ; description
         [ SP "OBSOLETE" ]          ; not active
         [ SP "AUX" SP oids ]       ; auxiliary object classes
         [ SP "MUST" SP oids ]      ; attribute types
         [ SP "MAY" SP oids ]       ; attribute types
         [ SP "NOT" SP oids ]       ; attribute types
         extensions WSP RPAREN      ; extensions

   where:
     <numericoid> is the object identifier of the structural object
         class associated with this DIT content rule;
     NAME <qdescrs> are short names (descriptors) identifying this DIT
         content rule;
     DESC <qdstring> is a short descriptive string;
     OBSOLETE indicates this DIT content rule use is not active;
     AUX specifies a list of auxiliary object classes that entries
         subject to this DIT content rule may belong to;



Zeilenga                    Standards Track                    [Page 29]

RFC 4512                      LDAP Models                      June 2006


     MUST, MAY, and NOT specify lists of attribute types that are
         required, allowed, or precluded, respectively, from appearing
         in entries subject to this DIT content rule; and
     <extensions> describe extensions.

4.1.7.  DIT Structure Rules and Name Forms

   It is sometimes desirable to regulate where object and alias entries
   can be placed in the DIT and how they can be named based upon their
   structural object class.

4.1.7.1.  DIT Structure Rules

   A DIT structure rule is a "rule governing the structure of the DIT by
   specifying a permitted superior to subordinate entry relationship.  A
   structure rule relates a name form, and therefore a structural object
   class, to superior structure rules.  This permits entries of the
   structural object class identified by the name form to exist in the
   DIT as subordinates to entries governed by the indicated superior
   structure rules" [X.501].

   DIT structure rule descriptions are written according to the ABNF:

     DITStructureRuleDescription = LPAREN WSP
         ruleid                     ; rule identifier
         [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
         [ SP "DESC" SP qdstring ]  ; description
         [ SP "OBSOLETE" ]          ; not active
         SP "FORM" SP oid           ; NameForm
         [ SP "SUP" ruleids ]       ; superior rules
         extensions WSP RPAREN      ; extensions

     ruleids = ruleid / ( LPAREN WSP ruleidlist WSP RPAREN )
     ruleidlist = ruleid *( SP ruleid )
     ruleid = number

   where:
     <ruleid> is the rule identifier of this DIT structure rule;
     NAME <qdescrs> are short names (descriptors) identifying this DIT
         structure rule;
     DESC <qdstring> is a short descriptive string;
     OBSOLETE indicates this DIT structure rule use is not active;
     FORM is specifies the name form associated with this DIT structure
         rule;
     SUP identifies superior rules (by rule id); and
     <extensions> describe extensions.





Zeilenga                    Standards Track                    [Page 30]

RFC 4512                      LDAP Models                      June 2006


   If no superior rules are identified, the DIT structure rule applies
   to an autonomous administrative point (e.g., the root vertex of the
   subtree controlled by the subschema) [X.501].

4.1.7.2.  Name Forms

   A name form "specifies a permissible RDN for entries of a particular
   structural object class.  A name form identifies a named object class
   and one or more attribute types to be used for naming (i.e., for the
   RDN).  Name forms are primitive pieces of specification used in the
   definition of DIT structure rules" [X.501].

   Each name form indicates the structural object class to be named, a
   set of required attribute types, and a set of allowed attribute
   types.  A particular attribute type cannot be in both sets.

   Entries governed by the form must be named using a value from each
   required attribute type and zero or more values from the allowed
   attribute types.

   Each name form is identified by an object identifier (OID) and,
   optionally, one or more short names (descriptors).

   Name form descriptions are written according to the ABNF:

     NameFormDescription = LPAREN WSP
         numericoid                 ; object identifier
         [ SP "NAME" SP qdescrs ]   ; short names (descriptors)
         [ SP "DESC" SP qdstring ]  ; description
         [ SP "OBSOLETE" ]          ; not active
         SP "OC" SP oid             ; structural object class
         SP "MUST" SP oids          ; attribute types
         [ SP "MAY" SP oids ]       ; attribute types
         extensions WSP RPAREN      ; extensions

   where:
     <numericoid> is object identifier that identifies this name form;
     NAME <qdescrs> are short names (descriptors) identifying this name
         form;
     DESC <qdstring> is a short descriptive string;
     OBSOLETE indicates this name form is not active;
     OC identifies the structural object class this rule applies to,
     MUST and MAY specify the sets of required and allowed,
         respectively, naming attributes for this name form; and
     <extensions> describe extensions.

   All attribute types in the required ("MUST") and allowed ("MAY")
   lists shall be different.



Zeilenga                    Standards Track                    [Page 31]

RFC 4512                      LDAP Models                      June 2006


4.2.  Subschema Subentries

   Subschema (sub)entries are used for administering information about
   the directory schema.  A single subschema (sub)entry contains all
   schema definitions (see Section 4.1) used by entries in a particular
   part of the directory tree.

   Servers that follow X.500(93) models SHOULD implement subschema using
   the X.500 subschema mechanisms (as detailed in Section 12 of
   [X.501]), so these are not ordinary object entries but subentries
   (see Section 3.2).  LDAP clients SHOULD NOT assume that servers
   implement any of the other aspects of X.500 subschema.

   Servers MAY allow subschema modification.  Procedures for subschema
   modification are discussed in Section 14.5 of [X.501].

   A server that masters entries and permits clients to modify these
   entries SHALL implement and provide access to these subschema
   (sub)entries including providing a 'subschemaSubentry' attribute in
   each modifiable entry.  This is so clients may discover the
   attributes and object classes that are permitted to be present.  It
   is strongly RECOMMENDED that all other servers implement this as
   well.

   The value of the 'subschemaSubentry' attribute is the name of the
   subschema (sub)entry holding the subschema controlling the entry.

      ( 2.5.18.10 NAME 'subschemaSubentry'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
        SINGLE-VALUE NO-USER-MODIFICATION
        USAGE directoryOperation )

   The 'distinguishedNameMatch' matching rule and the DistinguishedName
   (1.3.6.1.4.1.1466.115.121.1.12) syntax are defined in [RFC4517].

   Subschema is held in (sub)entries belonging to the subschema
   auxiliary object class.

      ( 2.5.20.1 NAME 'subschema' AUXILIARY
        MAY ( dITStructureRules $ nameForms $ ditContentRules $
          objectClasses $ attributeTypes $ matchingRules $
          matchingRuleUse ) )

   The 'ldapSyntaxes' operational attribute may also be present in
   subschema entries.





Zeilenga                    Standards Track                    [Page 32]

RFC 4512                      LDAP Models                      June 2006


   Servers MAY provide additional attributes (described in other
   documents) in subschema (sub)entries.

   Servers SHOULD provide the attributes 'createTimestamp' and
   'modifyTimestamp' in subschema (sub)entries, in order to allow
   clients to maintain their caches of schema information.

   The following subsections provide attribute type definitions for each
   of schema definition attribute types.

4.2.1.  'objectClasses'

   This attribute holds definitions of object classes.

      ( 2.5.21.6 NAME 'objectClasses'
        EQUALITY objectIdentifierFirstComponentMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.37
        USAGE directoryOperation )

   The 'objectIdentifierFirstComponentMatch' matching rule and the
   ObjectClassDescription (1.3.6.1.4.1.1466.115.121.1.37) syntax are
   defined in [RFC4517].

4.2.2.  'attributeTypes'

   This attribute holds definitions of attribute types.

      ( 2.5.21.5 NAME 'attributeTypes'
        EQUALITY objectIdentifierFirstComponentMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.3
        USAGE directoryOperation )

   The 'objectIdentifierFirstComponentMatch' matching rule and the
   AttributeTypeDescription (1.3.6.1.4.1.1466.115.121.1.3) syntax are
   defined in [RFC4517].

4.2.3.  'matchingRules'

   This attribute holds definitions of matching rules.

      ( 2.5.21.4 NAME 'matchingRules'
        EQUALITY objectIdentifierFirstComponentMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.30
        USAGE directoryOperation )

   The 'objectIdentifierFirstComponentMatch' matching rule and the
   MatchingRuleDescription (1.3.6.1.4.1.1466.115.121.1.30) syntax are
   defined in [RFC4517].



Zeilenga                    Standards Track                    [Page 33]

RFC 4512                      LDAP Models                      June 2006


4.2.4 'matchingRuleUse'

   This attribute holds definitions of matching rule uses.

      ( 2.5.21.8 NAME 'matchingRuleUse'
        EQUALITY objectIdentifierFirstComponentMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.31
        USAGE directoryOperation )

   The 'objectIdentifierFirstComponentMatch' matching rule and the
   MatchingRuleUseDescription (1.3.6.1.4.1.1466.115.121.1.31) syntax are
   defined in [RFC4517].

4.2.5.  'ldapSyntaxes'

   This attribute holds definitions of LDAP syntaxes.

      ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes'
        EQUALITY objectIdentifierFirstComponentMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.54
        USAGE directoryOperation )

   The 'objectIdentifierFirstComponentMatch' matching rule and the
   SyntaxDescription (1.3.6.1.4.1.1466.115.121.1.54) syntax are defined
   in [RFC4517].

4.2.6.  'dITContentRules'

   This attribute lists DIT Content Rules that are present in the
   subschema.

      ( 2.5.21.2 NAME 'dITContentRules'
        EQUALITY objectIdentifierFirstComponentMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.16
        USAGE directoryOperation )

   The 'objectIdentifierFirstComponentMatch' matching rule and the
   DITContentRuleDescription (1.3.6.1.4.1.1466.115.121.1.16) syntax are
   defined in [RFC4517].












Zeilenga                    Standards Track                    [Page 34]

RFC 4512                      LDAP Models                      June 2006


4.2.7.  'dITStructureRules'

   This attribute lists DIT Structure Rules that are present in the
   subschema.

      ( 2.5.21.1 NAME 'dITStructureRules'
        EQUALITY integerFirstComponentMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.17
        USAGE directoryOperation )

   The 'integerFirstComponentMatch' matching rule and the
   DITStructureRuleDescription (1.3.6.1.4.1.1466.115.121.1.17) syntax
   are defined in [RFC4517].

4.2.8 'nameForms'

   This attribute lists Name Forms that are in force.

      ( 2.5.21.7 NAME 'nameForms'
        EQUALITY objectIdentifierFirstComponentMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.35
        USAGE directoryOperation )

   The 'objectIdentifierFirstComponentMatch' matching rule and the
   NameFormDescription (1.3.6.1.4.1.1466.115.121.1.35) syntax are
   defined in [RFC4517].

4.3.  'extensibleObject' object class

   The 'extensibleObject' auxiliary object class allows entries that
   belong to it to hold any user attribute.  The set of allowed
   attribute types of this object class is implicitly the set of all
   attribute types of userApplications usage.

      ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject'
        SUP top AUXILIARY )

   The mandatory attributes of the other object classes of this entry
   are still required to be present, and any precluded attributes are
   still not allowed to be present.

4.4.  Subschema Discovery

   To discover the DN of the subschema (sub)entry holding the subschema
   controlling a particular entry, a client reads that entry's
   'subschemaSubentry' operational attribute.  To read schema attributes
   from the subschema (sub)entry, clients MUST issue a Search operation
   [RFC4511] where baseObject is the DN of the subschema (sub)entry,



Zeilenga                    Standards Track                    [Page 35]

RFC 4512                      LDAP Models                      June 2006


   scope is baseObject, filter is "(objectClass=subschema)" [RFC4515],
   and the attributes field lists the names of the desired schema
   attributes (as they are operational).  Note: the
   "(objectClass=subschema)" filter allows LDAP servers that gateway to
   X.500 to detect that subentry information is being requested.

   Clients SHOULD NOT assume that a published subschema is complete,
   that the server supports all of the schema elements it publishes, or
   that the server does not support an unpublished element.

5.  DSA (Server) Informational Model

   The LDAP protocol assumes there are one or more servers that jointly
   provide access to a Directory Information Tree (DIT).  The server
   holding the original information is called the "master" (for that
   information).  Servers that hold copies of the original information
   are referred to as "shadowing" or "caching" servers.


   As defined in [X.501]:

      context prefix: The sequence of RDNs leading from the Root of the
          DIT to the initial vertex of a naming context; corresponds to
          the distinguished name of that vertex.

      naming context: A subtree of entries held in a single master DSA.

   That is, a naming context is the largest collection of entries,
   starting at an entry that is mastered by a particular server, and
   including all its subordinates and their subordinates, down to the
   entries that are mastered by different servers.  The context prefix
   is the name of the initial entry.

   The root of the DIT is a DSA-specific Entry (DSE) and not part of any
   naming context (or any subtree); each server has different attribute
   values in the root DSE.

5.1.  Server-Specific Data Requirements

   An LDAP server SHALL provide information about itself and other
   information that is specific to each server.  This is represented as
   a group of attributes located in the root DSE, which is named with
   the DN with zero RDNs (whose [RFC4514] representation is as the
   zero-length string).

   These attributes are retrievable, subject to access control and other
   restrictions, if a client performs a Search operation [RFC4511] with
   an empty baseObject, scope of baseObject, the filter



Zeilenga                    Standards Track                    [Page 36]

RFC 4512                      LDAP Models                      June 2006


   "(objectClass=*)" [RFC4515], and the attributes field listing the
   names of the desired attributes.  It is noted that root DSE
   attributes are operational and, like other operational attributes,
   are not returned in search requests unless requested by name.

   The root DSE SHALL NOT be included if the client performs a subtree
   search starting from the root.

   Servers may allow clients to modify attributes of the root DSE, where
   appropriate.

   The following attributes of the root DSE are defined below.
   Additional attributes may be defined in other documents.

      - altServer: alternative servers;

      - namingContexts: naming contexts;

      - supportedControl: recognized LDAP controls;

      - supportedExtension: recognized LDAP extended operations;

      - supportedFeatures: recognized LDAP features;

      - supportedLDAPVersion: LDAP versions supported; and

      - supportedSASLMechanisms: recognized Simple Authentication and
        Security Layers (SASL) [RFC4422] mechanisms.

   The values provided for these attributes may depend on session-
   specific and other factors.  For example, a server supporting the
   SASL EXTERNAL mechanism might only list "EXTERNAL" when the client's
   identity has been established by a lower level.  See [RFC4513].

   The root DSE may also include a 'subschemaSubentry' attribute.  If it
   does, the attribute refers to the subschema (sub)entry holding the
   schema controlling the root DSE.  Clients SHOULD NOT assume that this
   subschema (sub)entry controls other entries held by the server.
   General subschema discovery procedures are provided in Section 4.4.












Zeilenga                    Standards Track                    [Page 37]

RFC 4512                      LDAP Models                      June 2006


5.1.1.  'altServer'

   The 'altServer' attribute lists URIs referring to alternative servers
   that may be contacted when this server becomes unavailable.  URIs for
   servers implementing the LDAP are written according to [RFC4516].
   Other kinds of URIs may be provided.  If the server does not know of
   any other servers that could be used, this attribute will be absent.
   Clients may cache this information in case their preferred server
   later becomes unavailable.

      ( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
        USAGE dSAOperation )

   The IA5String (1.3.6.1.4.1.1466.115.121.1.26) syntax is defined in
   [RFC4517].

5.1.2.  'namingContexts'

   The 'namingContexts' attribute lists the context prefixes of the
   naming contexts the server masters or shadows (in part or in whole).
   If the server is a first-level DSA [X.501], it should list (in
   addition) an empty string (indicating the root of the DIT).  If the
   server does not master or shadow any information (e.g., it is an LDAP
   gateway to a public X.500 directory) this attribute will be absent.
   If the server believes it masters or shadows the entire directory,
   the attribute will have a single value, and that value will be the
   empty string (indicating the root of the DIT).

   This attribute may be used, for example, to select a suitable entry
   name for subsequent operations with this server.

      ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
        USAGE dSAOperation )

   The DistinguishedName (1.3.6.1.4.1.1466.115.121.1.12) syntax is
   defined in [RFC4517].

5.1.3.  'supportedControl'

   The 'supportedControl' attribute lists object identifiers identifying
   the request controls [RFC4511] the server supports.  If the server
   does not support any request controls, this attribute will be absent.
   Object identifiers identifying response controls need not be listed.

   Procedures for registering object identifiers used to discovery of
   protocol mechanisms are detailed in BCP 64, RFC 4520 [RFC4520].



Zeilenga                    Standards Track                    [Page 38]

RFC 4512                      LDAP Models                      June 2006


      ( 1.3.6.1.4.1.1466.101.120.13 NAME 'supportedControl'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
        USAGE dSAOperation )

   The OBJECT IDENTIFIER (1.3.6.1.4.1.1466.115.121.1.38) syntax is
   defined in [RFC4517].

5.1.4.  'supportedExtension'

   The 'supportedExtension' attribute lists object identifiers
   identifying the extended operations [RFC4511] that the server
   supports.  If the server does not support any extended operations,
   this attribute will be absent.

   An extended operation generally consists of an extended request and
   an extended response but may also include other protocol data units
   (such as intermediate responses).  The object identifier assigned to
   the extended request is used to identify the extended operation.
   Other object identifiers used in the extended operation need not be
   listed as values of this attribute.

   Procedures for registering object identifiers used to discovery of
   protocol mechanisms are detailed in BCP 64, RFC 4520 [RFC4520].

      ( 1.3.6.1.4.1.1466.101.120.7 NAME 'supportedExtension'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
        USAGE dSAOperation )

   The OBJECT IDENTIFIER (1.3.6.1.4.1.1466.115.121.1.38) syntax is
   defined in [RFC4517].

5.1.5.  'supportedFeatures'

   The 'supportedFeatures' attribute lists object identifiers
   identifying elective features that the server supports.  If the
   server does not support any discoverable elective features, this
   attribute will be absent.

      ( 1.3.6.1.4.1.4203.1.3.5 NAME 'supportedFeatures'
          EQUALITY objectIdentifierMatch
          SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
          USAGE dSAOperation )

   Procedures for registering object identifiers used to discovery of
   protocol mechanisms are detailed in BCP 64, RFC 4520 [RFC4520].

   The OBJECT IDENTIFIER (1.3.6.1.4.1.1466.115.121.1.38) syntax and
   objectIdentifierMatch matching rule are defined in [RFC4517].



Zeilenga                    Standards Track                    [Page 39]

RFC 4512                      LDAP Models                      June 2006


5.1.6.  'supportedLDAPVersion'

   The 'supportedLDAPVersion' attribute lists the versions of LDAP that
   the server supports.

      ( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
        USAGE dSAOperation )

   The INTEGER (1.3.6.1.4.1.1466.115.121.1.27) syntax is defined in
   [RFC4517].

5.1.7.  'supportedSASLMechanisms'

   The 'supportedSASLMechanisms' attribute lists the SASL mechanisms
   [RFC4422] that the server recognizes and/or supports [RFC4513].  The
   contents of this attribute may depend on the current session state.
   If the server does not support any SASL mechanisms, this attribute
   will not be present.

      ( 1.3.6.1.4.1.1466.101.120.14 NAME 'supportedSASLMechanisms'
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        USAGE dSAOperation )

   The Directory String (1.3.6.1.4.1.1466.115.121.1.15) syntax is
   defined in [RFC4517].

6.  Other Considerations

6.1.  Preservation of User Information

   Syntaxes may be defined that have specific value and/or value form
   (representation) preservation requirements.  For example, a syntax
   containing digitally signed data can mandate that the server preserve
   both the value and form of value presented to ensure that the
   signature is not invalidated.

   Where such requirements have not been explicitly stated, servers
   SHOULD preserve the value of user information but MAY return the
   value in a different form.  And where a server is unable (or
   unwilling) to preserve the value of user information, the server
   SHALL ensure that an equivalent value (per Section 2.3) is returned.









Zeilenga                    Standards Track                    [Page 40]

RFC 4512                      LDAP Models                      June 2006


6.2.  Short Names

   Short names, also known as descriptors, are used as more readable
   aliases for object identifiers and are used to identify various
   schema elements.  However, it is not expected that LDAP
   implementations with human user interface would display these short
   names (or the object identifiers they refer to) to the user.
   Instead, they would most likely be performing translations (such as
   expressing the short name in one of the local national languages).
   For example, the short name "st" (stateOrProvinceName) might be
   displayed to a German-speaking user as "Land".

   The same short name might have different meaning in different
   subschemas, and, within a particular subschema, the same short name
   might refer to different object identifiers each identifying a
   different kind of schema element.

   Implementations MUST be prepared that the same short name might be
   used in a subschema to refer to the different kinds of schema
   elements.  That is, there might be an object class 'x-fubar' and an
   attribute type 'x-fubar' in a subschema.

   Implementations MUST be prepared that the same short name might be
   used in the different subschemas to refer to the different schema
   elements.  That is, there might be two matching rules 'x-fubar', each
   in different subschemas.

   Procedures for registering short names (descriptors) are detailed in
   BCP 64, RFC 4520 [RFC4520].

6.3.  Cache and Shadowing

   Some servers may hold cache or shadow copies of entries, which can be
   used to answer search and comparison queries, but will return
   referrals or contact other servers if modification operations are
   requested.  Servers that perform shadowing or caching MUST ensure
   that they do not violate any access control constraints placed on the
   data by the originating server.













Zeilenga                    Standards Track                    [Page 41]

RFC 4512                      LDAP Models                      June 2006


7.  Implementation Guidelines

7.1.  Server Guidelines

   Servers MUST recognize all names of attribute types and object
   classes defined in this document but, unless stated otherwise, need
   not support the associated functionality.  Servers SHOULD recognize
   all the names of attribute types and object classes defined in
   Section 3 and 4, respectively, of [RFC4519].

   Servers MUST ensure that entries conform to user and system schema
   rules or other data model constraints.

   Servers MAY support DIT Content Rules.  Servers MAY support DIT
   Structure Rules and Name Forms.

   Servers MAY support alias entries.

   Servers MAY support the 'extensibleObject' object class.

   Servers MAY support subentries.  If so, they MUST do so in accordance
   with [RFC3672].  Servers that do not support subentries SHOULD use
   object entries to mimic subentries as detailed in Section 3.2.

   Servers MAY implement additional schema elements.  Servers SHOULD
   provide definitions of all schema elements they support in subschema
   (sub)entries.

7.2.  Client Guidelines

   In the absence of prior agreements with servers, clients SHOULD NOT
   assume that servers support any particular schema elements beyond
   those referenced in Section 7.1.  The client can retrieve subschema
   information as described in Section 4.4.

   Clients MUST NOT display or attempt to decode a value as ASN.1 if the
   value's syntax is not known.  Clients MUST NOT assume the LDAP-
   specific string encoding is restricted to a UTF-8 encoded string of
   Unicode characters or any particular subset of Unicode (such as a
   printable subset) unless such restriction is explicitly stated.
   Clients SHOULD NOT send attribute values in a request that are not
   valid according to the syntax defined for the attributes.









Zeilenga                    Standards Track                    [Page 42]

RFC 4512                      LDAP Models                      June 2006


8.  Security Considerations

   Attributes of directory entries are used to provide descriptive
   information about the real-world objects they represent, which can be
   people, organizations, or devices.  Most countries have privacy laws
   regarding the publication of information about people.

   General security considerations for accessing directory information
   with LDAP are discussed in [RFC4511] and [RFC4513].

9.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has updated the LDAP
   descriptors registry as indicated in the following template:

      Subject: Request for LDAP Descriptor Registration Update
      Descriptor (short name): see comment
      Object Identifier: see comment
      Person & email address to contact for further information:
          Kurt Zeilenga <kurt@OpenLDAP.org>
      Usage: see comment
      Specification: RFC 4512
      Author/Change Controller: IESG
      Comments:

      The following descriptors (short names) has been added to
      the registry.

        NAME                         Type OID
        ------------------------     ---- -----------------
        governingStructureRule          A 2.5.21.10
        structuralObjectClass           A 2.5.21.9

      The following descriptors (short names) have been updated to
      refer to this RFC.

        NAME                         Type OID
        ------------------------     ---- -----------------
        alias                           O 2.5.6.1
        aliasedObjectName               A 2.5.4.1
        altServer                       A 1.3.6.1.4.1.1466.101.120.6
        attributeTypes                  A 2.5.21.5
        createTimestamp                 A 2.5.18.1
        creatorsName                    A 2.5.18.3
        dITContentRules                 A 2.5.21.2
        dITStructureRules               A 2.5.21.1
        extensibleObject                O 1.3.6.1.4.1.1466.101.120.111
        ldapSyntaxes                    A 1.3.6.1.4.1.1466.101.120.16



Zeilenga                    Standards Track                    [Page 43]

RFC 4512                      LDAP Models                      June 2006


        matchingRuleUse                 A 2.5.21.8
        matchingRules                   A 2.5.21.4
        modifiersName                   A 2.5.18.4
        modifyTimestamp                 A 2.5.18.2
        nameForms                       A 2.5.21.7
        namingContexts                  A 1.3.6.1.4.1.1466.101.120.5
        objectClass                     A 2.5.4.0
        objectClasses                   A 2.5.21.6
        subschema                       O 2.5.20.1
        subschemaSubentry               A 2.5.18.10
        supportedControl                A 1.3.6.1.4.1.1466.101.120.13
        supportedExtension              A 1.3.6.1.4.1.1466.101.120.7
        supportedFeatures               A 1.3.6.1.4.1.4203.1.3.5
        supportedLDAPVersion            A 1.3.6.1.4.1.1466.101.120.15
        supportedSASLMechanisms         A 1.3.6.1.4.1.1466.101.120.14
        top                             O 2.5.6.0

10.  Acknowledgements

   This document is based in part on RFC 2251 by M. Wahl, T. Howes, and
   S. Kille; RFC 2252 by M. Wahl, A. Coulbeck, T. Howes, S. Kille; and
   RFC 2556 by M. Wahl, all products of the IETF Access, Searching and
   Indexing of Directories (ASID) Working Group.  This document is also
   based in part on "The Directory: Models" [X.501], a product of the
   International Telephone Union (ITU).  Additional text was borrowed
   from RFC 2253 by M. Wahl, T. Howes, and S. Kille.

   This document is a product of the IETF LDAP Revision (LDAPBIS)
   Working Group.






















Zeilenga                    Standards Track                    [Page 44]

RFC 4512                      LDAP Models                      June 2006


11.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3629]     Yergeau, F., "UTF-8, a transformation format of ISO
                 10646", STD 63, RFC 3629, November 2003.

   [RFC3671]     Zeilenga, K., "Collective Attributes in the Lightweight
                 Directory Access Protocol (LDAP)", RFC 3671, December
                 2003.

   [RFC3672]     Zeilenga, K., "Subentries in the Lightweight Directory
                 Access Protocol (LDAP)", RFC 3672, December 2003.

   [RFC4234]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
                 Specifications: ABNF", RFC 4234, October 2005.

   [RFC4422]     Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
                 Authentication and Security Layer (SASL)", RFC 4422,
                 June 2006.

   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4513]     Harrison, R., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Authentication Methods and Security
                 Mechanisms", RFC 4513, June 2006.

   [RFC4514]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): String Representation of Distinguished
                 Names", RFC 4514, June 2006.

   [RFC4515]     Smith, M., Ed. and T. Howes, "Lightweight Directory
                 Access Protocol (LDAP): String Representation of Search
                 Filters", RFC 4515, June 2006.

   [RFC4516]     Smith, M., Ed. and T. Howes, "Lightweight Directory
                 Access Protocol (LDAP): Uniform Resource Locator", RFC
                 4516, June 2006.

   [RFC4517]     Legg, S., Ed., "Lightweight Directory Access Protocol
                 (LDAP): Syntaxes and Matching Rules", RFC 4517, June
                 2006.



Zeilenga                    Standards Track                    [Page 45]

RFC 4512                      LDAP Models                      June 2006


   [RFC4519]     Sciberras, A., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Schema for User Applications", RFC
                 4519, June 2006.

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
                 3.2.0" is defined by "The Unicode Standard, Version
                 3.0" (Reading, MA, Addison-Wesley, 2000.  ISBN 0-201-
                 61633-5), as amended by the "Unicode Standard Annex
                 #27: Unicode 3.1"
                 (http://www.unicode.org/reports/tr27/) and by the
                 "Unicode Standard Annex #28: Unicode 3.2"
                 (http://www.unicode.org/reports/tr28/).

   [X.500]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Overview of concepts, models and
                 services," X.500(1993) (also ISO/IEC 9594-1:1994).

   [X.501]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Models," X.501(1993) (also ISO/IEC 9594-
                 2:1994).

   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(2002) (also ISO/IEC 8824-1:2002).




















Zeilenga                    Standards Track                    [Page 46]

RFC 4512                      LDAP Models                      June 2006


Appendix A.  Changes

   This appendix is non-normative.

   This document amounts to nearly a complete rewrite of portions of RFC
   2251, RFC 2252, and RFC 2256.  This rewrite was undertaken to improve
   overall clarity of technical specification.  This appendix provides a
   summary of substantive changes made to the portions of these
   documents incorporated into this document.  Readers should consult
   [RFC4510], [RFC4511], [RFC4517], and [RFC4519] for summaries of
   remaining portions of these documents.

A.1.  Changes to RFC 2251

   This document incorporates from RFC 2251, Sections 3.2 and 3.4, and
   portions of Sections 4 and 6 as summarized below.

A.1.1.  Section 3.2 of RFC 2251

   Section 3.2 of RFC 2251 provided a brief introduction to the X.500
   data model, as used by LDAP.  The previous specification relied on
   [X.501] but lacked clarity in how X.500 models are adapted for use by
   LDAP.  This document describes the X.500 data models, as used by
   LDAP, in greater detail, especially in areas where adaptation is
   needed.

   Section 3.2.1 of RFC 2251 described an attribute as "a type with one
   or more associated values".  In LDAP, an attribute is better
   described as an attribute description, a type with zero or more
   options, and one or more associated values.

   Section 3.2.2 of RFC 2251 mandated that subschema subentries contain
   objectClasses and attributeTypes attributes, yet X.500(93) treats
   these attributes as optional.  While generally all implementations
   that support X.500(93) subschema mechanisms will provide both of
   these attributes, it is not absolutely required for interoperability
   that all servers do.  The mandate was removed for consistency with
   X.500(93).   The subschema discovery mechanism was also clarified to
   indicate that subschema controlling an entry is obtained by reading
   the (sub)entry referred to by that entry's 'subschemaSubentry'
   attribute.










Zeilenga                    Standards Track                    [Page 47]

RFC 4512                      LDAP Models                      June 2006


A.1.2.  Section 3.4 of RFC 2251

   Section 3.4 of RFC 2251 provided "Server-specific Data Requirements".
   This material, with changes, was incorporated in Section 5.1 of this
   document.

   Changes:

   - Clarify that attributes of the root DSE are subject to "other
     restrictions" in addition to access controls.

   - Clarify that only recognized extended requests need to be
     enumerated 'supportedExtension'.

   - Clarify that only recognized request controls need to be enumerated
     'supportedControl'.

   - Clarify that root DSE attributes are operational and, like other
     operational attributes, will not be returned in search requests
     unless requested by name.

   - Clarify that not all root DSE attributes are user modifiable.

   - Remove inconsistent text regarding handling of the
     'subschemaSubentry' attribute within the root DSE.  The previous
     specification stated that the 'subschemaSubentry' attribute held in
     the root DSE referred to "subschema entries (or subentries) known
     by this server".  This is inconsistent with the attribute's
     intended use as well as its formal definition as a single valued
     attribute [X.501].  It is also noted that a simple (possibly
     incomplete) list of subschema (sub)entries is not terribly useful.
     This document (in Section 5.1) specifies that the
     'subschemaSubentry' attribute of the root DSE refers to the
     subschema controlling the root DSE.  It is noted that the general
     subschema discovery mechanism remains available (see Section 4.4 of
     this document).

A.1.3.  Section 4 of RFC 2251

   Portions of Section 4 of RFC 2251 detailing aspects of the
   information model used by LDAP were incorporated in this document,
   including:

   - Restriction of distinguished values to attributes whose
     descriptions have no options (from Section 4.1.3);






Zeilenga                    Standards Track                    [Page 48]

RFC 4512                      LDAP Models                      June 2006


   - Data model aspects of Attribute Types (from Section 4.1.4),
     Attribute Descriptions (from 4.1.5), Attribute (from 4.1.8),
     Matching Rule Identifier (from 4.1.9); and

   - User schema requirements (from Sections 4.1.6, 4.5.1, and 4.7).

   Clarifications to these portions include:

   - Subtyping and AttributeDescriptions with options.

A.1.4.  Section 6 of RFC 2251

   The Section 6.1 and the second paragraph of Section 6.2 of RFC 2251
   where incorporated into this document.

A.2.  Changes to RFC 2252

   This document incorporates Sections 4, 5, and 7 from RFC 2252.

A.2.1.  Section 4 of RFC 2252

   The specification was updated to use Augmented BNF [RFC4234].  The
   string representation of an OBJECT IDENTIFIER was tightened to
   disallow leading zeros as described in RFC 2252.

   The <descr> syntax was changed to disallow semicolon (U+003B)
   characters in order to appear to be consistent its natural language
   specification "descr is the syntactic representation of an object
   descriptor, which consists of letters and digits, starting with a
   letter".  In a related change, the statement "an AttributeDescription
   can be used as the value in a NAME part of an
   AttributeTypeDescription" was deleted.  RFC 2252 provided no
   specification of the semantics of attribute options appearing in NAME
   fields.

   RFC 2252 stated that the <descr> form of <oid> SHOULD be preferred
   over the <numericoid> form.  However, <descr> form can be ambiguous.
   To address this issue, the imperative was replaced with a statement
   (in Section 1.4) that while the <descr> form is generally preferred,
   <numericoid> should be used where an unambiguous <descr> is not
   available.  Additionally, an expanded discussion of descriptor issues
   is in Section 6.2 ("Short Names").

   The ABNF for a quoted string (qdstring) was updated to reflect
   support for the escaping mechanism described in Section 4.3 of RFC
   2252.





Zeilenga                    Standards Track                    [Page 49]

RFC 4512                      LDAP Models                      June 2006


A.2.2.  Section 5 of RFC 2252

   Definitions of operational attributes provided in Section 5 of RFC
   2252 where incorporated into this document.

   The 'namingContexts' description was clarified.  A first-level DSA
   should publish, in addition to other values, "" indicating the root
   of the DIT.

   The 'altServer' description was clarified.  It may hold any URI.

   The 'supportedExtension' description was clarified.  A server need
   only list the OBJECT IDENTIFIERs associated with the extended
   requests of the extended operations it recognizes.

   The 'supportedControl' description was clarified.  A server need only
   list the OBJECT IDENTIFIERs associated with the request controls it
   recognizes.

   Descriptions for the 'structuralObjectClass' and
   'governingStructureRule' operational attribute types were added.

   The attribute definition of 'subschemaSubentry' was corrected to list
   the terms SINGLE-VALUE and NO-USER-MODIFICATION in proper order.

A.2.3.  Section 7 of RFC 2252

   Section 7 of RFC 2252 provides definitions of the 'subschema' and
   'extensibleObject' object classes.  These definitions where
   integrated into Section 4.2 and Section 4.3 of this document,
   respectively.  Section 7 of RFC 2252 also contained the object class
   implementation requirement.  This was incorporated into Section 7 of
   this document.

   The specification of 'extensibleObject' was clarified regarding how
   it interacts with precluded attributes.

A.3.  Changes to RFC 2256

   This document incorporates Sections 5.1, 5.2, 7.1, and 7.2 of RFC
   2256.

   Section 5.1 of RFC 2256 provided the definition of the 'objectClass'
   attribute type.  This was integrated into Section 2.4.1 of this
   document.  The statement "One of the values is either 'top' or
   'alias'" was replaced with statement that one of the values is 'top'
   as entries belonging to 'alias' also belong to 'top'.




Zeilenga                    Standards Track                    [Page 50]

RFC 4512                      LDAP Models                      June 2006


   Section 5.2 of RFC 2256 provided the definition of the
   'aliasedObjectName' attribute type.  This was integrated into Section
   2.6.2 of this document.

   Section 7.1 of RFC 2256 provided the definition of the 'top' object
   class.  This was integrated into Section 2.4.1 of this document.

   Section 7.2 of RFC 2256 provided the definition of the 'alias' object
   class.  This was integrated into Section 2.6.1 of this document.

A.4.  Changes to RFC 3674

   This document made no substantive change to the 'supportedFeatures'
   technical specification provided in RFC 3674.

Editor's Address

   Kurt D.  Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org






























Zeilenga                    Standards Track                    [Page 51]

RFC 4512                      LDAP Models                      June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                    [Page 52]

alt-openldap11-devel/rfc/rfc4532.txt000064400000033647150410163250013000 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4532                           OpenLDAP Foundation
Category: Standards Track                                      June 2006


              Lightweight Directory Access Protocol (LDAP)
                         "Who am I?" Operation

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This specification provides a mechanism for Lightweight Directory
   Access Protocol (LDAP) clients to obtain the authorization identity
   the server has associated with the user or application entity.  This
   mechanism is specified as an LDAP extended operation called the LDAP
   "Who am I?" operation.

1.  Background and Intent of Use

   This specification describes a Lightweight Directory Access Protocol
   (LDAP) [RFC4510] operation that clients can use to obtain the primary
   authorization identity, in its primary form, that the server has
   associated with the user or application entity.  The operation is
   called the "Who am I?" operation.

   This specification is intended to replace the existing Authorization
   Identity Controls [RFC3829] mechanism, which uses Bind request and
   response controls to request and return the authorization identity.
   Bind controls are not protected by security layers established by the
   Bind operation that includes them.  While it is possible to establish
   security layers using StartTLS [RFC4511][RFC4513] prior to the Bind
   operation, it is often desirable to use security layers established
   by the Bind operation.  An extended operation sent after a Bind
   operation is protected by the security layers established by the Bind
   operation.





Zeilenga                    Standards Track                     [Page 1]

RFC 4532               LDAP "Who am I?" Operation              June 2006


   There are other cases where it is desirable to request the
   authorization identity that the server associated with the client
   separately from the Bind operation.  For example, the "Who am I?"
   operation can be augmented with a Proxied Authorization Control
   [RFC4370] to determine the authorization identity that the server
   associates with the identity asserted in the Proxied Authorization
   Control.  The "Who am I?" operation can also be used prior to the
   Bind operation.

   Servers often associate multiple authorization identities with the
   client, and each authorization identity may be represented by
   multiple authzId [RFC4513] strings.  This operation requests and
   returns the authzId that the server considers primary.  In the
   specification, the term "the authorization identity" and "the
   authzId" are generally to be read as "the primary authorization
   identity" and the "the primary authzId", respectively.

1.1.  Conventions Used in This Document

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

2.  The "Who am I?" Operation

   The "Who am I?" operation is defined as an LDAP Extended Operation
   [RFC4511] identified by the whoamiOID Object Identifier (OID).  This
   section details the syntax of the operation's whoami request and
   response messages.

      whoamiOID ::= "1.3.6.1.4.1.4203.1.11.3"

2.1.  The whoami Request

   The whoami request is an ExtendedRequest with a requestName field
   containing the whoamiOID OID and an absent requestValue field.  For
   example, a whoami request could be encoded as the sequence of octets
   (in hex):

      30 1e 02 01 02 77 19 80  17 31 2e 33 2e 36 2e 31
      2e 34 2e 31 2e 34 32 30  33 2e 31 2e 31 31 2e 33










Zeilenga                    Standards Track                     [Page 2]

RFC 4532               LDAP "Who am I?" Operation              June 2006


2.2.  The whoami Response

   The whoami response is an ExtendedResponse where the responseName
   field is absent and the response field, if present, is empty or an
   authzId [RFC4513].  For example, a whoami response returning the
   authzId "u:xxyyz@EXAMPLE.NET" (in response to the example request)
   would be encoded as the sequence of octets (in hex):

      30 21 02 01 02 78 1c 0a  01 00 04 00 04 00 8b 13
      75 3a 78 78 79 79 7a 40  45 58 41 4d 50 4c 45 2e
      4e 45 54

3.  Operational Semantics

   The "Who am I?" operation provides a mechanism, a whoami Request, for
   the client to request that the server return the authorization
   identity it currently associates with the client.  It also provides a
   mechanism, a whoami Response, for the server to respond to that
   request.

   Servers indicate their support for this extended operation by
   providing a whoamiOID object identifier as a value of the
   'supportedExtension' attribute type in their root DSE.  The server
   SHOULD advertise this extension only when the client is willing and
   able to perform this operation.

   If the server is willing and able to provide the authorization
   identity it associates with the client, the server SHALL return a
   whoami Response with a success resultCode.  If the server is treating
   the client as an anonymous entity, the response field is present but
   empty.  Otherwise, the server provides the authzId [RFC4513]
   representing the authorization identity it currently associates with
   the client in the response field.

   If the server is unwilling or unable to provide the authorization
   identity it associates with the client, the server SHALL return a
   whoami Response with an appropriate non-success resultCode (such as
   operationsError, protocolError, confidentialityRequired,
   insufficientAccessRights, busy, unavailable, unwillingToPerform, or
   other) and an absent response field.

   As described in [RFC4511] and [RFC4513], an LDAP session has an
   "anonymous" association until the client has been successfully
   authenticated using the Bind operation.  Clients MUST NOT invoke the
   "Who am I?" operation while any Bind operation is in progress,
   including between two Bind requests made as part of a multi-stage





Zeilenga                    Standards Track                     [Page 3]

RFC 4532               LDAP "Who am I?" Operation              June 2006


   Bind operation.  Where a whoami Request is received in violation of
   this absolute prohibition, the server should return a whoami Response
   with an operationsError resultCode.

4.  Extending the "Who am I?" Operation with Controls

   Future specifications may extend the "Who am I?" operation using the
   control mechanism [RFC4511].  When extended by controls, the "Who am
   I?" operation requests and returns the authorization identity the
   server associates with the client in a particular context indicated
   by the controls.

4.1.  Proxied Authorization Control

   The Proxied Authorization Control [RFC4370] is used by clients to
   request that the operation it is attached to operate under the
   authorization of an assumed identity.  The client provides the
   identity to assume in the Proxied Authorization request control.  If
   the client is authorized to assume the requested identity, the server
   executes the operation as if the requested identity had issued the
   operation.

   As servers often map the asserted authzId to another identity
   [RFC4513], it is desirable to request that the server provide the
   authzId it associates with the assumed identity.

   When a Proxied Authorization Control is be attached to the "Who am
   I?"  operation, the operation requests the return of the authzId the
   server associates with the identity asserted in the Proxied
   Authorization Control.  The authorizationDenied (123) result code is
   used to indicate that the server does not allow the client to assume
   the asserted identity.

5.  Security Considerations

   Identities associated with users may be sensitive information.  When
   they are, security layers [RFC4511][RFC4513] should be established to
   protect this information.  This mechanism is specifically designed to
   allow security layers established by a Bind operation to protect the
   integrity and/or confidentiality of the authorization identity.

   Servers may place access control or other restrictions upon the use
   of this operation.  As stated in Section 3, the server SHOULD
   advertise this extension when it is willing and able to perform the
   operation.

   As with any other extended operations, general LDAP security
   considerations [RFC4510] apply.



Zeilenga                    Standards Track                     [Page 4]

RFC 4532               LDAP "Who am I?" Operation              June 2006


6.  IANA Considerations

   The OID 1.3.6.1.4.1.4203.1.11.3 is used to identify the LDAP "Who am
   I?" extended operation.  This OID was assigned [ASSIGN] by the
   OpenLDAP Foundation, under its IANA-assigned private enterprise
   allocation [PRIVATE], for use in this specification.

   Registration of this protocol mechanism [RFC4520] has been completed
   by the IANA.

   Subject: Request for LDAP Protocol Mechanism Registration
   Object Identifier: 1.3.6.1.4.1.4203.1.11.3
   Description: Who am I?
   Person & email address to contact for further information:
        Kurt Zeilenga <kurt@openldap.org>
   Usage: Extended Operation
   Specification: RFC 4532
   Author/Change Controller: IESG
   Comments: none

7.  Acknowledgement

   This document borrows from prior work in this area, including
   "Authentication Response Control" [RFC3829] by Rob Weltman, Mark
   Smith, and Mark Wahl.

   The LDAP "Who am I?" operation takes it's name from the UNIX
   whoami(1) command.  The whoami(1) command displays the effective user
   ID.

8.  References

8.1.  Normative References

   [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
             Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4370] Weltman, R., "Lightweight Directory Access Protocol (LDAP)
             Proxied Authorization Control", RFC 4370, February 2006.

   [RFC4510] Zeilenga, K., Ed., "Lightweight Directory Access Protocol
             (LDAP): Technical Specification Road Map", RFC 4510, June
             2006.

   [RFC4511] Sermersheim, J., Ed., "Lightweight Directory Access
             Protocol (LDAP): The Protocol", RFC 4511, June 2006.





Zeilenga                    Standards Track                     [Page 5]

RFC 4532               LDAP "Who am I?" Operation              June 2006


   [RFC4513] Harrison, R., Ed., "Lightweight Directory Access Protocol
             (LDAP): Authentication Methods and Security Mechanisms",
             RFC 4513, June 2006.

8.2.  Informative References

   [RFC3829] Weltman, R., Smith, M., and M. Wahl, "Lightweight Directory
             Access Protocol (LDAP) Authorization Identity Request and
             Response Controls", RFC 3829, July 2004.

   [RFC4520] Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
             Considerations for the Lightweight Directory Access
             Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [ASSIGN]  OpenLDAP Foundation, "OpenLDAP OID Delegations",
             http://www.openldap.org/foundation/oid-delegate.txt.

   [PRIVATE] IANA, "Private Enterprise Numbers",
             http://www.iana.org/assignments/enterprise-numbers.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org

























Zeilenga                    Standards Track                     [Page 6]

RFC 4532               LDAP "Who am I?" Operation              June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                     [Page 7]

alt-openldap11-devel/rfc/rfc2696.txt000064400000031011150410163250012770 0ustar00





Network Working Group                                        C. Weider
Request for Comments: 2696                                   A. Herron
Category: Informational                                     A. Anantha
                                                             Microsoft
                                                              T. Howes
                                                              Netscape
                                                        September 1999


      LDAP Control Extension for Simple Paged Results Manipulation

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

1. Abstract

   This document describes an LDAPv3 control extension for simple paging
   of search results. This control extension allows a client to control
   the rate at which an LDAP server returns the results of an LDAP
   search operation. This control may be useful when the LDAP client has
   limited resources and may not be able to process the entire result
   set from a given LDAP query, or when the LDAP client is connected
   over a low-bandwidth connection. Other operations on the result set
   are not defined in this extension. This extension is not designed to
   provide more sophisticated result set management.

   The key words "MUST", "SHOULD", and "MAY" used in this document are
   to be interpreted as described in [bradner97].

2. The Control

   This control is included in the searchRequest and searchResultDone
   messages as part of the controls field of the LDAPMessage, as defined
   in Section 4.1.12 of [LDAPv3]. The structure of this control is as
   follows:









Weider, et al.               Informational                      [Page 1]

RFC 2696       LDAP Control Ext. for Simple Paged Results September 1999


pagedResultsControl ::= SEQUENCE {
        controlType     1.2.840.113556.1.4.319,
        criticality     BOOLEAN DEFAULT FALSE,
        controlValue    searchControlValue
}

The searchControlValue is an OCTET STRING wrapping the BER-encoded
version of the following SEQUENCE:

realSearchControlValue ::= SEQUENCE {
        size            INTEGER (0..maxInt),
                                -- requested page size from client
                                -- result set size estimate from server
        cookie          OCTET STRING
}

3. Client-Server Interaction

   An LDAP client application that needs to control the rate at which
   results are returned MAY specify on the searchRequest a
   pagedResultsControl with size set to the desired page size and cookie
   set to the zero-length string. The page size specified MAY be greater
   than zero and less than the sizeLimit value specified in the
   searchRequest.

   If the page size is greater than or equal to the sizeLimit value, the
   server should ignore the control as the request can be satisfied in a
   single page. If the server does not support this control, the server
   MUST return an error of unsupportedCriticalExtension if the client
   requested it as critical, otherwise the server SHOULD ignore the
   control. The remainder of this section assumes the server does not
   ignore the client's pagedResultsControl.

   Each time the server returns a set of results to the client when
   processing a search request containing the pagedResultsControl, the
   server includes the pagedResultsControl control in the
   searchResultDone message. In the control returned to the client, the
   size MAY be set to the server's estimate of the total number of
   entries in the entire result set. Servers that cannot provide such an
   estimate MAY set this size to zero (0).  The cookie MUST be set to an
   empty value if there are no more entries to return (i.e., the page of
   search results returned was the last), or, if there are more entries
   to return, to an octet string of the server's choosing,used to resume
   the search.

   The client MUST consider the cookie to be an opaque structure and
   make no assumptions about its internal organization or value. When
   the client wants to retrieve more entries for the result set, it MUST



Weider, et al.               Informational                      [Page 2]

RFC 2696       LDAP Control Ext. for Simple Paged Results September 1999


   send to the server a searchRequest with all values identical to the
   initial request with the exception of the messageID, the cookie, and
   optionally a modified pageSize. The cookie MUST be the octet string
   on the last searchResultDone response returned by the server.
   Returning cookies from previous searchResultDone responses besides
   the last one is undefined, as the server implementation may restrict
   cookies from being reused.

   The server will then return the next set of results from the whole
   result set. This interaction will continue until the client has
   retrieved all the results, in which case the cookie in the
   searchResultDone field will be empty, or until the client abandons
   the search sequence as described below. Once the paged search
   sequence has been completed, the cookie is no longer valid and MUST
   NOT be used.

   A sequence of paged search requests is abandoned by the client
   sending a search request containing a pagedResultsControl with the
   size set to zero (0) and the cookie set to the last cookie returned
   by the server.  A client MAY use the LDAP Abandon operation to
   abandon one paged search request in progress, but this is discouraged
   as it MAY invalidate the client's cookie.

   If, for any reason, the server cannot resume a paged search operation
   for a client, then it SHOULD return the appropriate error in a
   searchResultDone entry. If this occurs, both client and server should
   assume the paged result set is closed and no longer resumable.

   A client may have any number of outstanding search requests pending,
   any of which may have used the pagedResultsControl.  A server
   implementation which requires a limit on the number of outstanding
   paged search requests from a given client MAY either return
   unwillingToPerform when the client attempts to create a new paged
   search request, or age out an older result set.  If the server
   implementation ages out an older paged search request, it SHOULD
   return "unwilling to perform" if the client attempts to resume the
   paged search that was aged out.

   A client may safely assume that all entries that satisfy a given
   search query are returned once and only once during the set of paged
   search requests/responses necessary to enumerate the entire result
   set, unless the result set for that query has changed since the
   searchRequest starting the request/response sequence was processed.
   In that case, the client may receive a given entry multiple times
   and/or may not receive all entries matching the given search
   criteria.





Weider, et al.               Informational                      [Page 3]

RFC 2696       LDAP Control Ext. for Simple Paged Results September 1999


4. Example

   The following example illustrates the client-server interaction
   between a client doing a search requesting a page size limit of 3.
   The entire result set returned by the server contains 5 entries.

   Lines beginning with "C:" indicate requests sent from client to
   server. Lines beginning with "S:" indicate responses sent from server
   to client. Lines beginning with "--" are comments to help explain the
   example.

   -- Client sends a search request asking for paged results
   -- with a page size of 3.
   C: SearchRequest + pagedResultsControl(3,"")
   -- Server responds with three entries plus an indication
   -- of 5 total entries in the search result and an opaque
   -- cooking to be used by the client when retrieving subsequent
   -- pages.
   S: SearchResultEntry
   S: SearchResultEntry
   S: SearchResultEntry
   S: SearchResultDone + pagedResultsControl(5, "opaque")
   -- Client sends an identical search request (except for
   -- message id), returning the opaque cooking, asking for
   -- the next page.
   C: SearchRequest + PagedResultsControl(3, "opaque")
   -- Server responds with two entries plus an indication
   -- that there are no more entries (null cookie).
   S: SearchResultEntry
   S: SearchResultEntry
   S: SearchResultDone + pagedResultsControl(5,"")

5. Relationship to X.500

   For LDAP servers providing a front end to X.500 (93) directories, the
   paged results control defined in this document may be mapped directly
   onto the X.500 (93) PagedResultsRequest defined in X.511 [x500]. The
   size parameter may be mapped onto pageSize.  The cookie parameter may
   be mapped onto queryReference.  The sortKeys and reverse fields in
   the X.500 PagedResultsRequest are excluded.











Weider, et al.               Informational                      [Page 4]

RFC 2696       LDAP Control Ext. for Simple Paged Results September 1999


6. Security Considerations

   Server implementors should consider the resources used when clients
   send searches with the simple paged control, to ensure that a
   client's misuse of this control does not lock out other legitimate
   operations.

   Servers implementations may enforce an overriding sizelimit, to
   prevent the retrieval of large portions of a publically-accessible
   directory.

   Clients can, using this control, determine how many entries match a
   particular filter, before the entries are returned to the client.
   This may require special processing in servers which perform access
   control checks on entries to determine whether the existence of the
   entry can be disclosed to the client.

7. References

   [LDAPv3]    Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
               Access Protocol (v3)", RFC 2251, December 1997.

   [Bradner97] Bradner, S., "Key Words for use in RFCs to Indicate
               Requirement Levels", BCP 14, RFC 2119, March 1997.



























Weider, et al.               Informational                      [Page 5]

RFC 2696       LDAP Control Ext. for Simple Paged Results September 1999


8. Authors' Addresses

   Chris Weider
   Microsoft Corp.
   1 Microsoft Way
   Redmond, WA 98052
   USA

   Phone: +1 425 882-8080
   EMail: cweider@microsoft.com


   Andy Herron
   Microsoft Corp.
   1 Microsoft Way
   Redmond, WA 98052
   USA

   Phone: +1 425 882-8080
   EMail: andyhe@microsoft.com


   Anoop Anantha
   Microsoft Corp.
   1 Microsoft Way
   Redmond, WA 98052
   USA

   Phone: +1 425 882-8080
   EMail: anoopa@microsoft.com


   Tim Howes
   Netscape Communications Corp.
   501 E. Middlefield Road
   Mountain View, CA 94043
   USA

   Phone: +1 415 937-2600
   EMail: howes@netscape.com











Weider, et al.               Informational                      [Page 6]

RFC 2696       LDAP Control Ext. for Simple Paged Results September 1999


9.  Full Copyright Statement

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Weider, et al.               Informational                      [Page 7]

alt-openldap11-devel/rfc/rfc3712.txt000064400000171535150410163250012776 0ustar00





Network Working Group                                         P. Fleming
Request for Comments: 3712                                           IBM
Category: Informational                                      I. McDonald
                                                              High North
                                                           February 2004


             Lightweight Directory Access Protocol (LDAP):
                      Schema for Printer Services

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).  All Rights Reserved.

Abstract

   This document defines a schema, object classes and attributes, for
   printers and printer services, for use with directories that support
   Lightweight Directory Access Protocol v3 (LDAP-TS).  This document is
   based on the printer attributes listed in Appendix E of Internet
   Printing Protocol/1.1 (IPP) (RFC 2911).  A few additional printer
   attributes are based on definitions in the Printer MIB (RFC 1759).

Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
       1.1.  Rationale for using DirectoryString Syntax . . . . . . .  3
       1.2.  Rationale for using caseIgnoreMatch. . . . . . . . . . .  4
       1.3.  Rationale for using caseIgnoreSubstringsMatch. . . . . .  5
   2.  Terminology and Conventions. . . . . . . . . . . . . . . . . .  5
   3.  Definition of Object Classes . . . . . . . . . . . . . . . . .  6
       3.1.  slpServicePrinter. . . . . . . . . . . . . . . . . . . .  6
       3.2.  printerAbstract. . . . . . . . . . . . . . . . . . . . .  7
       3.3.  printerService . . . . . . . . . . . . . . . . . . . . .  8
       3.4.  printerServiceAuxClass . . . . . . . . . . . . . . . . .  8
       3.5.  printerIPP . . . . . . . . . . . . . . . . . . . . . . .  8
       3.6.  printerLPR . . . . . . . . . . . . . . . . . . . . . . .  9
   4.  Definition of Attribute Types. . . . . . . . . . . . . . . . .  9
       4.1.  printer-uri. . . . . . . . . . . . . . . . . . . . . . . 11
       4.2.  printer-xri-supported. . . . . . . . . . . . . . . . . . 11
       4.3.  printer-name . . . . . . . . . . . . . . . . . . . . . . 13
       4.4.  printer-natural-language-configured. . . . . . . . . . . 13



Fleming & McDonald           Informational                      [Page 1]

RFC 3712            LDAP Schema for Printer Services       February 2004


       4.5.  printer-location . . . . . . . . . . . . . . . . . . . . 14
       4.6.  printer-info . . . . . . . . . . . . . . . . . . . . . . 14
       4.7.  printer-more-info. . . . . . . . . . . . . . . . . . . . 14
       4.8.  printer-make-and-model . . . . . . . . . . . . . . . . . 15
       4.9.  printer-ipp-versions-supported . . . . . . . . . . . . . 15
       4.10. printer-multiple-document-jobs-supported . . . . . . . . 16
       4.11. printer-charset-configured . . . . . . . . . . . . . . . 16
       4.12. printer-charset-supported. . . . . . . . . . . . . . . . 16
       4.13. printer-generated-natural-language-supported . . . . . . 17
       4.14. printer-document-format-supported. . . . . . . . . . . . 17
       4.15. printer-color-supported. . . . . . . . . . . . . . . . . 18
       4.16. printer-compression-supported. . . . . . . . . . . . . . 18
       4.17. printer-pages-per-minute . . . . . . . . . . . . . . . . 18
       4.18. printer-pages-per-minute-color . . . . . . . . . . . . . 19
       4.19. printer-finishings-supported . . . . . . . . . . . . . . 19
       4.20. printer-number-up-supported. . . . . . . . . . . . . . . 19
       4.21. printer-sides-supported. . . . . . . . . . . . . . . . . 20
       4.22. printer-media-supported. . . . . . . . . . . . . . . . . 20
       4.23. printer-media-local-supported. . . . . . . . . . . . . . 20
       4.24. printer-resolution-supported . . . . . . . . . . . . . . 21
       4.25. printer-print-quality-supported. . . . . . . . . . . . . 22
       4.26. printer-job-priority-supported . . . . . . . . . . . . . 22
       4.27. printer-copies-supported . . . . . . . . . . . . . . . . 22
       4.28. printer-job-k-octets-supported . . . . . . . . . . . . . 23
       4.29. printer-current-operator . . . . . . . . . . . . . . . . 23
       4.30. printer-service-person . . . . . . . . . . . . . . . . . 24
       4.31. printer-delivery-orientation-supported . . . . . . . . . 24
       4.32. printer-stacking-order-supported . . . . . . . . . . . . 24
       4.33. printer-output-features-supported. . . . . . . . . . . . 25
       4.34. printer-aliases. . . . . . . . . . . . . . . . . . . . . 25
   5.  Definition of Syntaxes . . . . . . . . . . . . . . . . . . . . 26
   6.  Definition of Matching Rules . . . . . . . . . . . . . . . . . 26
   7.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 26
       7.1.  Registration of Object Classes . . . . . . . . . . . . . 26
       7.2.  Registration of Attribute Types. . . . . . . . . . . . . 27
   8.  Internationalization Considerations. . . . . . . . . . . . . . 28
   9.  Security Considerations. . . . . . . . . . . . . . . . . . . . 29
   10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 29
       10.1. Normative References . . . . . . . . . . . . . . . . . . 29
       10.2. Informative References . . . . . . . . . . . . . . . . . 30
   11. Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . . 32
   12. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 32
   13. Full Copyright Statement . . . . . . . . . . . . . . . . . . . 33








Fleming & McDonald           Informational                      [Page 2]

RFC 3712            LDAP Schema for Printer Services       February 2004


1.  Introduction

   This document defines several object classes to provide Lightweight
   Directory Access Protocol v3 [LDAP-TS] applications with flexible
   options in defining printer information using LDAP schema.  Classes
   are provided for defining directory entries with common printer
   information as well as for extending existing directory entries with
   SLPv2 [RFC2608], IPP/1.1 [RFC2911], and LPR [RFC1179] specific
   information.

   The schema defined in this document is based on the printer
   attributes listed in Appendix E 'Generic Directory Schema' of
   Internet Printing Protocol/1.1 (IPP) [RFC2911].  A few additional
   printer attributes are based on definitions in the Printer MIB
   [RFC1759].

   The schema defined in this document is technically aligned with the
   stable IANA-registered 'service:printer:' v2.0 template [SLP-PRT],
   for compatibility with already deployed Service Location Protocol
   (SLPv2) [RFC2608] service advertising and discovery infrastructure.
   The attribute syntaxes are technically aligned with the
   'service:printer:' v2.0 template - therefore simpler types are
   sometimes used (for example, 'DirectoryString' [RFC2252] rather than
   'labeledURI' [RFC2079] for the 'printer-uri' attribute).

   Please send comments directly to the authors at the addresses listed
   in Section 13 "Authors' Addresses".

1.1.  Rationale for using DirectoryString Syntax

   The attribute syntax 'DirectoryString' (UTF-8 [RFC2279]) defined in
   [RFC2252] is specified for several groups of string attributes that
   are defined in this document:

   1)  URI
       - printer-uri, printer-xri-supported, printer-more-info

       The UTF-8 encoding is forward compatible with any future
       deployment of (UTF-8 based) IRI (Internationalized Resource
       Identifiers) [W3C-IRI] currently being developed by the W3C
       Internationalization Working Group.

   2)  Description
       - printer-name, printer-location, printer-info,
       printer-make-and-model






Fleming & McDonald           Informational                      [Page 3]

RFC 3712            LDAP Schema for Printer Services       February 2004


       The UTF-8 encoding supports descriptions in any language,
       conformant with the "IETF Policy on Character Sets and Languages"
       [RFC2277].

       Note:  The printer-natural-language-configured attribute contains
       a language tag [RFC3066] for these description attributes (for
       example, to support text-to-speech conversions).

   3)  Keyword
       - printer-compression-supported, printer-finishings-supported,
       printer-media-supported, printer-media-local-supported,
       printer-print-quality-supported

       The UTF-8 encoding is compatible with the current IPP/1.1
       [RFC2911] definition of the equivalent attributes, most of which
       have the IPP/1.1 union syntax 'keyword or name'.  The keyword
       attributes defined in this document are extensible by
       site-specific or vendor-specific 'names' which behave like new
       'keywords'

       Note:  In IPP/1.1, each value is strongly typed over-the-wire as
       either 'keyword' or 'name'.  This union selector is not preserved
       in the definitions of these equivalent LDAP attributes.

1.2.  Rationale for using caseIgnoreMatch

   The EQUALITY matching rule 'caseIgnoreMatch' defined in [RFC2252] is
   specified for several groups of string attributes that are defined in
   this document:

   1)  URI

       These URI attributes specify EQUALITY matching with
       'caseIgnoreMatch' (rather than with 'caseExactMatch') in order to
       conform to the spirit of [RFC2396], which requires case
       insensitive matching on the host part of a URI versus case
       sensitive matching on the remainder of a URI.

       These URI attributes follow existing practice of supporting case
       insensitive equality matching for host names in the
       associatedDomain attribute defined in [RFC1274].

       Either equality matching rule choice would be a compromise:
       a) case sensitive whole URI matching may lead to false negative
       matches and has been shown to be fragile (given deployed client
       applications that 'pretty up' host names displayed and
       transferred in URI);




Fleming & McDonald           Informational                      [Page 4]

RFC 3712            LDAP Schema for Printer Services       February 2004


       b) case insensitive whole URI matching may lead to false positive
       matches, although it is a dangerous practice to publish URI that
       differ only by case (for example, in the path elements).

   2)  Description

       Case insensitive equality matching is more user-friendly for
       description attributes.

   3)  Keyword

       Case insensitive equality matching is more user-friendly for
       keyword attributes.

1.3.  Rationale for using caseIgnoreSubstringsMatch

   The SUBSTR matching rule 'caseIgnoreSubstringsMatch' defined in
   [RFC2252] is specified for several groups of string attributes that
   are defined in this document:

   1)  URI

       These URI attributes follow existing practice of supporting case
       insensitive equality matching for host names in the
       associatedDomain attribute defined in [RFC1274].

   2)  Description

       Support for case insensitive substring matching is more
       user-friendly for description attributes.

   3)  Keyword

       Support for case insensitive substring matching is more
       user-friendly for keyword attributes.

2.  Terminology and Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

   Schema definitions are provided using LDAPv3 [LDAP-TS] description
   formats.  Definitions provided here are formatted (line wrapped) for
   readability.






Fleming & McDonald           Informational                      [Page 5]

RFC 3712            LDAP Schema for Printer Services       February 2004


3.  Definition of Object Classes

   We define the following LDAP object classes for use with both generic
   printer related information and services specific to SLPv2 [RFC2608],
   IPP/1.1 [RFC2911], and LPR [RFC1179].

   slpServicePrinter - auxiliary class for SLP registered printers
   printerAbstract - abstract class for all printer classes
   printerService - structural class for printers
   printerServiceAuxClass - auxiliary class for printers
   printerIPP - auxiliary class for IPP printers
   printerLPR - auxiliary class for LPR printers

   The following are some examples of how applications may choose to use
   these classes when creating directory entries:

   1)  Use printerService for directory entries containing common
       printer information.

   2)  Use both printerService and slpServicePrinter for directory
       entries containing common printer information for SLP registered
       printers.

   3)  Use printerService, printerLPR and printerIPP for directory
       entries containing common printer information for printers that
       support both LPR and IPP.

   4)  Use printerServiceAuxClass and object classes not defined by this
       document for directory entries containing common printer
       information.  In this example, printerServiceAuxClass is used for
       extending other structural classes defining printer information
       with common printer information defined in this document.

   Refer to Section 4 for definition of attribute types referenced by
   these object classes.  We use attribute names instead of OIDs in
   object class definitions for clarity.  Some attribute names described
   in [RFC2911] have been prefixed with 'printer-' as recommended in
   [RFC2926] and [SLP-PRT].

3.1.  slpServicePrinter

   ( 1.3.18.0.2.6.254
   NAME  'slpServicePrinter'
   DESC  'Service Location Protocol (SLP) information.'
   AUXILIARY
   SUP   slpService
   )




Fleming & McDonald           Informational                      [Page 6]

RFC 3712            LDAP Schema for Printer Services       February 2004


   This auxiliary class defines Service Location Protocol (SLPv2)
   [RFC2608] specific information.  It should be used with a structural
   class such as printerService.  It may be used to create new or extend
   existing directory entries with SLP 'service:printer' abstract
   service type information as defined in [SLP-PRT].  This object class
   is derived from 'slpService', the parent class for all SLP services,
   defined in [RFC2926].

3.2.  printerAbstract

   ( 1.3.18.0.2.6.258
   NAME  'printerAbstract'
   DESC  'Printer related information.'
   ABSTRACT
   SUP   top
   MAY   ( printer-name $
           printer-natural-language-configured $
           printer-location $ printer-info $ printer-more-info $
           printer-make-and-model $
           printer-multiple-document-jobs-supported $
           printer-charset-configured $ printer-charset-supported $
           printer-generated-natural-language-supported $
           printer-document-format-supported $ printer-color-supported $
           printer-compression-supported $ printer-pages-per-minute $
           printer-pages-per-minute-color $
           printer-finishings-supported $ printer-number-up-supported $
           printer-sides-supported $ printer-media-supported $
           printer-media-local-supported $
           printer-resolution-supported $
           printer-print-quality-supported $
           printer-job-priority-supported $ printer-copies-supported $
           printer-job-k-octets-supported $ printer-current-operator $
           printer-service-person $
           printer-delivery-orientation-supported $
           printer-stacking-order-supported $
           printer-output-features-supported )
   )

   This abstract class defines printer information.  It is a base class
   for deriving other printer related classes, such as, but not limited
   to, classes defined in this document.  It defines a common set of
   printer attributes that are not specific to any one type of service,
   protocol or operating system.








Fleming & McDonald           Informational                      [Page 7]

RFC 3712            LDAP Schema for Printer Services       February 2004


3.3.  printerService

   ( 1.3.18.0.2.6.255
   NAME  'printerService'
   DESC  'Printer information.'
   STRUCTURAL
   SUP   printerAbstract
   MAY   ( printer-uri $ printer-xri-supported )
   )

   This structural class defines printer information.  It is derived
   from class printerAbstract and thus inherits common printer
   attributes.  This class can be used with or without auxiliary classes
   to define printer information.  Auxiliary classes can be used to
   extend the common printer information with protocol, service or
   operating system specific information.

   Note:  When extending other structural classes with auxiliary
   classes, printerService should not be used.

3.4.  printerServiceAuxClass

   ( 1.3.18.0.2.6.257
   NAME  'printerServiceAuxClass'
   DESC  'Printer information.'
   AUXILIARY
   SUP   printerAbstract
   MAY   ( printer-uri $ printer-xri-supported )
   )

   This auxiliary class defines printer information.  It is derived from
   class printerAbstract and thus inherits common printer attributes.
   This class should be used with a structural class.

3.5.  printerIPP

   ( 1.3.18.0.2.6.256
   NAME  'printerIPP'
   DESC  'Internet Printing Protocol (IPP) information.'
   AUXILIARY
   SUP   top
   MAY   ( printer-ipp-versions-supported $
           printer-multiple-document-jobs-supported )
   )







Fleming & McDonald           Informational                      [Page 8]

RFC 3712            LDAP Schema for Printer Services       February 2004


   This auxiliary class defines Internet Printing Protocol (IPP/1.1)
   [RFC2911] information.  It should be used with a structural class
   such as printerService.  It is used to extend structural classes with
   IPP specific printer information.

3.6.  printerLPR

   ( 1.3.18.0.2.6.253
   NAME  'printerLPR'
   DESC  'LPR information.'
   AUXILIARY
   SUP   top
   MUST  ( printer-name )
   MAY   ( printer-aliases)
   )

   This auxiliary class defines LPR [RFC1179] information.  It should be
   used with a structural class such as printerService.  It is used to
   identify directory entries that support LPR.

4.  Definition of Attribute Types

   The following attribute types are referenced by the object classes
   defined in Section 3.

   The following attribute types reference syntax OIDs defined in
   Section 6 of [RFC2252] (see Section 5 'Definition of Syntaxes'
   below).

   The following attribute types reference matching rule names (instead
   of OIDs) for clarity (see Section 6 below).  For optional attributes,
   if the printer information is not known, the attribute value should
   not be set.  In the following definitions, referenced matching rules
   are defined in Section 8 of [RFC2252] and/or Section 2 of [RFC3698]
   (see Section 6 'Definition of Matching Rules' below).

   The following table is a summary of the attribute names defined by
   this document and their corresponding names from [RFC2911].  Some
   attribute names described in [RFC2911] have been prefixed with
   'printer-' as recommended in [RFC2926], to address the flat namespace
   for LDAP identifiers.










Fleming & McDonald           Informational                      [Page 9]

RFC 3712            LDAP Schema for Printer Services       February 2004


   LDAP & SLP Printer Schema       IPP Model [RFC2911]
   ------------------------------  -------------------------------------
   printer-uri
   printer-xri-supported
                                   [IPP printer-uri-supported]
                                   [IPP uri-authentication-supported]
                                   [IPP uri-security-supported]
   printer-name                    printer-name
   printer-natural-language-configured
                                   natural-language-configured
   printer-location                printer-location
   printer-info                    printer-info
   printer-more-info               printer-more-info
   printer-make-and-model          printer-make-and-model
   printer-ipp-versions-supported  ipp-versions-supported
   printer-multiple-document-jobs-supported
                                   multiple-document-jobs-supported
   printer-charset-configured      charset-configured
   printer-charset-supported       charset-supported
   printer-generated-natural-language-supported
                                   generated-natural-language-supported
   printer-document-format-supported
                                   document-format-supported
   printer-color-supported         color-supported
   printer-compression-supported   compression-supported
   printer-pages-per-minute        pages-per-minute
   printer-pages-per-minute-color  pages-per-minute-color
   printer-finishings-supported    finishings-supported
   printer-number-up-supported     number-up-supported
   printer-sides-supported         sides-supported
   printer-media-supported         media-supported
   printer-media-local-supported   [site names from IPP media-supported]
   printer-resolution-supported    printer-resolution-supported
   printer-print-quality-supported print-quality-supported
   printer-job-priority-supported  job-priority-supported
   printer-copies-supported        copies-supported
   printer-job-k-octets-supported  job-k-octets-supported
   printer-current-operator
   printer-service-person
   printer-delivery-orientation-supported
   printer-stacking-order-supported
   printer-output-features-supported
   printer-aliases








Fleming & McDonald           Informational                     [Page 10]

RFC 3712            LDAP Schema for Printer Services       February 2004


4.1.  printer-uri

   ( 1.3.18.0.2.4.1140
   NAME 'printer-uri'
   DESC 'A URI supported by this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15
   SINGLE-VALUE
   )

   If the printer-xri-supported LDAP attribute is implemented, then this
   printer-uri value should be listed in printer-xri-supported.

   Values of URI should conform to [RFC2396], although URI schemes may
   be defined which do not conform to [RFC2396] (see [RFC2717] and
   [RFC2718]).

   Note:  LDAP application clients should not attempt to use malformed
   URI values read from this attribute.  LDAP administrative clients
   should not write malformed URI values into this attribute.

   Note:  For SLP registered printers, the LDAP printer-uri attribute
   should be set to the value of the SLP-registered URL of the printer,
   for interworking with SLPv2 [RFC2608] service discovery.

   Note:  See Sections 1.1, 1.2, and 1.3 for rationale for design
   choices.

4.2.  printer-xri-supported

   ( 1.3.18.0.2.4.1107
   NAME 'printer-xri-supported'
   DESC 'The unordered list of XRI (extended resource identifiers)
         supported by this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   )

   A list of XRI (extended resource identifiers) supported by this
   printer.  Each value of this list should consist of a URI (uniform
   resource identifier) followed by (optional) authentication and
   security fields.

   Values of URI should conform to [RFC2396], although URI schemes may
   be defined which do not conform to [RFC2396] (see [RFC2717] and
   [RFC2718]).



Fleming & McDonald           Informational                     [Page 11]

RFC 3712            LDAP Schema for Printer Services       February 2004


   Note:  LDAP application clients should not attempt to use malformed
   URI values read from this attribute.  LDAP administrative clients
   should not write malformed URI values into this attribute.

   Note:  This attribute is based on 'printer-uri-supported', 'uri-
   authentication-supported', and `'uri-security-supported' (called the
   'Three Musketeers' because they are parallel ordered attributes)
   defined in IPP/1.1 [RFC2911].  This attribute unfolds those IPP/1.1
   attributes and thus avoids the ordering (and same number of values)
   constraints of the IPP/1.1 separate attributes.

   Defined keywords for fields include:

       'uri' (IPP 'printer-uri-supported')
       'auth' (IPP 'uri-authentication-supported')
       'sec' (IPP 'uri-security-supported')

   A missing 'auth' field should be interpreted to mean 'none'.  Per
   IPP/1.1 [RFC2911], defined values of the 'auth' field include:

       'none' (no authentication for this URI)
       'requesting-user-name' (from operation request)
       'basic' (HTTP/1.1 Basic [RFC2617])
       'digest' (HTTP/1.1 Basic, [RFC2617])
       'certificate' (from certificate)

   A missing 'sec' field should be interpreted to mean 'none'.  Per
   IPP/1.1 [RFC2911], defined values of the 'sec' field include:

       'none' (no security for this URI)
       'ssl3' (Netscape SSL3)
       'tls' (IETF TLS/1.0, [RFC2246])

   Each XRI field should be delimited by '<'.  For example:

       'uri=ipp://foo.com< auth=digest< sec=tls<'
       'uri=lpr://bar.com< auth=none< sec=none<'
       'uri=mailto:printer@foobar.com< auth=none< sec=none<'

   Note:  The syntax and delimiter for this attribute are aligned with
   the equivalent attribute in the 'service:printer:' v2.0 template
   [SLP-PRT].  Whitespace is permitted after (but not before) the
   delimiter '<'.  Note that this delimiter differs from printer-
   resolution-supported.

   Note:  See Sections 1.1, 1.2, and 1.3 for rationale for design
   choices.




Fleming & McDonald           Informational                     [Page 12]

RFC 3712            LDAP Schema for Printer Services       February 2004


4.3.  printer-name

   ( 1.3.18.0.2.4.1135
   NAME 'printer-name'
   DESC 'The site-specific administrative name of this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   SINGLE-VALUE
   )

   Values of this attribute should be specified in the language
   specified in printer-natural-language-configured (for example, to
   support text-to-speech conversions), although the printer's name may
   be specified in any language.  This name may be the last part of the
   printer's URI or it may be completely unrelated.  This name may
   contain characters that are not allowed in a conventional URI (see
   [RFC2396]).

4.4.  printer-natural-language-configured

   ( 1.3.18.0.2.4.1119
   NAME 'printer-natural-language-configured'
   DESC 'The configured natural language in which error and status
         messages will be generated (by default) by this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   SINGLE-VALUE
   )

   Also, a possible natural language for printer string attributes set
   by operator, system administrator, or manufacturer.  Also, the
   (declared) natural language of the printer-name, printer-location,
   printer-info, and printer-make-and-model attributes of this printer.

   Values of language tags should conform to "Tags for the
   Identification of Languages" [RFC3066].  For example:

       'en-us' (English as spoken in the US)
       'fr-fr' (French as spoken in France)

   For consistency with IPP/1.1 [RFC2911], language tags in this
   attribute should be lowercase normalized.







Fleming & McDonald           Informational                     [Page 13]

RFC 3712            LDAP Schema for Printer Services       February 2004


4.5.  printer-location

   ( 1.3.18.0.2.4.1136
   NAME 'printer-location'
   DESC 'The physical location of this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   SINGLE-VALUE
   )

   For example:

       'Room 123A'
       'Second floor of building XYZ'

4.6.  printer-info

   ( 1.3.18.0.2.4.1139
   NAME 'printer-info'
   DESC 'Descriptive information about this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   SINGLE-VALUE
   )

   For example:

      'This printer can be used for printing color transparencies for
       HR presentations'
      'Out of courtesy for others, please print only small (1-5 page)
       jobs at this printer'
      'This printer is going away on July 1, 1997, please find a new
       printer'

4.7.  printer-more-info

   ( 1.3.18.0.2.4.1134
   NAME 'printer-more-info'
   DESC 'A URI for more information about this specific printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15
   SINGLE-VALUE
   )





Fleming & McDonald           Informational                     [Page 14]

RFC 3712            LDAP Schema for Printer Services       February 2004


   For example, this could be an HTTP type URI referencing an HTML page
   accessible to a Web Browser.  The information obtained from this URI
   is intended for end user consumption.

   Values of URI should conform to [RFC2396], although URI schemes may
   be defined which do not conform to [RFC2396] (see [RFC2717] and
   [RFC2718]).

   Note:  LDAP application clients should not attempt to use malformed
   URI values read from this attribute.  LDAP administrative clients
   should not write malformed URI values into this attribute.

   Note:  See Sections 1.1, 1.2, and 1.3 for rationale for design
   choices.

4.8.  printer-make-and-model

   ( 1.3.18.0.2.4.1138
   NAME 'printer-make-and-model'
   DESC 'Make and model of this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   SINGLE-VALUE
   )

   Note:  The printer manufacturer may initially populate this
   attribute.

4.9.  printer-ipp-versions-supported

   ( 1.3.18.0.2.4.1133
   NAME 'printer-ipp-versions-supported'
   DESC 'IPP protocol version(s) that this printer supports.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   )

   The IPP protocol version(s) should include major and minor versions,
   i.e., the exact version numbers for which this Printer implementation
   meets the IPP version-specific conformance requirements.









Fleming & McDonald           Informational                     [Page 15]

RFC 3712            LDAP Schema for Printer Services       February 2004


4.10.  printer-multiple-document-jobs-supported

   ( 1.3.18.0.2.4.1132
   NAME 'printer-multiple-document-jobs-supported'
   DESC 'Indicates whether or not this printer supports more than one
         document per job.'
   EQUALITY booleanMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.7
   SINGLE-VALUE
   )

4.11.  printer-charset-configured

   ( 1.3.18.0.2.4.1109
   NAME 'printer-charset-configured'
   DESC 'The configured charset in which error and status messages will
         be generated (by default) by this printer.'
   EQUALITY caseIgnoreMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63}
   SINGLE-VALUE
   )

   Also, a possible charset for printer string attributes set by
   operator, system administrator, or manufacturer.  For example:

       'utf-8' (ISO 10646/Unicode in UTF-8 transform [RFC2279])
       'iso-8859-1' (Latin1)

   Values of charset tags should be defined in the IANA Registry of
   Coded Character Sets [IANA-CHAR] (see also [RFC2978]) and the
   '(preferred MIME name)' should be used as the charset tag in this
   attribute.

   For consistency with IPP/1.1 [RFC2911], charset tags in this
   attribute should be lowercase normalized.

4.12.  printer-charset-supported

   ( 1.3.18.0.2.4.1131
   NAME 'printer-charset-supported'
   DESC 'Set of charsets supported for the attribute values of syntax
         DirectoryString for this directory entry.'
   EQUALITY caseIgnoreMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63}
   )






Fleming & McDonald           Informational                     [Page 16]

RFC 3712            LDAP Schema for Printer Services       February 2004


   For example:

       'utf-8' (ISO 10646/Unicode in UTF-8 transform [RFC2279])
       'iso-8859-1' (Latin1)

   Values of charset tags should be defined in the IANA Registry of
   Coded Character Sets [IANA-CHAR] (see also [RFC2978]) and the
   '(preferred MIME name)' should be used as the charset tag in this
   attribute.

   For consistency with IPP/1.1 [RFC2911], charset tags in this
   attribute should be lowercase normalized.

4.13.  printer-generated-natural-language-supported

   ( 1.3.18.0.2.4.1137
   NAME 'printer-generated-natural-language-supported'
   DESC 'Natural language(s) supported for this directory entry.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63}
   )

   Values of language tags should conform to "Tags for the
   Identification of Languages" [RFC3066].  For example:

       'en-us' (English as spoken in the US)
       'fr-fr' (French as spoken in France)

   For consistency with IPP/1.1 [RFC2911], language tags in this
   attribute should be lowercase normalized.

4.14.  printer-document-format-supported

   ( 1.3.18.0.2.4.1130
   NAME 'printer-document-format-supported'
   DESC 'The possible source document formats which may be interpreted
         and printed by this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   )

   Values of document formats should be MIME media types defined in the
   IANA Registry of MIME Media Types [IANA-MIME] (see also [RFC2048]).






Fleming & McDonald           Informational                     [Page 17]

RFC 3712            LDAP Schema for Printer Services       February 2004


4.15.  printer-color-supported

   ( 1.3.18.0.2.4.1129
   NAME 'printer-color-supported'
   DESC 'Indicates whether this printer is capable of any type of color
         printing at all, including highlight color.'
   EQUALITY booleanMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.7
   SINGLE-VALUE
   )

4.16.  printer-compression-supported

   ( 1.3.18.0.2.4.1128
   NAME 'printer-compression-supported'
   DESC 'Compression algorithms supported by this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}
   )

   Values defined in IPP/1.1 [RFC2911] include:

       'none' (no compression is used)
       'deflate' (public domain ZIP described in [RFC1951])
       'gzip' (GNU ZIP described in [RFC1952])
       'compress' (UNIX compression described in [RFC1977])

4.17.  printer-pages-per-minute

   ( 1.3.18.0.2.4.1127
   NAME 'printer-pages-per-minute'
   DESC 'The nominal number of pages per minute which may be output by
         this printer.'
   EQUALITY integerMatch
   ORDERING integerOrderingMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   )

   This attribute is informative, not a service guarantee.  Typically,
   it is the value used in marketing literature to describe this
   printer.  For example, the value for a simplex or black-and-white
   print mode.







Fleming & McDonald           Informational                     [Page 18]

RFC 3712            LDAP Schema for Printer Services       February 2004


4.18.  printer-pages-per-minute-color

   ( 1.3.18.0.2.4.1126
   NAME 'printer-pages-per-minute-color'
   DESC 'The nominal number of color pages per minute which may be
         output by this printer.'
   EQUALITY integerMatch
   ORDERING integerOrderingMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   )

   This attribute is informative, not a service guarantee.  Typically,
   it is the value used in marketing literature to describe this
   printer.


4.19.  printer-finishings-supported

   ( 1.3.18.0.2.4.1125
   NAME 'printer-finishings-supported'
   DESC 'The possible finishing operations supported by this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}
   )

   Values defined in IPP/1.1 [RFC2911] include:  'none', 'staple',
   'punch', 'cover', 'bind', 'saddle-stitch', 'edge-stitch',
   'staple-top-left', 'staple-bottom-left', 'staple-top-right',
   'staple-bottom-right', 'edge-stitch-left', 'edge-stitch-top',
   'edge-stitch-right', 'edge-stitch-bottom', 'staple-dual-left',
   'staple-dual-top', 'staple-dual-right', 'staple-dual-bottom'.

   Note:  Implementations may support other values.

4.20.  printer-number-up-supported

   ( 1.3.18.0.2.4.1124
   NAME 'printer-number-up-supported'
   DESC 'The possible numbers of print-stream pages to impose upon a
         single side of an instance of a selected medium.'
   EQUALITY integerMatch
   ORDERING integerOrderingMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.27
   )





Fleming & McDonald           Informational                     [Page 19]

RFC 3712            LDAP Schema for Printer Services       February 2004


   Values defined in IPP/1.1 [RFC2911] include: '1', '2', and '4'.

   Note:  Implementations may support other values.

4.21.  printer-sides-supported

   ( 1.3.18.0.2.4.1123
   NAME 'printer-sides-supported'
   DESC 'The number of impression sides (one or two) and the two-sided
         impression rotations supported by this printer.'
   EQUALITY caseIgnoreMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   )

   Values defined in IPP/1.1 [RFC2911] include:  'one-sided', 'two-
   sided-long-edge', 'two-sided-short-edge'.'

4.22.  printer-media-supported

   ( 1.3.18.0.2.4.1122
   NAME 'printer-media-supported'
   DESC 'The standard names/types/sizes (and optional color suffixes) of
         the media supported by this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}
   )

   Values are defined in IPP/1.1 [RFC2911] or any IANA registered
   extensions.  For example:

       'iso-a4'
       'envelope'
       'na-letter-white'

4.23.  printer-media-local-supported

   ( 1.3.18.0.2.4.1117
   NAME 'printer-media-local-supported'
   DESC 'Site-specific names of media supported by this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}
   )

   Values should be in the natural language specified by printer-
   natural-language-configured.




Fleming & McDonald           Informational                     [Page 20]

RFC 3712            LDAP Schema for Printer Services       February 2004


   For example:

       'purchasing-form' (site-specific name)

   as opposed to 'na-letter' (standard keyword from IPP/1.1 [RFC2911])
   in the printer-media-supported attribute.

4.24.  printer-resolution-supported

   ( 1.3.18.0.2.4.1121
   NAME 'printer-resolution-supported'
   DESC 'List of resolutions supported for printing documents by this
         printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}
   )

   Each resolution value should be a string containing 3 fields:
   1)  Cross feed direction resolution (positive integer);
   2)  Feed direction resolution (positive integer);
   3)  Unit - 'dpi' (dots per inch) or 'dpcm' (dots per centimeter).

   Each resolution field should be delimited by '>'.  For example:

       '300> 300> dpi>'
       '600> 600> dpi>'

   Note:  This attribute is based on 'printer-resolution-supported'
   defined in IPP/1.1 [RFC2911] (which has a binary complex encoding)
   derived from 'prtMarkerAddressabilityFeedDir',
   'prtMarkerAddressabilityXFeedDir', and 'prtMarkerAddressabilityUnit'
   defined in the Printer MIB [RFC1759] (which have integer encodings).

   Note:  The syntax and delimiter for this attribute are aligned with
   the equivalent attribute in the 'service:printer:' v2.0 template
   [SLP-PRT].  Whitespace is permitted after (but not before) the
   delimiter '>'.  Note that this delimiter differs from printer-xri-
   supported.












Fleming & McDonald           Informational                     [Page 21]

RFC 3712            LDAP Schema for Printer Services       February 2004


4.25.  printer-print-quality-supported

   ( 1.3.18.0.2.4.1120
   NAME 'printer-print-quality-supported'
   DESC 'List of print qualities supported for printing documents on
         this printer.'
   EQUALITY caseIgnoreMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   )

   Values defined in IPP/1.1 [RFC2911] include:

       'unknown'
       'draft'
       'normal'
       'high'

4.26.  printer-job-priority-supported

   ( 1.3.18.0.2.4.1110
   NAME 'printer-job-priority-supported'
   DESC 'Indicates the number of job priority levels supported by this
         printer.'
   EQUALITY integerMatch
   ORDERING integerOrderingMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   )

   An IPP/1.1 [RFC2911] conformant Printer, which supports job priority,
   always supports a full range of priorities from '1' to '100' (to
   ensure consistent behavior), therefore this attribute describes the
   'granularity' of priority supported.  Values of this attribute are
   from '1' to '100'.

4.27.  printer-copies-supported

   ( 1.3.18.0.2.4.1118
   NAME 'printer-copies-supported'
   DESC 'The maximum number of copies of a document that may be printed
         as a single job on this printer.'
   EQUALITY integerMatch
   ORDERING integerOrderingMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   )





Fleming & McDonald           Informational                     [Page 22]

RFC 3712            LDAP Schema for Printer Services       February 2004


   A positive value indicates the maximum supported copies.  A value of
   '0' indicates no maximum limit.  A value of '-1' indicates 'unknown'.

   Note:  The syntax and values for this attribute are aligned with the
   equivalent attribute in the 'service:printer:' v2.0 template [SLP-
   PRT].

4.28.  printer-job-k-octets-supported

   ( 1.3.18.0.2.4.1111
   NAME 'printer-job-k-octets-supported'
   DESC 'The maximum size in kilobytes (1,024 octets actually) incoming
         print job that this printer will accept.'
   EQUALITY integerMatch
   ORDERING integerOrderingMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE
   )

   A positive value indicates the maximum supported job size.  A value
   of '0' indicates no maximum limit.  A value of '-1' indicates
   'unknown'.

   Note:  The syntax and values for this attribute are aligned with the
   equivalent attribute in the 'service:printer:' v2.0 template [SLP-
   PRT].

4.29.  printer-current-operator

   ( 1.3.18.0.2.4.1112
   NAME 'printer-current-operator'
   DESC 'The identity of the current human operator responsible for
         operating this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   SINGLE-VALUE
   )

   The value of this attribute should include information that would
   enable other humans to reach the operator, such as a telephone
   number.









Fleming & McDonald           Informational                     [Page 23]

RFC 3712            LDAP Schema for Printer Services       February 2004


4.30.  printer-service-person

   ( 1.3.18.0.2.4.1113
   NAME 'printer-service-person'
   DESC 'The identity of the current human service person responsible
         for servicing this printer.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   SINGLE-VALUE
   )

   The value of this attribute should include information that would
   enable other humans to reach the service person, such as a telephone
   number.

4.31.  printer-delivery-orientation-supported

   ( 1.3.18.0.2.4.1114
   NAME 'printer-delivery-orientation-supported'
   DESC 'The possible delivery orientations of pages as they are printed
         and ejected from this printer.'
   EQUALITY caseIgnoreMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   )

   Values defined include:

       'unknown'
       'face-up'
       'face-down'

   Note:  The syntax and values for this attribute are aligned with the
   equivalent attribute in the 'service:printer:' v2.0 template [SLP-
   PRT].

4.32.  printer-stacking-order-supported

   ( 1.3.18.0.2.4.1115
   NAME 'printer-stacking-order-supported'
   DESC 'The possible stacking order of pages as they are printed and
         ejected from this printer.'
   EQUALITY caseIgnoreMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   )






Fleming & McDonald           Informational                     [Page 24]

RFC 3712            LDAP Schema for Printer Services       February 2004


   Values defined include:

       'unknown'
       'first-to-last'
       'last-to-first'

   Note:  The syntax and values for this attribute are aligned with the
   equivalent attribute in the 'service:printer:' v2.0 template [SLP-
   PRT].

4.33.  printer-output-features-supported

   ( 1.3.18.0.2.4.1116
   NAME 'printer-output-features-supported'
   DESC 'The possible output features supported by this printer.'
   EQUALITY caseIgnoreMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   )

   Values defined include:

       'unknown'
       'bursting'
       'decollating'
       'page-collating'
       'offset-stacking'

   Note:  The syntax and values for this attribute are aligned with the
   equivalent attribute in the 'service:printer:' v2.0 template [SLP-
   PRT].

   Note:  Implementations may support other values.

4.34.  printer-aliases

   ( 1.3.18.0.2.4.1108
   NAME 'printer-aliases'
   DESC 'List of site-specific administrative names of this printer in
         addition to the value specified for printer-name.'
   EQUALITY caseIgnoreMatch
   SUBSTR caseIgnoreSubstringsMatch
   SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}
   )

   Values of this attribute should be specified in the language
   specified in printer-natural-language-configured (for example, to
   support text-to-speech conversions), although the printer's alias may
   be specified in any language.



Fleming & McDonald           Informational                     [Page 25]

RFC 3712            LDAP Schema for Printer Services       February 2004


5.  Definition of Syntaxes

   No new attribute syntaxes are defined by this document.

   The attribute types defined in Section 4 of this document reference
   syntax OIDs defined in Section 6 of [RFC2252], which are summarized
   below:

   Syntax OID                      Syntax Description
   ------------------------------  ------------------
   1.3.6.1.4.1.1466.115.121.1.7    Boolean
   1.3.6.1.4.1.1466.115.121.1.15   DirectoryString (UTF-8 [RFC2279])
   1.3.6.1.4.1.1466.115.121.1.27   Integer

6.  Definition of Matching Rules

   No new matching rules are defined by this document.

   The attribute types defined in Section 4 of this document reference
   matching rules defined in Section 8 of [RFC2252] and/or Section 2 of
   [RFC3698], which are summarized below:

   Matching Rule OID               Matching Rule Name          Usage
   ------------------------------  ------------------          -----
   2.5.13.13                       booleanMatch                EQUALITY
   2.5.13.2                        caseIgnoreMatch             EQUALITY
   2.5.13.14                       integerMatch                EQUALITY
   2.5.13.15                       integerOrderingMatch        ORDERING
   2.5.13.4                        caseIgnoreSubstringsMatch   SUBSTR

7.  IANA Considerations

   This document does not define any new syntaxes or matching rules.

   This document does define the following Object Identifier
   Descriptors.  They have been registered by the IANA:

7.1.  Registration of Object Classes

   Subject:  Request for LDAP Descriptor Registration

   Descriptor (short name):  see table below

   Object Identifier:  see table below

   Person & email address to contact for further information:  see below

   Usage:  object class



Fleming & McDonald           Informational                     [Page 26]

RFC 3712            LDAP Schema for Printer Services       February 2004


   Specification:  RFC3712

   Author/Change Controller:

       Pat Fleming
       IBM
       Highway 52 N
       Rochester, MN 55901
       USA
       Phone: +1 507-253-7583
       EMail: flemingp@us.ibm.com

   Comments:

   Object Class                                    OID
   ------------------------------------            ---------------------
   slpServicePrinter                               1.3.18.0.2.6.254
   printerAbstract                                 1.3.18.0.2.6.258
   printerService                                  1.3.18.0.2.6.255
   printerServiceAuxClass                          1.3.18.0.2.6.257
   printerIPP                                      1.3.18.0.2.6.256
   printerLPR                                      1.3.18.0.2.6.253

7.2.  Registration of Attribute Types

   Subject:  Request for LDAP Descriptor Registration

   Descriptor (short name):  see table below

   Object Identifier:  see table below

   Person & email address to contact for further information:  see below

   Usage:  attribute type

   Specification:  RFC3712

   Author/Change Controller:

       Pat Fleming
       IBM
       Highway 52 N
       Rochester, MN 55901
       USA
       Phone: +1 507-253-7583
       EMail: flemingp@us.ibm.com





Fleming & McDonald           Informational                     [Page 27]

RFC 3712            LDAP Schema for Printer Services       February 2004


   Comments:

   Attribute Type                                  OID
   ------------------------------------            ---------------------
   printer-uri                                     1.3.18.0.2.4.1140
   printer-xri-supported                           1.3.18.0.2.4.1107
   printer-name                                    1.3.18.0.2.4.1135
   printer-natural-language-configured             1.3.18.0.2.4.1119
   printer-location                                1.3.18.0.2.4.1136
   printer-info                                    1.3.18.0.2.4.1139
   printer-more-info                               1.3.18.0.2.4.1134
   printer-make-and-model                          1.3.18.0.2.4.1138
   printer-ipp-versions-supported                  1.3.18.0.2.4.1133
   printer-multiple-document-jobs-supported        1.3.18.0.2.4.1132
   printer-charset-configured                      1.3.18.0.2.4.1109
   printer-charset-supported                       1.3.18.0.2.4.1131
   printer-generated-natural-language-supported    1.3.18.0.2.4.1137
   printer-document-format-supported               1.3.18.0.2.4.1130
   printer-color-supported                         1.3.18.0.2.4.1129
   printer-compression-supported                   1.3.18.0.2.4.1128
   printer-pages-per-minute                        1.3.18.0.2.4.1127
   printer-pages-per-minute-color                  1.3.18.0.2.4.1126
   printer-finishings-supported                    1.3.18.0.2.4.1125
   printer-number-up-supported                     1.3.18.0.2.4.1124
   printer-sides-supported                         1.3.18.0.2.4.1123
   printer-media-supported                         1.3.18.0.2.4.1122
   printer-media-local-supported                   1.3.18.0.2.4.1117
   printer-resolution-supported                    1.3.18.0.2.4.1121
   printer-print-quality-supported                 1.3.18.0.2.4.1120
   printer-job-priority-supported                  1.3.18.0.2.4.1110
   printer-copies-supported                        1.3.18.0.2.4.1118
   printer-job-k-octets-supported                  1.3.18.0.2.4.1111
   printer-current-operator                        1.3.18.0.2.4.1112
   printer-service-person                          1.3.18.0.2.4.1113
   printer-delivery-orientation-supported          1.3.18.0.2.4.1114
   printer-stacking-order-supported                1.3.18.0.2.4.1115
   printer-output-features-supported               1.3.18.0.2.4.1116
   printer-aliases                                 1.3.18.0.2.4.1108

8.  Internationalization Considerations

   All text string attributes defined in this document of syntax
   [RFC2279], as required by [RFC2252].

   A language tag [RFC3066] for all of the text string attributes
   defined in this document is contained in the printer-natural-
   language-configured attribute.




Fleming & McDonald           Informational                     [Page 28]

RFC 3712            LDAP Schema for Printer Services       February 2004


   Therefore, all object classes defined in this document conform to the
   "IETF Policy on Character Sets and Languages" [RFC2277].

9.  Security Considerations

   See [RFC2829] for detailed guidance on authentication methods for
   LDAP.  See [RFC2830] for detailed guidance of using TLS/1.0 [RFC2246]
   to supply connection confidentiality and data integrity for LDAP
   sessions.

   As with any LDAP schema, it is important to protect specific entries
   and attributes with the appropriate access control.  It is
   particularly important that only administrators can modify entries
   defined in this LDAP printer schema.  Otherwise, an LDAP client might
   be fooled into diverting print service requests from the original
   printer (or spooler) to a malicious intruder's host system, thus
   exposing the information in printed documents.

   For additional security considerations of deploying printers in an
   IPP environment, see Section 8 of [RFC2911].

10.  References

10.1.  Normative References

   [IANA-CHAR] IANA Registry of Character Sets
               http://www.iana.org/assignments/charset-reg/...

   [IANA-MIME] IANA Registry of MIME Media Types
               http://www.iana.org/assignments/media-types/...

   [LDAP-TS]   Hodges, J. and R. Morgan, "Lightweight Directory Access
               Protocol (v3): Technical Specification", RFC 3377,
               September 2002.

   [RFC1274]   Barker, P. and S. Kille, "The COSINE and Internet X.500
               Schema", RFC 1274, November 1991.

   [RFC1759]   Smith, R., Wright, F., Hastings, T., Zilles, S. and J.
               Gyllenskog, "Printer MIB", RFC 1759, March 1995.

   [RFC2119]   Bradner, S., "Key words for use in RFCs to Indicate
               Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2252]   Wahl, M., Coulbeck, T., Howes, T. and S. Kille,
               "Lightweight Directory Access Protocol (v3): Attribute
               Syntax Definitions", RFC 2252, December 1997.




Fleming & McDonald           Informational                     [Page 29]

RFC 3712            LDAP Schema for Printer Services       February 2004


   [RFC2396]   Berners-Lee. T., Fielding, R. and L. Masinter, "URI
               Generic Syntax", RFC 2396, August 1998.

   [RFC2829]   Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
               "Authentication Methods for LDAP", RFC 2829, May 2000.

   [RFC2830]   Hodges, J., Morgan, R. and M. Wahl, "Lightweight
               Directory Access Protocol (v3): Extension for Transport
               Layer Security", RFC 2830, May 2000.

   [RFC2911]   Hastings, T., Ed.., Herrito, R., deBry, R., Isaacson, S.
               and P. Powell, "Internet Printing Protocol/1.1: Model and
               Semantics", RFC 2911, September 2000.

   [RFC2926]   Kempf, J., Moats, R. and P. St. Pierre, "Conversion of
               LDAP Schemas to and from SLP Templates", RFC 2926,
               September 2000.

   [RFC3066]   Alvestrand, H., "Tags for the Identification of
               Languages", BCP 47, RFC 3066, January 2001.

   [RFC3698]   Zeilenga, K., Ed., "Lightweight Directory Access Protocol
               (LDAP): Additional Matching Rules", RFC 3698, February
               2004.

10.2.  Informative References

   [IANA-SLPT] IANA Registry of SLP Templates
               http://www.iana.org/assignments/svrloc-templates/...

   [RFC1179]   McLaughlin, L., "Line Printer Daemon Protocol", RFC 1179,
               August 1990.

   [RFC1951]   Deutsch, P., "DEFLATE Compressed Data Format
               Specification Version 1.3", RFC 1951, May 1996.

   [RFC1952]   Deutsch, P., "GZIP File Format Specification Version
               4.3", RFC 1952, May 1996.

   [RFC1977]   Schryver, V., "PPP BSD Compression Protocol", RFC 1977,
               August 1996.

   [RFC2048]   Freed, N., Klensin, J. and J. Postel, "Multipurpose
               Internet Mail Extensions (MIME) Part Four: Registration
               Procedures", BCP 13, RFC 2048, November 1996.






Fleming & McDonald           Informational                     [Page 30]

RFC 3712            LDAP Schema for Printer Services       February 2004


   [RFC2079]   Smith, M., "Definition of an X.500 Attribute Type and an
               Object Class to Hold Uniform Resource Identifiers
               (URIs)", RFC 2079, January 1997.

   [RFC2246]   Dierks, T. and C. Allen, "TLS Protocol Version 1.0", RFC
               2246, January 1999.

   [RFC2277]   Alvestrand, H., "IETF Policy on Character Sets and
               Languages", RFC 2277, January 1998.

   [RFC2279]   Yergeau, F., "UTF-8, a Transformation Format of ISO
               10646", RFC 2279, January 1998.

   [RFC2608]   Guttman, E., Perkins, C., Veizades, J. and M. Day,
               "Service Location Protocol v2", RFC 2608, June 1999.

   [RFC2609]   Guttman, E., Perkins, C. and J. Kempf, "Service Templates
               and Service: Schemes", RFC 2609, June 1999.

   [RFC2617]   Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence,
               S., Leach, P., Luotonen, A. and L. Stewart, "HTTP
               Authentication: Basic and Digest Access Authentication",
               RFC 2617, June 1999.

   [RFC2717]   Petke, R. and I. King, "Registration Procedures for URL
               Scheme Names", RFC 2717, November 1999.

   [RFC2718]   Masinter, L., Alvestrand, H., Zigmond, D. and R. Petke,
               "Guidelines for new URL Schemes", BCP 19, RFC 2718,
               November 1999.

   [RFC2978]   Freed, N. and J.Postel, "IANA Charset Registration
               Procedures", RFC2978, October 2000.

   [SLP-PRT]   St. Pierre, Isaacson, McDonald.  Definition of the
               Printer Abstract Service Type v2.0, <durable URL below>,
               May 2000. Reviewed and approved by IETF SLP Designated
               Expert, according to Section 5 'IANA Considerations' in
               [RFC2609].

               Archived in the IANA Registry of SLP Templates [IANA-
               SLPT] at: http://www.iana.org/assignments/svrloc-
               templates/printer.2.0.en

   [W3C-IRI]   Duerst, Suignard, "Internationalized Resource Identifiers
               (IRI), Work in Progress.





Fleming & McDonald           Informational                     [Page 31]

RFC 3712            LDAP Schema for Printer Services       February 2004


11.  Acknowledgments

   The editors wish to acknowledge the very significant contributions of
   Ken Jones (Bytemobile) and Harry Lewis (IBM) during the development
   of this document.

   Thanks to Patrik Faltstrom (Cisco), Ryan Moats (Lemur Networks),
   Robert Moore (IBM), Lee Rafalow (IBM), Kimberly Reger (IBM), Kurt
   Zeilenga (OpenLDAP), and the members of the IETF IPP Working Group,
   for review comments and help in preparing this document.

12.  Authors' Addresses

   Please send comments to the authors at the addresses listed below.

   Pat Fleming
   IBM
   Highway 52 N
   Rochester, MN 55901
   USA

   Phone: +1 507-253-7583
   EMail: flemingp@us.ibm.com


   Ira McDonald
   High North Inc
   221 Ridge Ave
   Grand Marais, MI 49839
   USA

   Phone: +1 906-494-2434
   Email: imcdonald@sharplabs.com


















Fleming & McDonald           Informational                     [Page 32]

RFC 3712            LDAP Schema for Printer Services       February 2004


13.  Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78 and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
   REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE
   INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed
   to pertain to the implementation or use of the technology
   described in this document or the extent to which any license
   under such rights might or might not be available; nor does it
   represent that it has made any independent effort to identify any
   such rights.  Information on the procedures with respect to
   rights in RFC documents can be found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use
   of such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository
   at http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention
   any copyrights, patents or patent applications, or other
   proprietary rights that may cover technology that may be required
   to implement this standard.  Please address the information to the
   IETF at ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.









Fleming & McDonald           Informational                     [Page 33]

alt-openldap11-devel/rfc/rfc4403.txt000064400000231633150410163250012770 0ustar00





Network Working Group                                        B. Bergeson
Request for Comments: 4403                                    K. Boogert
Category: Informational                                     Novell, Inc.
                                                        V. Nanjundaswamy
                                                  Oracle India Pvt. Ltd.
                                                           February 2006


        Lightweight Directory Access Protocol (LDAP) Schema for
  Universal Description, Discovery, and Integration version 3 (UDDIv3)

Status of This Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document defines the Lightweight Directory Access Protocol
   (LDAPv3) schema for representing Universal Description, Discovery,
   and Integration (UDDI) data types in an LDAP directory.  It defines
   the LDAP object class and attribute definitions and containment rules
   to model UDDI entities, defined in the UDDI version 3 information
   model, in an LDAPv3-compliant directory.

Table of Contents

   1. Introduction ....................................................2
   2. Conventions Used in This Document ...............................2
   3. Representation of UDDI Data Structures ..........................2
   4. Attribute Type Definitions ......................................6
   5. Object Class Definitions .......................................28
   6. Name Forms .....................................................32
   7. DIT Structure Rules ............................................35
   8. Security Considerations ........................................37
   9. IANA Considerations ............................................37
   10. Normative References ..........................................40









Bergeson, et al.             Informational                      [Page 1]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


1.  Introduction

   This document defines the Lightweight Directory Access Protocol
   [LDAPv3] schema elements to represent the core data structures
   identified in the Universal Description, Discovery, and Integration
   version 3 [UDDIv3] information model.  This includes a
   businessEntity, a businessService, a bindingTemplate, a tModel, a
   publisherAssertion, and a Subscription.  Portions of [UDDIv3] are
   repeated here for clarity.

2.  Conventions Used in This Document

   The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in RFC 2119 [RFC2119].

   All schema definitions are provided using [RFC2252] descriptions, and
   are line-wrapped for readability only.

3.  Representation of UDDI Data Structures

   The information that makes up a registration in a UDDI registry
   consists of these data structure types.  This division by information
   type provides simple partitions to assist in the rapid location and
   understanding of the different information that makes up a
   registration.

   The individual instance data managed by a UDDI registry is sensitive
   to the parent/child relationships found in the schema.  A
   businessEntity object contains one or more unique businessService
   objects.  Similarly, individual businessService objects contain
   specific instances of bindingTemplate, which in turn contains
   information that includes pointers to specific instances of tModel
   objects.

   It is important to note that no single instance of a core schema type
   is ever "contained" by more than one parent instance.  This means
   that only one specific businessEntity object (identified by its
   unique key value) will ever contain or be used to express information
   about a specific instance of a businessService object (also
   identified by its own unique key value).

3.1.  businessEntity

   The businessEntity object represents all known information about a
   business or entity that publishes descriptive information about the
   entity as well as the services that it offers.  The businessEntity is
   the top-level container that accommodates holding descriptive



Bergeson, et al.             Informational                      [Page 2]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   information about a business or entity.  Service descriptions and
   technical information are expressed within a businessEntity by a
   containment relationship.

3.1.1.  Representation in the Directory

   A businessEntity is represented in the directory by the attributes
   uddiBusinessKey, uddiAuthorizedName, uddiOperator, uddiDiscoveryURLs,
   uddiName, uddiDescription, uddiIdentifierBag, uddiCategoryBag, and
   uddiv3DigitalSignature, along with corresponding v3 keys viz.
   uddiv3BusinessKey, as defined in Section 4.  A businessEntity may
   contain zero or more instances of uddiContact and
   uddiBusinessService.

   A mandatory attribute, uddiBusinessKey, contains the unique
   identifier for a given instance of a businessEntity.

   businessEntity's definition is given in Section 5.

3.2.  businessService

   The businessService instances represent a logical business service.
   Each businessService object is the logical child of a single
   businessEntity object.  Each businessService element contains
   descriptive information in business terms outlining the type of
   technical services found within each businessService instance.

   In some cases, businesses would like to share or reuse services,
   e.g., when a large enterprise publishes separate businessEntity
   structures.  This can be established by using the businessService
   instance as a projection to an already published businessService.

3.2.1.  Representation in the Directory

   A businessService is represented in the directory by the attributes
   uddiBusinessKey, uddiServiceKey, uddiName, uddiDescription,
   uddiCategoryBag, uddiIsProjection, and uddiv3DigitalSignature, along
   with corresponding v3 keys viz. uddiv3BusinessKey, and
   uddiv3ServiceKey, as defined in Section 4.  A businessService may
   contain zero or more instances of uddiBindingTemplate.

   The mandatory attribute, uddiServiceKey, contains the unique
   identifier for a given instance of a businessService.

   businessService's definition is given in Section 5.






Bergeson, et al.             Informational                      [Page 3]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


3.3.  bindingTemplate

   Technical descriptions of Web services are accommodated via
   individual contained instances of bindingTemplate objects.  These
   instances provide support for determining a technical entry point or
   optionally support remotely hosted services, as well as a lightweight
   facility for describing unique technical characteristics of a given
   implementation.  Support for technology and application specific
   parameters and settings files are also supported.

   Since UDDI's main purpose is to enable description and discovery of
   Web service information, it is the bindingTemplate that provides the
   most interesting technical data.  With UDDIv3, bindingTemplates also
   can have categorization information.

   Each bindingTemplate instance has a single logical businessService
   parent, which in turn has a single logical businessEntity parent.

3.3.1.  Representation in the Directory

   A bindingTemplate is represented in the directory by the attributes
   uddiBindingKey, uddiServiceKey, uddiDescription, uddiAccessPoint,
   uddiHostingRedirector, uddiCategoryBag, and uddiv3DigitalSignature,
   along with corresponding v3 keys viz. uddiv3ServiceKey and
   uddiv3BindingKey, as defined in Section 4.  A bindingTemplate may
   contain zero or more instances of uddiTModelInstanceDetails.

   The mandatory attribute, uddiBindingKey, contains the unique
   identifier for a given instance of a bindingTemplate.

   BindingTemplate's definition is given in Section 5.

3.4.  tModel

   The tModel object takes the form of keyed metadata (data about data).
   In a general sense, the purpose of a tModel within the UDDI registry
   is to provide a reference system based on abstraction.  Thus, the
   kind of data that a tModel represents is pretty nebulous.  In other
   words, a tModel registration can define just about anything, but in
   the current revision, two conventions have been applied for using
   tModels: as sources for determining compatibility and as keyed
   namespace references.

   The information that makes up a tModel is quite simple.  There are a
   key, a name, an optional description, and a Uniform Resource Locator
   [URL] that points somewhere--presumably somewhere where the curious
   can go to find out more about the actual concept represented by the
   metadata in the tModel itself.



Bergeson, et al.             Informational                      [Page 4]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


3.4.1.  Representation in the Directory

   A tModel is represented in the directory by the attributes
   uddiTModelKey, uddiAuthorizedName, uddiOperator, uddiName,
   uddiDescription, uddiOverviewDescription, uddiOverviewURL,
   uddiIdentifierBag, uddiCategoryBag, uddiIsHidden, and
   uddiv3DigitalSignature, along with the corresponding v3 key viz.
   uddiv3tModelKey, as defined in Section 4.  A tModel may also contain
   a uddiHidden to logically delete a tModel.

   A mandatory attribute, uddiTModelKey, contains the unique identifier
   for a given instance of a tModel.

   tModel's definition is given in Section 5.

3.5.  publisherAssertion

   Many businesses, such as large enterprises or marketplaces, are not
   effectively represented by a single businessEntity, since their
   description and discovery are likely to be diverse.  As a
   consequence, several businessEntity instances can be published,
   representing individual subsidiaries of a large enterprise or
   individual participants of a marketplace.  Nevertheless, they still
   represent a more or less coupled community and would like to make
   some of their relationships visible in their UDDI registrations.

3.5.1.  Representation in the Directory

   A publisherAssertion is represented in the directory by the
   attributes uddiFromKey, uddiToKey, uddiKeyedReference, and uddiUUID,
   and uddiv3DigitalSignature, as defined in Section 5.

   A mandatory attribute, uddiUUID, contains the unique identifier for a
   given instance of a publisherAssertion.

   publisherAssertion's definition is given in Section 5.

3.6.  Operational Information:

   With UDDIv3, the operational information associated with the core
   UDDI data structures is maintained in a separate OperationalInfo
   structure, so that the digital signature specified by the publisher
   remains valid.

   The operationalInfo structure is used to convey the operational
   information for the UDDIv3 core data structures, that is, the
   businessEntity, businessService, bindingTemplate, and tModel




Bergeson, et al.             Informational                      [Page 5]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   structures.  UDDIv3 OperationalInfo consists of 5 elements: created,
   Modified, modifiedIncludingChildren, nodeId, and authorizedName.

   Depending on the specific UDDIv3 core data structure, the
   operationalInformation is represented in the directory as a
   combination of implicit LDAP Standard Operational attributes:
   createTimestamp and modifyTimestamp, and the following explicit
   attributes: uddiAuthorizedName, uddiv3EntityCreationTime,
   uddiv3EntityModificationTime, and uddiv3NodeId.

4.  Attribute Type Definitions

   The OIDs for the attribute types in this document have been
   registered by the IANA.

4.1.  uddiBusinessKey

   This is used in uddiBusinessEntity and uddiBusinessService.

   The uddiBusinessKey is the unique identifier for a given instance of
   a uddiBusinessEntity.  The attribute is optional for businessService
   instances contained within a fully expressed parent that already
   contains a businessKey value.

   If the businessService instance is rendered into the Extensible
   Markup Language [XML] and has no containing parent that has within
   its data a businessKey, the value of the businessKey that is the
   parent of the businessService is required to be provided.  This
   behavior supports the ability to browse through the parent-child
   relationships given any of the core elements as a starting point.
   The businessKey may differ from the publishing businessEntity's
   businessKey to allow service projections.

      ( 1.3.6.1.1.10.4.1 NAME 'uddiBusinessKey'
        DESC 'businessEntity unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.2.  uddiAuthorizedName

   The uddiAuthorizedName is the recorded name of the individual who
   published the uddiBusinessEntity or uddiTModel data.  This data is
   generated by the controlling operator and should not be supplied
   within save_business operations.

   With UDDIv3, this attribute is part of the "operationalInformation"



Bergeson, et al.             Informational                      [Page 6]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   metadata associated with core data structures.

      ( 1.3.6.1.1.10.4.2 NAME 'uddiAuthorizedName'
        DESC 'businessEntity publisher name'
        EQUALITY distinguishedNameMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
        SINGLE-VALUE
      )

4.3.  uddiOperator

   The uddiOperator is the certified name of the UDDI registry site
   operator that manages the master copy of the uddiBusinessEntity or
   uddiTModel.  The controlling operator records this data at the time
   data is saved.  This data is generated and should not be supplied
   within save_business or save_tModel operations.

   With UDDIv3, this field is no longer used -- it is replaced by the
   nodeId (uddiv3NodeId) attribute that is part of the
   "operationalInformation" metadata.

      ( 1.3.6.1.1.10.4.3 NAME 'uddiOperator'
        DESC 'registry site operator of businessEntitys master copy'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.4.  uddiName

   This is used in uddiBusinessEntity, uddiBusinessService, and
   uddiTModel.

   These are the human-readable names recorded for the
   uddiBusinessEntity, uddiBusinessService, or uddiTModel, adorned with
   a unique xml:lang value to signify the language that they are
   expressed in.  Name search is provided via find_business,
   find_service, or find_tModel calls.

   The publishing of several names, e.g., for romanization purposes, is
   supported.  In order to signify the language that the names are
   expressed in, they carry unique xml:lang values.  Not more than one
   name element may omit specifying its language.  Names passed in this
   way will be assigned the default language code of the registering
   party.  This default language code is established at the time that
   publishing credentials are established with an individual Operator





Bergeson, et al.             Informational                      [Page 7]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   Site.  If no default language is provisioned at the time a publisher
   signs up, the operator can adopt an appropriate default language
   code.

   With UDDIv3, multiple values with the same language code are
   permitted.

      ( 1.3.6.1.1.10.4.4 NAME 'uddiName'
        DESC 'human readable name'
        EQUALITY caseIgnoreMatch
        ORDERING caseIgnoreOrderingMatch
        SUBSTR caseIgnoreSubstringsMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The xml:lang value precedes the name value, with the "#" character
   used as the separator.

4.5.  uddiDescription

   The uddiDescription is an optional repeating element of one or more
   descriptions.  One description is allowed per national language code
   supplied.  With UDDIv3, there is no restriction on the number of
   descriptions or on what xml:lang value that they may have.

      ( 1.3.6.1.1.10.4.5 NAME 'uddiDescription'
        DESC 'short description'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The xml:lang value precedes the name value, with the "#" character
   used as the separator.

4.6.  uddiDiscoveryURLs

   This is a list of Uniform Resource Locators (URLs) that point to
   alternate, file-based service discovery mechanisms.  Each recorded
   uddiBusinessEntity structure is automatically assigned a URL that
   returns the individual uddiBusinessEntity structure.  A URL search is
   provided via find_business call.

   The uddiDiscoveryURLs attribute is used to hold pointers to URL-
   addressable discovery documents.  The expected retrieval mechanism
   for URLs referenced in the data within this structure is via the
   Hypertext Transfer Protocol [HTTP] HTTP-GET operation.  The expected
   return document is not defined.  Rather, a framework for establishing
   conventions is provided, and two such conventions are defined within



Bergeson, et al.             Informational                      [Page 8]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   UDDI behaviors.  It is hoped that other conventions come about and
   use this structure to accommodate alternate means of discovery.  With
   UDDIv3, a new convention is defined with useType as "homepage".
   Further, a UDDIv3 server need not generate/add a discoveryURL itself,
   since this can invalidate the digital signature of signed the
   Business Entity saved by publishers.

      ( 1.3.6.1.1.10.4.6 NAME 'uddiDiscoveryURLs'
        DESC 'URL to retrieve a businessEntity instance'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The useType value precedes the URL value, with the "#" character used
   as the separator.

4.7.  uddiUseType

   The uddiUseType is used to describe the type of contact or address in
   freeform text.  Suggested examples for contact include "technical
   questions", "technical contact", "establish account", "sales
   contact", etc.  Suggested examples for address include
   "headquarters", "sales office", "billing department", etc.

      ( 1.3.6.1.1.10.4.7 NAME 'uddiUseType'
        DESC 'name of convention the referenced document follows'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.8.  uddiPersonName

   The uddiPersonName should list the name of the person or name of the
   job role that will be available behind the contact.  Examples of
   roles include "administrator" or "webmaster".

      ( 1.3.6.1.1.10.4.8 NAME 'uddiPersonName'
        DESC 'name of person or job role available for contact'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

   With UDDIv3, uddiPersonName becomes multi-valued and each name can
   have an xml:lang attribute.  The xml:lang value precedes the name
   value with the "#" character used as the separator.




Bergeson, et al.             Informational                      [Page 9]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.9.  uddiPhone

   This is used to hold telephone numbers for the contact.  This element
   can be adorned with an optional uddiUseType attribute for descriptive
   purposes.  If more than one phone element is saved, uddiUseType
   attributes are required on each.

      ( 1.3.6.1.1.10.4.9 NAME 'uddiPhone'
        DESC 'telephone number for contact'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The useType precedes the telephone number by a separating '#' (e.g.,
   "Work Number#123 456-7890") .

4.10.  uddiEMail

   This is used to hold email addresses for the contact.  This element
   can be adorned with an optional uddiUseType attribute for descriptive
   purposes.  If more than one email element is saved, uddiUseType
   attributes are required on each.

      ( 1.3.6.1.1.10.4.10 NAME 'uddiEMail'
        DESC 'e-mail address for contact'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The useType precedes the email address by a separating '#' (e.g.,
   "President of the United States #president@whitehouse.gov").

4.11.  uddiSortCode

   The uddiSortCode is used to drive the behavior of external display
   mechanisms that sort addresses.  The suggested values for
   uddiSortCode include numeric ordering values (e.g., 1, 2, 3),
   alphabetic character ordering values (e.g., a, b, c), or the first n
   positions of relevant data within the address.

      ( 1.3.6.1.1.10.4.11 NAME 'uddiSortCode'
        DESC 'specifies an external display mechanism'
        EQUALITY caseIgnoreMatch
        ORDERING caseIgnoreOrderingMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )




Bergeson, et al.             Informational                     [Page 10]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   With UDDIv3, the sortCode attribute is deprecated because of the
   guarantee of preserving the document Order.

4.12.  uddiTModelKey

   The uddiTModelKey is the unique identifier for a given instance of an
   uddiTModel.

   It is also used in a KeyedReference and in Address structures.  When
   used with a keyed reference, this is the unique key to identify a
   value set and implies that the keyName keyValue pair in a
   uddiIdentifier or uddiCategory Bag are to be interpreted by the value
   set referenced by the tModelKey.

   When used with Addressline elements, it implies that the keyName
   keyValue pair given by subsequent uddiAddressLine elements are to be
   interpreted by the address structure associated with the tModel that
   is referenced.

      ( 1.3.6.1.1.10.4.12 NAME 'uddiTModelKey'
        DESC 'tModel unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.13.  uddiAddressLine

   The uddiAddressLine contains the actual address in freeform text.  If
   the address element contains a uddiTModelKey, these uddiAddressLine
   elements are to be adorned, each with an optional keyName keyValue
   attribute pair.  Together with the uddiTModelKey, keyName and
   keyValue qualify the uddiAddressLine in order to describe its
   meaning.

   The uddiAddressLine elements contain string data with a line length
   limit of 80 character positions.  Each uddiAddressLine element can be
   adorned with two optional descriptive attributes, keyName and
   keyValue.  Both attributes must be present in each address line if a
   uddiTModelKey is assigned to the address structure.  By doing this,
   the otherwise arbitrary use of address lines becomes structured.
   Together with the address' uddiTModelKey, keyName and keyValue
   virtually build a uddiKeyedReference that represents an address line
   qualifier, given by the referenced uddiTModel.

   When no uddiTModelKey is provided for the address structure, the
   keyName and keyValue attributes can be used without restrictions, for
   example, to provide descriptive information for each uddiAddressLine



Bergeson, et al.             Informational                     [Page 11]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   by using the keyName attribute.  Since both the keyName and the
   keyValue attributes are optional, address line order is significant
   and will always be returned by the UDDI-compliant registry in the
   order originally provided during a call to save_business.

      ( 1.3.6.1.1.10.4.13 NAME 'uddiAddressLine'
        DESC 'address'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The keyName, keyValue, and addressData of this attribute are
   separated by "#" (e.g., "#"<keyName>"#"<keyValue>"#"<addressData>).
   The addressData is the only required portion of the attribute.

4.14.  uddiIdentifierBag

   The uddiIdentifierBag element allows uddiBusinessEntity or uddiTModel
   structures to include information about common forms of
   identification such as D-U-N-S_ numbers, tax identifiers, etc.  This
   data can be used to signify the identity of the uddiBusinessEntity or
   can be used to signify the identity of the publishing party.
   Including data of this sort is optional, but when used greatly
   enhances the search behaviors exposed via the find_xx messages
   defined in the UDDI Version 2.0 API Specification [UDDIapi].  For a
   full description of the structures involved in establishing an
   identity, see UDDI Version 2.0 Data Structure Specification -
   Appendix A:  Using Identifiers [UDDIdsr].

      ( 1.3.6.1.1.10.4.14  NAME 'uddiIdentifierBag'
        DESC 'identification information'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The tModel, keyName, and keyValue of this attribute are separated by
   "#" (e.g., <tModel>"#"<keyName>"#"<keyValue>).  The keyValue is the
   only required portion of the attribute.

4.15.  uddiCategoryBag

   The uddiCategoryBag element allows uddiBusinessEntity,
   uddiBusinessService, and uddiTModel structures to be categorized
   according to any of several available taxonomy-based classification
   schemes.  Operator Sites automatically provide validated
   categorization support for three taxonomies that cover industry codes
   (via NAICS), product and service classifications (via UNSPC), and
   geography (via ISO 3166).  Including data of this sort is optional,



Bergeson, et al.             Informational                     [Page 12]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   but when used, it greatly enhances the search behaviors exposed by
   the find_xx messages defined in the UDDI Version 2.0 API
   Specification [UDDIapi].  For a full description of structures
   involved in establishing categorization information, see UDDI Version
   2.03 Data Structure Specification--Appendix B: Using Categorization
   [UDDIdsr].

      ( 1.3.6.1.1.10.4.15 NAME 'uddiCategoryBag'
        DESC 'categorization information'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The tModel, keyName, and keyValue of this attribute are separated by
   "#" (e.g., <tModel>"#"<keyName>"#"<keyValue>).  The keyValue is the
   only required portion of the attribute.

   With UDDIv3, uddiBindingTemplates also supports the uddiCategoryBag
   element and they can also be categorized according to any of several
   available taxonomy-based classification schemes.

4.16.  uddiKeyedReference

   The uddiKeyedReference is a general-purpose attribute for a name-
   value pair, with an additional reference to a tModel.

      ( 1.3.6.1.1.10.4.16 NAME 'uddiKeyedReference'
        DESC 'categorization information'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The tModel, keyName, and keyValue of this attribute are separated by
   "#" (e.g., <tModel>"#"<keyName>"#"<keyValue>).  The keyValue is the
   only required portion of the attribute.  With UDDIv3, the tModelKey
   also becomes a mandatory part of the attribute.

   Also, UDDIv3 defines KeyedReferenceGroups for CategoryBags.  A
   keyedReferenceGroup contains a tModelKey and a simple list of
   KeyedReference structures.  The uddiKeyedReference attribute will
   support KeyedReferenceGroups by suffixing the tModelKey for
   KeyedReferenceGroup to each of the keyedReference values associated
   with the group.

   For example, to represent a keyedReference group containing a list of
   2 keyed references, the attribute will hold the following 2 strings
   as its values:




Bergeson, et al.             Informational                     [Page 13]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


      tModelKey1#KeyName1#KeyValue1#KeyedReferenceGroup1_tModelKey
      tModelKey2#KeyName2#KeyValue2#KeyedReferenceGroup1_tModelKey

4.17.  uddiServiceKey

   This is the unique key for a given uddiBusinessService.  When saving
   a new uddiBusinessService structure, pass an empty uddiServiceKey
   value.  This signifies that a UUID value is to be generated.  To
   update an existing uddiBusinessService structure, pass the UUID value
   that corresponds to the existing service.  If a uddiServiceKey is
   received via an inquiry operation, the key values may not be blank.
   When saving a new or updated service projection, pass the
   uddiServiceKey of the referenced uddiBusinessService structure.

   This attribute is optional when the uddiBindingTemplate data is
   contained within a fully expressed parent that already contains a
   uddiServiceKey value.  If the uddiBindingTemplate data is rendered
   into XML and has no containing parent that has within its data a
   uddiServiceKey, the value of the uddiServiceKey that is the ultimate
   containing parent of the uddiBindingTemplate is required to be
   provided.  This behavior supports the ability to browse through the
   parent-child relationships given any of the core elements as a
   starting point.

      ( 1.3.6.1.1.10.4.17 NAME 'uddiServiceKey'
        DESC 'businessService unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.18.  uddiBindingKey

   This is the unique key for a given uddiBindingTemplate.  When saving
   a new uddiBindingTemplate structure, pass an empty uddiBindingKey
   value.  This signifies that a UUID value is to be generated.  To
   update an existing uddiBindingTemplate, pass the UUID value that
   corresponds to the existing uddiBindingTemplate instance.  If a
   uddiBindingKey is received via an inquiry operation, the key values
   may not be blank.

      ( 1.3.6.1.1.10.4.18 NAME 'uddiBindingKey'
        DESC 'bindingTemplate unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )




Bergeson, et al.             Informational                     [Page 14]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.19.  uddiAccessPoint

   The uddiAccessPoint element is an attribute-qualified pointer to a
   service entry point.  The notion of service at the metadata level
   seen here is fairly abstract and many types of entry points are
   accommodated.  A single attribute is provided named URLType.

   Required attribute-qualified element8: This element is a text field
   that is used to convey the entry point address suitable for calling a
   particular Web service.  This may be a URL, an electronic mail
   address, or even a telephone number.  No assumptions about the type
   of data in this field can be made without first understanding the
   technical requirements associated with the Web service.

      ( 1.3.6.1.1.10.4.19 NAME 'uddiAccessPoint'
        DESC 'entry point address to call a web service'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

   The URLType value precedes the accessPoint value by a separating '#'.

   With UDDIv3, the "URLType" attribute is replaced by a "UseType"
   attribute.  Using this UseType attribute, the accessPoint attribute
   can model a hostingRedirector or support indirection to indicate that
   the accesspoint is specified within a remotely hosted WSDL document.

   For a UDDIv3 registry that needs to support UDDIv2 clients, the
   attribute must allow the representation of URLType and UseType values
   independently.

   The UDDIv3 spec specifies the following logic for mapping values
   between URLType and UseType: If an entity is saved with the v3
   namespace and a v2 inquiry is made, the URLType will be returned as
   "other".  In the case when a v3 inquiry is made on an entity
   published with the v2 namespace, the v3 useType attribute will be
   returned as "endPoint".

   For implementations that need to explicitly model both forms, the
   recommended format is as follows: v2URLType#v3UseType#Address

4.20.  uddiHostingRedirector

   The uddiHostingRedirector element is used to designate that a
   uddiBindingTemplate entry is a pointer to a different
   uddiBindingTemplate entry.  The value in providing this facility is
   seen when a business or entity wants to expose a service description



Bergeson, et al.             Informational                     [Page 15]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   (e.g., advertise that it has a service available that suits a
   specific purpose) that is actually a service described in a separate
   uddiBindingTemplate record.  This might occur when a service is
   remotely hosted (hence the name of this element), or when many
   service descriptions could benefit from a single service description.

   The uddiHostingRedirector element has a single attribute and no
   element content.  The attribute is a uddiBindingKey value that is
   suitable within the same UDDI registry instance for querying and
   obtaining the uddiBindingDetail data that is to be used.

   More on the uddiHostingRedirector can be found in the appendices for
   the UDDI Version 2.0 API Specification [UDDIapi].

   Required element if uddiAccessPoint is not provided: This element is
   adorned with a uddiBindingKey attribute, giving the redirected
   reference to a different uddiBindingTemplate.  If you query a
   uddiBindingTemplate and find a uddiHostingRedirector value, you
   should retrieve that uddiBindingTemplate and use it in place of the
   one containing the uddiHostingRedirector data.

      ( 1.3.6.1.1.10.4.20 NAME 'uddiHostingRedirector'
        DESC 'designates a pointer to another bindingTemplate'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

   With UDDIv3, the hostingRedirector is a deprecated element, since its
   functionality is now covered by the accessPoint.  For backward-
   compatibility, it can still be used, but it is not recommended.

4.21.  uddiInstanceDescription

   This is an optional repeating element.  This is one or more
   language-qualified text descriptions that designate what role a
   uddiTModel reference plays in the overall service description.

      ( 1.3.6.1.1.10.4.21 NAME 'uddiInstanceDescription'
        DESC 'instance details description'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The xml:lang value precedes the name value, with the "#" character
   used as the separator.





Bergeson, et al.             Informational                     [Page 16]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.22.  uddiInstanceParms

   The uddiInstanceParms is an optional element of the uddiInstance.  It
   is used to contain settings parameters or a URL reference to a file
   that contains settings or parameters required to use a specific facet
   of a uddiBindingTemplate description.  If used to house the
   parameters themselves, the suggested content is a namespace-qualified
   XML string using a namespace outside of the UDDI schema.  If used to
   house a URL pointer to a file, the suggested format is a URL that is
   suitable for retrieving the settings or parameters via HTTP-GET.

      ( 1.3.6.1.1.10.4.22 NAME 'uddiInstanceParms'
        DESC 'URL reference to required settings'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.23.  uddiOverviewDescription

   This is an optional repeating element.  This language-qualified
   string is intended to hold a short descriptive overview of how a
   particular uddiTModel is to be used.

      ( 1.3.6.1.1.10.4.23 NAME 'uddiOverviewDescription'
        DESC 'outlines tModel usage'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
      )

   The xml:lang value precedes the name value, with the "#" character
   used as the separator.



















Bergeson, et al.             Informational                     [Page 17]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.24.  uddiOverviewURL

   This is an optional element.  This string data element is to be used
   to hold a URL reference to a long form of an overview document that
   covers the way a particular uddiTModel specific reference is used as
   a component of an overall Web service description.  The recommended
   format for the overviewURL is a URI that is suitable for retrieving
   the actual overview document with an HTTP-GET operation, for example,
   via a Web browser.

      ( 1.3.6.1.1.10.4.24 NAME 'uddiOverviewURL'
        DESC 'URL reference to overview document'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

   With UDDIv3, uddiOverviewURL becomes multi-valued to allow the
   representation of multiple OverviewDocs within a single
   InstanceDetail element.

   Modeling multiple OverviewDocs within an InstanceDetail element:

   In UDDIv3, the InstanceDetails element in TmodelInstanceInfo can have
   multiple OverviewDoc's.  In UDDIv2, we could have only 1 OverviewDoc.
   To retain the grouping between a set of overviewDescriptions and
   overviewURL, we can make both OverviewDoc and OverviewURL multi-
   valued, and have a "group ID" Prefix to each value (to group
   OverviewDescriptions and OverviewURL).

   An example is shown below:

         Overview Description                            OverviewURL
         1#xml:lang#overviewDescription1         1#UseType#overviewURL
         1#xml:lang#overviewDescription2         2#UseType#overviewURL
         1#xml:lang#overviewDescription3         4#UseType#overviewURL
         3#xml:lang#overviewDescription1
         3#xml:lang#overviewDescription2
         4#xml:lang#overviewDescription1

   This implies that OverviewDoc1 has 3 overview descriptions and an
   overviewURL.  OverviewDoc2 has only an overviewURL.  OverviewDoc3 has
   only 2 overviewDescriptions.  OverviewDoc4 also has 1 overview
   description and an overviewURL.







Bergeson, et al.             Informational                     [Page 18]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.25.  uddiFromKey

   The uddiFromKey is a required element.  This is the unique key
   reference to the first uddiBusinessEntity for which the assertion is
   made.

      ( 1.3.6.1.1.10.4.25 NAME 'uddiFromKey'
        DESC 'unique businessEntity key reference'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.26.  uddiToKey

   The uddiToKey is a required element.  This is the unique key
   reference to the second uddiBusinessEntity for which the assertion is
   made.

      ( 1.3.6.1.1.10.4.26 NAME 'uddiToKey'
        DESC 'unique businessEntity key reference'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.27.  uddiUUID

   The uddiUUID is a required element.  This is to ensure unique
   identification of uddiContact, uddiAddress, and
   uddiPublisherAssertion objects.

      ( 1.3.6.1.1.10.4.27 NAME 'uddiUUID'
        DESC 'unique attribute'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

   With UDDIv3, this attribute will also be used for unique
   identification of Subscription-feature-related entities.










Bergeson, et al.             Informational                     [Page 19]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.28.  uddiIsHidden

   This is used to provide functionality for the delete_tModel
   operation.  Logical deletion hides the deleted tModels from
   find_tModel result sets but does not physically delete it.

      ( 1.3.6.1.1.10.4.28 NAME 'uddiIsHidden'
        DESC 'isHidden attribute'
        EQUALITY booleanMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
        SINGLE-VALUE
      )

   In case of UDDIv3, this attribute will represent the "deleted"
   attribute value.

4.29.  uddiIsProjection

   This is used to identify a Business Service that has a Service
   Projection.

      ( 1.3.6.1.1.10.4.29 NAME 'uddiIsProjection'
        DESC 'isServiceProjection attribute'
        EQUALITY booleanMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
        SINGLE-VALUE
      )

4.30.  uddiLang

   This is used to model the xml:lang value for the Address structure in
   UDDIv3.

      ( 1.3.6.1.1.10.4.30 NAME 'uddiLang'
        DESC 'xml:lang value in v3 Address structure'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

   The following are attribute definitions to model new elements/fields
   in UDDIv3 information model.  These attribute definitions have the
   "uddiv3" prefix to indicate that these attributes represent UDDI
   information model elements unique to UDDIv3.







Bergeson, et al.             Informational                     [Page 20]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.31.  uddiv3BusinessKey

   This is the unique UDDIv3 identifier for a given instance of
   uddiBusinessEntity.  It is used in uddiBusinessEntity and
   uddiBusinessService.

   A uddiBusinessEntity will include the uddiBusinessKey (the v2 form)
   for unique identification by UDDIv2 clients.  The uddiBusinessKey
   (36-char) will also be the LDAP naming attribute for the
   uddiBusinessEntity.  The uddiBusinessEntity entry MAY also include
   the uddiv3BusinessKey, the explicit v3 form key, which can be 255
   characters long.

      ( 1.3.6.1.1.10.4.31 NAME 'uddiv3BusinessKey'
        DESC 'UDDIv3 businessEntity unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.32.  uddiv3ServiceKey

   This is the unique UDDIv3 identifier for a given instance of
   uddiBusinessService.  It is used in uddiBusinessService and
   uddiBindingTemplate.

   A uddiBusinessService will include the uddiServiceKey (the v2 form)
   for unique identification by UDDIv2 clients.  The uddiServiceKey
   (36-char) will also be the LDAP naming attribute for the
   uddiBusinessService entry.  The uddiBusinessService entry MAY also
   include the uddiv3ServiceKey, the explicit v3 form key, which can be
   255 characters long.

      ( 1.3.6.1.1.10.4.32 NAME 'uddiv3ServiceKey'
        DESC 'UDDIv3 businessService unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.33.  uddiv3BindingKey

   This is the unique UDDIv3 identifier for a given instance of
   uddiBindingTemplate.

   A uddiBindingTemplate will include the uddiBindingKey (the v2 form)
   for unique identification by UDDIv2 clients.  The uddiBindingKey
   (36-char) will also be the LDAP naming attribute for the



Bergeson, et al.             Informational                     [Page 21]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   uddiBindingTemplate entry.  The uddiBindingTemplate entry MAY also
   include the uddiv3BindingKey, the explicit v3 form key, which can be
   255 characters long.

      ( 1.3.6.1.1.10.4.33 NAME 'uddiv3BindingKey'
        DESC 'UDDIv3 BindingTemplate unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.34.  uddiv3TModelKey

   This is the unique UDDIv3 identifier for a given instance of a
   uddiTModel.

   A uddiTModel will include the uddiTModelKey (the v2 form) for unique
   identification by UDDIv2 clients.  The uddiTModelKey (41-char) will
   also be the LDAP naming attribute for the uddiTModel entry.  The
   uddiTModel entry MAY also include the uddiv3TModelKey, the explicit
   v3 form key, which can be 255 characters long.

      ( 1.3.6.1.1.10.4.34 NAME 'uddiv3TModelKey'
        DESC 'UDDIv3 TModel unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

   The tModelKey is also used in a KeyedReference and in Address
   structures.  In all instances where a tModelKey is used as a
   reference to tModel, the v3 form of the tModel key (viz.
   uddiv3TModelKey) will be the form used, since using the v2 form key
   will require translating it to the v3 key by the UDDI Server, which
   may invalidate the digital signature of the entity.

4.35.  uddiv3DigitalSignature

   The UDDIv3 v3 schema supports the signing of the following UDDI
   elements using "XML-Signature Syntax and Processing" (see
   http://www.w3.org/TR/xmldsig-core/).

      ..businessEntity
      ..businessService
      ..bindingTemplate
      ..tModel
      ..publisherAssertion




Bergeson, et al.             Informational                     [Page 22]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   This uddiv3DigitalSignature attribute holds the digital signature for
   the corresponding UDDI entity.

      ( 1.3.6.1.1.10.4.35 NAME 'uddiv3DigitalSignature'
        DESC 'UDDIv3 entity digital signature'
        EQUALITY caseExactMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        )

   A Signature element SHOULD be generated according to the required
   steps of "Core Generation" in XML-Signature Syntax and Processing.
   The signature should be calculated on the top-level element that will
   be stored by the registry as a result of the Publication API call.
   This element, referred to as the data object in the XML-Signature and
   Syntax specification, is the businessEntity element for save_business
   API calls, the businessService element for save_service API calls,
   the bindingTemplate for save_binding API calls, the tModel for
   save_tModel API calls, and the publisherAssertion for
   set_publisherAssertions and add_publisherAssertion API calls.

   The signature should be generated on the elements before they are
   added to the body of an API call.  Also, according to the signature
   generation, all children of the element being signed are included in
   the generation of the signature unless first excluded by application
   of a transform.  Due to the containment of service projections as
   businessService elements within a businessEntity element, this also
   means that changes to the projected service will render a signature
   of the businessEntity containing the projection invalid, unless a
   businessService element representing a service projection is excluded
   using a transform.

   Due to the location of the sequence of Signature elements within an
   element that is to be signed, the signature is "enveloped".  As a
   result of the enveloping of the signature, it is necessary to apply
   at least one transformation on the signed entity to exclude the
   signature or signature(s).  The transformation selected by a
   publisher or the XML-Signature tool is specified in a Transform
   element inside the Signature element.













Bergeson, et al.             Informational                     [Page 23]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.36.  uddiv3NodeId

   This attribute contains the Node Identity for a UDDIv3 node.

      ( 1.3.6.1.1.10.4.36 NAME 'uddiv3NodeId'
        DESC 'UDDIv3 Node Identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.37.  uddiv3EntityModificationTime

   This attribute is used to maintain the last modification time for a
   UDDI entity.  It is needed in the context of maintaining the
   modifiedIncludingChildren element.  When a child entity (e.g.,
   uddiBindingTemplate) is updated, the parent entity (e.g.,
   uddiBusinessService) LDAP timestamp also gets updated.  The
   uddiv3EntityModificationTime attribute saves the last modification
   time of the parent entity (uddiBusinessService in this case).

      ( 1.3.6.1.1.10.4.37 NAME 'uddiv3EntityModificationTime'
        DESC 'UDDIv3 Last Modified Time for Entity'
        EQUALITY generalizedTimeMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
        SINGLE-VALUE
      )

   The following attribute definitions define attributes related to the
   modeling of UDDIv3 subscription-related entities in the LDAP
   directory.

   Subscription provides clients, known as subscribers, with the ability
   to register their interest in receiving information concerning
   changes made in a UDDI registry.  These changes can be scoped based
   on preferences provided with the request.  The uddiv3Subscription
   object class is used to model registered UDDIv3 subscriptions.














Bergeson, et al.             Informational                     [Page 24]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.38.  uddiv3SubscriptionKey

   This is the unique UDDIv3 identifier for a given instance of a
   uddiv3Subscription entity.

      ( 1.3.6.1.1.10.4.38 NAME 'uddiv3SubscriptionKey'
        DESC 'UDDIv3 Subscription unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.39.  uddiv3SubscriptionFilter

   This attribute contains the UDDIv3 Subscription Filter, specified as
   part of the save_subscription API, i.e., the Inquiry API specified as
   filtering criteria with a registered subscription.  The filtering
   criteria limits the scope of a subscription to a subset of registry
   records.  The get_xx and find_xx APIs are all valid choices for use
   as a subscriptionFilter.  Only one of these can be chosen for each
   subscription.

      ( 1.3.6.1.1.10.4.39 NAME 'uddiv3SubscriptionFilter'
        DESC 'UDDIv3 Subscription Filter'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.40.  uddiv3NotificationInterval

   This attribute contains the Notification Interval string.  It is of
   the type xsd:duration and specifies how often Asynchronous change
   notifications are to be provided to a subscriber.

      ( 1.3.6.1.1.10.4.40 NAME 'uddiv3NotificationInterval'
        DESC 'UDDIv3 Notification Interval'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )










Bergeson, et al.             Informational                     [Page 25]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.41.  uddiv3MaxEntities

   This attribute contains the maximum number of entities to be returned
   as part of a subscription notification.  It is an integer and
   specifies the maximum number of entities in a notification returned
   to a subscription listener.

      ( 1.3.6.1.1.10.4.41 NAME 'uddiv3MaxEntities'
        DESC 'UDDIv3 Subscription maxEntities field'
        EQUALITY integerMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
        SINGLE-VALUE
      )

4.42.  uddiv3ExpiresAfter

   This attribute specifies the Expiry Time associated with a
   subscription.  It is of the XML Schema type xsd:dateTime.

      ( 1.3.6.1.1.10.4.42 NAME 'uddiv3ExpiresAfter'
        DESC 'UDDIv3 Subscription ExpiresAfter field'
        EQUALITY generalizedTimeMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
        SINGLE-VALUE
      )

4.43.  uddiv3BriefResponse

   This attribute is a Boolean flag for Brief Response associated with a
   subscription entity.  It controls the level of detail returned to a
   subscription listener.  The default is "false" when omitted.  When
   set to "true", it indicates that the subscription results are to be
   returned to the subscriber in the form of a keyBag, listing all of
   the entities that matched the subscriptionFilter.

      ( 1.3.6.1.1.10.4.43 NAME 'uddiv3BriefResponse'
        DESC 'UDDIv3 Subscription ExpiresAfter field'
        EQUALITY booleanMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
        SINGLE-VALUE
      )










Bergeson, et al.             Informational                     [Page 26]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


4.44.  uddiv3EntityKey

   This is the unique UDDIv3 identifier for a given instance of a core
   UDDI data structure that is to be logged as an Obituary entry
   uddiv3EntityObituary.  When a core UDDIv3 Entity is deleted and there
   is an active subscription registered against this UDDI Entity, an
   Obituary entry is created, in which the v3 key of the deleted entry
   is logged as part of the uddiv3EntityKey attribute.

      ( 1.3.6.1.1.10.4.44 NAME 'uddiv3EntityKey'
        DESC 'UDDIv3 Entity unique identifier'
        EQUALITY caseIgnoreMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
        SINGLE-VALUE
      )

4.45.  uddiv3EntityCreationTime

   This attribute is used to log the original Creation Time for a UDDI
   Entity that is deleted in the uddiv3EntityObituary entry.

   It is also used in uddiBusinessService and uddiBindingTemplate.  A
   Move BS operation needs to delete and recreate BT sub-tree due to
   lack of support for moving a sub-tree in many LDAPv3 servers.  This
   attribute is used to save the original creation time of the BT during
   a Move BS.

      ( 1.3.6.1.1.10.4.45 NAME 'uddiv3EntityCreationTime'
        DESC 'UDDIv3 Entity Creation Time'
        EQUALITY generalizedTimeMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
        SINGLE-VALUE
      )

4.46.  uddiv3EntityDeletionTime

   This attribute is used to log the entity deletion time for a UDDI
   Entity that is deleted in the uddiv3EntityObituary entry.

      ( 1.3.6.1.1.10.4.46 NAME 'uddiv3EntityDeletionTime'
        DESC 'UDDIv3 Entity Deletion Time'
        EQUALITY generalizedTimeMatch
        SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
        SINGLE-VALUE
      )






Bergeson, et al.             Informational                     [Page 27]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


5.  Object Class Definitions

   The OIDs for the object classes in this document have been registered
   by the IANA.

5.1.  uddiBusinessEntity

   This structural object class represents a businessEntity.

      ( 1.3.6.1.1.10.6.1 NAME 'uddiBusinessEntity'
        SUP top
        STRUCTURAL
        MUST ( uddiBusinessKey $
               uddiName)
        MAY ( uddiAuthorizedName $
              uddiOperator $
              uddiDiscoveryURLs $
              uddiDescription $
              uddiIdentifierBag $
              uddiCategoryBag $
              uddiv3BusinessKey $
              uddiv3DigitalSignature $
              uddiv3EntityModificationTime $
              uddiv3NodeId)
      )

5.2.  uddiContact

   This structural object class represents a contact.  It is contained
   by a uddiBusinessEntity.

      ( 1.3.6.1.1.10.6.2 NAME 'uddiContact'
        SUP top
        STRUCTURAL
        MUST ( uddiPersonName $
               uddiUUID )
        MAY ( uddiUseType $
              uddiDescription $
              uddiPhone $
              uddiEMail )
      )










Bergeson, et al.             Informational                     [Page 28]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


5.3.  uddiAddress

   This structural object class represents an address.  It is contained
   by a uddiContact.

      ( 1.3.6.1.1.10.6.3 NAME 'uddiAddress'
        SUP top
        STRUCTURAL
        MUST ( uddiUUID )
        MAY ( uddiUseType $
              uddiSortCode $
              uddiTModelKey $
              uddiv3TmodelKey $
              uddiAddressLine $
              uddiLang)
      )

5.4.  uddiBusinessService

   This structural object class represents a businessService.

      ( 1.3.6.1.1.10.6.4 NAME 'uddiBusinessService'
        SUP top
        STRUCTURAL
        MUST ( uddiServiceKey )
        MAY ( uddiName $
           uddiBusinessKey $
              uddiDescription $
              uddiCategoryBag $
              uddiIsProjection $
              uddiv3ServiceKey $
              uddiv3BusinessKey $
              uddiv3DigitalSignature $
              uddiv3EntityCreationTime $
              uddiv3EntityModificationTime $
              uddiv3NodeId)
      )














Bergeson, et al.             Informational                     [Page 29]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


5.5.  uddiBindingTemplate

   This structural object class represents a bindingTemplate.

      ( 1.3.6.1.1.10.6.5 NAME 'uddiBindingTemplate'
        SUP top
        STRUCTURAL
        MUST ( uddiBindingKey )
        MAY ( uddiServiceKey $
              uddiDescription $
              uddiAccessPoint $
              uddiHostingRedirector
              uddiCategoryBag $
              uddiv3BindingKey $
              uddiv3ServiceKey $
              uddiv3DigitalSignature $
              uddiv3EntityCreationTime $
              uddiv3NodeId)
      )

5.6.  uddiTModelInstanceInfo

   This structural object class represents a tModelInstanceInfo.  It is
   contained by a uddiBindingTemplate.

      ( 1.3.6.1.1.10.6.6 NAME 'uddiTModelInstanceInfo'
        SUP top
        STRUCTURAL
        MUST ( uddiTModelKey )
        MAY ( uddiDescription $
              uddiInstanceDescription $
              uddiInstanceParms $
              uddiOverviewDescription $
              uddiOverviewURL $
              uddiv3TmodelKey)
      )















Bergeson, et al.             Informational                     [Page 30]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


5.7.  uddiTModel

   This structural object class represents a tModel.

      ( 1.3.6.1.1.10.6.7 NAME 'uddiTModel'
        SUP top
        STRUCTURAL
        MUST ( uddiTModelKey $
               uddiName )
        MAY ( uddiAuthorizedName $
              uddiOperator $
              uddiDescription $
              uddiOverviewDescription $
              uddiOverviewURL $
              uddiIdentifierBag $
              uddiCategoryBag $
              uddiIsHidden
              uddiv3TModelKey $
              uddiv3DigitalSignature $
              uddiv3NodeId)
      )

5.8.  uddiPublisherAssertion

   This structural object class represents a publisherAssertion.

      ( 1.3.6.1.1.10.6.8 NAME 'uddiPublisherAssertion'
        SUP top
        STRUCTURAL
        MUST ( uddiFromKey $
               uddiToKey $
               uddiKeyedReference $
               uddiUUID )
        MAY ( uddiv3DigitalSignature $
              uddiv3NodeId)
      )

   The following are object class definitions to model new data
   structures needed to implement the UDDIv3 information model.  These
   object class definitions have the "uddiv3" prefix to indicate that
   these attributes represent UDDI information model elements unique to
   UDDIv3.









Bergeson, et al.             Informational                     [Page 31]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


5.9.  uddiv3Subscription

   This structural object class represents a Subscription entity.

      ( 1.3.6.1.1.10.6.9 NAME 'uddiv3Subscription'
        SUP top
        STRUCTURAL
        MUST ( uddiv3SubscriptionFilter $
               uddiUUID)
        MAY (  uddiAuthorizedName $
               uddiv3SubscriptionKey $
               uddiv3BindingKey $
               uddiv3NotificationInterval $
               uddiv3MaxEntities $
               uddiv3ExpiresAfter $
               uddiv3BriefResponse $
               uddiv3NodeId)
      )

5.10.  uddiv3EntityObituary

   This structural object class represents an Obituary entry for and
   stores obituary information for deleted UDDIv3 entities needed for
   handling subscriptions.

      ( 1.3.6.1.1.10.6.10 NAME 'uddiv3EntityObituary'
        SUP top
        STRUCTURAL
        MUST ( uddiv3EntityKey $
               uddiUUID)
        MAY (  uddiAuthorizedName $
               uddiv3EntityCreationTime $
               uddiv3EntityDeletionTime $
               uddiv3NodeId)
      )

6.  Name Forms

   This section defines the required hierarchical structure rules and
   naming attributes for the object classes defined in Section 6.

   The OIDs for the structure rules in this document have been
   registered by the IANA.








Bergeson, et al.             Informational                     [Page 32]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


6.1.  uddiBusinessEntityNameForm

   This name form defines the naming attribute for a businessEntity.

      ( 1.3.6.1.1.10.15.1 NAME 'uddiBusinessEntityNameForm'
        OC uddiBusinessEntity
        MUST ( uddiBusinessKey )
      )

6.2.  uddiContactNameForm

   This name form defines the naming attribute for a contact.

      ( 1.3.6.1.1.10.15.2 NAME 'uddiContactNameForm'
        OC uddiContact
        MUST ( uddiUUID )
      )

6.3.  uddiAddressNameForm

   This name form defines the naming attribute for an address.

      ( 1.3.6.1.1.10.15.3 NAME 'uddiAddressNameForm'
        OC uddiAddress
        MUST ( uddiUUID )
      )

6.4.  uddiBusinessServiceNameForm

   This name form defines the naming attribute for a businessService.

      ( 1.3.6.1.1.10.15.4  NAME 'uddiBusinessServiceNameForm'
        OC uddiBusinessService
        MUST ( uddiServiceKey )
      )

6.5.  uddiBindingTemplateNameForm

   This name form defines the naming attribute for a bindingTemplate.

      ( 1.3.6.1.1.10.15.5 NAME 'uddiBindingTemplateNameForm'
        OC uddiBindingTemplate
        MUST ( uddiBindingKey )
      )







Bergeson, et al.             Informational                     [Page 33]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


6.6.  uddiTModelInstanceInfoNameForm

   This name form defines the naming attribute for a tModelInstanceInfo.

      ( 1.3.6.1.1.10.15.6 NAME 'uddiTModelInstanceInfoNameForm'
        OC uddiTModelInstanceInfo
        MUST ( uddiTModelKey )
      )

6.7.  uddiTModelNameForm

   This name form defines the naming attribute for a tModel.

      ( 1.3.6.1.1.10.15.7 NAME 'uddiTModelNameForm'
        OC uddiTModel
        MUST ( uddiTModelKey )
      )

6.8.  uddiPublisherAssertionNameForm

   This name form defines the naming attribute for a publisherAssertion.

      ( 1.3.6.1.1.10.15.8 NAME 'uddiPublisherAssertionNameForm'
        OC uddiPublisherAssertion
        MUST ( uddiUUID )
      )

6.9.  uddiv3SubscriptionNameForm

   This name form defines the naming attribute for a Subscription.

      ( 1.3.6.1.1.10.15.9 NAME 'uddiv3SubscriptionNameForm'
        OC uddiv3Subscription
        MUST ( uddiUUID )
      )

6.10.  uddiv3EntityObituaryNameForm

   This name form defines the naming attribute for an Entity Obituary.

      ( 1.3.6.1.1.10.15.10 NAME 'uddiv3EntityObituaryNameForm'
        OC uddiv3EntityObituary
        MUST ( uddiUUID )
      )







Bergeson, et al.             Informational                     [Page 34]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


7.  DIT Structure Rules

   This section defines the required hierarchical structure rules for
   the object classes defined in Section 6.

   Note that rule identifiers defined here show the relationship between
   structure rules.  Implementations may use different identifiers but
   must follow the same hierarchical model.

7.1.  uddiBusinessEntityStructureRule

      ( 1
        NAME 'uddiBusinessEntityStructureRule'
        FORM uddiBusinessEntityNameForm
      )

7.2.  uddiContactStructureRule

   This structure rule defines the object class containment for a
   contact.

      ( 2
        NAME 'uddiContactStructureRule'
        FORM uddiContactNameForm
        SUP ( 1 )
      )

7.3.  uddiAddressStructureRule

   This structure rule defines the object class containment for an
   address.

      ( 3
        NAME 'uddiAddressStructureRule'
        FORM uddiAddressNameForm
        SUP ( 2 )
      )

7.4.  uddiBusinessServiceStructureRule

   This structure rule defines the object class containment for a
   businessService.

      ( 4
        NAME 'uddiBusinessServiceStructureRule'
        FORM uddiBusinessServiceNameForm
        SUP ( 1 )
      )



Bergeson, et al.             Informational                     [Page 35]

RFC 4403                 LDAP Schema for UDDIv3            February 2006



7.5.  uddiBindingTemplateStructureRule

   This structure rule defines the object class containment for a
   bindingTemplate.

      ( 5
        NAME 'uddiBindingTemplateStructureRule'
        FORM uddiBindingTemplateNameForm
        SUP ( 4 )
      )

7.6.  uddiTModelInstanceInfoStructureRule

   This structure rule defines the object class containment for a
   tModelInstanceInfo.

      ( 6
        NAME 'uddiTModelInstanceInfoStructureRule'
        FORM uddiTModelInstanceInfoNameForm
        SUP ( 5 )
      )

7.7.  uddiTModelStructureRule

      ( 7
        NAME 'uddiTModelStructureRule'
        FORM uddiTModelNameForm
      )

7.8.  uddiPublisherAssertion

      ( 8
        NAME 'uddiPublisherAssertionStructureRule'
        FORM uddiPublisherAssertionNameForm
      )

7.9.  uddiv3SubscriptionStructureRule

      ( 9
        NAME 'uddiv3SubscriptionStructureRule'
        FORM uddiv3SubscriptionNameForm
      )








Bergeson, et al.             Informational                     [Page 36]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


7.10.  uddiv3EntityObituaryStructureRule

      ( 10
        NAME 'uddiv3EntityObituaryStructureRule'
        FORM uddiv3EntityObituaryNameForm
      )

8.  Security Considerations

   Storing UDDI data into the directory enables the data to be examined
   and used outside the environment in which it was originally created.
   The directory entry containing the UDDI data could be read and
   modified within the constraints imposed by the access control
   mechanisms of the directory.  With UDDIv3 [UDDIv3], publishers can
   digitally sign UDDI Entities enabling registry clients to validate
   the integrity of entries read from the UDDIv3 registry by verifying
   the digital signature.

   Each UDDI Entity has a uddiAuthorizedName attribute that contains an
   LDAP DN identifying the publisher/owner.  The referenced LDAP object
   can provide the public key of the signer to a registry client for
   integrity validation of the UDDI Entity.

   Other general LDAP [LDAPv3] security considerations apply.  Some of
   the UDDI attributes such as AccessPoints for services may contain
   sensitive information.  Use of strong authentication mechanisms and
   data integrity/confidentiality services [RFC2829][RFC2830] is
   advised.

9.  IANA Considerations

   Refer to RFC 3383, "Internet Assigned Numbers Authority (IANA)
   Considerations for the Lightweight Directory Access Protocol (LDAP)"
   [RFC3383].

















Bergeson, et al.             Informational                     [Page 37]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


9.1.  Object Identifier Registration

   The IANA has registered an LDAP Object Identifier for use in this
   technical specification, according to the following template:

   Subject: Request for LDAP OID Registration
   Person & email address to contact for further information:
      Bruce Bergeson (bruce.bergeson@novell.com)
   Specification: RFC 4403
   Author/Change Controller: IESG
   Comments:
      The assigned OID (10) will be used as a base for identifying
      a number of UDDI schema elements defined in this document.

9.2.  Object Identifier Descriptors

   The IANA has registered the LDAP Descriptors used in this technical
   specification as detailed in the following template:

   Subject: Request for LDAP Descriptor Registration Update
   Descriptor (short name): see table
   Object Identifier: see table
   Person & email address to contact for further information:
      Bruce Bergeson (bruce.bergeson@novell.com)
   Usage: see table
   Specification: RFC 4403
   Author/Change Controller: IESG
   Table:

   The following descriptors have been added:

   NAME                            Type    OID
   --------------                  ----    ------------
   uddiBusinessKey                 A       1.3.6.1.1.10.4.1
   uddiAuthorizedName              A       1.3.6.1.1.10.4.2
   uddiOperator                    A       1.3.6.1.1.10.4.3
   uddiName                        A       1.3.6.1.1.10.4.4
   uddiDescription                 A       1.3.6.1.1.10.4.5
   uddiDiscoveryURLs               A       1.3.6.1.1.10.4.6
   uddiUseType                     A       1.3.6.1.1.10.4.7
   uddiPersonName                  A       1.3.6.1.1.10.4.8
   uddiPhone                       A       1.3.6.1.1.10.4.9
   uddiEMail                       A       1.3.6.1.1.10.4.10
   uddiSortCode                    A       1.3.6.1.1.10.4.11
   uddiTModelKey                   A       1.3.6.1.1.10.4.12
   uddiAddressLine                 A       1.3.6.1.1.10.4.13





Bergeson, et al.             Informational                     [Page 38]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   NAME                            Type    OID
   --------------                  ----    ------------
   uddiIdentifierBag               A       1.3.6.1.1.10.4.14
   uddiCategoryBag                 A       1.3.6.1.1.10.4.15
   uddiKeyedReference              A       1.3.6.1.1.10.4.16
   uddiServiceKey                  A       1.3.6.1.1.10.4.17
   uddiBindingKey                  A       1.3.6.1.1.10.4.18
   uddiAccessPoint                 A       1.3.6.1.1.10.4.19
   uddiHostingRedirector           A       1.3.6.1.1.10.4.20
   uddiInstanceDescription         A       1.3.6.1.1.10.4.21
   uddiInstanceParms               A       1.3.6.1.1.10.4.22
   uddiOverviewDescription         A       1.3.6.1.1.10.4.23
   uddiOverviewURL                 A       1.3.6.1.1.10.4.24
   uddiFromKey                     A       1.3.6.1.1.10.4.25
   uddiToKey                       A       1.3.6.1.1.10.4.26
   uddiUUID                        A       1.3.6.1.1.10.4.27
   uddiIsHidden                    A       1.3.6.1.1.10.4.28
   uddiIsProjection                A       1.3.6.1.1.10.4.29
   uddiLang                        A       1.3.6.1.1.10.4.30
   uddiv3BusinessKey               A       1.3.6.1.1.10.4.31
   uddiv3ServiceKey                A       1.3.6.1.1.10.4.32
   uddiv3BindingKey                A       1.3.6.1.1.10.4.33
   uddiv3TmodelKey                 A       1.3.6.1.1.10.4.34
   uddiv3DigitalSignature          A       1.3.6.1.1.10.4.35
   uddiv3NodeId                    A       1.3.6.1.1.10.4.36
   uddiv3EntityModificationTime    A       1.3.6.1.1.10.4.37
   uddiv3SubscriptionKey           A       1.3.6.1.1.10.4.38
   uddiv3SubscriptionFilter        A       1.3.6.1.1.10.4.39
   uddiv3NotificationInterval      A       1.3.6.1.1.10.4.40
   uddiv3MaxEntities               A       1.3.6.1.1.10.4.41
   uddiv3ExpiresAfter              A       1.3.6.1.1.10.4.42
   uddiv3BriefResponse             A       1.3.6.1.1.10.4.43
   uddiv3EntityKey                 A       1.3.6.1.1.10.4.44
   uddiv3EntityCreationTime        A       1.3.6.1.1.10.4.45
   uddiv3EntityDeletionTime        A       1.3.6.1.1.10.4.46
   uddiBusinessEntity              O       1.3.6.1.1.10.6.1
   uddiContact                     O       1.3.6.1.1.10.6.2
   uddiAddress                     O       1.3.6.1.1.10.6.3
   uddiBusinessService             O       1.3.6.1.1.10.6.4
   uddiBindingTemplate             O       1.3.6.1.1.10.6.5
   uddiTModelInstanceInfo          O       1.3.6.1.1.10.6.6
   uddiTModel                      O       1.3.6.1.1.10.6.7
   uddiPublisherAssertion          O       1.3.6.1.1.10.6.8
   uddiv3Subscription              O       1.3.6.1.1.10.6.9
   uddiv3EntityObituary            O       1.3.6.1.1.10.6.10
   uddiBusinessEntityNameForm      N       1.3.6.1.1.10.15.1
   uddiContactNameForm             N       1.3.6.1.1.10.15.2
   uddiAddressNameForm             N       1.3.6.1.1.10.15.3



Bergeson, et al.             Informational                     [Page 39]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   NAME                            Type    OID
   --------------                  ----    ------------
   uddiBusinessServiceNameForm     N       1.3.6.1.1.10.15.4
   uddiBindingTemplateNameForm     N       1.3.6.1.1.10.15.5
   uddiTModelInstanceInfoNameForm  N       1.3.6.1.1.10.15.6
   uddiTModelNameForm              N       1.3.6.1.1.10.15.7
   uddiPublisherAssertionNameForm  N       1.3.6.1.1.10.15.8
   uddiv3SubscriptionNameForm      N       1.3.6.1.1.10.15.9
   uddiv3EntityObituaryNameForm    N       1.3.6.1.1.10.15.10

   where Type A is Attribute, Type O is ObjectClass, Type N is NameForm

   These assignments have been recorded in the following registry:

   http://www.iana.org/assignments/ldap-parameters

10.  Normative References

   [LDAPv3]  Hodges, J. and R. Morgan, "Lightweight Directory Access
             Protocol (v3): Technical Specification", RFC 3377,
             September 2002.

   [RFC2252] Wahl, M., Coulbeck, A., Howes, T., and S. Kille,
             "Lightweight Directory Access Protocol (v3): Attribute
             Syntax Definitions", RFC 2252, December 1997.

   [UDDIdsr] UDDI.ORG, "UDDI version 2.03 Data Structure Reference,"
             http://uddi.org/pubs/DataStructure-V2.03-Published-
             20020719.htm

   [UDDIapi] "UDDI Version 2.04 API Specification",
             http://uddi.org/pubs/ProgrammersAPI-V2.04-Published-
             20020719.htm

   [UDDIv3]  UDDI Version 3.0, Published Specification, 19 July 2002
             http://uddi.org/pubs/uddi-v3.00-published-20020719.htm

   [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
             Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2829] Wahl, M., Alvestrand, H., Hodges, J., and R. Morgan,
             "Authentication Methods for LDAP", RFC 2829, May 2000.

   [RFC2830] Hodges, J., Morgan, R., and M. Wahl, "Lightweight Directory
             Access Protocol (v3): Extension for Transport Layer
             Security", RFC 2830, May 2000.





Bergeson, et al.             Informational                     [Page 40]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


   [RFC3383] Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
             Considerations for the Lightweight Directory Access
             Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [XML]     Extensible Markup Language (XML) 1.0 (Second Edition) W3C
             Recommendation 6 October 2000 http://www.w3.org/TR/REC-xml

   [URL]     Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
             Resource Identifier (URI): Generic Syntax", STD 66, RFC
             3986, January 2005.

   [HTTP]    Fielding,  R., Gettys, J., Mogul, J., Frystyk, H.,
             Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
             Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.

Authors' Addresses

   Bruce Bergeson
   Novell, Inc.
   1800 S Novell Place
   Provo, UT  84606

   Phone: +1 801 861 3854
   EMail: bruce.bergeson@novell.com


   Kent Boogert
   Novell, Inc.
   1800 S Novell Place
   Provo, UT  84606

   Phone: +1 801 861 3212
   EMail: kent.boogert@novell.com


   Vijay Nanjundaswamy
   Oracle India Pvt. Ltd.
   Lexington Towers, Prestige St. John's Woods
   #18, 2nd Cross Road,
   Chikka Audugodi,
   Bangalore 560029
   India

   Phone: +11 9180 4108 5000
   EMail: vijay.nanjundaswamy@oracle.com






Bergeson, et al.             Informational                     [Page 41]

RFC 4403                 LDAP Schema for UDDIv3            February 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Bergeson, et al.             Informational                     [Page 42]

alt-openldap11-devel/rfc/rfc3296.txt000064400000065375150410163250013011 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 3296                           OpenLDAP Foundation
Category: Standards Track                                      July 2002


                    Named Subordinate References in
        Lightweight Directory Access Protocol (LDAP) Directories

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2002).  All Rights Reserved.

Abstract

   This document details schema and protocol elements for representing
   and managing named subordinate references in Lightweight Directory
   Access Protocol (LDAP) Directories.

Conventions

   Schema definitions are provided using LDAPv3 description formats
   [RFC2252].  Definitions provided here are formatted (line wrapped)
   for readability.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" used in
   this document are to be interpreted as described in BCP 14 [RFC2119].

1.  Background and Intended Usage

   The broadening of interest in LDAP (Lightweight Directory Access
   Protocol) [RFC2251] directories beyond their use as front ends to
   X.500 [X.500] directories has created a need to represent knowledge
   information in a more general way.  Knowledge information is
   information about one or more servers maintained in another server,
   used to link servers and services together.

   This document details schema and protocol elements for representing
   and manipulating named subordinate references in LDAP directories.  A
   referral object is used to hold subordinate reference information in



Zeilenga                    Standards Track                     [Page 1]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


   the directory.  These referral objects hold one or more URIs
   [RFC2396] contained in values of the ref attribute type and are used
   to generate protocol referrals and continuations.

   A control, ManageDsaIT, is defined to allow manipulation of referral
   and other special objects as normal objects.  As the name of control
   implies, it is intended to be analogous to the ManageDsaIT service
   option described in X.511(97) [X.511].

   Other forms of knowledge information are not detailed by this
   document.  These forms may be described in subsequent documents.

   This document details subordinate referral processing requirements
   for servers.  This document does not describe protocol syntax and
   semantics.  This is detailed in RFC 2251 [RFC2251].

   This document does not detail use of subordinate knowledge references
   to support replicated environments nor distributed operations (e.g.,
   chaining of operations from one server to other servers).

2.  Schema

2.1.  The referral Object Class

   A referral object is a directory entry whose structural object class
   is (or is derived from) the referral object class.

      ( 2.16.840.1.113730.3.2.6
          NAME 'referral'
          DESC 'named subordinate reference object'
          STRUCTURAL
          MUST ref )

   The referral object class is a structural object class used to
   represent a subordinate reference in the directory.  The referral
   object class SHOULD be used in conjunction with the extensibleObject
   object class to support the naming attributes used in the entry's
   Distinguished Name (DN) [RFC2253].

   Referral objects are normally instantiated at DSEs immediately
   subordinate to object entries within a naming context held by the
   DSA.  Referral objects are analogous to X.500 subordinate knowledge
   (subr) DSEs [X.501].








Zeilenga                    Standards Track                     [Page 2]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


   In the presence of a ManageDsaIT control, referral objects are
   treated as normal entries as described in section 3.  Note that the
   ref attribute is operational and will only be returned in a search
   entry response when requested.

   In the absence of a ManageDsaIT control, the content of referral
   objects are used to construct referrals and search references as
   described in Section 4 and, as such, the referral entries are not
   themselves visible to clients.

2.2  The ref Attribute Type

      ( 2.16.840.1.113730.3.1.34
          NAME 'ref'
          DESC 'named reference - a labeledURI'
          EQUALITY caseExactMatch
          SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
          USAGE distributedOperation )

   The ref attribute type has directoryString syntax and is case
   sensitive.  The ref attribute is multi-valued.  Values placed in the
   attribute MUST conform to the specification given for the labeledURI
   attribute [RFC2079].  The labeledURI specification defines a format
   that is a URI, optionally followed by whitespace and a label.  This
   document does not make use of the label portion of the syntax.
   Future documents MAY enable new functionality by imposing additional
   structure on the label portion of the syntax as it appears in the ref
   attribute.

   If the URI contained in a ref attribute value refers to a LDAP
   [RFC2251] server, it MUST be in the form of a LDAP URL [RFC2255].
   The LDAP URL SHOULD NOT contain an explicit scope specifier, filter,
   attribute description list, or any extensions.  The LDAP URL SHOULD
   contain a non-empty DN.  The handling of LDAP URLs with absent or
   empty DN parts or with explicit scope specifier is not defined by
   this specification.

   Other URI schemes MAY be used so long as all operations returning
   referrals based upon the value could be performed.  This document
   does not detail use of non-LDAP URIs.  This is left to future
   specifications.

   The referential integrity of the URI SHOULD NOT be validated by the
   server holding or returning the URI (whether as a value of the
   attribute or as part of a referral result or search reference
   response).





Zeilenga                    Standards Track                     [Page 3]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


   When returning a referral result or search continuation, the server
   MUST NOT return the separator or label portions of the attribute
   values as part of the reference.  When the attribute contains
   multiple values, the URI part of each value is used to construct the
   referral result or search continuation.

   The ref attribute values SHOULD NOT be used as a relative name-
   component of an entry's DN [RFC2253].

   This document uses the ref attribute in conjunction with the referral
   object class to represent subordinate references.  The ref attribute
   may be used for other purposes as defined by other documents.

3.  The ManageDsaIT Control

   The client may provide the ManageDsaIT control with an operation to
   indicate that the operation is intended to manage objects within the
   DSA (server) Information Tree.  The control causes Directory-specific
   entries (DSEs), regardless of type, to be treated as normal entries
   allowing clients to interrogate and update these entries using LDAP
   operations.

   A client MAY specify the following control when issuing an add,
   compare, delete, modify, modifyDN, search request or an extended
   operation for which the control is defined.

   The control type is 2.16.840.1.113730.3.4.2.  The control criticality
   may be TRUE or, if FALSE, absent.  The control value is absent.

   When the control is present in the request, the server SHALL NOT
   generate a referral or continuation reference based upon information
   held in referral objects and instead SHALL treat the referral object
   as a normal entry.  The server, however, is still free to return
   referrals for other reasons.  When not present, referral objects
   SHALL be handled as described above.

   The control MAY cause other objects to be treated as normal entries
   as defined by subsequent documents.

4.  Named Subordinate References

   A named subordinate reference is constructed by instantiating a
   referral object in the referencing server with ref attribute values
   which point to the corresponding subtree maintained in the referenced
   server.  In general, the name of the referral object is the same as
   the referenced object and this referenced object is a context prefix
   [X.501].




Zeilenga                    Standards Track                     [Page 4]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


   That is, if server A holds "DC=example,DC=net" and server B holds
   "DC=sub,DC=example,DC=net", server A may contain a referral object
   named "DC=sub,DC=example,DC=net" which contains a ref attribute with
   value of "ldap://B/DC=sub,DC=example,DC=net".

      dn: DC=sub,DC=example,DC=net
      dc: sub
      ref: ldap://B/DC=sub,DC=example,DC=net
      objectClass: referral
      objectClass: extensibleObject

   Typically the DN of the referral object and the DN of the object in
   the referenced server are the same.

   If the ref attribute has multiple values, all the DNs contained
   within the LDAP URLs SHOULD be equivalent.  Administrators SHOULD
   avoid configuring naming loops using referrals.

   Named references MUST be treated as normal entries if the request
   includes the ManageDsaIT control as described in section 3.

5.  Scenarios

   The following sections contain specifications of how referral objects
   should be used in different scenarios followed by examples that
   illustrate that usage.  The scenarios described here consist of
   referral object handling when finding target of a non-search
   operation, when finding the base of a search operation, and when
   generating search references.  Lastly, other operation processing
   considerations are presented.

   It is to be noted that, in this document, a search operation is
   conceptually divided into two distinct, sequential phases: (1)
   finding the base object where the search is to begin, and (2)
   performing the search itself.  The first phase is similar to, but not
   the same as, finding the target of a non-search operation.

   It should also be noted that the ref attribute may have multiple
   values and, where these sections refer to a single ref attribute
   value, multiple ref attribute values may be substituted and SHOULD be
   processed and returned (in any order) as a group in a referral or
   search reference in the same way as described for a single ref
   attribute value.

   Search references returned for a given request may be returned in any
   order.





Zeilenga                    Standards Track                     [Page 5]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


5.1.  Example Configuration

   For example, suppose the contacted server (hosta) holds the entry
   "O=MNN,C=WW" and the entry "CN=Manager,O=MNN,C=WW" and the following
   referral objects:

      dn: OU=People,O=MNN,C=WW
      ou: People
      ref: ldap://hostb/OU=People,O=MNN,C=US
      ref: ldap://hostc/OU=People,O=MNN,C=US
      objectClass: referral
      objectClass: extensibleObject

      dn: OU=Roles,O=MNN,C=WW
      ou: Roles
      ref: ldap://hostd/OU=Roles,O=MNN,C=WW
      objectClass: referral
      objectClass: extensibleObject

   The first referral object provides the server with the knowledge that
   subtree "OU=People,O=MNN,C=WW" is held by hostb and hostc (e.g., one
   is the master and the other a shadow).  The second referral object
   provides the server with the knowledge that the subtree
   "OU=Roles,O=MNN,C=WW" is held by hostd.

   Also, in the context of this document, the "nearest naming context"
   means the deepest context which the object is within.  That is, if
   the object is within multiple naming contexts, the nearest naming
   context is the one which is subordinate to all other naming contexts
   the object is within.

5.2.  Target Object Considerations

   This section details referral handling for add, compare, delete,
   modify, and modify DN operations.  If the client requests any of
   these operations, there are four cases that the server must handle
   with respect to the target object.

   The DN part MUST be modified such that it refers to the appropriate
   target in the referenced server (as detailed below).  Even where the
   DN to be returned is the same as the target DN, the DN part SHOULD
   NOT be trimmed.

   In cases where the URI to be returned is a LDAP URL, the server
   SHOULD trim any present scope, filter, or attribute list from the URI
   before returning it.  Critical extensions MUST NOT be trimmed or
   modified.




Zeilenga                    Standards Track                     [Page 6]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


   Case 1: The target object is not held by the server and is not within
      or subordinate to any naming context nor subordinate to any
      referral object held by the server.

      The server SHOULD process the request normally as appropriate for
      a non-existent base which is not within any naming context of the
      server (generally return noSuchObject or a referral based upon
      superior knowledge reference information).  This document does not
      detail management or processing of superior knowledge reference
      information.

   Case 2: The target object is held by the server and is a referral
      object.

      The server SHOULD return the URI value contained in the ref
      attribute of the referral object appropriately modified as
      described above.

   Example: If the client issues a modify request for the target object
      of "OU=People,O=MNN,c=WW", the server will return:

         ModifyResponse (referral) {
             ldap://hostb/OU=People,O=MNN,C=WW
             ldap://hostc/OU=People,O=MNN,C=WW
         }

   Case 3: The target object is not held by the server, but the nearest
      naming context contains no referral object which the target object
      is subordinate to.

      If the nearest naming context contains no referral object which
      the target is subordinate to, the server SHOULD process the
      request as appropriate for a nonexistent target (generally return
      noSuchObject).

   Case 4: The target object is not held by the server, but the nearest
      naming context contains a referral object which the target object
      is subordinate to.

      If a client requests an operation for which the target object is
      not held by the server and the nearest naming context contains a
      referral object which the target object is subordinate to, the
      server SHOULD return a referral response constructed from the URI
      portion of the ref value of the referral object.







Zeilenga                    Standards Track                     [Page 7]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


   Example: If the client issues an add request where the target object
      has a DN of "CN=Manager,OU=Roles,O=MNN,C=WW", the server will
      return:

         AddResponse (referral) {
             ldap://hostd/CN=Manager,OU=Roles,O=MNN,C=WW"
         }

      Note that the DN part of the LDAP URL is modified such that it
      refers to the appropriate entry in the referenced server.

5.3.  Base Object Considerations

   This section details referral handling for base object processing
   within search operations.  Like target object considerations for
   non-search operations, there are the four cases.

   In cases where the URI to be returned is a LDAP URL, the server MUST
   provide an explicit scope specifier from the LDAP URL prior to
   returning it.  In addition, the DN part MUST be modified such that it
   refers to the appropriate target in the referenced server (as
   detailed below).

   If aliasing dereferencing was necessary in finding the referral
   object, the DN part of the URI MUST be replaced with the base DN as
   modified by the alias dereferencing such that the return URL refers
   to the new target object per [RFC2251, 4.1.11].

   Critical extensions MUST NOT be trimmed nor modified.

   Case 1: The base object is not held by the server and is not within
      nor subordinate to any naming context held by the server.

      The server SHOULD process the request normally as appropriate for
      a non-existent base which not within any naming context of the
      server (generally return a superior referral or noSuchObject).
      This document does not detail management or processing of superior
      knowledge references.

   Case 2: The base object is held by the server and is a referral
      object.

      The server SHOULD return the URI value contained in the ref
      attribute of the referral object appropriately modified as
      described above.






Zeilenga                    Standards Track                     [Page 8]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


   Example: If the client issues a subtree search in which the base
      object is "OU=Roles,O=MNN,C=WW", the server will return

         SearchResultDone (referral) {
             ldap://hostd/OU=Roles,O=MNN,C=WW??sub
         }

      If the client were to issue a base or oneLevel search instead of
      subtree, the returned LDAP URL would explicitly specify "base" or
      "one", respectively, instead of "sub".

   Case 3: The base object is not held by the server, but the nearest
      naming context contains no referral object which the base object
      is subordinate to.

      If the nearest naming context contains no referral object which
      the base is subordinate to, the request SHOULD be processed
      normally as appropriate for a nonexistent base (generally return
      noSuchObject).

   Case 4: The base object is not held by the server, but the nearest
      naming context contains a referral object which the base object is
      subordinate to.

      If a client requests an operation for which the target object is
      not held by the server and the nearest naming context contains a
      referral object which the target object is subordinate to, the
      server SHOULD return a referral response which is constructed from
      the URI portion of the ref value of the referral object.

   Example: If the client issues a base search request for
      "CN=Manager,OU=Roles,O=MNN,C=WW", the server will return

         SearchResultDone (referral) {
             ldap://hostd/CN=Manager,OU=Roles,O=MNN,C=WW??base"
         }

      If the client were to issue a subtree or oneLevel search instead
      of subtree, the returned LDAP URL would explicitly specify "sub"
      or "one", respectively, instead of "base".

      Note that the DN part of the LDAP URL is modified such that it
      refers to the appropriate entry in the referenced server.








Zeilenga                    Standards Track                     [Page 9]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


5.4.  Search Continuation Considerations

   For search operations, once the base object has been found and
   determined not to be a referral object, the search may progress.  Any
   entry matching the filter and scope of the search which is not a
   referral object is returned to the client normally as described in
   [RFC2251].

   For each referral object within the requested scope, regardless of
   the search filter, the server SHOULD return a SearchResultReference
   which is constructed from the URI component of values of the ref
   attribute.  If the URI component is not a LDAP URL, it should be
   returned as is.  If the LDAP URL's DN part is absent or empty, the DN
   part must be modified to contain the DN of the referral object.  If
   the URI component is a LDAP URL, the URI SHOULD be modified to add an
   explicit scope specifier.

   Subtree Example:

      If a client requests a subtree search of "O=MNN,C=WW", then in
      addition to any entries within scope which match the filter, hosta
      will also return two search references as the two referral objects
      are within scope.  One possible response might be:

          SearchEntry for O=MNN,C=WW
          SearchResultReference {
              ldap://hostb/OU=People,O=MNN,C=WW??sub
              ldap://hostc/OU=People,O=MNN,C=WW??sub
          }
          SearchEntry for CN=Manager,O=MNN,C=WW
          SearchResultReference {
              ldap://hostd/OU=Roles,O=MNN,C=WW??sub
          }
          SearchResultDone (success)

   One Level Example:

      If a client requests a one level search of "O=MNN,C=WW" then, in
      addition to any entries one level below the "O=MNN,C=WW" entry
      matching the filter, the server will also return two search
      references as the two referral objects are within scope.  One
      possible sequence is shown:









Zeilenga                    Standards Track                    [Page 10]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


          SearchResultReference {
              ldap://hostb/OU=People,O=MNN,C=WW??base
              ldap://hostc/OU=People,O=MNN,C=WW??base
          }
          SearchEntry for CN=Manager,O=MNN,C=WW
          SearchResultReference {
              ldap://hostd/OU=Roles,O=MNN,C=WW??base
          }
          SearchResultDone (success)

   Note: Unlike the examples in Section 4.5.3.1 of RFC 2251, the LDAP
      URLs returned with the SearchResultReference messages contain, as
      required by this specification, an explicit scope specifier.

5.6.  Other Considerations

   This section details processing considerations for other operations.

5.6.1 Bind

   Servers SHOULD NOT return referral result code if the bind name (or
   authentication identity or authorization identity) is (or is
   subordinate to) a referral object but MAY use the knowledge
   information to process the bind request (such as in support a future
   distributed operation specification).  Where the server makes no use
   of the knowledge information, the server processes the request
   normally as appropriate for a non-existent authentication or
   authorization identity (e.g., return invalidCredentials).

5.6.2 Modify DN

   If the newSuperior is a referral object or is subordinate to a
   referral object, the server SHOULD return affectsMultipleDSAs.  If
   the newRDN already exists but is a referral object, the server SHOULD
   return affectsMultipleDSAs instead of entryAlreadyExists.

6.  Security Considerations

   This document defines mechanisms that can be used to tie LDAP (and
   other) servers together.  The information used to tie services
   together should be protected from unauthorized modification.  If the
   server topology information is not public information, it should be
   protected from unauthorized disclosure as well.








Zeilenga                    Standards Track                    [Page 11]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


7.  Acknowledgments

   This document borrows heavily from previous work by IETF LDAPext
   Working Group.  In particular, this document is based upon "Named
   Referral in LDAP Directories" (an expired Internet Draft) by
   Christopher Lukas, Tim Howes, Michael Roszkowski, Mark C. Smith, and
   Mark Wahl.

8. Normative References

   [RFC2079] Smith, M., "Definition of an X.500 Attribute Type and an
             Object Class to Hold Uniform Resource Identifiers (URIs)",
             RFC 2079, January 1997.

   [RFC2119] Bradner, S., "Key Words for use in RFCs to Indicate
             Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251] Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
             Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252] Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
             "Lightweight Directory Access Protocol (v3): Attribute
             Syntax Definitions", RFC 2252, December 1997.

   [RFC2253] Wahl, M., Kille, S. and T. Howes, "Lightweight Directory
             Access Protocol (v3): UTF-8 String Representation of
             Distinguished Names", RFC 2253, December 1997.

   [RFC2255] Howes, T. and M. Smith, "The LDAP URL Format", RFC 2255,
             December, 1997.

   [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
             Resource Identifiers (URI): Generic Syntax", RFC 2396,
             August 1998.

   [X.501]   ITU-T, "The Directory: Models", X.501, 1993.

9. Informative References

   [X.500]   ITU-T, "The Directory: Overview of Concepts, Models, and
             Services", X.500, 1993.

   [X.511]   ITU-T, "The Directory: Abstract Service Definition", X.500,
             1997.







Zeilenga                    Standards Track                    [Page 12]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


10.  Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org













































Zeilenga                    Standards Track                    [Page 13]

RFC 3296    Named Subordinate References in LDAP Directories   July 2002


11.  Full Copyright Statement

   Copyright (C) The Internet Society (2002).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Zeilenga                    Standards Track                    [Page 14]

alt-openldap11-devel/rfc/rfc2293.txt000064400000030373150410163260012774 0ustar00





Network Working Group                                            S. Kille
Request for Comments: 2293                                     Isode Ltd.
Obsoletes: 1837                                                March 1998
Category: Standards Track


        Representing Tables and Subtrees in the X.500 Directory

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

Abstract

   This document defines techniques for representing two types of
   information mapping in the OSI Directory [1].

   1.  Mapping from a key to a value (or set of values), as might
       be done in a table lookup.

   2.  Mapping from a distinguished name to an associated
       value (or values), where the values are not defined by the owner
       of the entry.  This is achieved by use of a directory subtree.

   These techniques were developed for supporting MHS use of Directory
   [2], but are specified separately as they have more general
   applicability.
















Kille                       Standards Track                     [Page 1]

RFC 2293            Table and Subtrees in the X.500           March 1998


1  Representing Flat Tables

   Before considering specific function, a general purpose technique for
   representing tables in the directory is introduced.  The schema for
   this is given in Figure 1.  A table can be considered as an unordered
   set of key to (single or multiple) value mappings, where the key
   cannot be represented as a global name.  There are four reasons why
   this may occur:

   1.  The object does not have a natural global name.

   2.  The object can only be named effectively in the context of
       being a key to a binding.  In this case, the object will be given
       a natural global name by the table.

   3.  The object has a global name, and the table is being used
       to associate parameters with this object, in cases where they
       cannot be placed in the objects global entry.  Reasons why they
       might not be so placed include:

        o  The object does not have a directory entry

        o  There is no authority to place the parameters in the
           global entry

        o  The parameters are not global --- they only make sense
           in the  context of the table.

   4.  It is desirable to group information together as a
       performance optimization, so that the block of information may be
       widely replicated.

   A table is represented as a single level subtree.  The root of the
   subtree is an entry of object class Table.  This is named with a
   common name descriptive of the table.  The table will be located
   somewhere appropriate to its function.  If a table is private to an
   MTA, it will be below the MTA's entry.  If it is shared by MTA's in
   an organization, it will be located under the organization.

   The generic table entry contains only a description.  All instances
   will be subclassed, and the subclass will define the naming
   attribute.  Two subclasses are defined:









Kille                       Standards Track                     [Page 2]

RFC 2293            Table and Subtrees in the X.500           March 1998


table OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MUST CONTAIN {commonName}
    MAY CONTAIN {manager}
    ID oc-table}


tableEntry OBJECT-CLASS ::= {
    SUBCLASS OF {top}
    MAY CONTAIN {description}                                       10
    ID oc-table-entry}

textTableEntry OBJECT-CLASS ::= {
    SUBCLASS OF {tableEntry}
    MUST CONTAIN {textTableKey}
    MAY CONTAIN {textTableValue}
    ID oc-text-table-entry}

textTableKey ATTRIBUTE ::= {
    SUBTYPE OF name                                                 20
    WITH SYNTAX DirectoryString {ub-name}
    ID at-text-table-key}

textTableValue ATTRIBUTE ::= {
    SUBTYPE OF name
    WITH SYNTAX  DirectoryString {ub-description}
    ID at-text-table-value}

distinguishedNameTableEntry OBJECT-CLASS ::= {
    SUBCLASS OF {tableEntry}                                        30
    MUST CONTAIN {distinguishedNameTableKey}
    ID oc-distinguished-name-table-entry}

distinguishedNameTableKey ATTRIBUTE ::= {
    SUBTYPE OF distinguishedName
    ID at-distinguished-name-table-key}

                     Figure 1:  Representing Tables


   1.  TextEntry, which define table entries with text keys,
       which may have single or multiple values of any type.  An
       attribute is defined to allow a text value, to support the
       frequent text key to text value mapping.  Additional values may
       be defined.






Kille                       Standards Track                     [Page 3]

RFC 2293            Table and Subtrees in the X.500           March 1998


   2.  DistinguishedNameEntry.  This is used for associating
       information with globally defined objects.  This approach should
       be used where the number of objects in the table is small or very
       sparsely spread over the DIT. In other cases where there are many
       objects or the objects are tightly clustered in the DIT, the
       subtree approach defined in Section 2 will be preferable.  No
       value attributes are defined for this type of entry.  An
       application of this will make appropriate subtyping to define the
       needed values.

   This is best illustrated by example.  Consider the MTA:

   CN=Bells, OU=Computer Science,
   O=University College London, C=GB

   Suppose that the MTA needs a table mapping from private keys to fully
   qualified domain names (this example is fictitious).  The table might
   be named as:

   CN=domain-nicknames,
   CN=Bells, OU=Computer Science,
   O=University College London, C=GB

   To represent a mapping in this table from "euclid" to
   "bloomsbury.ac.uk", the entry:

   TextTableKey=euclid, CN=domain-nicknames,
   CN=Bells, OU=Computer Science,
   O=University College London, C=GB

   will contain the attribute:

   TextTableValue=bloomsbury.ac.uk

   A second example, showing the use of DistinguishedNameEntry is now
   given.  Consider again the MTA:

   CN=Bells, OU=Computer Science,
   O=University College London, C=GB

   Suppose that the MTA needs a table mapping from MTA Name to bilateral
   agreement information of that MTA. The table might be named as:

   CN=MTA Bilateral Agreements,
   CN=Bells, OU=Computer Science,
   O=University College London, C=GB





Kille                       Standards Track                     [Page 4]

RFC 2293            Table and Subtrees in the X.500           March 1998


   To represent information on the MTA which has the Distinguished Name:

   CN=Q3T21, ADMD=Gold 400, C=GB

   There would be an entry in this table with the Relative Distinguished
   Name of the table entry being the Distinguished Name of the MTA being
   referred to.  The MTA Bilateral information would be an attribute in
   this entry.  Using a non-standard notation, the Distinguished Name of
   the table entry is:

   DistinguishedNameTableKey=<CN=Q3T21, ADMD=Gold 400, C=GB>,
   CN=MTA Bilateral Agreements,
   CN=Bells, OU=Computer Science,
   O=University College London, C=GB

2  Representing Subtrees

   A subtree is similar to a table, except that the keys are constructed
   as a distinguished name hierarchy relative to the location of the
   subtree in the DIT. The subtree effectively starts a private "root",
   and has distinguished names relative to this root.  Typically, this
   approach is used to associate local information with global objects.
   The schema used is defined in Figure 2.  Functionally, this is
   equivalent to a table with distinguished name keys.  The table
   approach is best when the tree is very sparse.  This approach is
   better for subtrees which are more populated.

   The subtree object class defines the root for a subtree in an
   analogous means to the table.  Information within the subtree will
   generally be defined in the same way as for the global object, and so

   subtree OBJECT-CLASS ::= {
       SUBCLASS OF {top}
       MUST CONTAIN {commonName}
       MAY CONTAIN {manager}
       ID oc-subtree}

                     Figure 2:  Representing Subtrees


   no specific object classes for subtree entries are needed.

   For example consider University College London.

   O=University College London, C=GB






Kille                       Standards Track                     [Page 5]

RFC 2293            Table and Subtrees in the X.500           March 1998


   Suppose that the UCL needs a private subtree, with interesting
   information about directory objects.  The table might be named as:

   CN=private subtree,
   O=University College London, C=GB

   UCL specific information on Inria might be stored in the entry:

   O=Inria, C=FR,
   CN=private subtree,
   O=University College London, C=GB

   Practical examples of this mapping are given in [2].

3  Acknowledgments

   Acknowledgments for work on this document are given in [2].

References

   [1] The Directory --- overview of concepts, models and services,
       1993. CCITT X.500 Series Recommendations.

   [2] Kille, S.E., "X.400-MHS use of the X.500 directory to support
       X.400-MHS routing," RFC 1801, June 1995.

4  Security Considerations

   Security considerations are not discussed in this memo.

5  Author's Address

   Steve Kille
   Isode Ltd
   The Dome
   The Square
   Richmond
   TW9 1DT
   England

   Phone:  +44-181-332-9091
   EMail:  S.Kille@ISODE.COM









Kille                       Standards Track                     [Page 6]

RFC 2293            Table and Subtrees in the X.500           March 1998


A  Object Identifier Assignment


mhs-ds OBJECT IDENTIFIER ::= {iso(1) org(3) dod(6) internet(1)
          private(4) enterprises(1) isode-consortium (453) mhs-ds (7)}

tables OBJECT IDENTIFIER ::= {mhs-ds 1}

oc OBJECT IDENTIFIER ::= {tables 1}
at OBJECT IDENTIFIER ::= {tables 2}

oc-subtree OBJECT IDENTIFIER ::= {oc 1}
oc-table OBJECT IDENTIFIER ::= {oc 2}                               10
oc-table-entry OBJECT IDENTIFIER ::= {oc 3}
oc-text-table-entry OBJECT IDENTIFIER ::= {oc 4}
oc-distinguished-name-table-entry  OBJECT IDENTIFIER ::= {oc 5}

at-text-table-key OBJECT IDENTIFIER ::= {at 1}
at-text-table-value OBJECT IDENTIFIER ::= {at 2}
at-distinguished-name-table-key OBJECT IDENTIFIER ::= {at 3}

                Figure 3:  Object Identifier Assignment





























Kille                       Standards Track                     [Page 7]

RFC 2293            Table and Subtrees in the X.500           March 1998


Full Copyright Statement

   Copyright (C) The Internet Society (1998).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
























Kille                       Standards Track                     [Page 8]

alt-openldap11-devel/rfc/rfc4519.txt000064400000176744150410163260013014 0ustar00





Network Working Group                                  A. Sciberras, Ed.
Request for Comments: 4519                                       eB2Bcom
Obsoletes: 2256                                                June 2006
Updates: 2247, 2798, 2377
Category: Standards Track


             Lightweight Directory Access Protocol (LDAP):
                      Schema for User Applications

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This document is an integral part of the Lightweight Directory Access
   Protocol (LDAP) technical specification.  It provides a technical
   specification of attribute types and object classes intended for use
   by LDAP directory clients for many directory services, such as White
   Pages.  These objects are widely used as a basis for the schema in
   many LDAP directories.  This document does not cover attributes used
   for the administration of directory servers, nor does it include
   directory objects defined for specific uses in other documents.



















Sciberras                   Standards Track                     [Page 1]

RFC 4519           LDAP: Schema for User Applications          June 2006


Table of Contents

   1. Introduction ....................................................3
      1.1. Relationship with Other Specifications .....................3
      1.2. Conventions ................................................4
      1.3. General Issues .............................................4
   2. Attribute Types .................................................4
      2.1. 'businessCategory' .........................................5
      2.2. 'c' ........................................................5
      2.3. 'cn' .......................................................5
      2.4. 'dc' .......................................................6
      2.5. 'description' ..............................................6
      2.6. 'destinationIndicator' .....................................7
      2.7. 'distinguishedName' ........................................7
      2.8. 'dnQualifier' ..............................................8
      2.9. 'enhancedSearchGuide' ......................................8
      2.10. 'facsimileTelephoneNumber' ................................9
      2.11. 'generationQualifier' .....................................9
      2.12. 'givenName' ...............................................9
      2.13. 'houseIdentifier' .........................................9
      2.14. 'initials' ...............................................10
      2.15. 'internationalISDNNumber' ................................10
      2.16. 'l' ......................................................10
      2.17. 'member' .................................................11
      2.18. 'name' ...................................................11
      2.19. 'o' ......................................................11
      2.20. 'ou' .....................................................12
      2.21. 'owner' ..................................................12
      2.22. 'physicalDeliveryOfficeName' .............................12
      2.23. 'postalAddress' ..........................................13
      2.24. 'postalCode' .............................................13
      2.25. 'postOfficeBox' ..........................................14
      2.26. 'preferredDeliveryMethod' ................................14
      2.27. 'registeredAddress' ......................................14
      2.28. 'roleOccupant' ...........................................15
      2.29. 'searchGuide' ............................................15
      2.30. 'seeAlso' ................................................15
      2.31. 'serialNumber' ...........................................16
      2.32. 'sn' .....................................................16
      2.33. 'st' .....................................................16
      2.34. 'street' .................................................17
      2.35. 'telephoneNumber' ........................................17
      2.36. 'teletexTerminalIdentifier' ..............................17
      2.37. 'telexNumber' ............................................18
      2.38. 'title' ..................................................18
      2.39. 'uid' ....................................................18
      2.40. 'uniqueMember' ...........................................19
      2.41. 'userPassword' ...........................................19



Sciberras                   Standards Track                     [Page 2]

RFC 4519           LDAP: Schema for User Applications          June 2006


      2.42. 'x121Address' ............................................20
      2.43. 'x500UniqueIdentifier' ...................................20
   3. Object Classes .................................................20
      3.1. 'applicationProcess' ......................................21
      3.2. 'country' .................................................21
      3.3. 'dcObject' ................................................21
      3.4. 'device' ..................................................21
      3.5. 'groupOfNames' ............................................22
      3.6. 'groupOfUniqueNames' ......................................22
      3.7. 'locality' ................................................23
      3.8. 'organization' ............................................23
      3.9. 'organizationalPerson' ....................................24
      3.10. 'organizationalRole' .....................................24
      3.11. 'organizationalUnit' .....................................24
      3.12. 'person' .................................................25
      3.13. 'residentialPerson' ......................................25
      3.14. 'uidObject' ..............................................26
   4. IANA Considerations ............................................26
   5. Security Considerations ........................................28
   6. Acknowledgements ...............................................28
   7. References .....................................................29
      7.1. Normative References ......................................29
      7.2. Informative References ....................................30
   Appendix A  Changes Made Since RFC 2256 ...........................32

1.  Introduction

   This document provides an overview of attribute types and object
   classes intended for use by Lightweight Directory Access Protocol
   (LDAP) directory clients for many directory services, such as White
   Pages.  Originally specified in the X.500 [X.500] documents, these
   objects are widely used as a basis for the schema in many LDAP
   directories.  This document does not cover attributes used for the
   administration of directory servers, nor does it include directory
   objects defined for specific uses in other documents.

1.1.  Relationship with Other Specifications

   This document is an integral part of the LDAP technical specification
   [RFC4510], which obsoletes the previously defined LDAP technical
   specification, RFC 3377, in its entirety.  In terms of RFC 2256,
   Sections 6 and 8 of RFC 2256 are obsoleted by [RFC4517].  Sections
   5.1, 5.2, 7.1, and 7.2 of RFC 2256 are obsoleted by [RFC4512].  The
   remainder of RFC 2256 is obsoleted by this document.  The technical
   specification for the 'dc' attribute type and 'dcObject' object class
   found in RFC 2247 are superseded by sections 2.4 and 3.3 of this
   document.  The remainder of RFC 2247 remains in force.




Sciberras                   Standards Track                     [Page 3]

RFC 4519           LDAP: Schema for User Applications          June 2006


   This document updates RFC 2798 by replacing the informative
   description of the 'uid' attribute type with the definitive
   description provided in Section 2.39 of this document.

   This document updates RFC 2377 by replacing the informative
   description of the 'uidObject' object class with the definitive
   description provided in Section 3.14 of this document.

   A number of schema elements that were included in the previous
   revision of the LDAP Technical Specification are not included in this
   revision of LDAP.  PKI-related schema elements are now specified in
   [RFC4523].  Unless reintroduced in future technical specifications,
   the remainder are to be considered Historic.

   The descriptions in this document SHALL be considered definitive for
   use in LDAP.

1.2.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in RFC 2119 [RFC2119].

1.3.  General Issues

   This document references Syntaxes defined in Section 3 of [RFC4517]
   and Matching Rules defined in Section 4 of [RFC4517].

   The definitions of Attribute Types and Object Classes are written
   using the Augmented Backus-Naur Form (ABNF) [RFC4234] of
   AttributeTypeDescription and ObjectClassDescription given in
   [RFC4512].  Lines have been folded for readability.  When such values
   are transferred as attribute values in the LDAP Protocol, the values
   will not contain line breaks.

2.  Attribute Types

   The attribute types contained in this section hold user information.

   There is no requirement that servers implement the 'searchGuide' and
   'teletexTerminalIdentifier' attribute types.  In fact, their use is
   greatly discouraged.

   An LDAP server implementation SHOULD recognize the rest of the
   attribute types described in this section.






Sciberras                   Standards Track                     [Page 4]

RFC 4519           LDAP: Schema for User Applications          June 2006


2.1.  'businessCategory'

   The 'businessCategory' attribute type describes the kinds of business
   performed by an organization.  Each kind is one value of this
   multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.15 NAME 'businessCategory'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

   Examples: "banking", "transportation", and "real estate".

2.2.  'c'

   The 'c' ('countryName' in X.500) attribute type contains a two-letter
   ISO 3166 [ISO3166] country code.
   (Source: X.520 [X.520])

      ( 2.5.4.6 NAME 'c'
         SUP name
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.11
         SINGLE-VALUE )

   1.3.6.1.4.1.1466.115.121.1.11 refers to the Country String syntax
   [RFC4517].

   Examples: "DE", "AU" and "FR".

2.3.  'cn'

   The 'cn' ('commonName' in X.500) attribute type contains names of an
   object.  Each name is one value of this multi-valued attribute.  If
   the object corresponds to a person, it is typically the person's full
   name.
   (Source: X.520 [X.520])

      ( 2.5.4.3 NAME 'cn'
         SUP name )

   Examples: "Martin K Smith", "Marty Smith" and "printer12".






Sciberras                   Standards Track                     [Page 5]

RFC 4519           LDAP: Schema for User Applications          June 2006


2.4.  'dc'

   The 'dc' ('domainComponent' in RFC 1274) attribute type is a string
   holding one component, a label, of a DNS domain name
   [RFC1034][RFC2181] naming a host [RFC1123].  That is, a value of this
   attribute is a string of ASCII characters adhering to the following
   ABNF [RFC4234]:

   label = (ALPHA / DIGIT) [*61(ALPHA / DIGIT / HYPHEN) (ALPHA / DIGIT)]
   ALPHA   = %x41-5A / %x61-7A     ; "A"-"Z" / "a"-"z"
   DIGIT   = %x30-39               ; "0"-"9"
   HYPHEN  = %x2D                  ; hyphen ("-")

   The encoding of IA5String for use in LDAP is simply the characters of
   the ASCII label.  The equality matching rule is case insensitive, as
   is today's DNS.  (Source: RFC 2247 [RFC2247] and RFC 1274 [RFC 1274])

      ( 0.9.2342.19200300.100.1.25 NAME 'dc'
         EQUALITY caseIgnoreIA5Match
         SUBSTR caseIgnoreIA5SubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
         SINGLE-VALUE )

   1.3.6.1.4.1.1466.115.121.1.26 refers to the IA5 String syntax
   [RFC4517].

   Examples: Valid values include "example" and "com" but not
   "example.com".  The latter is invalid as it contains multiple domain
   components.

   It is noted that the directory service will not ensure that values of
   this attribute conform to the host label restrictions [RFC1123]
   illustrated by the <label> production provided above.  It is the
   directory client's responsibility to ensure that the labels it stores
   in this attribute are appropriately restricted.

   Directory applications supporting International Domain Names SHALL
   use the ToASCII method [RFC3490] to produce the domain component
   label.  The special considerations discussed in Section 4 of RFC 3490
   [RFC3490] should be taken, depending on whether the domain component
   is used for "stored" or "query" purposes.

2.5.  'description'

   The 'description' attribute type contains human-readable descriptive
   phrases about the object.  Each description is one value of this
   multi-valued attribute.
   (Source: X.520 [X.520])



Sciberras                   Standards Track                     [Page 6]

RFC 4519           LDAP: Schema for User Applications          June 2006


      ( 2.5.4.13 NAME 'description'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

   Examples: "a color printer", "Maintenance is done every Monday, at
             1pm.", and "distribution list for all technical staff".

2.6.  'destinationIndicator'

   The 'destinationIndicator' attribute type contains country and city
   strings associated with the object (the addressee) needed to provide
   the Public Telegram Service.  The strings are composed in accordance
   with CCITT Recommendations F.1 [F.1] and F.31 [F.31].  Each string is
   one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.27 NAME 'destinationIndicator'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )

   1.3.6.1.4.1.1466.115.121.1.44 refers to the Printable String syntax
   [RFC4517].

   Examples: "AASD" as a destination indicator for Sydney, Australia.
             "GBLD" as a destination indicator for London, United
             Kingdom.

   It is noted that the directory will not ensure that values of this
   attribute conform to the F.1 and F.31 CCITT Recommendations.  It is
   the application's responsibility to ensure destination indicators
   that it stores in this attribute are appropriately constructed.

2.7.  'distinguishedName'

   The 'distinguishedName' attribute type is not used as the name of the
   object itself, but it is instead a base type from which some user
   attribute types with a DN syntax can inherit.

   It is unlikely that values of this type itself will occur in an
   entry.  LDAP server implementations that do not support attribute
   subtyping need not recognize this attribute in requests.  Client
   implementations MUST NOT assume that LDAP servers are capable of
   performing attribute subtyping.



Sciberras                   Standards Track                     [Page 7]

RFC 4519           LDAP: Schema for User Applications          June 2006


   (Source: X.520 [X.520])

      ( 2.5.4.49 NAME 'distinguishedName'
         EQUALITY distinguishedNameMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )

   1.3.6.1.4.1.1466.115.121.1.12 refers to the DN syntax [RFC4517].

2.8.  'dnQualifier'

   The 'dnQualifier' attribute type contains disambiguating information
   strings to add to the relative distinguished name of an entry.  The
   information is intended for use when merging data from multiple
   sources in order to prevent conflicts between entries that would
   otherwise have the same name.  Each string is one value of this
   multi-valued attribute.  It is recommended that a value of the
   'dnQualifier' attribute be the same for all entries from a particular
   source.
   (Source: X.520 [X.520])

      ( 2.5.4.46 NAME 'dnQualifier'
         EQUALITY caseIgnoreMatch
         ORDERING caseIgnoreOrderingMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )

   1.3.6.1.4.1.1466.115.121.1.44 refers to the Printable String syntax
   [RFC4517].

   Examples: "20050322123345Z" - timestamps can be used to disambiguate
             information.
             "123456A" - serial numbers can be used to disambiguate
             information.

2.9.  'enhancedSearchGuide'

   The 'enhancedSearchGuide' attribute type contains sets of information
   for use by directory clients in constructing search filters.  Each
   set is one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.47 NAME 'enhancedSearchGuide'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )

   1.3.6.1.4.1.1466.115.121.1.21 refers to the Enhanced Guide syntax
   [RFC4517].





Sciberras                   Standards Track                     [Page 8]

RFC 4519           LDAP: Schema for User Applications          June 2006


   Examples: "person#(sn$APPROX)#wholeSubtree" and
             "organizationalUnit#(ou$SUBSTR)#oneLevel".

2.10.  'facsimileTelephoneNumber'

   The 'facsimileTelephoneNumber' attribute type contains telephone
   numbers (and, optionally, the parameters) for facsimile terminals.
   Each telephone number is one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.23 NAME 'facsimileTelephoneNumber'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.22 )

   1.3.6.1.4.1.1466.115.121.1.22 refers to the Facsimile Telephone
   Number syntax [RFC4517].

   Examples: "+61 3 9896 7801" and "+81 3 347 7418$fineResolution".

2.11.  'generationQualifier'

   The 'generationQualifier' attribute type contains name strings that
   are typically the suffix part of a person's name.  Each string is one
   value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.44 NAME 'generationQualifier'
         SUP name )

   Examples: "III", "3rd", and "Jr.".

2.12.  'givenName'

   The 'givenName' attribute type contains name strings that are the
   part of a person's name that is not their surname.  Each string is
   one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.42 NAME 'givenName'
         SUP name )

   Examples: "Andrew", "Charles", and "Joanne".

2.13.  'houseIdentifier'

   The 'houseIdentifier' attribute type contains identifiers for a
   building within a location.  Each identifier is one value of this
   multi-valued attribute.
   (Source: X.520 [X.520])



Sciberras                   Standards Track                     [Page 9]

RFC 4519           LDAP: Schema for User Applications          June 2006


      ( 2.5.4.51 NAME 'houseIdentifier'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

   Example: "20" to represent the house number 20.

2.14.  'initials'

   The 'initials' attribute type contains strings of initials of some or
   all of an individual's names, except the surname(s).  Each string is
   one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.43 NAME 'initials'
         SUP name )

   Examples: "K. A." and "K".

2.15.  'internationalISDNNumber'

   The 'internationalISDNNumber' attribute type contains Integrated
   Services Digital Network (ISDN) addresses, as defined in the
   International Telecommunication Union (ITU) Recommendation E.164
   [E.164].  Each address is one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.25 NAME 'internationalISDNNumber'
         EQUALITY numericStringMatch
         SUBSTR numericStringSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )

   1.3.6.1.4.1.1466.115.121.1.36 refers to the Numeric String syntax
   [RFC4517].

   Example: "0198 333 333".

2.16.  'l'

   The 'l' ('localityName' in X.500) attribute type contains names of a
   locality or place, such as a city, county, or other geographic
   region.  Each name is one value of this multi-valued attribute.
   (Source: X.520 [X.520])





Sciberras                   Standards Track                    [Page 10]

RFC 4519           LDAP: Schema for User Applications          June 2006


      ( 2.5.4.7 NAME 'l'
         SUP name )

   Examples: "Geneva", "Paris", and "Edinburgh".

2.17.  'member'

   The 'member' attribute type contains the distinguished names of
   objects that are on a list or in a group.  Each name is one value of
   this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.31 NAME 'member'
         SUP distinguishedName )

   Examples: "cn=James Clarke,ou=Finance,o=Widget\, Inc." and
             "cn=John Xerri,ou=Finance,o=Widget\, Inc." may
             be two members of the financial team (group) at Widget,
             Inc., in which case, both of these distinguished names
             would be present as individual values of the member
             attribute.

2.18.  'name'

   The 'name' attribute type is the attribute supertype from which user
   attribute types with the name syntax inherit.  Such attribute types
   are typically used for naming.  The attribute type is multi-valued.

   It is unlikely that values of this type itself will occur in an
   entry.  LDAP server implementations that do not support attribute
   subtyping need not recognize this attribute in requests.  Client
   implementations MUST NOT assume that LDAP servers are capable of
   performing attribute subtyping.
   (Source: X.520 [X.520])

      ( 2.5.4.41 NAME 'name'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

2.19.  'o'

   The 'o' ('organizationName' in X.500) attribute type contains the
   names of an organization.  Each name is one value of this
   multi-valued attribute.



Sciberras                   Standards Track                    [Page 11]

RFC 4519           LDAP: Schema for User Applications          June 2006


   (Source: X.520 [X.520])

      ( 2.5.4.10 NAME 'o'
         SUP name )

   Examples: "Widget", "Widget, Inc.", and "Widget, Incorporated.".

2.20.  'ou'

   The 'ou' ('organizationalUnitName' in X.500) attribute type contains
   the names of an organizational unit.  Each name is one value of this
   multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.11 NAME 'ou'
         SUP name )

   Examples: "Finance", "Human Resources", and "Research and
             Development".

2.21.  'owner'

   The 'owner' attribute type contains the distinguished names of
   objects that have an ownership responsibility for the object that is
   owned.  Each owner's name is one value of this multi-valued
   attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.32 NAME 'owner'
         SUP distinguishedName )

   Example: The mailing list object, whose DN is "cn=All Employees,
            ou=Mailing List,o=Widget\, Inc.", is owned by the Human
            Resources Director.

            Therefore, the value of the 'owner' attribute within the
            mailing list object, would be the DN of the director (role):
            "cn=Human Resources Director,ou=employee,o=Widget\, Inc.".

2.22.  'physicalDeliveryOfficeName'

   The 'physicalDeliveryOfficeName' attribute type contains names that a
   Postal Service uses to identify a post office.
   (Source: X.520 [X.520])







Sciberras                   Standards Track                    [Page 12]

RFC 4519           LDAP: Schema for User Applications          June 2006


      ( 2.5.4.19 NAME 'physicalDeliveryOfficeName'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

   Examples: "Bremerhaven, Main" and "Bremerhaven, Bonnstrasse".

2.23.  'postalAddress'

   The 'postalAddress' attribute type contains addresses used by a
   Postal Service to perform services for the object.  Each address is
   one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.16 NAME 'postalAddress'
         EQUALITY caseIgnoreListMatch
         SUBSTR caseIgnoreListSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )

   1.3.6.1.4.1.1466.115.121.1.41 refers to the Postal Address syntax
   [RFC4517].

   Example: "15 Main St.$Ottawa$Canada".

2.24.  'postalCode'

   The 'postalCode' attribute type contains codes used by a Postal
   Service to identify postal service zones.  Each code is one value of
   this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.17 NAME 'postalCode'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

   Example: "22180", to identify Vienna, VA, in the USA.








Sciberras                   Standards Track                    [Page 13]

RFC 4519           LDAP: Schema for User Applications          June 2006


2.25.  'postOfficeBox'

   The 'postOfficeBox' attribute type contains postal box identifiers
   that a Postal Service uses when a customer arranges to receive mail
   at a box on the premises of the Postal Service.  Each postal box
   identifier is a single value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.18 NAME 'postOfficeBox'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

   Example: "Box 45".

2.26.  'preferredDeliveryMethod'

   The 'preferredDeliveryMethod' attribute type contains an indication
   of the preferred method of getting a message to the object.
   (Source: X.520 [X.520])

      ( 2.5.4.28 NAME 'preferredDeliveryMethod'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.14
         SINGLE-VALUE )

   1.3.6.1.4.1.1466.115.121.1.14 refers to the Delivery Method syntax
   [RFC4517].

   Example: If the mhs-delivery Delivery Method is preferred over
            telephone-delivery, which is preferred over all other
            methods, the value would be: "mhs $ telephone".

2.27.  'registeredAddress'

   The 'registeredAddress' attribute type contains postal addresses
   suitable for reception of telegrams or expedited documents, where it
   is necessary to have the recipient accept delivery.  Each address is
   one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.26 NAME 'registeredAddress'
         SUP postalAddress
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )





Sciberras                   Standards Track                    [Page 14]

RFC 4519           LDAP: Schema for User Applications          June 2006


   1.3.6.1.4.1.1466.115.121.1.41 refers to the Postal Address syntax
   [RFC4517].

   Example: "Receptionist$Widget, Inc.$15 Main St.$Ottawa$Canada".

2.28.  'roleOccupant'

   The 'roleOccupant' attribute type contains the distinguished names of
   objects (normally people) that fulfill the responsibilities of a role
   object.  Each distinguished name is one value of this multi-valued
   attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.33 NAME 'roleOccupant'
         SUP distinguishedName )

   Example: The role object, "cn=Human Resources
            Director,ou=Position,o=Widget\, Inc.", is fulfilled by two
            people whose object names are "cn=Mary
            Smith,ou=employee,o=Widget\, Inc." and "cn=James
            Brown,ou=employee,o=Widget\, Inc.".  The 'roleOccupant'
            attribute will contain both of these distinguished names,
            since they are the occupants of this role.

2.29.  'searchGuide'

   The 'searchGuide' attribute type contains sets of information for use
   by clients in constructing search filters.  It is superseded by
   'enhancedSearchGuide', described above in Section 2.9.  Each set is
   one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.14 NAME 'searchGuide'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.25 )

   1.3.6.1.4.1.1466.115.121.1.25 refers to the Guide syntax [RFC4517].

   Example: "person#sn$EQ".

2.30.  'seeAlso'

   The 'seeAlso' attribute type contains the distinguished names of
   objects that are related to the subject object.  Each related object
   name is one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.34 NAME 'seeAlso'
         SUP distinguishedName )



Sciberras                   Standards Track                    [Page 15]

RFC 4519           LDAP: Schema for User Applications          June 2006


   Example: The person object "cn=James Brown,ou=employee,o=Widget\,
            Inc." is related to the role objects "cn=Football Team
            Captain,ou=sponsored activities,o=Widget\, Inc." and
            "cn=Chess Team,ou=sponsored activities,o=Widget\, Inc.".
            Since the role objects are related to the person object, the
            'seeAlso' attribute will contain the distinguished name of
            each role object as separate values.

2.31.  'serialNumber'

   The 'serialNumber' attribute type contains the serial numbers of
   devices.  Each serial number is one value of this multi-valued
   attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.5 NAME 'serialNumber'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )

   1.3.6.1.4.1.1466.115.121.1.44 refers to the Printable String syntax
   [RFC4517].

   Examples: "WI-3005" and "XF551426".

2.32.  'sn'

   The 'sn' ('surname' in X.500) attribute type contains name strings
   for the family names of a person.  Each string is one value of this
   multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.4 NAME 'sn'
         SUP name )

   Example: "Smith".

2.33.  'st'

   The 'st' ('stateOrProvinceName' in X.500) attribute type contains the
   full names of states or provinces.  Each name is one value of this
   multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.8 NAME 'st'
         SUP name )

   Example: "California".



Sciberras                   Standards Track                    [Page 16]

RFC 4519           LDAP: Schema for User Applications          June 2006


2.34.  'street'

   The 'street' ('streetAddress' in X.500) attribute type contains site
   information from a postal address (i.e., the street name, place,
   avenue, and the house number).  Each street is one value of this
   multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.9 NAME 'street'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

   Example: "15 Main St.".

2.35.  'telephoneNumber'

   The 'telephoneNumber' attribute type contains telephone numbers that
   comply with the ITU Recommendation E.123 [E.123].  Each number is one
   value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.20 NAME 'telephoneNumber'
         EQUALITY telephoneNumberMatch
         SUBSTR telephoneNumberSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )

   1.3.6.1.4.1.1466.115.121.1.50 refers to the Telephone Number syntax
   [RFC4517].

   Example: "+1 234 567 8901".

2.36.  'teletexTerminalIdentifier'

   The withdrawal of Recommendation F.200 has resulted in the withdrawal
   of this attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.22 NAME 'teletexTerminalIdentifier'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )

   1.3.6.1.4.1.1466.115.121.1.51 refers to the Teletex Terminal
   Identifier syntax [RFC4517].





Sciberras                   Standards Track                    [Page 17]

RFC 4519           LDAP: Schema for User Applications          June 2006


2.37.  'telexNumber'

   The 'telexNumber' attribute type contains sets of strings that are a
   telex number, country code, and answerback code of a telex terminal.
   Each set is one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.21 NAME 'telexNumber'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )

   1.3.6.1.4.1.1466.115.121.1.52 refers to the Telex Number syntax
   [RFC4517].

   Example: "12345$023$ABCDE".

2.38.  'title'

   The 'title' attribute type contains the title of a person in their
   organizational context.  Each title is one value of this multi-valued
   attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.12 NAME 'title'
         SUP name )
   Examples: "Vice President", "Software Engineer", and "CEO".

2.39.  'uid'

   The 'uid' ('userid' in RFC 1274) attribute type contains computer
   system login names associated with the object.  Each name is one
   value of this multi-valued attribute.
   (Source: RFC 2798 [RFC2798] and RFC 1274 [RFC1274])

      ( 0.9.2342.19200300.100.1.1 NAME 'uid'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   1.3.6.1.4.1.1466.115.121.1.15 refers to the Directory String syntax
   [RFC4517].

   Examples: "s9709015", "admin", and "Administrator".









Sciberras                   Standards Track                    [Page 18]

RFC 4519           LDAP: Schema for User Applications          June 2006


2.40.  'uniqueMember'

   The 'uniqueMember' attribute type contains the distinguished names of
   an object that is on a list or in a group, where the relative
   distinguished names of the object include a value that distinguishes
   between objects when a distinguished name has been reused.  Each
   distinguished name is one value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.50 NAME 'uniqueMember'
         EQUALITY uniqueMemberMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )

   1.3.6.1.4.1.1466.115.121.1.34 refers to the Name and Optional UID
   syntax [RFC4517].

   Example: If "ou=1st Battalion,o=Defense,c=US" is a battalion that was
            disbanded, establishing a new battalion with the "same" name
            would have a unique identifier value added, resulting in
            "ou=1st Battalion, o=Defense,c=US#'010101'B".

2.41.  'userPassword'

   The 'userPassword' attribute contains octet strings that are known
   only to the user and the system to which the user has access.  Each
   string is one value of this multi-valued attribute.

   The application SHOULD prepare textual strings used as passwords by
   transcoding them to Unicode, applying SASLprep [RFC4013], and
   encoding as UTF-8.  The determination of whether a password is
   textual is a local client matter.
   (Source: X.509 [X.509])

      ( 2.5.4.35 NAME 'userPassword'
         EQUALITY octetStringMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

   1.3.6.1.4.1.1466.115.121.1.40 refers to the Octet String syntax
   [RFC4517].

   Passwords are stored using an Octet String syntax and are not
   encrypted.  Transfer of cleartext passwords is strongly discouraged
   where the underlying transport service cannot guarantee
   confidentiality and may result in disclosure of the password to
   unauthorized parties.

   An example of a need for multiple values in the 'userPassword'
   attribute is an environment where every month the user is expected to



Sciberras                   Standards Track                    [Page 19]

RFC 4519           LDAP: Schema for User Applications          June 2006


   use a different password generated by some automated system.  During
   transitional periods, like the last and first day of the periods, it
   may be necessary to allow two passwords for the two consecutive
   periods to be valid in the system.

2.42.  'x121Address'

   The 'x121Address' attribute type contains data network addresses as
   defined by ITU Recommendation X.121 [X.121].  Each address is one
   value of this multi-valued attribute.
   (Source: X.520 [X.520])

      ( 2.5.4.24 NAME 'x121Address'
         EQUALITY numericStringMatch
         SUBSTR numericStringSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )

   1.3.6.1.4.1.1466.115.121.1.36 refers to the Numeric String syntax
   [RFC4517].

   Example: "36111222333444555".

2.43.  'x500UniqueIdentifier'

   The 'x500UniqueIdentifier' attribute type contains binary strings
   that are used to distinguish between objects when a distinguished
   name has been reused.  Each string is one value of this multi-valued
   attribute.

   In X.520 [X.520], this attribute type is called 'uniqueIdentifier'.
   This is a different attribute type from both the 'uid' and
   'uniqueIdentifier' LDAP attribute types.  The 'uniqueIdentifier'
   attribute type is defined in [RFC4524].
   (Source: X.520 [X.520])

      ( 2.5.4.45 NAME 'x500UniqueIdentifier'
         EQUALITY bitStringMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )

   1.3.6.1.4.1.1466.115.121.1.6 refers to the Bit String syntax
   [RFC4517].

3.  Object Classes

   LDAP servers SHOULD recognize all the Object Classes listed here as
   values of the 'objectClass' attribute (see [RFC4512]).





Sciberras                   Standards Track                    [Page 20]

RFC 4519           LDAP: Schema for User Applications          June 2006


3.1.  'applicationProcess'

   The 'applicationProcess' object class definition is the basis of an
   entry that represents an application executing in a computer system.
   (Source: X.521 [X.521])

      ( 2.5.6.11 NAME 'applicationProcess'
         SUP top
         STRUCTURAL
         MUST cn
         MAY ( seeAlso $
               ou $
               l $
               description ) )

3.2.  'country'

   The 'country' object class definition is the basis of an entry that
   represents a country.
   (Source: X.521 [X.521])

      ( 2.5.6.2 NAME 'country'
         SUP top
         STRUCTURAL
         MUST c
         MAY ( searchGuide $
               description ) )

3.3.  'dcObject'

   The 'dcObject' object class permits an entry to contains domain
   component information.  This object class is defined as auxiliary,
   because it will be used in conjunction with an existing structural
   object class.
   (Source: RFC 2247 [RFC2247])

      ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
         SUP top
         AUXILIARY
         MUST dc )

3.4.  'device'

   The 'device' object class is the basis of an entry that represents an
   appliance, computer, or network element.
   (Source: X.521 [X.521])





Sciberras                   Standards Track                    [Page 21]

RFC 4519           LDAP: Schema for User Applications          June 2006


      ( 2.5.6.14 NAME 'device'
         SUP top
         STRUCTURAL
         MUST cn
         MAY ( serialNumber $
               seeAlso $
               owner $
               ou $
               o $
               l $
               description ) )

3.5.  'groupOfNames'

   The 'groupOfNames' object class is the basis of an entry that
   represents a set of named objects including information related to
   the purpose or maintenance of the set.
   (Source: X.521 [X.521])

      ( 2.5.6.9 NAME 'groupOfNames'
         SUP top
         STRUCTURAL
         MUST ( member $
               cn )
         MAY ( businessCategory $
               seeAlso $
               owner $
               ou $
               o $
               description ) )

3.6.  'groupOfUniqueNames'

   The 'groupOfUniqueNames' object class is the same as the
   'groupOfNames' object class except that the object names are not
   repeated or reassigned within a set scope.
   (Source: X.521 [X.521])














Sciberras                   Standards Track                    [Page 22]

RFC 4519           LDAP: Schema for User Applications          June 2006


      ( 2.5.6.17 NAME 'groupOfUniqueNames'
         SUP top
         STRUCTURAL
         MUST ( uniqueMember $
               cn )
         MAY ( businessCategory $
               seeAlso $
               owner $
               ou $
               o $
               description ) )

3.7.  'locality'

   The 'locality' object class is the basis of an entry that represents
   a place in the physical world.
   (Source: X.521 [X.521])

      ( 2.5.6.3 NAME 'locality'
         SUP top
         STRUCTURAL
         MAY ( street $
               seeAlso $
               searchGuide $
               st $
               l $
               description ) )

3.8.  'organization'

   The 'organization' object class is the basis of an entry that
   represents a structured group of people.
   (Source: X.521 [X.521])

      ( 2.5.6.4 NAME 'organization'
         SUP top
         STRUCTURAL
         MUST o
         MAY ( userPassword $ searchGuide $ seeAlso $
               businessCategory $ x121Address $ registeredAddress $
               destinationIndicator $ preferredDeliveryMethod $
               telexNumber $ teletexTerminalIdentifier $
               telephoneNumber $ internationalISDNNumber $
               facsimileTelephoneNumber $ street $ postOfficeBox $
               postalCode $ postalAddress $ physicalDeliveryOfficeName $
               st $ l $ description ) )





Sciberras                   Standards Track                    [Page 23]

RFC 4519           LDAP: Schema for User Applications          June 2006


3.9.  'organizationalPerson'

   The 'organizationalPerson' object class is the basis of an entry that
   represents a person in relation to an organization.
   (Source: X.521 [X.521])

      ( 2.5.6.7 NAME 'organizationalPerson'
         SUP person
         STRUCTURAL
         MAY ( title $ x121Address $ registeredAddress $
               destinationIndicator $ preferredDeliveryMethod $
               telexNumber $ teletexTerminalIdentifier $
               telephoneNumber $ internationalISDNNumber $
               facsimileTelephoneNumber $ street $ postOfficeBox $
               postalCode $ postalAddress $ physicalDeliveryOfficeName $
               ou $ st $ l ) )

3.10.  'organizationalRole'

   The 'organizationalRole' object class is the basis of an entry that
   represents a job, function, or position in an organization.
   (Source: X.521 [X.521])

      ( 2.5.6.8 NAME 'organizationalRole'
         SUP top
         STRUCTURAL
         MUST cn
         MAY ( x121Address $ registeredAddress $ destinationIndicator $
               preferredDeliveryMethod $ telexNumber $
               teletexTerminalIdentifier $ telephoneNumber $
               internationalISDNNumber $ facsimileTelephoneNumber $
               seeAlso $ roleOccupant $ preferredDeliveryMethod $
               street $ postOfficeBox $ postalCode $ postalAddress $
               physicalDeliveryOfficeName $ ou $ st $ l $
               description ) )

3.11.  'organizationalUnit'

   The 'organizationalUnit' object class is the basis of an entry that
   represents a piece of an organization.
   (Source: X.521 [X.521])










Sciberras                   Standards Track                    [Page 24]

RFC 4519           LDAP: Schema for User Applications          June 2006


      ( 2.5.6.5 NAME 'organizationalUnit'
         SUP top
         STRUCTURAL
         MUST ou
         MAY ( businessCategory $ description $ destinationIndicator $
               facsimileTelephoneNumber $ internationalISDNNumber $ l $
               physicalDeliveryOfficeName $ postalAddress $ postalCode $
               postOfficeBox $ preferredDeliveryMethod $
               registeredAddress $ searchGuide $ seeAlso $ st $ street $
               telephoneNumber $ teletexTerminalIdentifier $
               telexNumber $ userPassword $ x121Address ) )

3.12  'person'

   The 'person' object class is the basis of an entry that represents a
   human being.
   (Source: X.521 [X.521])

      ( 2.5.6.6 NAME 'person'
         SUP top
         STRUCTURAL
         MUST ( sn $
               cn )
         MAY ( userPassword $
               telephoneNumber $
               seeAlso $ description ) )

3.13.  'residentialPerson'

   The 'residentialPerson' object class is the basis of an entry that
   includes a person's residence in the representation of the person.
   (Source: X.521 [X.521])

      ( 2.5.6.10 NAME 'residentialPerson'
         SUP person
         STRUCTURAL
         MUST l
         MAY ( businessCategory $ x121Address $ registeredAddress $
               destinationIndicator $ preferredDeliveryMethod $
               telexNumber $ teletexTerminalIdentifier $
               telephoneNumber $ internationalISDNNumber $
               facsimileTelephoneNumber $ preferredDeliveryMethod $
               street $ postOfficeBox $ postalCode $ postalAddress $
               physicalDeliveryOfficeName $ st $ l ) )







Sciberras                   Standards Track                    [Page 25]

RFC 4519           LDAP: Schema for User Applications          June 2006


3.14.  'uidObject'

   The 'uidObject' object class permits an entry to contains user
   identification information.  This object class is defined as
   auxiliary, because it will be used in conjunction with an existing
   structural object class.
   (Source: RFC 2377 [RFC2377])

      ( 1.3.6.1.1.3.1 NAME 'uidObject'
         SUP top
         AUXILIARY
         MUST uid )

4.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has updated the LDAP
   descriptors registry as indicated in the following template:

      Subject: Request for LDAP Descriptor Registration Update
      Descriptor (short name): see comments
      Object Identifier: see comments
      Person & email address to contact for further information:
         Andrew Sciberras <andrew.sciberras@eb2bcom.com>
      Usage: (A = attribute type, O = Object Class) see comment
      Specification: RFC 4519
      Author/Change Controller: IESG

   Comments

      In the LDAP descriptors registry, the following descriptors (short
      names) have been updated to refer to RFC 4519.  Names that need to
      be reserved, rather than assigned to an Object Identifier, will
      contain an Object Identifier value of RESERVED.

      NAME                         Type OID
      ------------------------     ---- ----------------------------
      applicationProcess           O    2.5.6.11
      businessCategory             A    2.5.4.15
      c                            A    2.5.4.6
      cn                           A    2.5.4.3
      commonName                   A    2.5.4.3
      country                      O    2.5.6.2
      countryName                  A    2.5.4.6
      dc                           A    0.9.2342.19200300.100.1.25
      dcObject                     O    1.3.6.1.4.1.1466.344
      description                  A    2.5.4.13
      destinationIndicator         A    2.5.4.27
      device                       O    2.5.6.14



Sciberras                   Standards Track                    [Page 26]

RFC 4519           LDAP: Schema for User Applications          June 2006


      NAME                         Type OID
      ------------------------     ---- ----------------------------
      distinguishedName            A    2.5.4.49
      dnQualifier                  A    2.5.4.46
      domainComponent              A    0.9.2342.19200300.100.1.25
      enhancedSearchGuide          A    2.5.4.47
      facsimileTelephoneNumber     A    2.5.4.23
      generationQualifier          A    2.5.4.44
      givenName                    A    2.5.4.42
      gn                           A    RESERVED
      groupOfNames                 O    2.5.6.9
      groupOfUniqueNames           O    2.5.6.17
      houseIdentifier              A    2.5.4.51
      initials                     A    2.5.4.43
      internationalISDNNumber      A    2.5.4.25
      l                            A    2.5.4.7
      locality                     O    2.5.6.3
      localityName                 A    2.5.4.7
      member                       A    2.5.4.31
      name                         A    2.5.4.41
      o                            A    2.5.4.10
      organization                 O    2.5.6.4
      organizationName             A    2.5.4.10
      organizationalPerson         O    2.5.6.7
      organizationalRole           O    2.5.6.8
      organizationalUnit           O    2.5.6.5
      organizationalUnitName       A    2.5.4.11
      ou                           A    2.5.4.11
      owner                        A    2.5.4.32
      person                       O    2.5.6.6
      physicalDeliveryOfficeName   A    2.5.4.19
      postalAddress                A    2.5.4.16
      postalCode                   A    2.5.4.17
      postOfficeBox                A    2.5.4.18
      preferredDeliveryMethod      A    2.5.4.28
      registeredAddress            A    2.5.4.26
      residentialPerson            O    2.5.6.10
      roleOccupant                 A    2.5.4.33
      searchGuide                  A    2.5.4.14
      seeAlso                      A    2.5.4.34
      serialNumber                 A    2.5.4.5
      sn                           A    2.5.4.4
      st                           A    2.5.4.8
      street                       A    2.5.4.9
      surname                      A    2.5.4.4
      telephoneNumber              A    2.5.4.20
      teletexTerminalIdentifier    A    2.5.4.22
      telexNumber                  A    2.5.4.21



Sciberras                   Standards Track                    [Page 27]

RFC 4519           LDAP: Schema for User Applications          June 2006


      NAME                         Type OID
      ------------------------     ---- ----------------------------
      title                        A    2.5.4.12
      uid                          A    0.9.2342.19200300.100.1.1
      uidObject                    O    1.3.6.1.1.3.1
      uniqueMember                 A    2.5.4.50
      userid                       A    0.9.2342.19200300.100.1.1
      userPassword                 A    2.5.4.35
      x121Address                  A    2.5.4.24
      x500UniqueIdentifier         A    2.5.4.45

5.  Security Considerations

   Attributes of directory entries are used to provide descriptive
   information about the real-world objects they represent, which can be
   people, organizations, or devices.  Most countries have privacy laws
   regarding the publication of information about people.

   Transfer of cleartext passwords is strongly discouraged where the
   underlying transport service cannot guarantee confidentiality and
   integrity, since this may result in disclosure of the password to
   unauthorized parties.

   Multiple attribute values for the 'userPassword' attribute need to be
   used with care.  Especially reset/deletion of a password by an
   administrator without knowing the old user password gets tricky or
   impossible if multiple values for different applications are present.

   Certainly, applications that intend to replace the 'userPassword'
   value(s) with new value(s) should use modify/replaceValues (or
   modify/deleteAttribute+addAttribute).  In addition, server
   implementations are encouraged to provide administrative controls
   that, if enabled, restrict the 'userPassword' attribute to one value.

   Note that when used for authentication purposes [RFC4513], the user
   need only prove knowledge of one of the values, not all of the
   values.

6.  Acknowledgements

   The definitions, on which this document is based, have been developed
   by committees for telecommunications and international standards.

   This document is an update of RFC 2256 by Mark Wahl.  RFC 2256 was a
   product of the IETF ASID Working Group.






Sciberras                   Standards Track                    [Page 28]

RFC 4519           LDAP: Schema for User Applications          June 2006


   The 'dc' attribute type definition and the 'dcObject' object class
   definition in this document supersede the specification in RFC 2247
   by S. Kille, M. Wahl, A. Grimstad, R. Huber, and S. Sataluri.

   The 'uid' attribute type definition in this document supersedes the
   specification of the 'userid' in RFC 1274 by P. Barker and S. Kille
   and of the uid in RFC 2798 by M. Smith.

   The 'uidObject' object class definition in this document supersedes
   the specification of the 'uidObject' in RFC 2377 by A. Grimstad, R.
   Huber, S. Sataluri, and M. Wahl.

   This document is based upon input of the IETF LDAPBIS working group.
   The author wishes to thank S. Legg and K. Zeilenga for their
   significant contribution to this update.  The author would also like
   to thank Kathy Dally, who edited early versions of this document.

7.  References

7.1.  Normative References

   [E.123]    Notation for national and international telephone numbers,
              ITU-T Recommendation E.123, 1988

   [E.164]    The international public telecommunication numbering plan,
              ITU-T Recommendation E.164, 1997

   [F.1]      Operational Provisions For The International Public
              Telegram Service Transmission System, CCITT Recommendation
              F.1, 1992

   [F.31]     Telegram Retransmission System, CCITT Recommendation F.31,
              1988

   [ISO3166]  ISO 3166, "Codes for the representation of names of
              countries".

   [RFC1034]  Mockapetris, P., "Domain names - concepts and facilities",
              STD 13, RFC 1034, November 1987.

   [RFC1123]  Braden, R., "Requirements for Internet Hosts - Application
              and Support", STD 3, RFC 1123, October 1989.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2181]  Elz, R. and R. Bush, "Clarifications to the DNS
              Specification", RFC 2181, July 1997.



Sciberras                   Standards Track                    [Page 29]

RFC 4519           LDAP: Schema for User Applications          June 2006


   [RFC3490]  Faltstrom, P., Hoffman, P., and A. Costello,
              "Internationalizing Domain Names in Applications (IDNA)",
              RFC 3490, March 2003.

   [RFC4013]  Zeilenga, K., "SASLprep: Stringprep Profile for User Names
              and Passwords", RFC 4013, February 2005.

   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", RFC 4234, October 2005.

   [RFC4510]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC 4510, June
              2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512, June
              2006.

   [RFC4517]  Legg, S., Ed., "Lightweight Directory Access Protocol
              (LDAP): Syntaxes and Matching Rules", RFC 4517, June 2006.

   [X.121]    International numbering plan for public data networks,
              ITU-T Recommendation X.121, 1996

   [X.509]    The Directory:  Authentication Framework, ITU-T
              Recommendation X.509, 1993

   [X.520]    The Directory: Selected Attribute Types, ITU-T
              Recommendation X.520, 1993

   [X.521]    The Directory: Selected Object Classes.  ITU-T
              Recommendation X.521, 1993

7.2.  Informative References

   [RFC1274]  Barker, P. and S. Kille, "The COSINE and Internet X.500
              Schema", RFC 1274, November 1991.

   [RFC2247]  Kille, S., Wahl, M., Grimstad, A., Huber, R., and S.
              Sataluri, "Using Domains in LDAP/X.500 Distinguished
              Names", RFC 2247, January 1998.

   [RFC2377]  Grimstad, A., Huber, R., Sataluri, S., and M. Wahl,
              "Naming Plan for Internet Directory-Enabled Applications",
              RFC 2377, September 1998.

   [RFC2798]  Smith, M., "Definition of the inetOrgPerson LDAP Object
              Class", RFC 2798, April 2000.



Sciberras                   Standards Track                    [Page 30]

RFC 4519           LDAP: Schema for User Applications          June 2006


   [RFC4513]  Harrison R., Ed., "Lightweight Directory Access Protocol
              (LDAP): Authentication Methods and Security Mechanisms",
              RFC 4513, June 2006.

   [RFC4523]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP) Schema Definitions for X.509 Certificates", RFC
              4523, June 2006.

   [RFC4524]  Zeilenga, E., Ed., "COSINE LDAP/X.500 Schema", RFC 4524,
              June 2006.

   [X.500]    ITU-T Recommendations X.500 (1993) | ISO/IEC 9594-1:1994,
              Information Technology - Open Systems Interconnection -
              The Directory: Overview of concepts, models and services.





































Sciberras                   Standards Track                    [Page 31]

RFC 4519           LDAP: Schema for User Applications          June 2006


Appendix A.  Changes Made Since RFC 2256

   This appendix lists the changes that have been made from RFC 2256 to
   RFC 4519.

   This appendix is not a normative part of this specification, which
   has been provided for informational purposes only.

      1.  Replaced the document title.

      2.  Removed the IESG Note.

      3.  Dependencies on RFC 1274 have been eliminated.

      4.  Added a Security Considerations section and an IANA
          Considerations section.

      5.  Deleted the conformance requirement for subschema object
          classes in favor of a statement in [RFC4517].

      6.  Added explanation to attribute types and to each object class.

      7.  Removed Section 4, Syntaxes, and Section 6, Matching Rules,
          (moved to [RFC4517]).

      8.  Removed the certificate-related attribute types:
          authorityRevocationList, cACertificate,
          certificateRevocationList, crossCertificatePair,
          deltaRevocationList, supportedAlgorithms, and userCertificate.

          Removed the certificate-related Object Classes:
          certificationAuthority, certificationAuthority-V2,
          cRLDistributionPoint, strongAuthenticationUser, and
          userSecurityInformation

          LDAP PKI is now discussed in [RFC4523].

      9.  Removed the dmdName, knowledgeInformation,
          presentationAddress, protocolInformation, and
          supportedApplicationContext attribute types and the dmd,
          applicationEntity, and dSA object classes.

      10. Deleted the aliasedObjectName and objectClass attribute type
          definitions.  Deleted the alias and top object class
          definitions.  They are included in [RFC4512].






Sciberras                   Standards Track                    [Page 32]

RFC 4519           LDAP: Schema for User Applications          June 2006


      11. Added the 'dc' attribute type from RFC 2247, making the
          distinction between 'stored' and 'query' values when preparing
          IDN strings.

      12. Numerous editorial changes.

      13. Removed upper bound after the SYNTAX oid in all attribute
          definitions where it appeared.

      14. Added text about Unicode, SASLprep [RFC4013], and UTF-8 for
          userPassword.

      15. Included definitions, comments and references for 'dcObject'
          and 'uidObject'.

      16. Replaced PKI schema references to use RFC 4523.

      17. Spelt out and referenced ABNF on first usage.

      18. Removed Section 2.4 (Source).  Replaced the source table with
          explicit references for each definition.

      19. All references to an attribute type or object class are
          enclosed in single quotes.

      20. The layout of attribute type definitions has been changed to
          provide consistency throughout the document:
          > Section Heading
          > Description of Attribute type
          > Multivalued description
          > Source Information
          > Definition
          > Example
          > Additional Comments

          Adding this consistent output included the addition of
          examples to some definitions.

      21. References to alternate names for attributes types are
          provided with a reference to where they were originally
          specified.

      22. Clarification of the description of 'distinguishedName' and
          'name', in regards to these attribute types being supertypes.

      23. Spelt out ISDN on first usage.





Sciberras                   Standards Track                    [Page 33]

RFC 4519           LDAP: Schema for User Applications          June 2006


      24. Inserted a reference to [RFC4517] for the
          'teletexTerminalIdentifier' definition's SYNTAX OID.

      25. Additional names were added to the IANA Considerations.  Names
          include 'commonName', 'dcObject', 'domainComponent', 'GN',
          'localityName', 'organizationName', 'organizationUnitName',
          'surname', 'uidObject' and 'userid'.

      26. Renamed all instances of supercede to supersede.

      27. Moved [F.1], [F.31] and [RFC4013] from informative to
          normative references.

      28. Changed the 'c' definition to be consistent with X.500.

Author's Address

   Andrew Sciberras
   eB2Bcom
   Suite 3, Woodhouse Corporate Centre,
   935 Station Street,
   Box Hill North, Victoria 3129
   AUSTRALIA

   Phone: +61 3 9896 7833
   EMail: andrew.sciberras@eb2bcom.com

























Sciberras                   Standards Track                    [Page 34]

RFC 4519           LDAP: Schema for User Applications          June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Sciberras                   Standards Track                    [Page 35]

alt-openldap11-devel/rfc/rfc3672.txt000064400000057577150410163260013015 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 3672                           OpenLDAP Foundation
Category: Standards Track                                        S. Legg
                                                     Adacel Technologies
                                                           December 2003


     Subentries in the Lightweight Directory Access Protocol (LDAP)

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2003).  All Rights Reserved.

Abstract

   In X.500 directories, subentries are special entries used to hold
   information associated with a subtree or subtree refinement.  This
   document adapts X.500 subentries mechanisms for use with the
   Lightweight Directory Access Protocol (LDAP).

1.  Overview

   From [X.501]:

       A subentry is a special kind of entry immediately subordinate to
       an administrative point.  It contains attributes that pertain to
       a subtree (or subtree refinement) associated with its
       administrative point.  The subentries and their administrative
       point are part of the same naming context.

       A single subentry may serve all or several aspects of
       administrative authority.  Alternatively, a specific aspect of
       administrative authority may be handled through one or more of
       its own subentries.

   Subentries in the Lightweight Directory Access Protocol (LDAP)
   [RFC3377] SHALL behave in accordance with X.501 unless noted
   otherwise in this specification.





Zeilenga & Legg             Standards Track                     [Page 1]

RFC 3672                   Subentries in LDAP              December 2003


   In absence of the subentries control (detailed in Section 3),
   subentries SHALL NOT be considered in one-level and subtree scope
   search operations.  For all other operations, including base scope
   search operations, subentries SHALL be considered.

1.1.  Conventions

   Schema definitions are provided using LDAP description formats
   [RFC2252].  Definitions provided here are formatted (line wrapped)
   for readability.

   Protocol elements are described using ASN.1 [X.680].  The term "BER-
   encoded" means the element is to be encoded using the Basic Encoding
   Rules [X.690] under the restrictions detailed in Section 5.1 of
   [RFC2251].

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

2.  Subentry Schema

2.1.  Subtree Specification Syntax

   The Subtree Specification syntax provides a general purpose mechanism
   for the specification of a subset of entries in a subtree of the
   Directory Information Tree (DIT).  A subtree begins at some base
   entry and includes the subordinates of that entry down to some
   identified lower boundary, possibly extending to the leaf entries.  A
   subtree specification is always used within a context or scope which
   implicitly determines the bounds of the subtree.  For example, the
   scope of a subtree specification for a subschema administrative area
   does not include the subtrees of any subordinate administrative point
   entries for subschema administration.  Where a subtree specification
   does not identify a contiguous subset of the entries within a single
   subtree the collection is termed a subtree refinement.

   This syntax corresponds to the SubtreeSpecification ASN.1 type
   described in [X.501], Section 11.3.  This ASN.1 data type definition
   is reproduced here for completeness.

     SubtreeSpecification ::= SEQUENCE {
         base                [0] LocalName DEFAULT { },
                                 COMPONENTS OF ChopSpecification,
         specificationFilter [4] Refinement OPTIONAL }

     LocalName ::= RDNSequence




Zeilenga & Legg             Standards Track                     [Page 2]

RFC 3672                   Subentries in LDAP              December 2003


     ChopSpecification ::= SEQUENCE {
         specificExclusions  [1] SET OF CHOICE {
                                 chopBefore [0] LocalName,
                                 chopAfter [1] LocalName } OPTIONAL,
         minimum             [2] BaseDistance DEFAULT 0,
         maximum             [3] BaseDistance OPTIONAL }

     BaseDistance ::= INTEGER (0 .. MAX)

     Refinement ::= CHOICE {
         item                [0] OBJECT-CLASS.&id,
         and                 [1] SET OF Refinement,
         or                  [2] SET OF Refinement,
         not                 [3] Refinement }

   The components of SubtreeSpecification are: base, which identifies
   the base entry of the subtree or subtree refinement, and
   specificExclusions, minimum, maximum and specificationFilter, which
   then reduce the set of subordinate entries of the base entry.  The
   subtree or subtree refinement contains all the entries within scope
   that are not excluded by any of the components of the subtree
   specification.  When all of the components of SubtreeSpecification
   are absent (i.e., when a value of the Subtree Specification syntax is
   the empty sequence, {}), the specified subtree implicitly includes
   all the entries within scope.

   Any particular use of this mechanism MAY impose limitations or
   constraints on the components of SubtreeSpecification.

   The LDAP syntax specification is:

       ( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )

   The LDAP-specific encoding of values of this syntax is defined by the
   Generic String Encoding Rules [RFC3641].  Appendix A provides an
   equivalent Augmented Backus-Naur Form (ABNF) [RFC2234] for this
   syntax.

2.1.1.  Base

   The base component of SubtreeSpecification nominates the base entry
   of the subtree or subtree refinement.  The base entry may be an entry
   which is subordinate to the root entry of the scope in which the
   subtree specification is used, in which case the base component
   contains a sequence of Relative Distinguished Names (RDNs) relative
   to the root entry of the scope, or may be the root entry of the scope
   itself (the default), in which case the base component is absent or
   contains an empty sequence of RDNs.



Zeilenga & Legg             Standards Track                     [Page 3]

RFC 3672                   Subentries in LDAP              December 2003


   Entries that are not subordinates of the base entry are excluded from
   the subtree or subtree refinement.

2.1.2.  Specific Exclusions

   The specificExclusions component of a ChopSpecification is a list of
   exclusions that specify entries and their subordinates to be excluded
   from the subtree or subtree refinement.  The entry is specified by a
   sequence of RDNs relative to the base entry (i.e., a LocalName).
   Each exclusion is of either the chopBefore or chopAfter form.  If the
   chopBefore form is used then the specified entry and its subordinates
   are excluded from the subtree or subtree refinement.  If the
   chopAfter form is used then only the subordinates of the specified
   entry are excluded from the subtree or subtree refinement.

2.1.3.  Minimum and Maximum

   The minimum and maximum components of a ChopSpecification allow the
   exclusion of entries based on their depth in the DIT.

   Entries that are less than the minimum number of RDN arcs below the
   base entry are excluded from the subtree or subtree refinement.  A
   minimum value of zero (the default) corresponds to the base entry.

   Entries that are more than the maximum number of RDN arcs below the
   base entry are excluded from the subtree or subtree refinement.  An
   absent maximum component indicates that there is no upper limit on
   the number of RDN arcs below the base entry for entries in the
   subtree or subtree refinement.

2.1.4.  Specification Filter

   The specificationFilter component is a boolean expression of
   assertions about the values of the objectClass attribute of the base
   entry and its subordinates.  A Refinement assertion item evaluates to
   true for an entry if that entry's objectClass attribute contains the
   OID nominated in the assertion.  Entries for which the overall filter
   evaluates to false are excluded from the subtree refinement.  If the
   specificationFilter is absent then no entries are excluded from the
   subtree or subtree refinement because of their objectClass attribute
   values.










Zeilenga & Legg             Standards Track                     [Page 4]

RFC 3672                   Subentries in LDAP              December 2003


2.2.  Administrative Role Attribute Type

   The Administrative Model defined in [X.501], clause 10 requires that
   administrative entries contain an administrativeRole attribute to
   indicate that the associated administrative area is concerned with
   one or more administrative roles.

   The administrativeRole operational attribute is specified as follows:

       ( 2.5.18.5 NAME 'administrativeRole'
           EQUALITY objectIdentifierMatch
           USAGE directoryOperation
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )

   The possible values of this attribute defined in X.501 are:

        OID            NAME
        --------  -------------------------------
       2.5.23.1   autonomousArea
       2.5.23.2   accessControlSpecificArea
       2.5.23.3   accessControlInnerArea
       2.5.23.4   subschemaAdminSpecificArea
       2.5.23.5   collectiveAttributeSpecificArea
       2.5.23.6   collectiveAttributeInnerArea

   Other values may be defined in other specifications.  Names
   associated with each administrative role are Object Identifier
   Descriptors [RFC3383].

   The administrativeRole operational attribute is also used to regulate
   the subentries permitted to be subordinate to an administrative
   entry.  A subentry not of a class permitted by the administrativeRole
   attribute cannot be subordinate to the administrative entry.

2.3.  Subtree Specification Attribute Type

   The subtreeSpecification operational attribute is defined as follows:

       ( 2.5.18.6 NAME 'subtreeSpecification'
           SINGLE-VALUE
           USAGE directoryOperation
           SYNTAX 1.3.6.1.4.1.1466.115.121.1.45 )

   This attribute is present in all subentries.  See [X.501], clause 10.
   Values of the subtreeSpecification attribute nominate collections of
   entries within the DIT for one or more aspects of administrative
   authority.




Zeilenga & Legg             Standards Track                     [Page 5]

RFC 3672                   Subentries in LDAP              December 2003


2.4.  Subentry Object Class

   The subentry object class is a structural object class.

       ( 2.5.17.0 NAME 'subentry'
           SUP top STRUCTURAL
           MUST ( cn $ subtreeSpecification ) )

3.  Subentries Control

   The subentries control MAY be sent with a searchRequest to control
   the visibility of entries and subentries which are within scope.
   Non-visible entries or subentries are not returned in response to the
   request.

   The subentries control is an LDAP Control whose controlType is
   1.3.6.1.4.1.4203.1.10.1, criticality is TRUE or FALSE (hence absent),
   and controlValue contains a BER-encoded BOOLEAN indicating
   visibility.  A controlValue containing the value TRUE indicates that
   subentries are visible and normal entries are not.  A controlValue
   containing the value FALSE indicates that normal entries are visible
   and subentries are not.

   Note that TRUE visibility has the three octet encoding { 01 01 FF }
   and FALSE visibility has the three octet encoding { 01 01 00 }.

   The controlValue SHALL NOT be absent.

   In absence of this control, subentries are not visible to singleLevel
   and wholeSubtree scope Search requests but are visible to baseObject
   scope Search requests.

   There is no corresponding response control.

   This control is not appropriate for non-Search operations.

4.  Security Considerations

   Subentries often hold administrative information or other sensitive
   information and should be protected from unauthorized access and
   disclosure as described in [RFC2829][RFC2830].

   General LDAP [RFC3377] security considerations also apply.








Zeilenga & Legg             Standards Track                     [Page 6]

RFC 3672                   Subentries in LDAP              December 2003


5.  IANA Considerations

5.1.  Descriptors

   The IANA has registered the LDAP descriptors detailed in this
   technical specification.  The following registration template is
   suggested:

       Subject: Request for LDAP Descriptor Registration
       Descriptor (short name): see comment
       Object Identifier: see comment
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Usage: see comment
       Specification: RFC3672
       Author/Change Controller: IESG
       Comments:

         NAME                            Type OID
         ------------------------        ---- --------
         accessControlInnerArea          R    2.5.23.3
         accessControlSpecificArea       R    2.5.23.2
         administrativeRole              A    2.5.18.5
         autonomousArea                  R    2.5.23.1
         collectiveAttributeInnerArea    R    2.5.23.6
         collectiveAttributeSpecificArea R    2.5.23.5
         subentry                        O    2.5.17.0
         subschemaAdminSpecificArea      R    2.5.23.4
         subtreeSpecification            A    2.5.18.6

       where Type A is Attribute, Type O is ObjectClass, and Type R is
       Administrative Role.

5.2.  Object Identifiers

   This document uses the OID 1.3.6.1.4.1.4203.1.10.1 to identify an
   LDAP protocol element defined herein.  This OID was assigned [ASSIGN]
   by OpenLDAP Foundation, under its IANA-assigned private enterprise
   allocation [PRIVATE], for use in this specification.

   Other OIDs which appear in this document were either assigned by the
   ISO/IEC Joint Technical Committee 1 - Subcommittee 6 to identify
   elements of X.500 schema or assigned in RFC 2252 for the use
   described here.







Zeilenga & Legg             Standards Track                     [Page 7]

RFC 3672                   Subentries in LDAP              December 2003


5.3.  Protocol Mechanisms

   The IANA has registered the LDAP protocol mechanisms [RFC3383]
   detailed in this specification.

   Subject: Request for LDAP Protocol Mechanism Registration

   Description: Subentries

   Person & email address to contact for further information:
        Kurt Zeilenga <kurt@openldap.org>

   Usage: Control

   Specification: RFC3672

   Author/Change Controller: IESG

   Comments: none

6.  Acknowledgment

   This document is based on engineering done by IETF LDUP and LDAPext
   Working Groups including "LDAP Subentry Schema" by Ed Reed.  This
   document also borrows from a number of ITU documents including X.501.

7.  Intellectual Property Statement

   The IETF takes no position regarding the validity or scope of any
   intellectual property or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; neither does it represent that it
   has made any effort to identify any such rights.  Information on the
   IETF's procedures with respect to rights in standards-track and
   standards-related documentation can be found in BCP-11.  Copies of
   claims of rights made available for publication and any assurances of
   licenses to be made available, or the result of an attempt made to
   obtain a general license or permission for the use of such
   proprietary rights by implementors or users of this specification can
   be obtained from the IETF Secretariat.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights which may cover technology that may be required to practice
   this standard.  Please address the information to the IETF Executive
   Director.




Zeilenga & Legg             Standards Track                     [Page 8]

RFC 3672                   Subentries in LDAP              December 2003


A.  Subtree Specification ABNF

   This appendix is non-normative.

   The LDAP-specific string encoding for the Subtree Specification
   syntax is specified by the Generic String Encoding Rules [RFC3641].
   The ABNF [RFC2234] in this appendix for this syntax is provided only
   as a convenience and is equivalent to the encoding specified by the
   application of [RFC3641].  Since the SubtreeSpecification ASN.1 type
   may be extended in future editions of [X.501], the provided ABNF
   should be regarded as a snapshot in time.  The LDAP-specific encoding
   for any extension to the SubtreeSpecification ASN.1 type can be
   determined from [RFC3641].

   In the event that there is a discrepancy between this ABNF and the
   encoding determined by [RFC3641], [RFC3641] is to be taken as
   definitive.

   SubtreeSpecification = "{"    [ sp ss-base ]
                             [ sep sp ss-specificExclusions ]
                             [ sep sp ss-minimum ]
                             [ sep sp ss-maximum ]
                             [ sep sp ss-specificationFilter ]
                                   sp "}"

   ss-base                = id-base                msp LocalName
   ss-specificExclusions  = id-specificExclusions  msp
                               SpecificExclusions
   ss-minimum             = id-minimum             msp BaseDistance
   ss-maximum             = id-maximum             msp BaseDistance
   ss-specificationFilter = id-specificationFilter msp Refinement

   id-base                = %x62.61.73.65 ; "base"
   id-specificExclusions  = %x73.70.65.63.69.66.69.63.45.78.63.6C.75.73
                               %x69.6F.6E.73 ; "specificExclusions"
   id-minimum             = %x6D.69.6E.69.6D.75.6D ; "minimum"
   id-maximum             = %x6D.61.78.69.6D.75.6D ; "maximum"
   id-specificationFilter = %x73.70.65.63.69.66.69.63.61.74.69.6F.6E.46
                               %x69.6C.74.65.72 ; "specificationFilter"

   SpecificExclusions = "{" [ sp SpecificExclusion
                           *( "," sp SpecificExclusion ) ] sp "}"
   SpecificExclusion  = chopBefore / chopAfter
   chopBefore         = id-chopBefore ":" LocalName
   chopAfter          = id-chopAfter  ":" LocalName
   id-chopBefore      = %x63.68.6F.70.42.65.66.6F.72.65 ; "chopBefore"
   id-chopAfter       = %x63.68.6F.70.41.66.74.65.72    ; "chopAfter"




Zeilenga & Legg             Standards Track                     [Page 9]

RFC 3672                   Subentries in LDAP              December 2003


   Refinement  = item / and / or / not
   item        = id-item ":" OBJECT-IDENTIFIER
   and         = id-and  ":" Refinements
   or          = id-or   ":" Refinements
   not         = id-not  ":" Refinement
   Refinements = "{" [ sp Refinement
                    *( "," sp Refinement ) ] sp "}"
   id-item     = %x69.74.65.6D ; "item"
   id-and      = %x61.6E.64    ; "and"
   id-or       = %x6F.72       ; "or"
   id-not      = %x6E.6F.74    ; "not"

   BaseDistance = INTEGER-0-MAX

   The <sp>, <msp>, <sep>, <INTEGER>, <INTEGER-0-MAX>, <OBJECT-
   IDENTIFIER> and <LocalName> rules are defined in [RFC3642].

Normative References

   [X.501]     ITU-T, "The Directory -- Models," X.501, 1993.

   [X.680]     ITU-T, "Abstract Syntax Notation One (ASN.1) -
               Specification of Basic Notation", X.680, 1994.

   [X.690]     ITU-T, "Specification of ASN.1 encoding rules:  Basic,
               Canonical, and Distinguished Encoding Rules", X.690,
               1994.

   [RFC2119]   Bradner, S., "Key words for use in RFCs to Indicate
               Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251]   Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
               Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252]   Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
               "Lightweight Directory Access Protocol (v3):  Attribute
               Syntax Definitions", RFC 2252, December 1997.

   [RFC2829]   Wahl, M., Alvestrand, H., Hodges, J. and R. Morgan,
               "Authentication Methods for LDAP", RFC 2829, May 2000.

   [RFC2830]   Hodges, J., Morgan, R. and M. Wahl, "Lightweight
               Directory Access Protocol (v3): Extension for Transport
               Layer Security", RFC 2830, May 2000.

   [RFC3377]   Hodges, J. and R. Morgan, "Lightweight Directory Access
               Protocol (v3): Technical Specification", RFC 3377,
               September 2002.



Zeilenga & Legg             Standards Track                    [Page 10]

RFC 3672                   Subentries in LDAP              December 2003


   [RFC3383]   Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
               Considerations for the Lightweight Directory Access
               Protocol (LDAP)", RFC 3383, September 2002.

   [RFC3641]   Legg, S., "Generic String Encoding Rules (GSER) for ASN.1
               Types", RFC 3641, October 2003.

Informative References

   [RFC2234]   Crocker, D. and P. Overell, "Augmented BNF for Syntax
               Specifications: ABNF", RFC 2234, November 1997.

   [RFC3642]   Legg, S., "Common Elements of Generic String Encoding
               Rules (GSER) Encodings", RFC 3642, October 2003.

   [ASSIGN]    OpenLDAP Foundation, "OpenLDAP OID Delegations",
               http://www.openldap.org/foundation/oid-delegate.txt

   [PRIVATE]   IANA, "Private Enterprise Numbers",
               http://www.iana.org/assignments/enterprise-numbers

Authors' Addresses

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org


   Steven Legg
   Adacel Technologies Ltd.
   250 Bay Street
   Brighton, Victoria 3186
   AUSTRALIA

   Phone: +61 3 8530 7710
   Fax:   +61 3 8530 7888
   EMail: steven.legg@adacel.com.au













Zeilenga & Legg             Standards Track                    [Page 11]

RFC 3672                   Subentries in LDAP              December 2003


Full Copyright Statement

   Copyright (C) The Internet Society (2003).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assignees.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Zeilenga & Legg             Standards Track                    [Page 12]

alt-openldap11-devel/rfc/rfc2713.txt000064400000117451150410163260012774 0ustar00





Network Working Group                                            V. Ryan
Request for Comments: 2713                                   S. Seligman
Category: Informational                                           R. Lee
                                                  Sun Microsystems, Inc.
                                                            October 1999


     Schema for Representing Java(tm) Objects in an LDAP Directory

Status of this Memo

   This memo provides information for the Internet community.  It does
   not specify an Internet standard of any kind.  Distribution of this
   memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

Abstract

   This document defines the schema for representing Java(tm) objects in
   an LDAP directory [LDAPv3].  It defines schema elements to represent
   a Java serialized object [Serial], a Java marshalled object [RMI], a
   Java remote object [RMI], and a JNDI reference [JNDI].

1. Introduction

   This document assumes that the reader has a general knowledge of the
   Java programming language [Java].  For brevity we use the term "Java
   object" in place of "object in the Java programming language"
   throughout this text.

   Traditionally, LDAP directories have been used to store data. Users
   and programmers think of the directory as a hierarchy of directory
   entries, each containing a set of attributes.  You look up an entry
   from the directory and extract the attribute(s) of interest.  For
   example, you can look up a person's telephone number from the
   directory.  Alternatively, you can search the directory for entries
   with a particular set of attributes.  For example, you can search for
   all persons in the directory with the surname "Smith".

   For applications written in the Java programming language, a kind of
   data that is typically shared are Java objects themselves.  For such
   applications, it makes sense to be able to use the directory as a
   repository for Java objects.  The directory provides a centrally
   administered, and possibly replicated, service for use by Java
   applications distributed across the network.



Ryan, et al.                 Informational                      [Page 1]

RFC 2713                Schema for Java Objects             October 1999


   For example, an application server might use the directory for
   "registering" objects representing the services that it manages, so
   that a client can later search the directory to locate those services
   as it needs.

   The motivation for this document is to define a common way for
   applications to store and retrieve Java objects from the directory.
   Using this common schema, any Java application that needs to read or
   store Java objects in the directory can do so in an interoperable
   way.

2 Representation of Java Objects

   This document defines schema elements to represent three types of
   Java objects:  a Java serialized object, a Java marshalled object,
   and a JNDI reference. A Java remote object is stored as either a Java
   marshalled object or a JNDI reference.

2.1 Common Representations

   A Java object is stored in the LDAP directory by using the object
   class javaObject. This is the base class from which other Java object
   related classes derive: javaSerializedObject, javaMarshalledObject,
   and javaNamingReference.  javaObject is an abstract object class,
   which means that a javaObject cannot exist by itself in the
   directory; only auxiliary or structural subclasses of it can exist in
   the directory.

   The object class javaContainer represents a directory entry dedicated
   to storing a Java object. It is a structural object class.  In cases
   where a subclass of javaObject is mixed in with another structural
   object class, javaContainer is not required.

   The definitions for the object classes javaObject and javaContainer
   are presented in Section 4.

   The javaObject class has one mandatory attribute (javaClassName) and
   four optional attributes (javaClassNames, javaCodebase, javaDoc,
   description).  javaClassName is a single valued attribute that is
   used to store the fully qualified name of the object's Java class
   (for example, "java.lang.String").  This may be the object's most
   derived class's name, but does not have to be; that of a superclass
   or interface in some cases might be most appropriate.  This attribute
   is intended for storing the name of the object's "distinguished"
   class, that is, the class or interface with which the object should
   be identified.





Ryan, et al.                 Informational                      [Page 2]

RFC 2713                Schema for Java Objects             October 1999


   javaClassNames is a multivalued attribute that is used to store the
   fully qualified names of the object's Java classes and interfaces
   (for example, "java.lang.Byte"). Like all multivalued attributes, the
   javaClassNames attribute's values are unordered and so no one value
   is more "distinguished" than the others. This attribute is intended
   for storing an object's class and interface names and those of its
   ancestor classes and interfaces, although the list of values does not
   have to be complete.  If the javaClassNames attribute is present, it
   should include the value of javaClassName.

   For example, suppose an object is stored in the directory with a
   javaClassName attribute of "java.io.FilePermission", and a
   javaClassNames attribute of {"java.security.Permission",
   "java.io.FilePermission", "java.security.Guard",
   "java.io.Serializable"}. An application searching a directory for
   Java objects might use javaClassName to produce a summary of the
   names and types of Java objects in that directory.  Another
   application might use the javaClassNames attribute to find, for
   example, all java.security.Permission objects.

   javaCodebase is a multivalued attribute that is used to store the
   location(s) of the object's class definition.  javaDoc is used to
   store a pointer (URL) to the Java documentation for the class.
   description is used to store a textual description of a Java object
   and is defined in [v3Schema]. The definitions of these attributes are
   presented in Section 3.

2.2 Serialized Objects

   To "serialize" an object means to convert its state into a byte
   stream in such a way that the byte stream can be converted back into
   a copy of the object.  A Java object is "serializable" if its class
   or any of its superclasses implements either the java.io.Serializable
   interface or its subinterface java.io.Externalizable.
   "Deserialization" is the process of converting the serialized form of
   an object back into a copy of the object.  When an object is
   serialized, the entire tree of objects rooted at the object is also
   serialized. When it is deserialized, the tree is reconstructed. For
   example, suppose a serializable Book object contains (a serializable
   field of) an array of Page objects.  When a Book object is
   serialized, so is the array of Page objects.

   The Java platform specifies a default algorithm by which serializable
   objects are serialized. A Java class can also override this default
   serialization with its own algorithm.  [Serial] describes object
   serialization in detail.





Ryan, et al.                 Informational                      [Page 3]

RFC 2713                Schema for Java Objects             October 1999


   When an object is serialized, information that identifies its class
   is recorded in the serialized stream. However, the class's definition
   ("class file") itself is not recorded. It is the responsibility of
   the system that is deserializing the object to determine the
   mechanism to use for locating and loading the associated class
   definitions. For example, the Java application might include in its
   classpath a JAR file containing the class definitions of the
   serialized object, or load the class definitions using information
   from the directory, as explained below.

2.2.1 Representation in the Directory

   A serialized object is represented in the directory by the attributes
   javaClassName, javaClassNames, javaCodebase, and javaSerializedData,
   as defined in Section 3.  The mandatory attribute,
   javaSerializedData, contains the serialized form of the object.
   Although the serialized form already contains the class name, the
   mandatory javaClassName attribute also records the class name of the
   serialized object so that applications can determined class
   information without having to first deserialize the object.  The
   optional javaClassNames attribute is used to record additional class
   information about the serialized object.  The optional javaCodebase
   attribute is used to record the locations of the class definitions
   needed to deserialize the serialized object.

   A directory entry that contains a serialized object is represented by
   the object class javaSerializedObject, which is a subclass of
   javaObject.  javaSerializedObject is an auxiliary object class, which
   means that it needs to be mixed in with a structural object class.
   javaSerializedObject's definition is given in Section 4.

2.3 Marshalled Objects

   To "marshal" an object means to record its state and codebase(s) in
   such a way that when the marshalled object is "unmarshalled," a copy
   of the original object is obtained, possibly by automatically loading
   the class definitions of the object.  You can marshal any object that
   is serializable or remote (that is, implements the java.rmi.Remote
   interface).  Marshalling is like serialization, except marshalling
   also records codebases. Marshalling is different from serialization
   in that marshalling treats remote objects specially. If an object is
   a java.rmi.Remote object, marshalling records the remote object's
   "stub" (see Section 2.5), instead of the remote object itself.  Like
   serialization, when an object is marshalled, the entire tree of
   objects rooted at the object is marshalled. When it is unmarshalled,
   the tree is reconstructed.





Ryan, et al.                 Informational                      [Page 4]

RFC 2713                Schema for Java Objects             October 1999


   A "marshalled" object is the represented by the
   java.rmi.MarshalledObject class. Here's an example of how to create
   MarshalledObjects for serializable and remote objects:

       java.io.Serializable sobj = ...;
       java.rmi.MarshalledObject mobj1 =
           new java.rmi.MarshalledObject(sobj);

       java.rmi.Remote robj = ...;
       java.rmi.MarshalledObject mobj2 =
           new java.rmi.MarshalledObject(robj);

   Then, to retrieve the original objects from the MarshalledObjects, do
   as follows:

       java.io.Serializable sobj = (java.io.Serializable) mobj1.get();
       java.io.Remote rstub = (java.io.Remote) mobj2.get();

   MarshalledObject is available only on the Java 2 Platform, Standard
   Edition, v1.2, and higher releases.

2.3.1 Representation in the Directory

   A marshalled object is represented in the directory by the attributes
   javaClassName, javaClassNames, and javaSerializedData, as defined in
   Section 3.  The mandatory attribute, javaSerializedData, contains the
   serialized form of the marshalled object (that is, the serialized
   form of a MarshalledObject instance).  The mandatory javaClassName
   attribute records the distinguished class name of the object before
   it has been marshalled.  The optional javaClassNames attribute is
   used to record additional class information about the object before
   it has been marshalled.

   A directory entry that contains a marshalled object is represented by
   the object class javaMarshalledObject, which is a subclass of
   javaObject.  javaMarshalledObject is an auxiliary object class, which
   means that it needs to be mixed in with a structural object class.
   javaMarshalledObject's definition is given in Section 4.

   As evident in this description, a javaMarshalledObject differs from a
   javaSerializedObject only in the interpretation of the javaClassName
   and javaClassNames attributes.









Ryan, et al.                 Informational                      [Page 5]

RFC 2713                Schema for Java Objects             October 1999


2.4 JNDI References

   Java Naming and Directory Interface(tm) (JNDI) is a directory access
   API specified in the Java programming language [JNDI].  It provides
   an object-oriented view of the directory, allowing Java objects to be
   added to and retrieved from the directory without requiring the
   client to manage data representation issues.

   JNDI defines the notion of a "reference" for use when an object
   cannot be stored in the directory directly, or when it is
   inappropriate or undesirable to do so.  An object with an associated
   reference is stored in the directory indirectly, by storing its
   reference instead.

2.4.1 Contents of a Reference

   A JNDI reference is a Java object of class javax.naming.Reference.
   It consists of class information about the object being referenced
   and an ordered list of addresses.  An address is a Java object of
   class javax.naming.RefAddr.  Each address contains information on how
   to construct the object.

   A common use for JNDI references is to represent connections to a
   network service such as a database, directory, or file system.  Each
   address may then identify a "communications endpoint" for that
   service, containing information on how to contact the service.
   Multiple addresses may arise for various reasons, such as replication
   or the object offering interfaces over more than one communication
   mechanism.

   A reference also contains information to assist in the creation of an
   instance of the object to which the reference refers.  It contains
   the Java class name of that object, and the class name and location
   of the object factory to be used to create the object.  The
   procedures for creating an object given its reference and the reverse
   are described in [JNDI].

2.4.2 Representation in the Directory

   A JNDI reference is stored in the directory by using the attributes
   javaClassName, javaClassNames, javaCodebase, javaReferenceAddress,
   and javaFactory, defined in Section 3.  These attributes store
   information corresponding to the contents of a reference described
   above.  javaReferenceAddress is a multivalued optional attribute for
   storing reference addresses.  javaFactory is the optional attribute
   for storing the object factory's fully qualified class name.  The
   mandatory javaClassName attribute is used to store the name of the
   distinguished class of the object.  The optional javaClassNames



Ryan, et al.                 Informational                      [Page 6]

RFC 2713                Schema for Java Objects             October 1999


   attribute is used to record additional class and interface names.
   The optional javaCodebase attribute is used to store the locations of
   the object factory's and the object's class definitions.

   A directory entry containing a JNDI reference is represented by the
   object class javaNamingReference, which is a subclass of javaObject.
   javaNamingReference is an auxiliary object class, which means that it
   needs to be mixed in with a structural object class.
   javaNamingReference's definition is given in Section 4.

2.5 Remote Objects

   The Java Remote Method Invocation (RMI) system [RMI] is a mechanism
   that enables an object on one Java virtual machine to invoke methods
   on an object in another Java virtual machine. Any object whose
   methods can be invoked in this way must implement the java.rmi.Remote
   interface.  When such an object is invoked, its arguments are
   marshalled and sent from the local virtual machine to the remote one,
   where the arguments are unmarshalled and used.  When the method
   terminates, the results are marshalled from the remote machine and
   sent to the caller's virtual machine.

   To make a remote object accessible to other virtual machines, a
   program typically registers it with the RMI registry.  The program
   supplies to the RMI registry the string name of the remote object and
   the remote object itself.  When a program wants to access a remote
   object, it supplies the object's string name to the RMI registry on
   the same machine as the remote object.  The RMI registry returns to
   the caller a reference (called "stub") to the remote object.  When
   the program receives the stub for the remote object, it can invoke
   methods on the remote object (through the stub).  A program can also
   obtain references to remote objects as a result of remote calls to
   other remote objects or from other naming services.  For example, the
   program can look up a reference to a remote object from an LDAP
   server that supports the schema defined in this document.

   The string name accepted by the RMI registry has the syntax
   "rmi://hostname:port/remoteObjectName", where "hostname" and "port"
   identify the machine and port on which the RMI registry is running,
   respectively, and "remoteObjectName" is the string name of the remote
   object.  "hostname", "port", and the prefix, "rmi:", are optional. If
   "hostname" is not specified, it defaults to the local host.  If
   "port" is not specified, it defaults to 1099.  If "remoteObjectName"
   is not specified, then the object being named is the RMI registry
   itself.  See [RMI] for details.






Ryan, et al.                 Informational                      [Page 7]

RFC 2713                Schema for Java Objects             October 1999


   RMI can be supported using different protocols: the Java Remote
   Method Protocol (JRMP) and the Internet Inter-ORB Protocol (IIOP).
   The JRMP is a specialized protocol designed for RMI; the IIOP is the
   standard protocol for communication between CORBA objects [CORBA].
   RMI over IIOP allows Java remote objects to communicate with CORBA
   objects which might be written in a non-Java programming language
   [RMI-IIOP].

2.5.1 Representation in the Directory

   Remote objects that use the IIOP are represented in the directory as
   CORBA object references [CORBA-LDAP].  Remote objects that use the
   JRMP are represented in the directory in one of two ways: as a
   marshalled object, or as a JNDI reference.

   A marshalled object records the codebases of the remote object's stub
   and any serializable or remote objects that it references, and
   replaces remote objects with their stubs.  To store a Remote object
   as a marshalled object (java.rmi.MarshalledObject), you first create
   a java.rmi.MarshalledObject instance for it.

       java.rmi.Remote robj = ...;
       java.rmi.MarshalledObject mobj =
           new java.rmi.MarshalledObject(robj);

   You can then store the MarshalledObject instance as a
   javaMarshalledObject.  The javaClassName attribute should contain the
   fully qualified name of the distinguished class of the remote object.
   The javaClassNames attribute should contain the names of the classes
   and interfaces of the remote object.  To read the remote object back
   from the directory, first deserialize the contents of the
   javaSerializedData to get a MarshalledObject (mobj), then retrieve it
   from the MarshalledObject as follows:

       java.rmi.Remote robj = (java.rmi.Remote)mobj.get();

   This returns the remote stub, which you can then use to invoke remote
   methods.

   MarshalledObject is available only on the Java 2 Platform, Standard
   Edition, v1.2 and higher releases. Therefore, a remote object stored
   as a MarshalledObject can only be read by clients using the the Java
   2 Platform, Standard Edition, v1.2 or higher releases.








Ryan, et al.                 Informational                      [Page 8]

RFC 2713                Schema for Java Objects             October 1999


   To store a remote object as a JNDI reference, you first create a
   javax.naming.Reference object instance for it using the remote
   object's string name as it has been, or will be, recorded with the
   RMI registry, with the additional restriction that the "rmi:" prefix
   must be present. Here's an example:

       javax.naming.Reference ref = new javax.naming.Reference(
         obj.getClass().getName(),
         new javax.naming.StringRefAddr("URL",
             "rmi://rserver/AppRemoteObjectX"));

   You then store the javax.naming.Reference instance as a
   javaNamingReference.  The advantage of using a JNDI reference is that
   this can be done without a reference to the remote object. In fact,
   the remote object does not have to exist at the time that this
   recording in the directory is made.  The remote object needs to exist
   and be bound with the RMI registry when the object is looked up from
   the directory.

2.6  Serialized Objects Vs. Marshalled Objects Vs. References

   The object classes defined in this document store different aspects
   of the Java objects.

   A javaSerializedObject or a serializable object stored as a
   javaMarshalledObject represents the object itself, while a
   javaNamingReference or a remote object stored as a
   javaMarshalledObject represents a "pointer" to the object.

   When storing a serializable object in the directory, you have a
   choice of storing it as a javaSerializedObject or a
   javaMarshalledObject.  The javaSerializedObject object class provides
   the basic way in which to store serializable objects. When you create
   an LDAP entry using the javaSerializableObject object class, you must
   explicitly set the javaCodebase attribute if you want readers of that
   entry to know where to load the class definitions of the object. When
   you create an LDAP entry using the javaMarshalledObject object class,
   you use the MarshalledObject class.  The MarshalledObject class uses
   the RMI infrastructure available on the Java platform to automate how
   codebase information is gathered and recorded, thus freeing you from
   having to set the javaCodebase attribute. On the other hand, the
   javaCodebase attribute is human-readable and can be updated easily by
   using text-based tools without having to change other parts of the
   entry.  This allows you, for instance, to move the class definitions
   to another location and then update the javaCodebase attribute to
   reflect the move without having to update the serialized object
   itself.




Ryan, et al.                 Informational                      [Page 9]

RFC 2713                Schema for Java Objects             October 1999


   A javaNamingReference provides a way of recording address information
   about an object which itself is not directly stored in the directory.
   A remote object stored as a javaMarshalledObject also records address
   information (the object's "stub") of an object which itself is not
   directory stored in the directory.  In other words, you can think of
   these as compact representations of the information required to
   access the object.

   A javaNamingReference typically consists of a small number of human-
   readable strings.  Standard text-based tools for directory
   administration may therefore be used to add, read, or modify
   reference entries -- if so desired -- quite easily.  Serialized and
   marshalled objects are not intended to be read or manipulated
   directly by humans.

3 Attribute Type Definitions

   The following attribute types are defined in this document:

       javaClassName
       javaClassNames
       javaCodebase
       javaSerializedData
       javaFactory
       javaReferenceAddress
       javaDoc

3.1 javaClassName

   This attribute stores the fully qualified name of the Java object's
   "distinguished" class or interface (for example, "java.lang.String").
   It is a single-valued attribute. This attribute's syntax is '
   Directory String' and its case is significant.

       ( 1.3.6.1.4.1.42.2.27.4.1.6
         NAME 'javaClassName'
         DESC 'Fully qualified name of distinguished Java class or
               interface'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
         SINGLE-VALUE
       )









Ryan, et al.                 Informational                     [Page 10]

RFC 2713                Schema for Java Objects             October 1999


3.2 javaCodebase

   This attribute stores the Java class definition's locations.  It
   specifies the locations from which to load the class definition for
   the class specified by the javaClassName attribute.  Each value of
   the attribute contains an ordered list of URLs, separated by spaces.
   For example, a value of "url1 url2 url3" means that the three
   (possibly interdependent) URLs (url1, url2, and url3) form the
   codebase for loading in the Java class definition.

   If the javaCodebase attribute contains more than one value, each
   value is an independent codebase. That is, there is no relationship
   between the URLs in one value and those in another; each value can be
   viewed as an alternate source for loading the Java class definition.
   See [Java] for information regarding class loading.

   This attribute's syntax is 'IA5 String' and its case is significant.

       ( 1.3.6.1.4.1.42.2.27.4.1.7
         NAME 'javaCodebase'
         DESC 'URL(s) specifying the location of class definition'
         EQUALITY caseExactIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
       )

3.3 javaClassNames

   This attribute stores the Java object's fully qualified class or
   interface names (for example, "java.lang.String").  It is a
   multivalued attribute. When more than one value is present, each is
   the name of a class or interface, or ancestor class or interface, of
   this object.

   This attribute's syntax is 'Directory String' and its case is
   significant.

       ( 1.3.6.1.4.1.42.2.27.4.1.13
         NAME 'javaClassNames'
         DESC 'Fully qualified Java class or interface name'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
       )









Ryan, et al.                 Informational                     [Page 11]

RFC 2713                Schema for Java Objects             October 1999


3.4 javaSerializedData

   This attribute stores the serialized form of a Java object.  The
   serialized form is described in [Serial].

   This attribute's syntax is 'Octet String'.

       ( 1.3.6.1.4.1.42.2.27.4.1.8
         NAME 'javaSerializedData
         DESC 'Serialized form of a Java object'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
         SINGLE-VALUE
       )

3.5 javaFactory

   This attribute stores the fully qualified class name of the object
   factory (for example, "com.wiz.jndi.WizObjectFactory") that can be
   used to create an instance of the object identified by the
   javaClassName attribute.

   This attribute's syntax is 'Directory String' and its case is
   significant.

       ( 1.3.6.1.4.1.42.2.27.4.1.10
         NAME 'javaFactory'
         DESC 'Fully qualified Java class name of a JNDI object factory'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
         SINGLE-VALUE
       )

3.6 javaReferenceAddress

   This attribute represents the sequence of addresses of a JNDI
   reference.  Each of its values represents one address, a Java object
   of type javax.naming.RefAddr.  Its value is a concatenation of the
   address type and address contents, preceded by a sequence number (the
   order of addresses in a JNDI reference is significant).  For example:

       #0#TypeA#ValA
       #1#TypeB#ValB
       #2#TypeC##rO0ABXNyABpq...

   In more detail, the value is encoded as follows:






Ryan, et al.                 Informational                     [Page 12]

RFC 2713                Schema for Java Objects             October 1999


   The delimiter is the first character of the value.  For readability
   the character '#' is recommended when it is not otherwise used
   anywhere in the value, but any character may be used subject to
   restrictions given below.

   The first delimiter is followed by the sequence number.  The sequence
   number of an address is its position in the JNDI reference, with the
   first address being numbered 0.  It is represented by its shortest
   string form, in decimal notation.

   The sequence number is followed by a delimiter, then by the address
   type, and then by another delimiter.  If the address is of Java class
   javax.naming.StringRefAddr, then this delimiter is followed by the
   value of the address contents (which is a string).  Otherwise, this
   delimiter is followed immediately by another delimiter, and then by
   the Base64 encoding of the serialized form of the entire address.

   The delimiter may be any character other than a digit or a character
   contained in the address type.  In addition, if the address contents
   is a string, the delimiter may not be the first character of that
   string.

   This attribute's syntax is 'Directory String' and its case is
   significant.  It can contain multiple values.

       ( 1.3.6.1.4.1.42.2.27.4.1.11
         NAME 'javaReferenceAddress'
         DESC 'Addresses associated with a JNDI Reference'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
       )

3.7 javaDoc

   This attribute stores a pointer to the Java documentation for the
   class.  It's value is a URL. For example, the following URL points to
   the specification of the java.lang.String class:
   http://java.sun.com/products/jdk/1.2/docs/api/java/lang/String.html

   This attribute's syntax is 'IA5 String' and its case is significant.

       ( 1.3.6.1.4.1.42.2.27.4.1.12
         NAME 'javaDoc'
         DESC 'The Java documentation for the class'
         EQUALITY caseExactIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
       )




Ryan, et al.                 Informational                     [Page 13]

RFC 2713                Schema for Java Objects             October 1999


4 Object Class Definitions

   The following object classes are defined in this document:

       javaContainer
       javaObject
       javaSerializedObject
       javaMarshalledObject
       javaNamingReference

4.1 javaContainer

   This structural object class represents a container for a Java
   object.

       ( 1.3.6.1.4.1.42.2.27.4.2.1
         NAME 'javaContainer'
         DESC 'Container for a Java object'
         SUP top
         STRUCTURAL
         MUST ( cn )
       )

4.2 javaObject

   This abstract object class represents a Java object.  A javaObject
   cannot exist in the directory; only auxiliary or structural
   subclasses of it can exist in the directory.

       ( 1.3.6.1.4.1.42.2.27.4.2.4
         NAME 'javaObject'
         DESC 'Java object representation'
         SUP top
         ABSTRACT
         MUST ( javaClassName )
         MAY ( javaClassNames $
               javaCodebase $
               javaDoc $
               description )
       )











Ryan, et al.                 Informational                     [Page 14]

RFC 2713                Schema for Java Objects             October 1999


4.3 javaSerializedObject

   This auxiliary object class represents a Java serialized object.  It
   must be mixed in with a structural object class.

       ( 1.3.6.1.4.1.42.2.27.4.2.5
         NAME 'javaSerializedObject'
         DESC 'Java serialized object'
         SUP javaObject
         AUXILIARY
         MUST ( javaSerializedData )
       )

4.4 javaMarshalledObject

   This auxiliary object class represents a Java marshalled object.  It
   must be mixed in with a structural object class.

       ( 1.3.6.1.4.1.42.2.27.4.2.8
         NAME 'javaMarshalledObject'
         DESC 'Java marshalled object'
         SUP javaObject
         AUXILIARY
         MUST ( javaSerializedData )
       )

4.5 javaNamingReference

   This auxiliary object class represents a JNDI reference.  It must be
   mixed in with a structural object class.

       ( 1.3.6.1.4.1.42.2.27.4.2.7
         NAME 'javaNamingReference'
         DESC 'JNDI reference'
         SUP javaObject
         AUXILIARY
         MAY ( javaReferenceAddress $
               javaFactory )
       )












Ryan, et al.                 Informational                     [Page 15]

RFC 2713                Schema for Java Objects             October 1999


5. Security Considerations

   Serializing an object and storing it into the directory enables (a
   copy of) the object to be examined and used outside the environment
   in which it was originally created.  The directory entry containing
   the serialized object could be read and modified within the
   constraints imposed by the access control mechanisms of the
   directory.  If an object contains sensitive information or
   information that could be misused outside of the context in which it
   was created, the object should not be stored in the directory.  For
   more details on security issues relating to serialization in general,
   see [Serial].

6. Acknowledgements

   We would like to thank Joseph Fialli, Peter Jones, Roger Riggs, Bob
   Scheifler, and Ann Wollrath of Sun Microsystems for their comments
   and suggestions.

7. References

   [CORBA]      The Object Management Group, "Common Object Request
                Broker Architecture Specification 2.0,"
                http://www.omg.org

   [CORBA-LDAP] Ryan, V., Lee, R. and S. Seligman, "Schema for
                Representing CORBA Object References in an LDAP
                Directory", RFC 2714, October 1999.

   [Java]       Ken Arnold and James Gosling, "The Java(tm) Programming
                Language," Second Edition, ISBN 0-201-31006-6.

   [JNDI]       Java Software, Sun Microsystems, Inc., "The Java(tm)
                Naming and Directory Interface (tm) Specification,"
                February 1998.  http://java.sun.com/products/jndi/

   [LDAPv3]     Wahl, M., Howes, T. and  S. Kille, "Lightweight
                Directory Access Protocol (v3)", RFC 2251, December
                1997.

   [RMI]        Java Software, Sun Microsystems, Inc., "Remote Method
                Invocation," November 1998.
                http://java.sun.com/products/jdk/1.2/docs/guide/rmi








Ryan, et al.                 Informational                     [Page 16]

RFC 2713                Schema for Java Objects             October 1999


   [RMI-IIOP]   IBM and Java Software, Sun Microsystems, Inc., "RMI over
                IIOP", June 1999.
                http://java.sun.com/products/rmi-iiop/

   [Serial]     Java Software, Sun Microsystems, Inc., "Object
                Serialization Specification," November 1998.
                http://java.sun.com/products/jdk/1.2/docs/guide/
                serialization

   [v3Schema]   Wahl, M., "A Summary of the X.500(96) User Schema for
                use with LDAPv3", RFC 2256, December 1997.

8. Authors' Addresses

   Vincent Ryan
   Sun Microsystems, Inc.
   Mail Stop EDUB03
   901 San Antonio Road
   Palo Alto, CA 94303
   USA

   Phone: +353 1 819 9151
   EMail: vincent.ryan@ireland.sun.com


   Scott Seligman
   Sun Microsystems, Inc.
   Mail Stop UCUP02-209
   901 San Antonio Road
   Palo Alto, CA 94303
   USA

   Phone: +1 408 863 3222
   EMail: scott.seligman@eng.sun.com


   Rosanna Lee
   Sun Microsystems, Inc.
   Mail Stop UCUP02-206
   901 San Antonio Road
   Palo Alto, CA 94303
   USA

   Phone: +1 408 863 3221
   EMail: rosanna.lee@eng.sun.com






Ryan, et al.                 Informational                     [Page 17]

RFC 2713                Schema for Java Objects             October 1999


Appendix - LDAP Schema

  -- Attribute types --

  ( 1.3.6.1.4.1.42.2.27.4.1.6
    NAME 'javaClassName'
    DESC 'Fully qualified name of distinguished Java class or interface'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    SINGLE-VALUE
  )

  ( 1.3.6.1.4.1.42.2.27.4.1.7
    NAME 'javaCodebase'
    DESC 'URL(s) specifying the location of class definition'
    EQUALITY caseExactIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
  )

  ( 1.3.6.1.4.1.42.2.27.4.1.8
    NAME 'javaSerializedData'
    DESC 'Serialized form of a Java object'
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
    SINGLE-VALUE
  )

  ( 1.3.6.1.4.1.42.2.27.4.1.10
    NAME 'javaFactory'
    DESC 'Fully qualified Java class name of a JNDI object factory'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    SINGLE-VALUE
  )

  ( 1.3.6.1.4.1.42.2.27.4.1.11
    NAME 'javaReferenceAddress'
    DESC 'Addresses associated with a JNDI Reference'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  )

  ( 1.3.6.1.4.1.42.2.27.4.1.12
    NAME 'javaDoc'
    DESC 'The Java documentation for the class'
    EQUALITY caseExactIA5Match
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
  )




Ryan, et al.                 Informational                     [Page 18]

RFC 2713                Schema for Java Objects             October 1999


  ( 1.3.6.1.4.1.42.2.27.4.1.13
    NAME 'javaClassNames'
    DESC 'Fully qualified Java class or interface name'
    EQUALITY caseExactMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  )

  -- from RFC-2256 --

  ( 2.5.4.13
    NAME 'description'
    EQUALITY caseIgnoreMatch
    SUBSTR caseIgnoreSubstringsMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024}
  )

  -- Object classes --

  ( 1.3.6.1.4.1.42.2.27.4.2.1
    NAME 'javaContainer'
    DESC 'Container for a Java object'
    SUP top
    STRUCTURAL
    MUST ( cn )
  )

  ( 1.3.6.1.4.1.42.2.27.4.2.4
    NAME 'javaObject'
    DESC 'Java object representation'
    SUP top
    ABSTRACT
    MUST ( javaClassName )
    MAY ( javaClassNames $ javaCodebase $ javaDoc $ description )
  )

  ( 1.3.6.1.4.1.42.2.27.4.2.5
    NAME 'javaSerializedObject'
    DESC 'Java serialized object'
    SUP javaObject
    AUXILIARY
    MUST ( javaSerializedData )
  )









Ryan, et al.                 Informational                     [Page 19]

RFC 2713                Schema for Java Objects             October 1999


  ( 1.3.6.1.4.1.42.2.27.4.2.7
    NAME 'javaNamingReference'
    DESC 'JNDI reference'
    SUP javaObject
    AUXILIARY
    MAY ( javaReferenceAddress $ javaFactory )
  )

  ( 1.3.6.1.4.1.42.2.27.4.2.8
    NAME 'javaMarshalledObject'
    DESC 'Java marshalled object'
    SUP javaObject
    AUXILIARY
    MUST ( javaSerializedData )
  )

  -- Matching rule from ISO X.520 --

  ( 2.5.13.5
    NAME 'caseExactMatch'
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  )





























Ryan, et al.                 Informational                     [Page 20]

RFC 2713                Schema for Java Objects             October 1999


Full Copyright Statement

   Copyright (C) The Internet Society (1999).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Ryan, et al.                 Informational                     [Page 21]

alt-openldap11-devel/rfc/rfc4521.txt000064400000103431150410163260012764 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4521                           OpenLDAP Foundation
BCP: 118                                                       June 2006
Category: Best Current Practice


                          Considerations for
        Lightweight Directory Access Protocol (LDAP) Extensions

Status of This Memo

   This document specifies an Internet Best Current Practices for the
   Internet Community, and requests discussion and suggestions for
   improvements.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   The Lightweight Directory Access Protocol (LDAP) is extensible.  It
   provides mechanisms for adding new operations, extending existing
   operations, and expanding user and system schemas.  This document
   discusses considerations for designers of LDAP extensions.


























Zeilenga                 Best Current Practice                  [Page 1]

RFC 4521                    LDAP Extensions                    June 2006


Table of Contents

   1. Introduction ....................................................3
      1.1. Terminology ................................................3
   2. General Considerations ..........................................4
      2.1. Scope of Extension .........................................4
      2.2. Interaction between extensions .............................4
      2.3. Discovery Mechanism ........................................4
      2.4. Internationalization Considerations ........................5
      2.5. Use of the Basic Encoding Rules ............................5
      2.6. Use of Formal Languages ....................................5
      2.7. Examples ...................................................5
      2.8. Registration of Protocol Values ............................5
   3. LDAP Operation Extensions .......................................6
      3.1. Controls ...................................................6
           3.1.1. Extending Bind Operation with Controls ..............6
           3.1.2. Extending the Start TLS Operation with Controls .....7
           3.1.3. Extending the Search Operation with Controls ........7
           3.1.4. Extending the Update Operations with Controls .......8
           3.1.5. Extending the Responseless Operations with Controls..8
      3.2. Extended Operations ........................................8
      3.3. Intermediate Responses .....................................8
      3.4. Unsolicited Notifications ..................................9
   4. Extending the LDAP ASN.1 Definition .............................9
      4.1. Result Codes ...............................................9
      4.2. LDAP Message Types .........................................9
      4.3. Authentication Methods ....................................10
      4.4. General ASN.1 Extensibility ...............................10
   5. Schema Extensions ..............................................10
      5.1. LDAP Syntaxes .............................................11
      5.2. Matching Rules ............................................11
      5.3. Attribute Types ...........................................12
      5.4. Object Classes ............................................12
   6. Other Extension Mechanisms .....................................12
      6.1. Attribute Description Options .............................12
      6.2. Authorization Identities ..................................12
      6.3. LDAP URL Extensions .......................................12
   7. Security Considerations ........................................12
   8. Acknowledgements ...............................................13
   9. References .....................................................13
      9.1. Normative References ......................................13
      9.2. Informative References ....................................15









Zeilenga                 Best Current Practice                  [Page 2]

RFC 4521                    LDAP Extensions                    June 2006


1.  Introduction

   The Lightweight Directory Access Protocol (LDAP) [RFC4510] is an
   extensible protocol.

   LDAP allows for new operations to be added and for existing
   operations to be enhanced [RFC4511].

   LDAP allows additional schema to be defined [RFC4512][RFC4517].  This
   can include additional object classes, attribute types, matching
   rules, additional syntaxes, and other elements of schema.  LDAP
   provides an ability to extend attribute types with options [RFC4512].

   LDAP supports a Simple Authentication and Security Layer (SASL)
   authentication method [RFC4511][RFC4513].  SASL [RFC4422] is
   extensible.  LDAP may be extended to support additional
   authentication methods [RFC4511].

   LDAP supports establishment of Transport Layer Security (TLS)
   [RFC4511][RFC4513].  TLS [RFC4346] is extensible.

   LDAP has an extensible Uniform Resource Locator (URL) format
   [RFC4516].

   Lastly, LDAP allows for certain extensions to the protocol's Abstract
   Syntax Notation - One (ASN.1) [X.680] definition to be made.  This
   facilitates a wide range of protocol enhancements, for example, new
   result codes needed to support extensions to be added through
   extension of the protocol's ASN.1 definition.

   This document describes practices that engineers should consider when
   designing extensions to LDAP.

1.1.  Terminology

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].  In
   this document, "the specification", as used by BCP 14, RFC 2119,
   refers to the engineering of LDAP extensions.

   The term "Request Control" refers to a control attached to a client-
   generated message sent to a server.  The term "Response Control"
   refers to a control attached to a server-generated message sent to a
   client.






Zeilenga                 Best Current Practice                  [Page 3]

RFC 4521                    LDAP Extensions                    June 2006


   DIT stands for Directory Information Tree.
   DSA stands for Directory System Agent, a server.
   DSE stands for DSA-Specific Entry.
   DUA stands for Directory User Agent, a client.
   DN stands for Distinguished Name.

2.  General Considerations

2.1.  Scope of Extension

   Mutually agreeing peers may, within the confines of an extension,
   agree to significant changes in protocol semantics.  However,
   designers MUST consider the impact of an extension upon protocol
   peers that have not agreed to implement or otherwise recognize and
   support the extension.  Extensions MUST be "truly optional"
   [RFC2119].

2.2.  Interaction between extensions

   Designers SHOULD consider how extensions they engineer interact with
   other extensions.

   Designers SHOULD consider the extensibility of extensions they
   specify.  Extensions to LDAP SHOULD themselves be extensible.

   Except where it is stated otherwise, extensibility is implied.

2.3.  Discovery Mechanism

   Extensions SHOULD provide adequate discovery mechanisms.

   As LDAP design is based upon the client-request/server-response
   paradigm, the general discovery approach is for the client to
   discover the capabilities of the server before utilizing a particular
   extension.  Commonly, this discovery involves querying the root DSE
   and/or other DSEs for operational information associated with the
   extension.  LDAP provides no mechanism for a server to discover the
   capabilities of a client.

   The 'supportedControl' attribute [RFC4512] is used to advertise
   supported controls.  The 'supportedExtension' attribute [RFC4512] is
   used to advertise supported extended operations.  The
   'supportedFeatures' attribute [RFC4512] is used to advertise
   features.  Other root DSE attributes MAY be defined to advertise
   other capabilities.






Zeilenga                 Best Current Practice                  [Page 4]

RFC 4521                    LDAP Extensions                    June 2006


2.4.  Internationalization Considerations

   LDAP is designed to support the full Unicode [Unicode] repertory of
   characters.  Extensions SHOULD avoid unnecessarily restricting
   applications to subsets of Unicode (e.g., Basic Multilingual Plane,
   ISO 8859-1, ASCII, Printable String).

   LDAP Language Tag options [RFC3866] provide a mechanism for tagging
   text (and other) values with language information.  Extensions that
   define attribute types SHOULD allow use of language tags with these
   attributes.

2.5.  Use of the Basic Encoding Rules

   Numerous elements of LDAP are described using ASN.1 [X.680] and are
   encoded using a particular subset [Protocol, Section 5.2] of the
   Basic Encoding Rules (BER) [X.690].  To allow reuse of
   parsers/generators used in implementing the LDAP "core" technical
   specification [RFC4510], it is RECOMMENDED that extension elements
   (e.g., extension specific contents of controlValue, requestValue,
   responseValue fields) described by ASN.1 and encoded using BER be
   subjected to the restrictions of [Protocol, Section 5.2].

2.6.  Use of Formal Languages

   Formal languages SHOULD be used in specifications in accordance with
   IESG guidelines [FORMAL].

2.7.  Examples

   Example DN strings SHOULD conform to the syntax defined in [RFC4518].
   Example LDAP filter strings SHOULD conform to the syntax defined in
   [RFC4515].  Example LDAP URLs SHOULD conform to the syntax defined in
   [RFC4516].  Entries SHOULD be represented using LDIF [RFC2849].

2.8.  Registration of Protocol Values

   Designers SHALL register protocol values of their LDAP extensions in
   accordance with BCP 64, RFC 4520 [RFC4520].  Specifications that
   create new extensible protocol elements SHALL extend existing
   registries or establish new registries for values of these elements
   in accordance with BCP 64, RFC 4520 [RFC4520] and BCP 26, RFC 2434
   [RFC2434].








Zeilenga                 Best Current Practice                  [Page 5]

RFC 4521                    LDAP Extensions                    June 2006


3.  LDAP Operation Extensions

   Extensions SHOULD use controls in defining extensions that complement
   existing operations.  Where the extension to be defined does not
   complement an existing operation, designers SHOULD consider defining
   an extended operation instead.

   For example, a subtree delete operation could be designed as either
   an extension of the delete operation or as a new operation.  As the
   feature complements the existing delete operation, use of the control
   mechanism to extend the delete operation is likely more appropriate.

   As a counter (and contrived) example, a locate services operation (an
   operation that would return for a DN a set of LDAP URLs to services
   that may hold the entry named by this DN) could be designed as either
   a search operation or a new operation.  As the feature doesn't
   complement the search operation (e.g., the operation is not contrived
   to search for entries held in the Directory Information Tree), it is
   likely more appropriate to define a new operation using the extended
   operation mechanism.

3.1.  Controls

   Controls [Protocol, Section 4.1.11] are the RECOMMENDED mechanism for
   extending existing operations.  The existing operation can be a base
   operation defined in [RFC4511] (e.g., search, modify) , an extended
   operation (e.g., Start TLS [RFC4511], Password Modify [RFC3062]), or
   an operation defined as an extension to a base or extended operation.

   Extensions SHOULD NOT return Response controls unless the server has
   specific knowledge that the client can make use of the control.
   Generally, the client requests the return of a particular response
   control by providing a related request control.

   An existing operation MAY be extended to return IntermediateResponse
   messages [Protocol, Section 4.13].

   Specifications of controls SHALL NOT attach additional semantics to
   the criticality of controls beyond those defined in [Protocol,
   Section 4.1.11].  A specification MAY mandate the criticality take on
   a particular value (e.g., TRUE or FALSE), where appropriate.

3.1.1.  Extending Bind Operation with Controls

   Controls attached to the request and response messages of a Bind
   Operation [RFC4511] are not protected by any security layers
   established by that Bind operation.




Zeilenga                 Best Current Practice                  [Page 6]

RFC 4521                    LDAP Extensions                    June 2006


   Specifications detailing controls extending the Bind operation SHALL
   detail that the Bind negotiated security layers do not protect the
   information contained in these controls and SHALL detail how the
   information in these controls is protected or why the information
   does not need protection.

   It is RECOMMENDED that designers consider alternative mechanisms for
   providing the function.  For example, an extended operation issued
   subsequent to the Bind operation (hence, protected by the security
   layers negotiated by the Bind operation) might be used to provide the
   desired function.

   Additionally, designers of Bind control extensions MUST also consider
   how the controls' semantics interact with individual steps of a
   multi-step Bind operation.  Note that some steps are optional and
   thus may require special attention in the design.

3.1.2.  Extending the Start TLS Operation with Controls

   Controls attached to the request and response messages of a Start TLS
   Operation [RFC4511] are not protected by the security layers
   established by the Start TLS operation.

   Specifications detailing controls extending the Start TLS operation
   SHALL detail that the Start TLS negotiated security layers do not
   protect the information contained in these controls and SHALL detail
   how the information in these controls is protected or why the
   information does not need protection.

   It is RECOMMENDED that designers consider alternative mechanisms for
   providing the function.  For example, an extended operation issued
   subsequent to the Start TLS operation (hence, protected by the
   security layers negotiated by the Start TLS operation) might be used
   to provided the desired function.

3.1.3.  Extending the Search Operation with Controls

   The Search operation processing has two distinct phases:

      -  finding the base object; and

      -  searching for objects at or under that base object.

   Specifications of controls extending the Search Operation should
   clearly state in which phase(s) the control's semantics apply.
   Semantics of controls that are not specific to the Search Operation
   SHOULD apply in the finding phase.




Zeilenga                 Best Current Practice                  [Page 7]

RFC 4521                    LDAP Extensions                    June 2006


3.1.4.  Extending the Update Operations with Controls

   Update operations have properties of atomicity, consistency,
   isolation, and durability ([ACID]).

      -  atomicity: All or none of the DIT changes requested are made.

      -  consistency: The resulting DIT state must be conform to schema
         and other constraints.

      -  isolation: Intermediate states are not exposed.

      -  durability: The resulting DIT state is preserved until
         subsequently updated.

   When defining a control that requests additional (or other) DIT
   changes be made to the DIT, these additional changes SHOULD NOT be
   treated as part of a separate transaction.  The specification MUST be
   clear as to whether the additional DIT changes are part of the same
   or a separate transaction as the DIT changes expressed in the request
   of the base operation.

   When defining a control that requests additional (or other) DIT
   changes be made to the DIT, the specification MUST be clear as to the
   order in which these and the base changes are to be applied to the
   DIT.

3.1.5.  Extending the Responseless Operations with Controls

   The Abandon and Unbind operations do not include a response message.
   For this reason, specifications for controls designed to be attached
   to Abandon and Unbind requests SHOULD mandate that the control's
   criticality be FALSE.

3.2.  Extended Operations

   Extended Operations [Protocol, Section 4.12] are the RECOMMENDED
   mechanism for defining new operations.  An extended operation
   consists of an ExtendedRequest message, zero or more
   IntermediateResponse messages, and an ExtendedResponse message.

3.3.  Intermediate Responses

   Extensions SHALL use IntermediateResponse messages instead of
   ExtendedResponse messages to return intermediate results.






Zeilenga                 Best Current Practice                  [Page 8]

RFC 4521                    LDAP Extensions                    June 2006


3.4.  Unsolicited Notifications

   Unsolicited notifications [Protocol, Section 4.4] offer a capability
   for the server to notify the client of events not associated with the
   operation currently being processed.

   Extensions SHOULD be designed such that unsolicited notifications are
   not returned unless the server has specific knowledge that the client
   can make use of the notification.  Generally, the client requests the
   return of a particular unsolicited notification by performing a
   related extended operation.

   For example, a time hack extension could be designed to return
   unsolicited notifications at regular intervals that were enabled by
   an extended operation (which possibly specified the desired
   interval).

4.  Extending the LDAP ASN.1 Definition

   LDAP allows limited extension [Protocol, Section 4] of the LDAP ASN.1
   definition [Protocol, Appendix B] to be made.

4.1.  Result Codes

   Extensions that specify new operations or enhance existing operations
   often need to define new result codes.  The extension SHOULD be
   designed such that a client has a reasonably clear indication of the
   nature of the successful or non-successful result.

   Extensions SHOULD use existing result codes to indicate conditions
   that are consistent with the intended meaning [RFC4511][X.511] of
   these codes.  Extensions MAY introduce new result codes [RFC4520]
   where no existing result code provides an adequate indication of the
   nature of the result.

   Extensions SHALL NOT disallow or otherwise restrict the return of
   general service result codes, especially those reporting a protocol,
   service, or security problem, or indicating that the server is unable
   or unwilling to complete the operation.

4.2.  LDAP Message Types

   While extensions can specify new types of LDAP messages by extending
   the protocolOp CHOICE of the LDAPMessage SEQUENCE, this is generally
   unnecessary and inappropriate.  Existing operation extension
   mechanisms (e.g., extended operations, unsolicited notifications, and
   intermediate responses) SHOULD be used instead.  However, there may
   be cases where an extension does not fit well into these mechanisms.



Zeilenga                 Best Current Practice                  [Page 9]

RFC 4521                    LDAP Extensions                    June 2006


   In such cases, a new extension mechanism SHOULD be defined that can
   be used by multiple extensions that have similar needs.

4.3.  Authentication Methods

   The Bind operation currently supports two authentication methods,
   simple and SASL.  SASL [RFC4422] is an extensible authentication
   framework used by multiple application-level protocols (e.g., BEEP,
   IMAP, SMTP).  It is RECOMMENDED that new authentication processes be
   defined as SASL mechanisms.  New LDAP authentication methods MAY be
   added to support new authentication frameworks.

   The Bind operation's primary function is to establish the LDAP
   association [RFC4513].  No other operation SHALL be defined (or
   extended) to establish the LDAP association.  However, other
   operations MAY be defined to establish other security associations
   (e.g., IPsec).

4.4.  General ASN.1 Extensibility

   Section 4 of [RFC4511] states the following:

      In order to support future extensions to this protocol,
      extensibility is implied where it is allowed per ASN.1 (i.e.,
      sequence, set, choice, and enumerated types are extensible).  In
      addition, ellipses (...)  have been supplied in ASN.1 types that
      are explicitly extensible as discussed in [RFC4520].  Because of
      the implied extensibility, clients and servers MUST (unless
      otherwise specified) ignore trailing SEQUENCE components whose
      tags they do not recognize.

   Designers SHOULD avoid introducing extensions that rely on
   unsuspecting implementations to ignore trailing components of
   SEQUENCE whose tags they do not recognize.

5.  Schema Extensions

   Extensions defining LDAP schema elements SHALL provide schema
   definitions conforming with syntaxes defined in [Models, Section
   4.1].  While provided definitions MAY be reformatted (line wrapped)
   for readability, this SHALL be noted in the specification.

   For definitions that allow a NAME field, new schema elements SHOULD
   provide one and only one name.  The name SHOULD be short.

   Each schema definition allows a DESC field.  The DESC field, if
   provided, SHOULD contain a short descriptive phrase.  The DESC field
   MUST be regarded as informational.  That is, the specification MUST



Zeilenga                 Best Current Practice                 [Page 10]

RFC 4521                    LDAP Extensions                    June 2006


   be written such that its interpretation is the same with and without
   the provided DESC fields.

   The extension SHALL NOT mandate that implementations provide the same
   DESC field in the schema they publish.  Implementors MAY replace or
   remove the DESC field.

   Published schema elements SHALL NOT be redefined.  Replacement schema
   elements (new OIDs, new NAMEs) SHOULD be defined as needed.

   Schema designers SHOULD reuse existing schema elements, where
   appropriate.  However, any reuse MUST not alter the semantics of the
   element.

5.1.  LDAP Syntaxes

   Each LDAP syntax [RFC4517] is defined in terms of ASN.1 [X.680].
   Each extension detailing an LDAP syntax MUST specify the ASN.1 data
   definition associated with the syntax.  A distinct LDAP syntax SHOULD
   be created for each distinct ASN.1 data definition (including
   constraints).

   Each LDAP syntax SHOULD have a string encoding defined for it.  It is
   RECOMMENDED that this string encoding be restricted to UTF-8
   [RFC3629] encoded Unicode [Unicode] characters.  Use of Generic
   String Encoding Rules (GSER) [RFC3641][RFC3642] or other generic
   string encoding rules to provide string encodings for complex ASN.1
   data definitions is RECOMMENDED.  Otherwise, it is RECOMMENDED that
   the string encoding be described using a formal language (e.g., ABNF
   [RFC4234]).  Formal languages SHOULD be used in specifications in
   accordance with IESG guidelines [FORMAL].

   If no string encoding is defined, the extension SHALL specify how the
   transfer encoding is to be indicated.  Generally, the extension
   SHOULD mandate use of binary or other transfer encoding option.

5.2.  Matching Rules

   Three basic kinds of matching rules (e.g., EQUALITY, ORDERING, and
   SUBSTRING) may be associated with an attribute type.  In addition,
   LDAP provides an extensible matching rule mechanism.

   The matching rule specification SHOULD detail which kind of matching
   rule it is and SHOULD describe which kinds of values it can be used
   with.

   In addition to requirements stated in the LDAP technical
   specification, equality matching rules SHOULD be commutative.



Zeilenga                 Best Current Practice                 [Page 11]

RFC 4521                    LDAP Extensions                    June 2006


5.3.  Attribute Types

   Designers SHOULD carefully consider how the structure of values is to
   be restricted.  Designers SHOULD consider that servers will only
   enforce constraints of the attribute's syntax.  That is, an attribute
   intended to hold URIs, but that has directoryString syntax, is not
   restricted to values that are URIs.

   Designers SHOULD carefully consider which matching rules, if any, are
   appropriate for the attribute type.  Matching rules specified for an
   attribute type MUST be compatible with the attribute type's syntax.

   Extensions specifying operational attributes MUST detail how servers
   are to maintain and/or utilize values of each operational attribute.

5.4.  Object Classes

   Designers SHOULD carefully consider whether each attribute of an
   object class is required ("MUST") or allowed ("MAY").

   Extensions specifying object classes that allow (or require)
   operational attributes MUST specify how servers are to maintain
   and/or utilize entries belonging to these object classes.

6.  Other Extension Mechanisms

6.1.  Attribute Description Options

   Each option is identified by a string of letters, numbers, and
   hyphens.  This string SHOULD be short.

6.2.  Authorization Identities

   Extensions interacting with authorization identities SHALL support
   the LDAP authzId format [RFC4513].  The authzId format is extensible.

6.3.  LDAP URL Extensions

   LDAP URL extensions are identified by a short string, a descriptor.
   Like other descriptors, the string SHOULD be short.

7.  Security Considerations

   LDAP does not place undue restrictions on the kinds of extensions
   that can be implemented.  While this document attempts to outline
   some specific issues that designers need to consider, it is not (and





Zeilenga                 Best Current Practice                 [Page 12]

RFC 4521                    LDAP Extensions                    June 2006


   cannot be) all encompassing.  Designers MUST do their own evaluations
   of the security considerations applicable to their extensions.

   Designers MUST NOT assume that the LDAP "core" technical
   specification [RFC4510] adequately addresses the specific concerns
   surrounding their extensions or assume that their extensions have no
   specific concerns.

   Extension specifications, however, SHOULD note whether security
   considerations specific to the feature they are extending, as well as
   general LDAP security considerations, apply to the extension.

8.  Acknowledgements

   The author thanks the IETF LDAP community for their thoughtful
   comments.

   This work builds upon "LDAP Extension Style Guide" [GUIDE] by Bruce
   Greenblatt.

9.  References

9.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2434]  Narten, T. and H. Alvestrand, "Guidelines for Writing an
              IANA Considerations Section in RFCs", BCP 26, RFC 2434,
              October 1998.

   [RFC2849]  Good, G., "The LDAP Data Interchange Format (LDIF) -
              Technical Specification", RFC 2849, June 2000.

   [RFC3629]  Yergeau, F., "UTF-8, a transformation format of ISO
              10646", STD 63, RFC 3629, November 2003.

   [RFC3641]  Legg, S., "Generic String Encoding Rules (GSER) for ASN.1
              Types", RFC 3641, October 2003.

   [RFC3642]  Legg, S., "Common Elements of Generic String Encoding
              Rules (GSER) Encodings", RFC 3642, October 2003.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512, June
              2006.





Zeilenga                 Best Current Practice                 [Page 13]

RFC 4521                    LDAP Extensions                    June 2006


   [RFC3866]  Zeilenga, K., Ed., "Language Tags and Ranges in the
              Lightweight Directory Access Protocol (LDAP)", RFC 3866,
              July 2004.

   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", RFC 4234, October 2005.

   [RFC4510]  Zeilenga, K., Ed., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC 4510, June
              2006.

   [RFC4511]  Sermersheim, J., Ed., "Lightweight Directory Access
              Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512, June
              2006.

   [RFC4513]  Harrison, R., Ed., "Lightweight Directory Access Protocol
              (LDAP): Authentication Methods and Security Mechanisms",
              RFC 4513, June 2006.

   [RFC4515]  Smith, M., Ed. and T. Howes, "Lightweight Directory Access
              Protocol (LDAP): String Representation of Search Filters",
              RFC 4515, June 2006.

   [RFC4516]  Smith, M., Ed. and T. Howes, "Lightweight Directory Access
              Protocol (LDAP): Uniform Resource Locator", RFC 4516, June
              2006.

   [RFC4517]  Legg, S., Ed., "Lightweight Directory Access Protocol
              (LDAP): Syntaxes and Matching Rules", RFC 4517, June 2006.

   [RFC4518]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): String Representation of Distinguished Names", RFC
              4518, June 2006.

   [RFC4520]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [RFC4422]  Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
              Authentication and Security Layer (SASL)", RFC 4422, June
              2006.







Zeilenga                 Best Current Practice                 [Page 14]

RFC 4521                    LDAP Extensions                    June 2006


   [Unicode]  The Unicode Consortium, "The Unicode Standard, Version
              3.2.0" is defined by "The Unicode Standard, Version 3.0"
              (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-61633-5),
              as amended by the "Unicode Standard Annex #27: Unicode
              3.1" (http://www.unicode.org/reports/tr27/) and by the
              "Unicode Standard Annex #28: Unicode 3.2"
              (http://www.unicode.org/reports/tr28/).

   [FORMAL]   IESG, "Guidelines for the use of formal languages in IETF
              specifications",
              <http://www.ietf.org/IESG/STATEMENTS/pseudo-code-in-
              specs.txt>, 2001.

   [X.511]    International Telecommunication Union - Telecommunication
              Standardization Sector, "The Directory: Abstract Service
              Definition", X.511(1993) (also ISO/IEC 9594-3:1993).

   [X.680]    International Telecommunication Union - Telecommunication
              Standardization Sector, "Abstract Syntax Notation One
              (ASN.1) - Specification of Basic Notation", X.680(2002)
              (also ISO/IEC 8824-1:2002).

   [X.690]    International Telecommunication Union - Telecommunication
              Standardization Sector, "Specification of ASN.1 encoding
              rules: Basic Encoding Rules (BER), Canonical Encoding
              Rules (CER), and Distinguished Encoding Rules (DER)",
              X.690(2002) (also ISO/IEC 8825-1:2002).

9.2.  Informative References

   [ACID]     Section 4 of ISO/IEC 10026-1:1992.

   [GUIDE]    Greenblatt, B., "LDAP Extension Style Guide", Work in
              Progress.

   [RFC3062]  Zeilenga, K., "LDAP Password Modify Extended Operation",
              RFC 3062, February 2001.

   [RFC4346]  Dierks, T. and E. Rescorla, "The Transport Layer Security
              (TLS) Protocol Version 1.1", RFC 4346, April 2006.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org




Zeilenga                 Best Current Practice                 [Page 15]

RFC 4521                    LDAP Extensions                    June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                 Best Current Practice                 [Page 16]

alt-openldap11-devel/rfc/rfc3698.txt000064400000042232150410163260013003 0ustar00





Network Working Group                                   K. Zeilenga, Ed.
Request for Comments: 3698                           OpenLDAP Foundation
Updates: 2798                                              February 2004
Category: Standards Track


             Lightweight Directory Access Protocol (LDAP):
                       Additional Matching Rules

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2004).  All Rights Reserved.

Abstract

   This document provides a collection of matching rules for use with
   the Lightweight Directory Access Protocol (LDAP).  As these matching
   rules are simple adaptations of matching rules specified for use with
   the X.500 Directory, most are already in wide use.

Table of Contents

   1.  Background and Intended Use. . . . . . . . . . . . . . . . . .  2
   2.  Matching Rules . . . . . . . . . . . . . . . . . . . . . . . .  2
       2.1.  booleanMatch . . . . . . . . . . . . . . . . . . . . . .  2
       2.2.  caseExactMatch . . . . . . . . . . . . . . . . . . . . .  2
       2.3.  caseExactOrderingMatch . . . . . . . . . . . . . . . . .  3
       2.4.  caseExactSubstringsMatch . . . . . . . . . . . . . . . .  3
       2.5.  caseIgnoreListSubstringsMatch. . . . . . . . . . . . . .  3
       2.6.  directoryStringFirstComponentMatch . . . . . . . . . . .  4
       2.7.  integerOrderingMatch . . . . . . . . . . . . . . . . . .  4
       2.8.  keywordMatch . . . . . . . . . . . . . . . . . . . . . .  4
       2.9.  numericStringOrderingMatch . . . . . . . . . . . . . . .  5
       2.10. octetStringOrderingMatch . . . . . . . . . . . . . . . .  5
       2.11. storedPrefixMatch. . . . . . . . . . . . . . . . . . . .  5
       2.12. wordMatch. . . . . . . . . . . . . . . . . . . . . . . .  6
   3.  Security Considerations. . . . . . . . . . . . . . . . . . . .  6
   4.  IANA Considerations. . . . . . . . . . . . . . . . . . . . . .  6
   5.  Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . .  7
   6.  References . . . . . . . . . . . . . . . . . . . . . . . . . .  7



Zeilenga                    Standards Track                     [Page 1]

RFC 3698            LDAP: Additional Matching Rules        February 2004


       6.1.  Normative References . . . . . . . . . . . . . . . . . .  7
       6.2.  Informative References . . . . . . . . . . . . . . . . .  7
   7.  Author's Address . . . . . . . . . . . . . . . . . . . . . . .  8
   8.  Full Copyright Statement . . . . . . . . . . . . . . . . . . .  9

1.  Background and Intended Use

   This document adapts additional X.500 Directory [X.500] matching
   rules [X.520] for use with the Lightweight Directory Access Protocol
   (LDAP) [RFC3377].  Most of these rules are widely used today on the
   Internet, such as in support of the inetOrgPerson [RFC2798] and
   Policy Core Information Model [RFC3703] LDAP schemas.  The rules are
   applicable to many other applications.

   This document supersedes the informational matching rules
   descriptions provided in RFC 2798 that are now provided in this
   document.  Specifically, section 2 of this document replaces section
   9.3.3 of RFC 2798.

   Schema definitions are provided using LDAP description formats
   [RFC2252].  Definitions provided here are formatted (line wrapped)
   for readability.

2.  Matching Rules

2.1.  booleanMatch

   The booleanMatch rule compares for equality a asserted Boolean value
   with an attribute value of BOOLEAN syntax.  The rule returns TRUE if
   and only if the values are the same, i.e., both are TRUE or both are
   FALSE.  (Source: X.520)

       ( 2.5.13.13 NAME 'booleanMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )

   The BOOLEAN (1.3.6.1.4.1.1466.115.121.1.7) syntax is described in
   [RFC2252].

2.2.  caseExactMatch

   The caseExactMatch rule compares for equality the asserted value with
   an attribute value of DirectoryString syntax.  The rule is identical
   to the caseIgnoreMatch [RFC2252] rule except that case is not
   ignored.  (Source: X.520)







Zeilenga                    Standards Track                     [Page 2]

RFC 3698            LDAP: Additional Matching Rules        February 2004


       ( 2.5.13.5 NAME 'caseExactMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax is
   described in [RFC2252].

2.3.  caseExactOrderingMatch

   The caseExactOrderingMatch rule compares the collation order of the
   asserted string with an attribute value of DirectoryString syntax.
   The rule is identical to the caseIgnoreOrderingMatch [RFC2252] rule
   except that letters are not folded.  (Source: X.520)

       ( 2.5.13.6 NAME 'caseExactOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax is
   described in [RFC2252].

2.4.  caseExactSubstringsMatch

   The caseExactSubstringsMatch rule determines whether the asserted
   value(s) are substrings of an attribute value of DirectoryString
   syntax.  The rule is identical to the caseIgnoreSubstringsMatch
   [RFC2252] rule except that case is not ignored.  (Source: X.520)

       ( 2.5.13.7 NAME 'caseExactSubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )

   The SubstringsAssertion (1.3.6.1.4.1.1466.115.121.1.58) syntax is
   described in [RFC2252].

2.5. caseIgnoreListSubstringsMatch

   The caseIgnoreListSubstringMatch rule compares the asserted substring
   with an attribute value which is a sequence of DirectoryStrings, but
   where the case (upper or lower) is not significant for comparison
   purposes.  The asserted value matches a stored value if and only if
   the asserted value matches the string formed by concatenating the
   strings of the stored value.  This matching is done according to the
   caseIgnoreSubstringsMatch [RFC2252] rule; however, none of the
   initial, any, or final values of the asserted value are considered to
   match a substring of the concatenated string which spans more than
   one of the strings of the stored value.  (Source: X.520)

       ( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )




Zeilenga                    Standards Track                     [Page 3]

RFC 3698            LDAP: Additional Matching Rules        February 2004


   The SubstringsAssertion (1.3.6.1.4.1.1466.115.121.1.58) syntax is
   described in [RFC2252].

2.6.  directoryStringFirstComponentMatch

   The directoryStringFirstComponentMatch rule compares for equality the
   asserted DirectoryString value with an attribute value of type
   SEQUENCE whose first component is mandatory and of type
   DirectoryString.  The rule returns TRUE if and only if the attribute
   value has a first component whose value matches the asserted
   DirectoryString using the rules of caseIgnoreMatch [RFC2252].  A
   value of the assertion syntax is derived from a value of the
   attribute syntax by using the value of the first component of the
   SEQUENCE.  (Source: X.520)

       ( 2.5.13.31 NAME 'directoryStringFirstComponentMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax is
   described in [RFC2252].

2.7.  integerOrderingMatch

   The integerOrderingMatch rule compares the ordering of the asserted
   integer with an attribute value of INTEGER syntax.  The rule returns
   True if the attribute value is less than the asserted value. (Source:
   X.520)

       ( 2.5.13.15 NAME 'integerOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )

   The INTEGER (1.3.6.1.4.1.1466.115.121.1.27) syntax is described in
   [RFC2252].

2.8.  keywordMatch

   The keywordMatch rule compares the asserted string with keywords in
   an attribute value of DirectoryString syntax.  The rule returns TRUE
   if and only if the asserted value matches any keyword in the
   attribute value.  The identification of keywords in an attribute
   value and of the exactness of match are both implementation specific.
   (Source: X.520)

       ( 2.5.13.33 NAME 'keywordMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax is
   described in [RFC2252].



Zeilenga                    Standards Track                     [Page 4]

RFC 3698            LDAP: Additional Matching Rules        February 2004


2.9.  numericStringOrderingMatch

   The numericStringOrderingMatch rule compares the collation order of
   the asserted string with an attribute value of NumericString syntax.
   The rule is identical to the caseIgnoreOrderingMatch [RFC2252] rule
   except that all space characters are skipped during comparison (case
   is irrelevant as characters are numeric).  (Source: X.520)

       ( 2.5.13.9 NAME 'numericStringOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )

   The NumericString (1.3.6.1.4.1.1466.115.121.1.36) syntax is described
   in [RFC2252].

2.10.  octetStringOrderingMatch

   The octetStringOrderingMatch rule compares the collation order of the
   asserted octet string with an attribute value of OCTET STRING syntax.
   The rule compares octet strings from first octet to last octet, and
   from the most significant bit to the least significant bit within the
   octet.  The first occurrence of a different bit determines the
   ordering of the strings.  A zero bit precedes a one bit.  If the
   strings are identical but contain different numbers of octets, the
   shorter string precedes the longer string.  (Source: X.520)

       ( 2.5.13.18 NAME 'octetStringOrderingMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )

   The OCTET STRING (1.3.6.1.4.1.1466.115.121.1.40) syntax is described
   in [RFC2252].

2.11.  storedPrefixMatch

   The storedPrefixMatch rule determines whether an attribute value,
   whose syntax is DirectoryString is a prefix (i.e., initial substring)
   of the asserted value, without regard to the case (upper or lower) of
   the strings.  The rule returns TRUE if and only if the attribute
   value is an initial substring of the asserted value with
   corresponding characters identical except possibly with regard to
   case.  (Source: X.520)

       ( 2.5.13.41 NAME 'storedPrefixMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )








Zeilenga                    Standards Track                     [Page 5]

RFC 3698            LDAP: Additional Matching Rules        February 2004


   Note: This rule can be used, for example, to compare values in the
         Directory which are telephone area codes with a purported value
         which is a telephone number.

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax is
   described in [RFC2252].

2.12.  wordMatch

   The wordMatch rule compares the asserted string with words in an
   attribute value of DirectoryString syntax.  The rule returns TRUE if
   and only if the asserted word matches any word in the attribute
   value.  Individual word matching is as for the caseIgnoreMatch
   [RFC2252] matching rule.  The precise definition of a "word" is
   implementation specific.  (Source: X.520)

       ( 2.5.13.32 NAME 'wordMatch'
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

   The DirectoryString (1.3.6.1.4.1.1466.115.121.1.15) syntax is
   described in [RFC2252].

3.  Security Considerations

   General LDAP security considerations [RFC3377] is applicable to the
   use of this schema.  Additional considerations are noted above where
   appropriate.

4.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) has updated the LDAP
   descriptors registry [RFC3383] as indicated in the following
   template:

       Subject: Request for LDAP Descriptor Registration Update
       Descriptor (short name): see comment
       Object Identifier: see comments
       Person & email address to contact for further information:
           Kurt Zeilenga <kurt@OpenLDAP.org>
       Usage: see comments
       Specification: RFC 3698
       Author/Change Controller: IESG
       Comments:








Zeilenga                    Standards Track                     [Page 6]

RFC 3698            LDAP: Additional Matching Rules        February 2004


       The following descriptors have been added:

         NAME                               Type OID
         ------------------------           ---- ---------
         booleanMatch                       M    2.5.13.13
         caseExactMatch                     M    2.5.13.5
         caseExactOrderingMatch             M    2.5.13.6
         caseExactSubstringsMatch           M    2.5.13.7
         caseIgnoreListSubstringsMatch      M    2.5.13.12
         directoryStringFirstComponentMatch M    2.5.13.31
         integerOrderingMatch               M    2.5.13.15
         keywordMatch                       M    2.5.13.33
         numericStringOrderingMatch         M    2.5.13.9
         octetStringOrderingMatch           M    2.5.13.18
         storedPrefixMatch                  M    2.5.13.41
         wordMatch                          M    2.5.13.32

       where Type M is Matching Rule.

   This document makes no new OID assignments.  It only associates LDAP
   matching rule descriptions with existing X.500 matching rules.

5.  Acknowledgments

   This document borrows from [X.520], an ITU-T Recommendation.

6.  References

6.1.  Normative References

   [RFC2252]     Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
                 "Lightweight Directory Access Protocol (v3):  Attribute
                 Syntax Definitions", RFC 2252, December 1997.

   [RFC3377]     Hodges, J. and R. Morgan, "Lightweight Directory Access
                 Protocol (v3): Technical Specification", RFC 3377,
                 September 2002.

6.2.  Informative References

   [RFC2798]     Smith, M., "The LDAP inetOrgPerson Object Class", RFC
                 2798, April 2000.

   [RFC3383]     Zeilenga, K., "IANA Considerations for LDAP", BCP 64
                 RFC 3383, September 2002.

   [RFC3703]     Strassner, J., Moore, B., Moats, R. and E. Ellesson,
                 "Policy Core LDAP Schema", RFC 3703, February 2004.



Zeilenga                    Standards Track                     [Page 7]

RFC 3698            LDAP: Additional Matching Rules        February 2004


   [X.500]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Overview of concepts, models and
                 services," X.500(1993) (also ISO/IEC 9594-1:1994).

   [X.520]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory: Selected Attribute Types", X.520(1997).

7.  Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org




































Zeilenga                    Standards Track                     [Page 8]

RFC 3698            LDAP: Additional Matching Rules        February 2004


8.  Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78 and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
   REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE
   INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed
   to pertain to the implementation or use of the technology
   described in this document or the extent to which any license
   under such rights might or might not be available; nor does it
   represent that it has made any independent effort to identify any
   such rights.  Information on the procedures with respect to
   rights in RFC documents can be found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use
   of such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository
   at http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention
   any copyrights, patents or patent applications, or other
   proprietary rights that may cover technology that may be required
   to implement this standard.  Please address the information to the
   IETF at ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.









Zeilenga                    Standards Track                     [Page 9]

alt-openldap11-devel/rfc/rfc2891.txt000064400000036731150410163260013004 0ustar00





Network Working Group                                           T. Howes
Request for Comments: 2891                                     Loudcloud
Category: Standards Track                                        M. Wahl
                                                        Sun Microsystems
                                                              A. Anantha
                                                               Microsoft
                                                             August 2000


    LDAP Control Extension for Server Side Sorting of Search Results

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2000).  All Rights Reserved.

Abstract

   This document describes two LDAPv3 control extensions for server side
   sorting of search results. These controls allows a client to specify
   the attribute types and matching rules a server should use when
   returning the results to an LDAP search request. The controls may be
   useful when the LDAP client has limited functionality or for some
   other reason cannot sort the results but still needs them sorted.
   Other permissible controls on search operations are not defined in
   this extension.

   The sort controls allow a server to return a result code for the
   sorting of the results that is independent of the result code
   returned for the search operation.

   The key words "MUST", "SHOULD", and "MAY" used in this document are
   to be interpreted as described in [bradner97].











Howes, et al.               Standards Track                     [Page 1]

RFC 2891     LDAP Control Extension for Server Side Sorting  August 2000


1.  The Controls

1.1 Request Control

   This control is included in the searchRequest message as part of the
   controls field of the LDAPMessage, as defined in Section 4.1.12 of
   [LDAPv3].

   The controlType is set to "1.2.840.113556.1.4.473". The criticality
   MAY be either TRUE or FALSE (where absent is also equivalent to
   FALSE) at the client's option. The controlValue is an OCTET STRING,
   whose value is the BER encoding of a value of the following SEQUENCE:

      SortKeyList ::= SEQUENCE OF SEQUENCE {
                 attributeType   AttributeDescription,
                 orderingRule    [0] MatchingRuleId OPTIONAL,
                 reverseOrder    [1] BOOLEAN DEFAULT FALSE }

   The SortKeyList sequence is in order of highest to lowest sort key
   precedence.

   The MatchingRuleId, as defined in section 4.1.9 of [LDAPv3], SHOULD
   be one that is valid for the attribute type it applies to.  If it is
   not, the server will return inappropriateMatching.

   Each attributeType should only occur in the SortKeyList once. If an
   attributeType is included in the sort key list multiple times, the
   server should return an error in the sortResult of
   unwillingToPerform.

   If the orderingRule is omitted, the ordering MatchingRule defined for
   use with this attribute MUST be used.

   Any conformant implementation of this control MUST allow a sort key
   list with at least one key.

1.2 Response Control

   This control is included in the searchResultDone message as part of
   the controls field of the LDAPMessage, as defined in Section  4.1.12
   of [LDAPv3].

   The controlType is set to "1.2.840.113556.1.4.474". The criticality
   is FALSE (MAY be absent). The controlValue is an OCTET STRING, whose
   value is the BER encoding of a value of the following SEQUENCE:






Howes, et al.               Standards Track                     [Page 2]

RFC 2891     LDAP Control Extension for Server Side Sorting  August 2000


      SortResult ::= SEQUENCE {
         sortResult  ENUMERATED {
             success                   (0), -- results are sorted
             operationsError           (1), -- server internal failure
             timeLimitExceeded         (3), -- timelimit reached before
                                            -- sorting was completed
             strongAuthRequired        (8), -- refused to return sorted
                                            -- results via insecure
                                            -- protocol
             adminLimitExceeded       (11), -- too many matching entries
                                            -- for the server to sort
             noSuchAttribute          (16), -- unrecognized attribute
                                            -- type in sort key
             inappropriateMatching    (18), -- unrecognized or
                                            -- inappropriate matching
                                            -- rule in sort key
             insufficientAccessRights (50), -- refused to return sorted
                                            -- results to this client
             busy                     (51), -- too busy to process
             unwillingToPerform       (53), -- unable to sort
             other                    (80)
             },
       attributeType [0] AttributeDescription OPTIONAL }

2.  Client-Server Interaction

   The sortKeyRequestControl specifies one or more attribute types and
   matching rules for the results returned by a search request. The
   server SHOULD return all results for the search request in the order
   specified by the sort keys. If the reverseOrder field is set to TRUE,
   then the entries will be presented in reverse sorted order for the
   specified key.

   There are six possible scenarios that may occur as a result of the
   sort control being included on the search request:

   1 - If the server does not support this sorting control and the
       client specified TRUE for the control's criticality field, then
       the server MUST return unavailableCriticalExtension as a return
       code in the searchResultDone message and not send back any other
       results. This behavior is specified in section 4.1.12 of
       [LDAPv3].

   2 - If the server does not support this sorting control and the
       client specified FALSE for the control's criticality field, then
       the server MUST ignore the sort control and process the search
       request as if it were not present. This behavior is specified in
       section 4.1.12 of [LDAPv3].



Howes, et al.               Standards Track                     [Page 3]

RFC 2891     LDAP Control Extension for Server Side Sorting  August 2000


   3 - If the server supports this sorting control but for some reason
       cannot sort the search results using the specified sort keys and
       the client specified TRUE for the control's criticality field,
       then the server SHOULD do the following: return
       unavailableCriticalExtension as a return code in the
       searchResultDone message; include the sortKeyResponseControl in
       the searchResultDone message, and not send back any search result
       entries.

   4 - If the server supports this sorting control but for some reason
       cannot sort the search results using the specified sort keys and
       the client specified FALSE for the control's criticality field,
       then the server should return all search results unsorted and
       include the sortKeyResponseControl in the searchResultDone
       message.

   5 - If the server supports this sorting control and can sort the
       search results using the specified sort keys, then it should
       include the sortKeyResponseControl in the searchResultDone
       message with a sortResult of success.

   6 - If the search request failed for any reason and/or there are no
       searchResultEntry messages returned for the search response, then
       the server SHOULD omit the sortKeyResponseControl from the
       searchResultDone message.

   The client application is assured that the results are sorted in the
   specified key order if and only if the result code in the
   sortKeyResponseControl is success. If the server omits the
   sortKeyResponseControl from the searchResultDone message, the client
   SHOULD assume that the sort control was ignored by the server.

   The sortKeyResponseControl, if included by the server in the
   searchResultDone message, should have the sortResult set to either
   success if the results were sorted in accordance with the keys
   specified in the sortKeyRequestControl or set to the appropriate
   error code as to why it could not sort the data (such as
   noSuchAttribute or inappropriateMatching). Optionally, the server MAY
   set the attributeType to the first attribute type specified in the
   SortKeyList that was in error. The client SHOULD ignore the
   attributeType field if the sortResult is success.

   The server may not be able to sort the results using the specified
   sort keys because it may not recognize one of the attribute types,
   the matching rule associated with an attribute type is not
   applicable, or none of the attributes in the search response are of
   these types.  Servers may also restrict the number of keys allowed in
   the control, such as only supporting a single key.



Howes, et al.               Standards Track                     [Page 4]

RFC 2891     LDAP Control Extension for Server Side Sorting  August 2000


   Servers that chain requests to other LDAP servers should ensure that
   the server satisfying the client's request sort the entire result set
   prior to sending back the results.

2.1 Behavior in a chained environment

   If a server receives a sort request, the client expects to receive a
   set of sorted results. If a client submits a sort request to a server
   which chains the request and gets entries from multiple servers, and
   the client has set the criticality of the sort extension to TRUE, the
   server MUST merge sort the results before returning them to the
   client or MUST return unwillingToPerform.

2.2 Other sort issues

   An entry that meets the search criteria may be missing one or more of
   the sort keys. In that case, the entry is considered to have a value
   of NULL for that key. This standard considers NULL to be a larger
   value than all other valid values for that key. For example, if only
   one key is specified, entries which meet the search criteria but do
   not have that key collate after all the entries which do have that
   key. If the reverseOrder flag is set, and only one key is specified,
   entries which meet the search criteria but do not have that key
   collate BEFORE all the entries which do have that key.

   If a sort key is a multi-valued attribute, and an entry happens to
   have multiple values for that attribute and no other controls are
   present that affect the sorting order, then the server SHOULD use the
   least value (according to the ORDERING rule for that attribute).

3.  Interaction with other search controls

   When the sortKeyRequestControl control is included with the
   pagedResultsControl control as specified in [LdapPaged], then the
   server should send the searchResultEntry messages sorted according to
   the sort keys applied to the entire result set. The server should not
   simply sort each page, as this will give erroneous results to the
   client.

   The sortKeyList must be present on each searchRequest message for the
   paged result. It also must not change between searchRequests for the
   same result set. If the server has sorted the data, then it SHOULD
   send back a sortKeyResponseControl control on every searchResultDone
   message for each page. This will allow clients to quickly determine
   if the result set is sorted, rather than waiting to receive the
   entire result set.





Howes, et al.               Standards Track                     [Page 5]

RFC 2891     LDAP Control Extension for Server Side Sorting  August 2000


4.  Security Considerations

   Implementors and administrators should be aware that allowing sorting
   of results could enable the retrieval of a large number of records
   from a given directory service, regardless of administrative limits
   set on the maximum number of records to return.

   A client that desired to pull all records out of a directory service
   could use a combination of sorting and updating of search filters to
   retrieve all records in a database in small result sets, thus
   circumventing administrative limits.

   This behavior can be overcome by the judicious use of permissions on
   the directory entries by the administrator and by intelligent
   implementations of administrative limits on the number of records
   retrieved by a client.

5.  References

   [LDAPv3]    Wahl, M, Kille, S. and T. Howes, "Lightweight Directory
               Access Protocol (v3)", RFC 2251, December 1997.

   [Bradner97] Bradner, S., "Key Words for use in RFCs to Indicate
               Requirement Levels", BCP 14, RFC 2119, March 1997.

   [LdapPaged] Weider, C., Herron, A., Anantha, A. and T. Howes, "LDAP
               Control Extension for Simple Paged Results Manipulation",
               RFC 2696, September 1999.























Howes, et al.               Standards Track                     [Page 6]

RFC 2891     LDAP Control Extension for Server Side Sorting  August 2000


6.  Authors' Addresses

   Anoop Anantha
   Microsoft Corp.
   1 Microsoft Way
   Redmond, WA 98052
   USA

   Phone: +1 425 882-8080
   EMail: anoopa@microsoft.com


   Tim Howes
   Loudcloud, Inc.
   615 Tasman Dr.
   Sunnyvale, CA 94089
   USA

   EMail: howes@loudcloud.com


   Mark Wahl
   Sun Microsystems, Inc.
   8911 Capital of Texas Hwy Suite 4140
   Austin, TX 78759
   USA

   EMail: Mark.Wahl@sun.com























Howes, et al.               Standards Track                     [Page 7]

RFC 2891     LDAP Control Extension for Server Side Sorting  August 2000


7.  Full Copyright Statement

   Copyright (C) The Internet Society (2000).  All Rights Reserved.

   This document and translations of it may be copied and furnished to
   others, and derivative works that comment on or otherwise explain it
   or assist in its implementation may be prepared, copied, published
   and distributed, in whole or in part, without restriction of any
   kind, provided that the above copyright notice and this paragraph are
   included on all such copies and derivative works.  However, this
   document itself may not be modified in any way, such as by removing
   the copyright notice or references to the Internet Society or other
   Internet organizations, except as needed for the purpose of
   developing Internet standards in which case the procedures for
   copyrights defined in the Internet Standards process must be
   followed, or as required to translate it into languages other than
   English.

   The limited permissions granted above are perpetual and will not be
   revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on an
   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Acknowledgement

   Funding for the RFC Editor function is currently provided by the
   Internet Society.



















Howes, et al.               Standards Track                     [Page 8]

alt-openldap11-devel/rfc/rfc4518.txt000064400000067006150410163260013001 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4518                           OpenLDAP Foundation
Category: Standards Track                                      June 2006


             Lightweight Directory Access Protocol (LDAP):
                  Internationalized String Preparation

Status of This Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   The previous Lightweight Directory Access Protocol (LDAP) technical
   specifications did not precisely define how character string matching
   is to be performed.  This led to a number of usability and
   interoperability problems.  This document defines string preparation
   algorithms for character-based matching rules defined for use in
   LDAP.

1.  Introduction

1.1.  Background

   A Lightweight Directory Access Protocol (LDAP) [RFC4510] matching
   rule [RFC4517] defines an algorithm for determining whether a
   presented value matches an attribute value in accordance with the
   criteria defined for the rule.  The proposition may be evaluated to
   True, False, or Undefined.

      True      - the attribute contains a matching value,

      False     - the attribute contains no matching value,

      Undefined - it cannot be determined whether the attribute contains
                  a matching value.






Zeilenga                    Standards Track                     [Page 1]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   For instance, the caseIgnoreMatch matching rule may be used to
   compare whether the commonName attribute contains a particular value
   without regard for case and insignificant spaces.

1.2.  X.500 String Matching Rules

   "X.520: Selected attribute types" [X.520] provides (among other
   things) value syntaxes and matching rules for comparing values
   commonly used in the directory [X.500].  These specifications are
   inadequate for strings composed of Unicode [Unicode] characters.

   The caseIgnoreMatch matching rule [X.520], for example, is simply
   defined as being a case-insensitive comparison where insignificant
   spaces are ignored.  For printableString, there is only one space
   character and case mapping is bijective, hence this definition is
   sufficient.  However, for Unicode string types such as
   universalString, this is not sufficient.  For example, a case-
   insensitive matching implementation that folded lowercase characters
   to uppercase would yield different results than an implementation
   that used uppercase to lowercase folding.  Or one implementation may
   view space as referring to only SPACE (U+0020), a second
   implementation may view any character with the space separator (Zs)
   property as a space, and another implementation may view any
   character with the whitespace (WS) category as a space.

   The lack of precise specification for character string matching has
   led to significant interoperability problems.  When used in
   certificate chain validation, security vulnerabilities can arise.  To
   address these problems, this document defines precise algorithms for
   preparing character strings for matching.

1.3.  Relationship to "stringprep"

   The character string preparation algorithms described in this
   document are based upon the "stringprep" approach [RFC3454].  In
   "stringprep", presented and stored values are first prepared for
   comparison so that a character-by-character comparison yields the
   "correct" result.

   The approach used here is a refinement of the "stringprep" [RFC3454]
   approach.  Each algorithm involves two additional preparation steps.

   a) Prior to applying the Unicode string preparation steps outlined in
      "stringprep", the string is transcoded to Unicode.

   b) After applying the Unicode string preparation steps outlined in
      "stringprep", the string is modified to appropriately handle
      characters insignificant to the matching rule.



Zeilenga                    Standards Track                     [Page 2]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   Hence, preparation of character strings for X.500 [X.500] matching
   [X.501] involves the following steps:

      1) Transcode
      2) Map
      3) Normalize
      4) Prohibit
      5) Check Bidi (Bidirectional)
      6) Insignificant Character Handling

   These steps are described in Section 2.

   It is noted that while various tables of Unicode characters included
   or referenced by this specification are derived from Unicode
   [Unicode] data, these tables are to be considered definitive for the
   purpose of implementing this specification.

1.4.  Relationship to the LDAP Technical Specification

   This document is an integral part of the LDAP technical specification
   [RFC4510], which obsoletes the previously defined LDAP technical
   specification [RFC3377] in its entirety.

   This document details new LDAP internationalized character string
   preparation algorithms used by [RFC4517] and possible other technical
   specifications defining LDAP syntaxes and/or matching rules.

1.5.  Relationship to X.500

   LDAP is defined [RFC4510] in X.500 terms as an X.500 access
   mechanism.  As such, there is a strong desire for alignment between
   LDAP and X.500 syntax and semantics.  The character string
   preparation algorithms described in this document are based upon
   "Internationalized String Matching Rules for X.500" [XMATCH] proposal
   to ITU/ISO Joint Study Group 2.

1.6.  Conventions and Terms

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in BCP 14 [RFC2119].

   Character names in this document use the notation for code points and
   names from the Unicode Standard [Unicode].  For example, the letter
   "a" may be represented as either <U+0061> or <LATIN SMALL LETTER A>.
   In the lists of mappings and the prohibited characters, the "U+" is





Zeilenga                    Standards Track                     [Page 3]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   left off to make the lists easier to read.  The comments for
   character ranges are shown in square brackets (such as "[CONTROL
   CHARACTERS]") and do not come from the standard.

   Note: a glossary of terms used in Unicode can be found in [Glossary].
   Information on the Unicode character encoding model can be found in
   [CharModel].

   The term "combining mark", as used in this specification, refers to
   any Unicode [Unicode] code point that has a mark property (Mn, Mc,
   Me).  Appendix A provides a definitive list of combining marks.

2.  String Preparation

   The following six-step process SHALL be applied to each presented and
   attribute value in preparation for character string matching rule
   evaluation.

      1) Transcode
      2) Map
      3) Normalize
      4) Prohibit
      5) Check bidi
      6) Insignificant Character Handling

   Failure in any step causes the assertion to evaluate to Undefined.

   The character repertoire of this process is Unicode 3.2 [Unicode].

   Note that this six-step process specification is intended to describe
   expected matching behavior.  Implementations are free to use
   alternative processes so long as the matching rule evaluation
   behavior provided is consistent with the behavior described by this
   specification.

2.1.  Transcode

   Each non-Unicode string value is transcoded to Unicode.

   PrintableString [X.680] values are transcoded directly to Unicode.

   UniversalString, UTF8String, and bmpString [X.680] values need not be
   transcoded as they are Unicode-based strings (in the case of
   bmpString, a subset of Unicode).

   TeletexString [X.680] values are transcoded to Unicode.  As there is
   no standard for mapping TeletexString values to Unicode, the mapping
   is left a local matter.



Zeilenga                    Standards Track                     [Page 4]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   For these and other reasons, use of TeletexString is NOT RECOMMENDED.

   The output is the transcoded string.

2.2.  Map

   SOFT HYPHEN (U+00AD) and MONGOLIAN TODO SOFT HYPHEN (U+1806) code
   points are mapped to nothing.  COMBINING GRAPHEME JOINER (U+034F) and
   VARIATION SELECTORs (U+180B-180D, FF00-FE0F) code points are also
   mapped to nothing.  The OBJECT REPLACEMENT CHARACTER (U+FFFC) is
   mapped to nothing.

   CHARACTER TABULATION (U+0009), LINE FEED (LF) (U+000A), LINE
   TABULATION (U+000B), FORM FEED (FF) (U+000C), CARRIAGE RETURN (CR)
   (U+000D), and NEXT LINE (NEL) (U+0085) are mapped to SPACE (U+0020).

   All other control code (e.g., Cc) points or code points with a
   control function (e.g., Cf) are mapped to nothing.  The following is
   a complete list of these code points: U+0000-0008, 000E-001F, 007F-
   0084, 0086-009F, 06DD, 070F, 180E, 200C-200F, 202A-202E, 2060-2063,
   206A-206F, FEFF, FFF9-FFFB, 1D173-1D17A, E0001, E0020-E007F.

   ZERO WIDTH SPACE (U+200B) is mapped to nothing.  All other code
   points with Separator (space, line, or paragraph) property (e.g., Zs,
   Zl, or Zp) are mapped to SPACE (U+0020).  The following is a complete
   list of these code points: U+0020, 00A0, 1680, 2000-200A, 2028-2029,
   202F, 205F, 3000.

   For case ignore, numeric, and stored prefix string matching rules,
   characters are case folded per B.2 of [RFC3454].

   The output is the mapped string.

2.3.  Normalize

   The input string is to be normalized to Unicode Form KC
   (compatibility composed) as described in [UAX15].  The output is the
   normalized string.

2.4.  Prohibit

   All Unassigned code points are prohibited.  Unassigned code points
   are listed in Table A.1 of [RFC3454].

   Characters that, per Section 5.8 of [RFC3454], change display
   properties or are deprecated are prohibited.  These characters are
   listed in Table C.8 of [RFC3454].




Zeilenga                    Standards Track                     [Page 5]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   Private Use code points are prohibited.  These characters are listed
   in Table C.3 of [RFC3454].

   All non-character code points are prohibited.  These code points are
   listed in Table C.4 of [RFC3454].

   Surrogate codes are prohibited.  These characters are listed in Table
   C.5 of [RFC3454].

   The REPLACEMENT CHARACTER (U+FFFD) code point is prohibited.

   The step fails if the input string contains any prohibited code
   point.  Otherwise, the output is the input string.

2.5.  Check bidi

   Bidirectional characters are ignored.

2.6.  Insignificant Character Handling

   In this step, the string is modified to ensure proper handling of
   characters insignificant to the matching rule.  This modification
   differs from matching rule to matching rule.

   Section 2.6.1 applies to case ignore and exact string matching.
   Section 2.6.2 applies to numericString matching.
   Section 2.6.3 applies to telephoneNumber matching.

2.6.1.  Insignificant Space Handling

   For the purposes of this section, a space is defined to be the SPACE
   (U+0020) code point followed by no combining marks.

       NOTE - The previous steps ensure that the string cannot contain
              any code points in the separator class, other than SPACE
              (U+0020).

   For input strings that are attribute values or non-substring
   assertion values:  If the input string contains no non-space
   character, then the output is exactly two SPACEs.  Otherwise (the
   input string contains at least one non-space character), the string
   is modified such that the string starts with exactly one space
   character, ends with exactly one SPACE character, and any inner
   (non-empty) sequence of space characters is replaced with exactly two
   SPACE characters.  For instance, the input strings
   "foo<SPACE>bar<SPACE><SPACE>", result in the output
   "<SPACE>foo<SPACE><SPACE>bar<SPACE>".




Zeilenga                    Standards Track                     [Page 6]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   For input strings that are substring assertion values: If the string
   being prepared contains no non-space characters, then the output
   string is exactly one SPACE.  Otherwise, the following steps are
   taken:

   -  If the input string is an initial substring, it is modified to
      start with exactly one SPACE character;

   -  If the input string is an initial or an any substring that ends in
      one or more space characters, it is modified to end with exactly
      one SPACE character;

   -  If the input string is an any or a final substring that starts in
      one or more space characters, it is modified to start with exactly
      one SPACE character; and

   -  If the input string is a final substring, it is modified to end
      with exactly one SPACE character.

   For instance, for the input string "foo<SPACE>bar<SPACE><SPACE>" as
   an initial substring, the output would be
   "<SPACE>foo<SPACE><SPACE>bar<SPACE>".  As an any or final substring,
   the same input would result in "foo<SPACE>bar<SPACE>".

   Appendix B discusses the rationale for the behavior.

2.6.2.  numericString Insignificant Character Handling

   For the purposes of this section, a space is defined to be the SPACE
   (U+0020) code point followed by no combining marks.

   All spaces are regarded as insignificant and are to be removed.

   For example, removal of spaces from the Form KC string:
       "<SPACE><SPACE>123<SPACE><SPACE>456<SPACE><SPACE>"
   would result in the output string:
       "123456"
   and the Form KC string:
       "<SPACE><SPACE><SPACE>"
   would result in the output string:
       "" (an empty string).

2.6.3.  telephoneNumber Insignificant Character Handling

   For the purposes of this section, a hyphen is defined to be a
   HYPHEN-MINUS (U+002D), ARMENIAN HYPHEN (U+058A), HYPHEN (U+2010),
   NON-BREAKING HYPHEN (U+2011), MINUS SIGN (U+2212), SMALL HYPHEN-MINUS
   (U+FE63), or FULLWIDTH HYPHEN-MINUS (U+FF0D) code point followed by



Zeilenga                    Standards Track                     [Page 7]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   no combining marks and a space is defined to be the SPACE (U+0020)
   code point followed by no combining marks.

   All hyphens and spaces are considered insignificant and are to be
   removed.

   For example, removal of hyphens and spaces from the Form KC string:
       "<SPACE><HYPHEN>123<SPACE><SPACE>456<SPACE><HYPHEN>"
   would result in the output string:
       "123456"
   and the Form KC string:
       "<HYPHEN><HYPHEN><HYPHEN>"
   would result in the (empty) output string:
       "".

3.  Security Considerations

   "Preparation of Internationalized Strings ("stringprep")" [RFC3454]
   security considerations generally apply to the algorithms described
   here.

4.  Acknowledgements

   The approach used in this document is based upon design principles
   and algorithms described in "Preparation of Internationalized Strings
   ('stringprep')" [RFC3454] by Paul Hoffman and Marc Blanchet.  Some
   additional guidance was drawn from Unicode Technical Standards,
   Technical Reports, and Notes.

   This document is a product of the IETF LDAP Revision (LDAPBIS)
   Working Group.

5.  References

5.1.  Normative References

   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                 Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3454]     Hoffman, P. and M. Blanchet, "Preparation of
                 Internationalized Strings ("stringprep")", RFC 3454,
                 December 2002.

   [RFC4510]     Zeilenga, K., "Lightweight Directory Access Protocol
                 (LDAP): Technical Specification Road Map", RFC 4510,
                 June 2006.





Zeilenga                    Standards Track                     [Page 8]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   [RFC4517]     Legg, S., Ed., "Lightweight Directory Access Protocol
                 (LDAP): Syntaxes and Matching Rules", RFC 4517, June
                 2006.

   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
                 3.2.0" is defined by "The Unicode Standard, Version
                 3.0" (Reading, MA, Addison-Wesley, 2000.  ISBN 0-201-
                 61633-5), as amended by the "Unicode Standard Annex
                 #27: Unicode 3.1"
                 (http://www.unicode.org/reports/tr27/) and by the
                 "Unicode Standard Annex #28: Unicode 3.2"
                 (http://www.unicode.org/reports/tr28/).

   [UAX15]       Davis, M. and M. Duerst, "Unicode Standard Annex #15:
                 Unicode Normalization Forms, Version 3.2.0".
                 <http://www.unicode.org/unicode/reports/tr15/tr15-
                 22.html>, March 2002.

   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(2002) (also ISO/IEC 8824-1:2002).

5.2.  Informative References

   [X.500]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Overview of concepts, models and
                 services," X.500(1993) (also ISO/IEC 9594-1:1994).

   [X.501]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory -- Models," X.501(1993) (also ISO/IEC 9594-
                 2:1994).

   [X.520]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "The
                 Directory: Selected Attribute Types", X.520(1993) (also
                 ISO/IEC 9594-6:1994).

   [Glossary]    The Unicode Consortium, "Unicode Glossary",
                 <http://www.unicode.org/glossary/>.

   [CharModel]   Whistler, K. and M. Davis, "Unicode Technical Report
                 #17, Character Encoding Model", UTR17,
                 <http://www.unicode.org/unicode/reports/tr17/>, August
                 2000.




Zeilenga                    Standards Track                     [Page 9]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   [RFC3377]     Hodges, J. and R. Morgan, "Lightweight Directory Access
                 Protocol (v3): Technical Specification", RFC 3377,
                 September 2002.

   [RFC4515]     Smith, M., Ed. and T. Howes, "Lightweight Directory
                 Access Protocol (LDAP): String Representation of Search
                 Filters", RFC 4515, June 2006.

   [XMATCH]      Zeilenga, K., "Internationalized String Matching Rules
                 for X.500", Work in Progress.









































Zeilenga                    Standards Track                    [Page 10]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


Appendix A.  Combining Marks

   This appendix is normative.

   This table was derived from Unicode [Unicode] data files; it lists
   all code points with the Mn, Mc, or Me properties.  This table is to
   be considered definitive for the purposes of implementation of this
   specification.

         0300-034F 0360-036F 0483-0486 0488-0489 0591-05A1
         05A3-05B9 05BB-05BC 05BF 05C1-05C2 05C4 064B-0655 0670
         06D6-06DC 06DE-06E4 06E7-06E8 06EA-06ED 0711 0730-074A
         07A6-07B0 0901-0903 093C 093E-094F 0951-0954 0962-0963
         0981-0983 09BC 09BE-09C4 09C7-09C8 09CB-09CD 09D7
         09E2-09E3 0A02 0A3C 0A3E-0A42 0A47-0A48 0A4B-0A4D
         0A70-0A71 0A81-0A83 0ABC 0ABE-0AC5 0AC7-0AC9 0ACB-0ACD
         0B01-0B03 0B3C 0B3E-0B43 0B47-0B48 0B4B-0B4D 0B56-0B57
         0B82 0BBE-0BC2 0BC6-0BC8 0BCA-0BCD 0BD7 0C01-0C03
         0C3E-0C44 0C46-0C48 0C4A-0C4D 0C55-0C56 0C82-0C83
         0CBE-0CC4 0CC6-0CC8 0CCA-0CCD 0CD5-0CD6 0D02-0D03
         0D3E-0D43 0D46-0D48 0D4A-0D4D 0D57 0D82-0D83 0DCA
         0DCF-0DD4 0DD6 0DD8-0DDF 0DF2-0DF3 0E31 0E34-0E3A
         0E47-0E4E 0EB1 0EB4-0EB9 0EBB-0EBC 0EC8-0ECD 0F18-0F19
         0F35 0F37 0F39 0F3E-0F3F 0F71-0F84 0F86-0F87 0F90-0F97
         0F99-0FBC 0FC6 102C-1032 1036-1039 1056-1059 1712-1714
         1732-1734 1752-1753 1772-1773 17B4-17D3 180B-180D 18A9
         20D0-20EA 302A-302F 3099-309A FB1E FE00-FE0F FE20-FE23
         1D165-1D169 1D16D-1D172 1D17B-1D182 1D185-1D18B
         1D1AA-1D1AD

Appendix B.  Substrings Matching

   This appendix is non-normative.

   In the absence of substrings matching, the insignificant space
   handling for case ignore/exact matching could be simplified.
   Specifically, the handling could be to require that all sequences of
   one or more spaces be replaced with one space and, if the string
   contains non-space characters, removal of all leading spaces and
   trailing spaces.

   In the presence of substrings matching, this simplified space
   handling would lead to unexpected and undesirable matching behavior.
   For instance:

   1) (CN=foo\20*\20bar) would match the CN value "foobar";





Zeilenga                    Standards Track                    [Page 11]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   2) (CN=*\20foobar\20*) would match "foobar", but
      (CN=*\20*foobar*\20*) would not.

   Note to readers not familiar with LDAP substrings matching: the LDAP
   filter [RFC4515] assertion (CN=A*B*C) says to "match any value (of
   the attribute CN) that begins with A, contains B after A, ends with C
   where C is also after B."

   The first case illustrates that this simplified space handling would
   cause leading and trailing spaces in substrings of the string to be
   regarded as insignificant.  However, only leading and trailing (as
   well as multiple consecutive spaces) of the string (as a whole) are
   insignificant.

   The second case illustrates that this simplified space handling would
   cause sub-partitioning failures.  That is, if a prepared any
   substring matches a partition of the attribute value, then an
   assertion constructed by subdividing that substring into multiple
   substrings should also match.

   In designing an appropriate approach for space handling for
   substrings matching, one must study key aspects of X.500 case
   exact/ignore matching.  X.520 [X.520] says:

      The [substrings] rule returns TRUE if there is a partitioning of
      the attribute value (into portions) such that:

         -  the specified substrings (initial, any, final) match
            different portions of the value in the order of the strings
            sequence;

         -  initial, if present, matches the first portion of the value;

         -  final, if present, matches the last portion of the value;

         -  any, if present, matches some arbitrary portion of the
            value.

   That is, the substrings assertion (CN=foo\20*\20bar) matches the
   attribute value "foo<SPACE><SPACE>bar" as the value can be
   partitioned into the portions "foo<SPACE>" and "<SPACE>bar" meeting
   the above requirements.









Zeilenga                    Standards Track                    [Page 12]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


   X.520 also says:

      [T]he following spaces are regarded as not significant:

         -  leading spaces (i.e., those preceding the first character
            that is not a space);

         -  trailing spaces (i.e., those following the last character
            that is not a space);

         -  multiple consecutive spaces (these are taken as equivalent
            to a single space character).

   This statement applies to the assertion values and attribute values
   as whole strings, and not individually to substrings of an assertion
   value.  In particular, the statements should be taken to mean that if
   an assertion value and attribute value match without any
   consideration to insignificant characters, then that assertion value
   should also match any attribute value that differs only by inclusion
   nor removal of insignificant characters.

   Hence the assertion (CN=foo\20*\20bar) matches
   "foo<SPACE><SPACE><SPACE>bar" and "foo<SPACE>bar" as these values
   only differ from "foo<SPACE><SPACE>bar" by the inclusion or removal
   of insignificant spaces.

   Astute readers of this text will also note that there are special
   cases where the specified space handling does not ignore spaces that
   could be considered insignificant.  For instance, the assertion
   (CN=\20*\20*\20) does not match "<SPACE><SPACE><SPACE>"
   (insignificant spaces present in value) or " " (insignificant spaces
   not present in value).  However, as these cases have no practical
   application that cannot be met by simple assertions, e.g., (cn=\20),
   and this minor anomaly can only be fully addressed by a preparation
   algorithm to be used in conjunction with character-by-character
   partitioning and matching, the anomaly is considered acceptable.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org








Zeilenga                    Standards Track                    [Page 13]

RFC 4518       LDAP: Internationalized String Preparation      June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                    Standards Track                    [Page 14]

alt-openldap11-devel/rfc/rfc4531.txt000064400000045052150410163260012771 0ustar00





Network Working Group                                        K. Zeilenga
Request for Comments: 4531                           OpenLDAP Foundation
Category: Experimental                                         June 2006


              Lightweight Directory Access Protocol (LDAP)
                             Turn Operation


Status of This Memo

   This memo defines an Experimental Protocol for the Internet
   community.  It does not specify an Internet standard of any kind.
   Discussion and suggestions for improvement are requested.
   Distribution of this memo is unlimited.

Copyright Notice

   Copyright (C) The Internet Society (2006).

Abstract

   This specification describes a Lightweight Directory Access Protocol
   (LDAP) extended operation to reverse (or "turn") the roles of client
   and server for subsequent protocol exchanges in the session, or to
   enable each peer to act as both client and server with respect to the
   other.

Table of Contents

   1. Background and Intent of Use ....................................2
      1.1. Terminology ................................................2
   2. Turn Operation ..................................................2
      2.1. Turn Request ...............................................3
      2.2. Turn Response ..............................................3
   3. Authentication ..................................................3
      3.1. Use with TLS and Simple Authentication .....................4
      3.2. Use with TLS and SASL EXTERNAL .............................4
      3.3. Use of Mutual Authentication and SASL EXTERNAL .............4
   4. TLS and SASL Security Layers ....................................5
   5. Security Considerations .........................................6
   6. IANA Considerations .............................................6
      6.1. Object Identifier ..........................................6
      6.2. LDAP Protocol Mechanism ....................................7
   7. References ......................................................7
      7.1. Normative References .......................................7
      7.2. Informative References .....................................8




Zeilenga                      Experimental                      [Page 1]

RFC 4531                  LDAP Turn Operation                  June 2006


1.  Background and Intent of Use

   The Lightweight Directory Access Protocol (LDAP) [RFC4510][RFC4511]
   is a client-server protocol that typically operates over reliable
   octet-stream transports, such as the Transport Control Protocol
   (TCP).  Generally, the client initiates the stream by connecting to
   the server's listener at some well-known address.

   There are cases where it is desirable for the server to initiate the
   stream.  Although it certainly is possible to write a technical
   specification detailing how to implement server-initiated LDAP
   sessions, this would require the design of new authentication and
   other security mechanisms to support server-initiated LDAP sessions.

   Instead, this document introduces an operation, the Turn operation,
   which may be used to reverse the client-server roles of the protocol
   peers.  This allows the initiating protocol peer to become the server
   (after the reversal).

   As an additional feature, the Turn operation may be used to allow
   both peers to act in both roles.  This is useful where both peers are
   directory servers that desire to request, as LDAP clients, that
   operations be performed by the other.  This may be useful in
   replicated and/or distributed environments.

   This operation is intended to be used between protocol peers that
   have established a mutual agreement, by means outside of the
   protocol, that requires reversal of client-server roles, or allows
   both peers to act both as client and server.

1.1.  Terminology

   Protocol elements are described using ASN.1 [X.680] with implicit
   tags.  The term "BER-encoded" means the element is to be encoded
   using the Basic Encoding Rules [X.690] under the restrictions
   detailed in Section 5.1 of [RFC4511].

2.  Turn Operation

   The Turn operation is defined as an LDAP-Extended Operation
   [Protocol, Section 4.12] identified by the 1.3.6.1.1.19 OID.  The
   function of the Turn Operation is to request that the client-server
   roles be reversed, or, optionally, to request that both protocol
   peers be able to act both as client and server in respect to the
   other.






Zeilenga                      Experimental                      [Page 2]

RFC 4531                  LDAP Turn Operation                  June 2006


2.1.  Turn Request

   The Turn request is an ExtendedRequest where the requestName field
   contains the 1.3.6.1.1.19 OID and the requestValue field is a BER-
   encoded turnValue:

        turnValue ::= SEQUENCE {
             mutual         BOOLEAN DEFAULT FALSE,
             identifier     LDAPString
        }

   A TRUE mutual field value indicates a request to allow both peers to
   act both as client and server.  A FALSE mutual field value indicates
   a request to reserve the client and server roles.

   The value of the identifier field is a locally defined policy
   identifier (typically associated with a mutual agreement for which
   this turn is be executed as part of).

2.2.  Turn Response

   A Turn response is an ExtendedResponse where the responseName and
   responseValue fields are absent.  A resultCode of success is returned
   if and only if the responder is willing and able to turn the session
   as requested.  Otherwise, a different resultCode is returned.

3.  Authentication

   This extension's authentication model assumes separate authentication
   of the peers in each of their roles.  A separate Bind exchange is
   expected between the peers in their new roles to establish identities
   in these roles.

   Upon completion of the Turn, the responding peer in its new client
   role has an anonymous association at the initiating peer in its new
   server role.  If the turn was mutual, the authentication association
   of the initiating peer in its pre-existing client role is left intact
   at the responding peer in its pre-existing server role.  If the turn
   was not mutual, this association is void.

   The responding peer may establish its identity in its client role by
   requesting and successfully completing a Bind operation.

   The remainder of this section discusses some authentication
   scenarios.  In the protocol exchange illustrations, A refers to the
   initiating peer (the original client) and B refers to the responding
   peer (the original server).




Zeilenga                      Experimental                      [Page 3]

RFC 4531                  LDAP Turn Operation                  June 2006


3.1.  Use with TLS and Simple Authentication

       A->B: StartTLS Request
       B->A: StartTLS(success) Response
       A->B: Bind(Simple(cn=B,dc=example,dc=net,B's secret)) Request
       B->A: Bind(success) Response
       A->B: Turn(TRUE,"XXYYZ") Request
       B->A: Turn(success) Response
       B->A: Bind(Simple(cn=A,dc=example,dc=net,A's secret)) Request
       A->B: Bind(success) Response

   In this scenario, TLS (Transport Layer Security) [RFC4346] is started
   and the initiating peer (the original client) establishes its
   identity with the responding peer prior to the Turn using the
   DN/password mechanism of the Simple method of the Bind operation.
   After the turn, the responding peer, in its new client role,
   establishes its identity with the initiating peer in its new server
   role.

3.2.  Use with TLS and SASL EXTERNAL

       A->B: StartTLS Request
       B->A: StartTLS(success) Response
       A->B: Bind(SASL(EXTERNAL)) Request
       B->A: Bind(success) Response
       A->B: Turn(TRUE,"XXYYZ") Request
       B->A: Turn(success) Response
       B->A: Bind(SASL(EXTERNAL)) Request
       A->B: Bind(success) Response

   In this scenario, TLS is started (with each peer providing a valid
   certificate), and the initiating peer (the original client)
   establishes its identity through the use of the EXTERNAL mechanism of
   the SASL (Simple Authentication and Security Layer) [RFC4422] method
   of the Bind operation prior to the Turn.  After the turn, the
   responding peer, in its new client role, establishes its identity
   with the initiating peer in its new server role.

3.3.  Use of Mutual Authentication and SASL EXTERNAL

   A number of SASL mechanisms, such as GSSAPI [SASL-K5], support mutual
   authentication.  The initiating peer, in its new server role, may use
   the identity of the responding peer, established by a prior
   authentication exchange, as its source for "external" identity in
   subsequent EXTERNAL exchange.

       A->B: Bind(SASL(GSSAPI)) Request
       <intermediate messages>



Zeilenga                      Experimental                      [Page 4]

RFC 4531                  LDAP Turn Operation                  June 2006


       B->A: Bind(success) Response
       A->B: Turn(TRUE,"XXYYZ") Request
       B->A: Turn(success) Response
       B->A: Bind(SASL(EXTERNAL)) Request
       A->B: Bind(success) Response

   In this scenario, a GSSAPI mutual-authentication exchange is
   completed between the initiating peer (the original client) and the
   responding server (the original server) prior to the turn.  After the
   turn, the responding peer, in its new client role, requests that the
   initiating peer utilize an "external" identity to establish its LDAP
   authorization identity.

4.  TLS and SASL Security Layers

   As described in [RFC4511], LDAP supports both Transport Layer
   Security (TLS) [RFC4346] and Simple Authentication and Security Layer
   (SASL) [RFC4422] security frameworks.  The following table
   illustrates the relationship between the LDAP message layer, SASL
   layer, TLS layer, and transport connection within an LDAP session.

                  +----------------------+
                  |  LDAP message layer  |
                  +----------------------+ > LDAP PDUs
                  +----------------------+ < data
                  |      SASL layer      |
                  +----------------------+ > SASL-protected data
                  +----------------------+ < data
                  |       TLS layer      |
      Application +----------------------+ > TLS-protected data
      ------------+----------------------+ < data
        Transport | transport connection |
                  +----------------------+

   This extension does not alter this relationship, nor does it remove
   the general restriction against multiple TLS layers, nor does it
   remove the general restriction against multiple SASL layers.

   As specified in [RFC4511], the StartTLS operation is used to initiate
   negotiation of a TLS layer.  If a TLS is already installed, the
   StartTLS operation must fail.  Upon establishment of the TLS layer,
   regardless of which peer issued the request to start TLS, the peer
   that initiated the LDAP session (the original client) performs the
   "server identity check", as described in Section 3.1.5 of [RFC4513],
   treating itself as the "client" and its peer as the "server".

   As specified in [RFC4422], a newly negotiated SASL security layer
   replaces the installed SASL security layer.  Though the client/server



Zeilenga                      Experimental                      [Page 5]

RFC 4531                  LDAP Turn Operation                  June 2006


   roles in LDAP, and hence SASL, may be reversed in subsequent
   exchanges, only one SASL security layer may be installed at any
   instance.

5.  Security Considerations

   Implementors should be aware that the reversing of client/server
   roles and/or allowing both peers to act as client and server likely
   introduces security considerations not foreseen by the authors of
   this document.  In particular, the security implications of the
   design choices made in the authentication and data security models
   for this extension (discussed in Sections 3 and 4, respectively) are
   not fully studied.  It is hoped that experimentation with this
   extension will lead to better understanding of the security
   implications of these models and other aspects of this extension, and
   that appropriate considerations will be documented in a future
   document.  The following security considerations are apparent at this
   time.

   Implementors should take special care to process LDAP, SASL, TLS, and
   other events in the appropriate roles for the peers.  Note that while
   the Turn reverses the client/server roles with LDAP, and in SASL
   authentication exchanges, it does not reverse the roles within the
   TLS layer or the transport connection.

   The responding server (the original server) should restrict use of
   this operation to authorized clients.  Client knowledge of a valid
   identifier should not be the sole factor in determining authorization
   to turn.

   Where the peers except to establish TLS, TLS should be started prior
   to the Turn and any request to authenticate via the Bind operation.

   LDAP security considerations [RFC4511][RFC4513] generally apply to
   this extension.

6.  IANA Considerations

   The following values [RFC4520] have been registered by the IANA.

6.1.  Object Identifier

   The IANA has assigned an LDAP Object Identifier to identify the LDAP
   Turn Operation, as defined in this document.







Zeilenga                      Experimental                      [Page 6]

RFC 4531                  LDAP Turn Operation                  June 2006


       Subject: Request for LDAP Object Identifier Registration
       Person & email address to contact for further information:
            Kurt Zeilenga <kurt@OpenLDAP.org>
       Specification: RFC 4531
       Author/Change Controller: Author
       Comments:
            Identifies the LDAP Turn Operation

6.2.  LDAP Protocol Mechanism

   The IANA has registered the LDAP Protocol Mechanism described in this
   document.

       Subject: Request for LDAP Protocol Mechanism Registration
       Object Identifier: 1.3.6.1.1.19
       Description: LDAP Turn Operation
       Person & email address to contact for further information:
            Kurt Zeilenga <kurt@openldap.org>
       Usage: Extended Operation
       Specification: RFC 4531
       Author/Change Controller: Author
       Comments: none

7.  References

7.1.  Normative References

   [RFC4346]     Dierks, T. and, E. Rescorla, "The Transport Layer
                 Security (TLS) Protocol Version 1.1", RFC 4346, April
                 2006.

   [RFC4422]     Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
                 Authentication and Security Layer (SASL)", RFC 4422,
                 June 2006.

   [RFC4510]     Zeilenga, K., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Technical Specification Road Map", RFC
                 4510, June 2006.

   [RFC4511]     Sermersheim, J., Ed., "Lightweight Directory Access
                 Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4513]     Harrison, R., Ed., "Lightweight Directory Access
                 Protocol (LDAP): Authentication Methods and Security
                 Mechanisms", RFC 4513, June 2006.






Zeilenga                      Experimental                      [Page 7]

RFC 4531                  LDAP Turn Operation                  June 2006


   [X.680]       International Telecommunication Union -
                 Telecommunication Standardization Sector, "Abstract
                 Syntax Notation One (ASN.1) - Specification of Basic
                 Notation", X.680(2002) (also ISO/IEC 8824-1:2002).

   [X.690]       International Telecommunication Union -
                 Telecommunication Standardization Sector,
                 "Specification of ASN.1 encoding rules: Basic Encoding
                 Rules (BER), Canonical Encoding Rules (CER), and
                 Distinguished Encoding Rules (DER)", X.690(2002) (also
                 ISO/IEC 8825-1:2002).

7.2.  Informative References

   [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                 (IANA) Considerations for the Lightweight Directory
                 Access Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [SASL-K5]     Melnikov, A., Ed., "The Kerberos V5 ("GSSAPI") SASL
                 Mechanism", Work in Progress, May 2006.

Author's Address

   Kurt D. Zeilenga
   OpenLDAP Foundation

   EMail: Kurt@OpenLDAP.org
























Zeilenga                      Experimental                      [Page 8]

RFC 4531                  LDAP Turn Operation                  June 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Acknowledgement

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).







Zeilenga                      Experimental                      [Page 9]

alt-openldap11-devel/drafts/draft-howard-rfc2307bis-xx.txt000064400000146721150410163270017222 0ustar00


Network Working Group                                          L. Howard
Internet-Draft                                             PADL Software
Obsoletes: 2307 (if approved)                                H. Chu, Ed.
Intended status: Informational                               Symas Corp.
Expires: February 10, 2010                                August 9, 2009


      An Approach for Using LDAP as a Network Information Service
                     draft-howard-rfc2307bis-02.txt

Status of this Memo

   This Internet-Draft is submitted to IETF in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on February 10, 2010.

Copyright Notice

   Copyright (c) 2009 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents in effect on the date of
   publication of this document (http://trustee.ietf.org/license-info).
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.








Howard & Chu            Expires February 10, 2010               [Page 1]

Internet-Draft           LDAP NameService Schema             August 2009


Abstract

   This document describes a mechanism for mapping entities related to
   TCP/IP and the UNIX system [UNIX] into [X.500] entries so that they
   may be resolved with the Lightweight Directory Access Protocol
   [RFC4511].  A set of attribute types and object classes are proposed,
   along with specific guidelines for interpreting them.  The intention
   is to assist the deployment of LDAP as an organizational nameservice.
   No proposed solutions are intended as standards for the Internet.
   Rather, it is hoped that a general consensus will emerge as to the
   appropriate solution to such problems, leading eventually to the
   adoption of standards.  The proposed mechanism has already been
   implemented with some success.






































Howard & Chu            Expires February 10, 2010               [Page 2]

Internet-Draft           LDAP NameService Schema             August 2009


1.  Background and Motivation

   The UNIX (R) operating system, and its derivatives (specifically,
   those which support TCP/IP and conform to the X/Open Single UNIX
   specification [UNIX]) require a means of looking up entities, by
   matching them against search criteria or by enumeration.  (Other
   operating systems that support TCP/IP may provide some means of
   resolving some of these entities.  This schema is applicable to those
   environments also.)

   These entities include users, groups, IP services (which map names to
   IP ports and protocols, and vice versa), IP protocols (which map
   names to IP protocol numbers and vice versa), RPCs (which map names
   to ONC Remote Procedure Call [RFC1057] numbers and vice versa), NIS
   netgroups, booting information (boot parameters and MAC address
   mappings), filesystem mounts, IP hosts and networks.

   Resolution requests are made through a set of C functions, provided
   in the UNIX system's C library.  For example, the UNIX system utility
   "ls", which enumerates the contents of a filesystem directory, uses
   the C library function getpwuid() in order to map user IDs to login
   names.  Once the request is made, it is resolved using a
   "nameservice" which is supported by the client library.  The
   nameservice may be, at its simplest, a collection of files in the
   local filesystem which are opened and searched by the C library.
   Other common nameservices include the Network Information Service
   (NIS) and the Domain Name System (DNS) [RFC1034].  (The latter is
   typically used for resolving hosts, services and networks.)  Both
   these nameservices have the advantage of being distributed and thus
   permitting a common set of entities to be shared amongst many
   clients.

   LDAP is a distributed, hierarchical directory service access protocol
   which is used to access repositories of users and other network-
   related entities.  Because LDAP is often not tightly integrated with
   the host operating system, information such as users may need to be
   kept both in LDAP and in an operating system supported nameservice
   such as NIS.  By using LDAP as the primary means of resolving these
   entities, these redundancy issues are minimized and the scalability
   of LDAP can be exploited.  (By comparison, NIS services based on flat
   files do not have the scalability or extensibility of LDAP or X.500.)

   The object classes and attributes defined below are suitable for
   representing the aforementioned entities in a form compatible with
   LDAP and X.500 directory services.






Howard & Chu            Expires February 10, 2010               [Page 3]

Internet-Draft           LDAP NameService Schema             August 2009


2.  General Issues

2.1.  Terminology

   The key words "MUST", "SHOULD", and "MAY" used in this document are
   to be interpreted as described in [RFC2119].

   For the purposes of this document, the term "nameservice" refers to a
   service, such as NIS or flat files, that is used by the operating
   system to resolve entities within a single, local naming context.
   Contrast this with a "directory service" such as LDAP, which supports
   extensible schema and multiple naming contexts.

   The term "NIS-related entities" broadly refers to entities which are
   typically resolved using the Network Information Service.  (NIS was
   previously known as YP.)  Deploying LDAP for resolving these entities
   does not imply that NIS be used, as a gateway or otherwise.  In
   particular, the host and network classes are generically applicable,
   and may be implemented on any system that wishes to use LDAP or X.500
   for host and network resolution.

   The "DUA" (directory user agent) refers to the LDAP client querying
   these entities, such as an LDAP to NIS gateway or the C library.  The
   "client" refers to the application which ultimately makes use of the
   information returned by the resolution.  It is irrelevant whether the
   DUA and the client reside within the same address space.  The act of
   the DUA making this information to the client is termed
   "republishing".

   To avoid confusion, the term "login name" refers to the user's login
   name (being the value of the uid attribute) and the term "user ID"
   refers to the user's integer identification number (being the value
   of the uidNumber attribute).

   The phrases "resolving an entity" and "resolution of entities" refer
   respectively to enumerating NIS-related entities of a given type, and
   matching them against a given search criterion.  One or more entities
   are returned as a result of successful "resolutions" (a "match"
   operation will only return one entity).

   The use of the term UNIX does not confer upon this schema the
   endorsement of owners of the UNIX trademark.  Where necessary, the
   term "TCP/IP entity" is used to refer to protocols, services, hosts,
   and networks, and the term "UNIX entity" to its complement.  (The
   former category does not mandate the host operating system supporting
   the interfaces required for resolving UNIX entities.)

   The OIDs defined below are derived from iso(1) org(3) dod(6)



Howard & Chu            Expires February 10, 2010               [Page 4]

Internet-Draft           LDAP NameService Schema             August 2009


   internet(1) directory(1) nisSchema(1)

2.2.  Schema

   The attributes and classes defined in this document are summarized
   below.

2.2.1.  Attributes

   The following attributes are defined in this document:

      uidNumber
      gidNumber
      gecos
      homeDirectory
      loginShell
      shadowLastChange
      shadowMin
      shadowMax
      shadowWarning
      shadowInactive
      shadowExpire
      shadowFlag
      memberUid
      memberNisNetgroup
      nisNetgroupTriple
      ipServicePort
      ipServiceProtocol
      ipProtocolNumber
      oncRpcNumber
      ipHostNumber
      ipNetworkNumber
      ipNetmaskNumber
      macAddress
      bootParameter
      bootFile
      nisMapName
      nisMapEntry
      nisPublicKey
      nisSecretKey
      nisDomain
      automountMapName
      automountKey
      automountInformation

   Additionally, some of the attributes defined in [RFC4519] and
   [RFC3112] are required.




Howard & Chu            Expires February 10, 2010               [Page 5]

Internet-Draft           LDAP NameService Schema             August 2009


2.2.2.  Attribute Option

   Centralizing a name service in LDAP allows heterogeneous systems to
   obtain their information from a single place.  However in some cases,
   this information cannot be used uniformly on all of the client
   systems.  These attribute options are defined to allow system-
   specific values to be used where necessary.  The options are defined
   as the following:

      host-<hostname>
      hostos-<ostype>

   where hostname is a string representing the name of a specific
   machine, and ostype is a string representing a particular operating
   system.

   For example, a user named "Babs Jensen" may have a different home
   directory on different machines.  This could be represented as:

      homeDirectory: /home/babsj
      homeDirectory;hostos-sunos: /export/home/bjensen
      homeDirectory;host-babshost: /home/root

   These attribute options follow sub-typing semantics.  If a DUA
   requests an attribute to be returned in a search operation, and does
   not specify an option, all subtypes of that attribute are returned.

2.2.3.  Object Classes

   The following object classes are defined in this document:

      posixAccount
      shadowAccount
      posixGroup
      ipService
      ipProtocol
      oncRpc
      ipHost
      ipNetwork
      nisNetgroup
      nisMap
      nisObject
      ieee802Device
      bootableDevice
      nisKeyObject
      nisDomainObject
      automountMap
      automount



Howard & Chu            Expires February 10, 2010               [Page 6]

Internet-Draft           LDAP NameService Schema             August 2009


   Additionally, some of the attributes defined in [RFC4519] are
   required.

















































Howard & Chu            Expires February 10, 2010               [Page 7]

Internet-Draft           LDAP NameService Schema             August 2009


3.  Attribute Definitions

   This section contains attribute definitions to be implemented by DUAs
   supporting this schema:

     ( 1.3.6.1.1.1.1.0 NAME 'uidNumber'
         DESC 'An integer uniquely identifying a user in an
               administrative domain'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.1 NAME 'gidNumber'
         DESC 'An integer uniquely identifying a group in an
               administrative domain'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.2 NAME 'gecos'
         DESC 'The GECOS field; the common name'
         EQUALITY caseIgnoreMatch
         SUBSTRINGS caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory'
         DESC 'The absolute path to the home directory'
         EQUALITY caseExactIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.4 NAME 'loginShell'
         DESC 'The path to the login shell'
         EQUALITY caseExactIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
         SINGLE-VALUE )








Howard & Chu            Expires February 10, 2010               [Page 8]

Internet-Draft           LDAP NameService Schema             August 2009


     ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.6 NAME 'shadowMin'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.7 NAME 'shadowMax'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )




Howard & Chu            Expires February 10, 2010               [Page 9]

Internet-Draft           LDAP NameService Schema             August 2009


     ( 1.3.6.1.1.1.1.12 NAME 'memberUid'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )


     ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )


     ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
         DESC 'Netgroup triple'
         EQUALITY caseIgnoreMatch
         SUBSTRINGS caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )


     ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort'
         DESC 'Service port number'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol'
         DESC 'Service protocol name'
         EQUALITY caseIgnoreMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )


     ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber'
         DESC 'IP protocol number'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber'
         DESC 'ONC RPC number'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )






Howard & Chu            Expires February 10, 2010              [Page 10]

Internet-Draft           LDAP NameService Schema             August 2009


     ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber'
         DESC 'IPv4 addresses as a dotted decimal omitting leading
               zeros or IPv6 addresses as defined in RFC2373'
         EQUALITY caseIgnoreIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )


     ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber'
         DESC 'IP network omitting leading zeros, eg. 192.168'
         EQUALITY caseIgnoreIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber'
         DESC 'IP netmask omitting leading zeros, eg. 255.255.255.0'
         EQUALITY caseIgnoreIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.22 NAME 'macAddress'
         DESC 'MAC address in maximal, colon separated hex
               notation, eg. 00:00:92:90:ee:e2'
         EQUALITY caseIgnoreIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )


     ( 1.3.6.1.1.1.1.23 NAME 'bootParameter'
         DESC 'rpc.bootparamd parameter'
         EQUALITY caseExactIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )


     ( 1.3.6.1.1.1.1.24 NAME 'bootFile'
         DESC 'Boot image name'
         EQUALITY caseExactIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )


     ( 1.3.6.1.1.1.1.26 NAME 'nisMapName'
         DESC 'Name of a generic NIS map'
         EQUALITY caseIgnoreMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{64} )







Howard & Chu            Expires February 10, 2010              [Page 11]

Internet-Draft           LDAP NameService Schema             August 2009


     ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry'
         DESC 'A generic NIS entry'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024}
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.28 NAME 'nisPublicKey'
         DESC 'NIS public key'
         EQUALITY octetStringMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.29 NAME 'nisSecretKey'
         DESC 'NIS secret key'
         EQUALITY octetStringMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.30 NAME 'nisDomain'
         DESC 'NIS domain'
         EQUALITY caseIgnoreIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )


     ( 1.3.6.1.1.1.1.31 NAME 'automountMapName'
         DESC 'automount Map Name'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.32 NAME 'automountKey'
         DESC 'Automount Key value'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
         SINGLE-VALUE )


     ( 1.3.6.1.1.1.1.33 NAME 'automountInformation'
         DESC 'Automount information'
         EQUALITY caseExactMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
         SINGLE-VALUE )





Howard & Chu            Expires February 10, 2010              [Page 12]

Internet-Draft           LDAP NameService Schema             August 2009


4.  Class Definitions

   This section contains class definitions to be implemented by DUAs
   supporting the schema.

   Various schema for mail routing and delivery using LDAP directories
   have been proposed, and as such this document does not consider
   schema for representing mail aliases or distribution lists.

     ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY
         DESC 'Abstraction of an account with POSIX attributes'
         MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
         MAY ( authPassword $ userPassword $ loginShell $ gecos $
               description ) )


     ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' SUP top AUXILIARY
         DESC 'Additional attributes for shadow passwords'
         MUST uid
         MAY ( authPassword $ userPassword $ description $
               shadowLastChange $ shadowMin $ shadowMax $
               shadowWarning $ shadowInactive $
               shadowExpire $ shadowFlag ) )


     ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' SUP top AUXILIARY
         DESC 'Abstraction of a group of accounts'
         MUST gidNumber
         MAY ( authPassword $ userPassword $ memberUid $
               description ) )


     ( 1.3.6.1.1.1.2.3 NAME 'ipService' SUP top STRUCTURAL
         DESC 'Abstraction an Internet Protocol service.
               Maps an IP port and protocol (such as tcp or udp)
               to one or more names; the distinguished value of
               the cn attribute denotes the service's canonical
               name'
         MUST ( cn $ ipServicePort $ ipServiceProtocol )
         MAY description )


     ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' SUP top STRUCTURAL
         DESC 'Abstraction of an IP protocol. Maps a protocol number
               to one or more names. The distinguished value of the cn
               attribute denotes the protocol canonical name'
         MUST ( cn $ ipProtocolNumber )
         MAY description )



Howard & Chu            Expires February 10, 2010              [Page 13]

Internet-Draft           LDAP NameService Schema             August 2009


     ( 1.3.6.1.1.1.2.5 NAME 'oncRpc' SUP top STRUCTURAL
         DESC 'Abstraction of an Open Network Computing (ONC)
              [RFC1057] Remote Procedure Call (RPC) binding.
              This class maps an ONC RPC number to a name.
              The distinguished value of the cn attribute denotes
              the RPC service canonical name'
         MUST ( cn $ oncRpcNumber )
         MAY description )


     ( 1.3.6.1.1.1.2.6 NAME 'ipHost' SUP top AUXILIARY
         DESC 'Abstraction of a host, an IP device. The distinguished
               value of the cn attribute denotes the host's canonical
            name. Device SHOULD be used as a structural class'
         MUST ( cn $ ipHostNumber )
         MAY ( authPassword $ userPassword $ l $ description $
               manager ) )


     ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' SUP top STRUCTURAL
         DESC 'Abstraction of a network. The distinguished value of
               the cn attribute denotes the network canonical name'
         MUST ipNetworkNumber
         MAY ( cn $ ipNetmaskNumber $ l $ description $ manager ) )


     ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' SUP top STRUCTURAL
         DESC 'Abstraction of a netgroup. May refer to other
               netgroups'
         MUST cn
         MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )


     ( 1.3.6.1.1.1.2.9 NAME 'nisMap' SUP top STRUCTURAL
         DESC 'A generic abstraction of a NIS map'
         MUST nisMapName
         MAY description )


     ( 1.3.6.1.1.1.2.10 NAME 'nisObject' SUP top STRUCTURAL
         DESC 'An entry in a NIS map'
         MUST ( cn $ nisMapEntry $ nisMapName )


     ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' SUP top AUXILIARY
         DESC 'A device with a MAC address; device SHOULD be
               used as a structural class'
         MAY macAddress )



Howard & Chu            Expires February 10, 2010              [Page 14]

Internet-Draft           LDAP NameService Schema             August 2009


     ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' SUP top AUXILIARY
         DESC 'A device with boot parameters; device SHOULD be
               used as a structural class'
         MAY ( bootFile $ bootParameter ) )


     ( 1.3.6.1.1.1.2.14 NAME 'nisKeyObject' SUP top AUXILIARY
         DESC 'An object with a public and secret key'
         MUST ( cn $ nisPublicKey $ nisSecretKey )
         MAY ( uidNumber $ description ) )


     ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top AUXILIARY
         DESC 'Associates a NIS domain with a naming context'
         MUST nisDomain )


     ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top STRUCTURAL
         MUST ( automountMapName )
         MAY description )


     ( 1.3.6.1.1.1.2.17 NAME 'automount' SUP top STRUCTURAL
         DESC 'Automount information'
         MUST ( automountKey $ automountInformation )
         MAY description )


     ( 1.3.6.1.1.1.2.18 NAME 'groupOfMembers' SUP top STRUCTURAL
         DESC 'A group with members (DNs)'
         MUST cn
         MAY ( businessCategory $ seeAlso $ owner $ ou $ o $
               description $ member ) )


















Howard & Chu            Expires February 10, 2010              [Page 15]

Internet-Draft           LDAP NameService Schema             August 2009


5.  Implementation Details

5.1.  Suggested Resolution Methods

   The preferred means of directing a client application (one using the
   shared services of the C library) to use LDAP as its information
   source for the functions listed in Appendix B is to modify the source
   code to directly query LDAP.  As the source to commercial C libraries
   and applications is rarely available to the end-user, one could
   emulate a supported nameservice (such as NIS).  (This is also an
   appropriate opportunity to perform caching of entries across process
   address spaces.)  In the case of NIS, reference implementations are
   widely available and the RPC interface is well known.

   The means by which the operating system is directed to use LDAP is
   implementation dependent.  For example, some operating systems and C
   libraries support end-user extensible resolvers using dynamically
   loadable libraries and a nameservice "switch" (NSS).  The means in
   which the DUA locates LDAP servers is also implementation dependent.

5.2.  Interpreting User and Group Entries

   User and group resolution is initiated by the functions prefixed by
   getpw and getgr respectively.  The uid attribute contains the user's
   login name.  The cn attribute, in posixGroup entries, contains the
   group's name.  This document preserves the use of the uid attribute
   even though, being a naming attribute, its syntax is case
   insensitive.  This may cause a problem with existing deployments
   where there exist login names differing only in case.  If DUAs
   support attribute mapping, a different attribute MAY be used to
   represent users' login names.

   The account object class provides a convenient structural class for
   posixAccount, and SHOULD be used where additional attributes are not
   required.  Likewise, the groupOfMembers object class SHOULD be used
   for groups.  (The groupOfUniqueNames object class is deprecated and
   SHOULD NOT be used.)

   It is suggested that uid and cn are used as the naming attribute for
   posixAccount and posixGroup entries, respectively.  Group members may
   either be login names (values of memberUid) or distinguished names
   (values of member).  In the latter case, the distinguished name must
   be mapped to one or more login names by examining the name's RDN or,
   if it is not distinguished by uid, performing a base search on the DN
   with a filter of "(objectclass=*)".  DUAs MAY wish to cache DN to
   login name mappings.  The DUA MAY traverse nested groups.

   An account's GECOS field is preferably determined by a value of the



Howard & Chu            Expires February 10, 2010              [Page 16]

Internet-Draft           LDAP NameService Schema             August 2009


   gecos attribute.  If no gecos attribute exists, the value of the cn
   attribute MUST be used.  (The existence of the gecos attribute allows
   information embedded in the GECOS field, such as a user's telephone
   number, to be returned to the client without overloading the cn
   attribute.  It also accommodates directories where the common name
   does not contain the user's full name.)

5.2.1.  Using Attribute Options

   Some posixAccount attributes may be accompanied by options
   (Section 2.2.2) identifying particular hosts or operating system
   types.  The attribute with a hostos option matching the operating
   system of the DUA SHOULD be used in preference to an attribute
   without any associated options.  The attribute with a host option
   matching the hostname of the DUA SHOULD be used in preference to any
   other attribute.

5.2.2.  Authentication Considerations

5.2.2.1.  Using Password Values

   When authenticating using a NIS to LDAP gateway or using NSS, a
   lookup is performed to retrieve the password attribute and the value
   is used in the DUA to authenticate a user.  This approach to
   authentication is deprecated, as it requires that read access to the
   password attribute be granted across a network.

   An entry of class posixAccount, posixGroup, or shadowAccount without
   an authPassword or userPassword attribute MUST NOT be used for
   authentication.  In this case the client SHOULD be returned a non-
   matchable password such as "x".

   If userPassword is used, its values MUST be represented by the
   following syntax:

       passwordvalue   = schemeprefix hashedpasswd
       schemeprefix    = "{" scheme "}"
       scheme          = "crypt" / "md5" / "sha" / "ssha" / altscheme
       altscheme       = "x-" keystring
       hashedpasswd    = hashed password

   The hashed password contains a plaintext key hashed using the
   algorithm scheme.  If the schema is "sha", the hashed password is the
   base64 encoding of the SHA-1 digest of the plaintext password.

   userPassword values which do not adhere to this syntax MUST NOT be
   used for authentication.  The DUA MUST iterate through the values of
   the attribute until a value matching the above syntax is found.  Only



Howard & Chu            Expires February 10, 2010              [Page 17]

Internet-Draft           LDAP NameService Schema             August 2009


   if hashedpassword is an empty string does the user have no password.
   DUAs are not required to consider hashing schemes which the client
   will not recognize; in most cases, it may be sufficient to consider
   only "crypt".

   DUA MAY use the authPassword attribute instead of userPassword,
   defined in [RFC3112].  The DUA MUST iterate the values of the
   authPassword attribute until a value whose scheme is CRYPT is found.
   The DUA MAY iterate through the values of the userPassword attribute,
   using the syntax defined here, until a value whose scheme is CRYPT is
   found.  If no conforming value is found, the client MUST be returned
   a non-matchable password such as "x".  Authentication using schemes
   other than CRYPT is, although advisable, beyond the scope of this
   document

   Below is an example of an authPassword attribute:

       authPassword: CRYPT$X5/DBrWPOQQaI

   Below is an example of a (deprecated) userPassword attribute:

       userPassword: {CRYPT}X5/DBrWPOQQaI

   A DUA MAY utilize the attributes in the shadowAccount class to
   provide shadow password service (getspnam() and getspent()).  In such
   cases, the DUA MUST NOT make use of the userPassword attribute for
   getpwnam() et al, and MUST return a non-matchable password (such as
   "x") to the client instead.

5.2.2.2.  Using LDAP Bind

   The preferred method for authenticating users with LDAP is to perform
   an LDAP Bind operation with the user's name and password.  In this
   case the method the DSA uses to store and verify the password is
   completely internal to the DSA and not of any concern to the DUA.

   Likewise, using the shadowAccount attributes requires the DUA to
   handle password policy enforcement.  However the policies expressed
   in the shadowAccount are limited in scope, and not uniformly
   applicable to all the systems that will be using LDAP.

   The preferred method is to leave password policy enforcement to the
   DSA, so that it will be uniformly enforced across all of the various
   systems that rely on the directory.  This enforcement occurs
   implicitly when authenticating using LDAP Bind if the DSA supports
   the LDAP password policy [I-D.behera-ldap-password-policy]
   mechanisms.




Howard & Chu            Expires February 10, 2010              [Page 18]

Internet-Draft           LDAP NameService Schema             August 2009


   The means in which authentication in the DUA is configured is
   implementation dependent.  Typically it is accomplished using [PAM].
   Further details of authentication are beyond the scope of this
   document.

5.2.3.  Naming Considerations

   On UNIX systems, users and groups reside in separate name spaces and
   it is common for the same name to be used by both a user and a group.
   Since they are in separate name spaces there is no ambiguity and no
   conflict.  However, when integrating a name service into LDAP the
   directory may be used with other systems besides UNIX and its
   derivatives.  In particular, the Microsoft Windows operating system
   may also use LDAP for its own name service.  In Windows, users and
   groups reside in a single name space and so one cannot use the same
   name for both a user and a group.

   Conflicts in naming conventions may arise in other deployments as
   well, and should be carefully taken into account when migrating from
   other naming services into LDAP.

5.3.  Interpreting Hosts and Networks

   The ipHostNumber and ipNetworkNumber attributes are defined in
   preference to dNSRecord (defined in [RFC1279]), in order to simplify
   the DUA's role in interpreting entries in the directory.  A dNSRecord
   expresses a complete resource record, including time to live and
   class data, which is extraneous to this schema.

   Additionally, the ipHost and ipNetwork classes permit a host or
   network (respectively) and all its aliases to be represented by a
   single entry in the directory.  This is not necessarily possible if a
   DNS resource record is mapped directly to an LDAP entry.
   Implementations that wish to use LDAP to master DNS zone information
   are not precluded from doing so, and may simply avoid the ipHost and
   ipNetwork classes.

   This document redefines, although not exclusively, the ipNetwork
   class defined in [RFC1279], in order to achieve consistent naming
   with ipHost.  The ipNetworkNumber attribute is also used in the
   siteContact object class [ROSE].

   The authPassword and userPassword attributes are included in ipHost
   such that hosts MAY be treated as authentication principals.  The
   treatment of these attributes and inherent caveats considered in
   Section 5.2 apply here also.

   The trailing zeros in a network address MUST be omitted.  CIDR-style



Howard & Chu            Expires February 10, 2010              [Page 19]

Internet-Draft           LDAP NameService Schema             August 2009


   network addresses (eg. 192.168.1/24) MAY be used.  Leading zeros MUST
   be removed from all components of an IPv6 address string as defined
   by [RFC2373], section 2.2, item 1.  The IPv6 address string MUST be
   further normalized by following the "::" syntax as defined in
   [RFC2373], section 2.2, item 2.  In addition, "::" MUST be used to
   replace the longest string of zero bits.  If there are two or more
   longest strings of zero bits, then the first string MUST be replaced.
   In addition, the syntax defined by [RFC2373], section 2.2, item 3
   MUST NOT be used.  IPv4 addresses MUST be represented by the IPv4
   dotted decimal string syntax.

   For example the following address:

       1080:0000:0:0:08:800:200C:417A
       FF01:0:0:0:0:0:01
       0:0:0:0:0:0:0:0001
       0:0:0:0:0:0:0:0

   MUST be normalized as:

       1080::8:800:200C:417A
       FF01::101
       0::1
       ::

5.4.  Interpreting Other Entities

   In general, a one-to-one mapping between entities and LDAP entries is
   proposed, in that each entity has exactly one representation in the
   DIT.  In some cases this is not feasible; for example, a service
   which is represented in more than one protocol domain.  Consider the
   following entry:

       dn: cn=domain,ou=services,dc=aja,dc=com
       objectClass: top
       objectClass: ipService
       cn: domain
       cn: nameserver
       ipServicePort: 53
       ipServiceProtocol: tcp
       ipServiceProtocol: udp

   This entry MUST map to the following two (2) services entities:

       domain  53/tcp  nameserver
       domain  53/udp  nameserver

   While the above two entities may be represented as separate LDAP



Howard & Chu            Expires February 10, 2010              [Page 20]

Internet-Draft           LDAP NameService Schema             August 2009


   entities, with different distinguished names (such as cn=domain+
   ipServiceProtocol=tcp, ... and cn=domain+ipServiceProtocol=udp, ...)
   it is convenient to represent them as a single entry.  If a service
   is represented in multiple protocol domains with different ports,
   then multiple entries are required; multi-valued RDNs MAY be used to
   distinguish them.)

   With the exception of authPassword and userPassword values, empty
   values (consisting of a zero length string) are returned by the DUA
   to the client.  The DUA MUST reject any entries which do not conform
   to the schema (missing mandatory attributes).  Non-conforming entries
   SHOULD be ignored while enumerating entries.

   The nisDomainObject object class is provided to associate a NIS
   domain with a naming context.  A DUA would retrieve the NIS domain
   name from a configuration file and enumerate the naming contexts
   served by an LDAP server, searching each naming context for
   (nisDomain=%s).  The first matching entry that is found MAY be used
   as a search base for configuration profile information or for entries
   themselves.  For example, the following example shows an association
   between the NIS domain "nis.aja.com" and the naming context
   "dc=aja,dc=com":

       dn: dc=aja,dc=com
       objectClass: top
       objectClass: domain
       objectClass: nisDomainObject
       dc: aja
       nisDomain: nis.aja.com

   The nisObject object class MAY be used as a generic means of
   representing NIS entities.  Its use is not encouraged; where support
   for entities not described in this schema is desired, an appropriate
   schema should be devised.  Implementers are strongly advised to
   support end-user extensible mappings between NIS entities and object
   classes.  (Where the nisObject class is used, the nisMapName
   attribute MAY be used as a RDN.)  The nisObject class might be used
   to represent automount information.

5.5.  Canonicalizing entries with multi-valued naming attributes

   For entities such as hosts, services, networks, protocols, and RPCs,
   where there may be one or more aliases, the respective entry's
   relative distinguished name SHOULD be used to determine the canonical
   name.  Any other values for the same attribute are used as aliases.
   For example, the service described in Section 5.4 has the canonical
   name "domain" and exactly one alias, "nameserver".




Howard & Chu            Expires February 10, 2010              [Page 21]

Internet-Draft           LDAP NameService Schema             August 2009


   The schema in this document generally only defines one attribute per
   class which is suitable for distinguishing an entity (excluding any
   attributes with integer syntax; it is assumed that entries will be
   distinguished on name).  Usually, this is the common name (cn)
   attribute.  This aids the DUA in determining the canonical name of an
   entity, as it can examine the value of the relative distinguished
   name.  Aliases are thus any values of the distinguishing attribute
   (such as cn) which do not match the canonical name of the entity.

   In the event that a different attribute is used to distinguish the
   entry, as may be the case where these object classes are used as
   auxiliary classes, the entry's canonical name may not be present in
   the RDN.  In this case, the DUA MUST choose one of the non-
   distinguished values to represent the entity's canonical name.  As
   the directory server guarantees no ordering of attribute values, it
   may not be possible to distinguish an entry deterministically.  This
   ambiguity SHOULD NOT be resolved by mapping one directory entry into
   multiple entities.

































Howard & Chu            Expires February 10, 2010              [Page 22]

Internet-Draft           LDAP NameService Schema             August 2009


6.  Implementation Focus

   Gateways between NIS and LDAP have been developed by PADL Software
   and Sun Microsystems.  They both support this schema.

   An open source implementation of the C library resolution code has
   been written and is available from PADL Software.  It supports C
   libraries on GNU, BSD, AIX, and Solaris operating systems.  PADL have
   also made available a set of scripts for migrating flat files into a
   form suitable for loading into an LDAP server.  Another open source
   implementation of the C library code is available from the OpenLDAP
   Project.







































Howard & Chu            Expires February 10, 2010              [Page 23]

Internet-Draft           LDAP NameService Schema             August 2009


7.  Security Considerations

   The entirety of related security considerations are outside the scope
   of this document.  It is noted that making passwords encrypted with a
   widely understood hash function (such as crypt()) available to non-
   privileged users is dangerous because it exposes them to dictionary
   and brute-force attacks.  This is proposed only for compatibility
   with existing UNIX system implementations.  Sites where security is
   critical SHOULD consider using a strong authentication service for
   user authentication.

   Alternatively, the encrypted password could be made available only to
   a subset of privileged DUAs, which would provide "shadow" password
   service to client applications.  This may be difficult to enforce.

   Because the schema represents operating system-level entities, access
   to these entities SHOULD be granted on a discretionary basis.  (There
   is little point in restricting access to data which will be
   republished without restriction, however.)  It is particularly
   important that only administrators can modify entries defined in this
   schema, with the exception of allowing a principal to change their
   password (which MAY be done on behalf of the user by a client bound
   as a superior principal, such that password restrictions MAY be
   enforced).  For example, if a user were allowed to change the value
   of their uidNumber attribute, they could subvert security by
   equivalencing their account with the superuser account.

   A subtree of the DIT which is to be republished by a DUA (such as a
   NIS gateway) SHOULD be within the same administrative domain that the
   republishing DUA represents.  (For example, principals outside an
   organization, while conceivably part of the DIT, should not be
   considered with the same degree of authority as those within the
   organization.)

   Finally, care should be exercised with integer attributes of a
   sensitive nature (particularly the uidNumber and gidNumber
   attributes) which contain zero-length values.  DUAs MAY treat such
   values as corresponding to the "nobody" or "nogroup" user and group,
   respectively.












Howard & Chu            Expires February 10, 2010              [Page 24]

Internet-Draft           LDAP NameService Schema             August 2009


8.  Acknowledgements

   Thanks to Bob Joslin of the Hewlett Packard Company, and to all those
   that helped with this document's predecessor, RFC 2307.

   UNIX is a registered trademark of The Open Group.













































Howard & Chu            Expires February 10, 2010              [Page 25]

Internet-Draft           LDAP NameService Schema             August 2009


9.  References

   [RFC1034]  Mockapetris, P., "Domain names - concepts and facilities",
              STD 13, RFC 1034, November 1987.

   [RFC1057]  Sun Microsystems, Inc., "RPC: Remote Procedure Call
              Protocol specification: Version 2", RFC 1057, June 1988.

   [RFC1279]  Hardcastle-Kille, S., "X.500 and Domains", RFC 1279,
              November 1991.

   [RFC2373]  Hinden, R. and S. Deering, "IP Version 6 Addressing
              Architecture", RFC 2373, July 1998.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4511]  Sermersheim, J., "Lightweight Directory Access Protocol
              (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4515]  Smith, M. and T. Howes, "Lightweight Directory Access
              Protocol (LDAP): String Representation of Search Filters",
              RFC 4515, June 2006.

   [RFC4519]  Sciberras, A., "Lightweight Directory Access Protocol
              (LDAP): Schema for User Applications", RFC 4519,
              June 2006.

   [RFC3112]  Zeilenga, K., "LDAP Authentication Password Schema",
              RFC 3112, May 2001.

   [I-D.behera-ldap-password-policy]
              Sermersheim, J., Poitou, L., and H. Chu, "Password Policy
              for LDAP Directories",
              draft-behera-ldap-password-policy-10 (work in progress),
              August 2009.

   [ROSE]     Rose, M., "The Little Black Book: Mail Bonding with OSI
              Directory Services", ISBN 0-13-683210-5, 2001.

   [X.500]    ISO/IEC JTC 1/SC21, "Information Processing Systems - Open
              Systems Interconnection - The Directory: Overview of
              Concepts, Models and Service", 1988.

   [UNIX]     Institute of Electrical and Electronics Engineers and The
              Open Group, "IEEE Std 1003.1, 2004 Edition, Single UNIX
              Specification Version 3", IEEE Standard 1003.1, 2004.




Howard & Chu            Expires February 10, 2010              [Page 26]

Internet-Draft           LDAP NameService Schema             August 2009


   [PAM]      Samar, V. and R. Schemers, "Unified Login with Pluggable
              Authentication Modules (PAM)", OSF RFC 86.0, October 1995.

















































Howard & Chu            Expires February 10, 2010              [Page 27]

Internet-Draft           LDAP NameService Schema             August 2009


Appendix A.  Example Entries

   The examples described in this section are provided to illustrate the
   schema described in this draft.  They are not meant to be exhaustive.

   The following entry is an example of the posixAccount class:

       dn: uid=lester,ou=people,dc=aja,dc=com
       objectClass: top
       objectClass: account
       objectClass: posixAccount
       uid: lester
       cn: Lester the Nightfly
       gecos: Lester
       uidNumber: 10
       gidNumber: 10
       loginShell: /bin/csh
       userPassword: {crypt}$X5/DBrWPOQQaI
       homeDirectory: /home/lester

   This corresponds to the UNIX system password file entry:

       lester:X5/DBrWPOQQaI:10:10:Lester:/home/lester:/bin/sh

   The following entry is an example of the ipHost class:

       dn: cn=josie.aja.com,ou=hosts,dc=aja,dc=com
       objectClass: top
       objectClass: device
       objectClass: ipHost
       objectClass: bootableDevice
       objectClass: ieee802Device
       cn: josie.aja.com
       cn: www.aja.com
       ipHostNumber: 10.0.0.1
       macAddress: 00:00:92:90:ee:e2
       bootFile: mach
       bootParameter: root=dan.aja.com:/nfsroot/peg
       bootParameter: swap=dan.aja.com:/nfsswap/peg
       bootParameter: dump=dan.aja.com:/nfsdump/peg

   This entry represents the host canonically josie.aja.com, also known
   as www.aja.com.  The Ethernet address and four boot parameters are
   also specified.

   An example of the nisNetgroup class:





Howard & Chu            Expires February 10, 2010              [Page 28]

Internet-Draft           LDAP NameService Schema             August 2009


       dn: cn=nightfly,ou=netgroup,dc=aja,dc=com
       objectClass: top
       objectClass: nisNetgroup
       cn: nightfly
       nisNetgroupTriple: (charlemagne,peg,dunes.aja.com)
       nisNetgroupTriple: (lester,-,)
       memberNisNetgroup: kamakiriad

   This entry represents the netgroup nightfly, which contains two
   triples (the user charlemagne, the host peg, and the domain
   dunes.aja.com; and, the user lester, no host, and any domain) and one
   netgroup (kamakiriad).

   Finally, an example of the nisObject class:

       dn: nisMapName=tracks,dc=dunes,dc=aja,dc=com
       objectClass: top
       objectClass: nisMap
       nisMapName: tracks

       dn: cn=Maxine,nisMapName=tracks,dc=dunes,dc=aja,dc=com
       objectClass: top
       objectClass: nisObject
       cn: Maxine
       nisMapName: tracks
       nisMapEntry: Nightfly$4

   This represents the NIS map tracks, and a single map entry.























Howard & Chu            Expires February 10, 2010              [Page 29]

Internet-Draft           LDAP NameService Schema             August 2009


Appendix B.  Affected Library Functions

   The following functions are typically found in the C libraries of
   most UNIX and POSIX compliant systems [UNIX].  An LDAP search filter
   string [RFC4515] which may be used to satisfy the function call is
   included alongside each function name.  Parameters are denoted by %s
   and %d for string and integer arguments, respectively.  Long lines
   are broken:

       getpwnam()         (&(objectClass=posixAccount)(uid=%s))
       getpwuid()         (&(objectClass=posixAccount)(uidNumber=%d))
       getpwent()         (objectClass=posixAccount)
       getspnam()         (&(objectClass=shadowAccount)(uid=%s))
       getspent()         (objectClass=shadowAccount)

       getgrnam()         (&(objectClass=posixGroup)(cn=%s))
       getgrgid()         (&(objectClass=posixGroup)(gidNumber=%d))
       getgrent()         (objectClass=posixGroup)

       getservbyname()    (&(objectClass=ipService)(cn=%s)
                           (ipServiceProtocol=%s))
       getservbyport()    (&(objectClass=ipService)(ipServicePort=%d)
                            (ipServiceProtocol=%s))
       getservent()       (objectClass=ipService)

       getrpcbyname()     (&(objectClass=oncRpc)(cn=%s))
       getrpcbynumber()   (&(objectClass=oncRpc)(oncRpcNumber=%d))
       getrpcent()        (objectClass=oncRpc)

       getprotobyname()   (&(objectClass=ipProtocol)(cn=%s))
       getprotobynumber() (&(objectClass=ipProtocol)
                             (ipProtocolNumber=%d))
       getprotoent()      (objectClass=ipProtocol)

       gethostbyname()    (&(objectClass=ipHost)(cn=%s))
       gethostbyaddr()    (&(objectClass=ipHost)(ipHostNumber=%s))
       gethostent()       (objectClass=ipHost)

       getnetbyname()     (&(objectClass=ipNetwork)(cn=%s))
       getnetbyaddr()     (&(objectClass=ipNetwork)(ipNetworkNumber=%s))
       getnetent()        (objectClass=ipNetwork)

       setnetgrent()      (&(objectClass=nisNetgroup)(cn=%s))
       getpublickey()     (&(objectClass=nisKeyObject)(...))







Howard & Chu            Expires February 10, 2010              [Page 30]

Internet-Draft           LDAP NameService Schema             August 2009


Appendix C.  Suggested DIT structure

   The cn attribute is typically used to name entities.  The
   ipHostNumber, ipNetworkNumber, and ipServiceProtocol attributes are
   also naming attributes, such that multi-valued RDNs may be used to
   distinguish between, for example, different interfaces of a
   multihomed host.

   The following DIT structure MAY be used for deploying this schema.
   It is not required that DC-naming be used, but it is encouraged:

       Naming context                        ObjectClass
       ============================================================
       ou=people,dc=...                      posixAccount
                                             shadowAcount
       ou=group,dc=...                       posixGroup
       ou=services,dc=...                    ipService
       ou=protocols,dc=...                   ipProtocol
       ou=rpc,dc=...                         oncRpc
       ou=hosts,dc=...                       ipHost
       ou=ethers,dc=...                      ieee802Device
                                             bootableDevice
       ou=networks,dc=...                    ipNetwork
       ou=netgroup,dc=...                    nisNetgroup
       nisMapName=...,dc=...                 nisObject
       automountMapName=...,dc=...           automountMap

























Howard & Chu            Expires February 10, 2010              [Page 31]

Internet-Draft           LDAP NameService Schema             August 2009


Authors' Addresses

   Luke Howard
   PADL Software Pty. Ltd.
   PO Box 59
   Central Park, Vic  3145
   AU

   Email: lukeh@padl.com


   Howard Chu (editor)
   Symas Corp.
   18740 Oxnard Street, Suite 313A
   Tarzana, California  91356
   US

   Phone: +1 818 757-7087
   Email: hyc@symas.com
































Howard & Chu            Expires February 10, 2010              [Page 32]

alt-openldap11-devel/drafts/draft-zeilenga-ldap-c-api-concurrency-xx.txt000064400000065344150410163270022210 0ustar00INTERNET-DRAFT                                        Kurt D. Zeilenga
Intended Category: Standards Track                 OpenLDAP Foundation
Extends: draft-ietf-ldapext-ldap-c-api-03.txt
Expires: 28 March 2000
                                                     28 September 1999

                    LDAP C API Concurrency Extensions
              <draft-zeilenga-ldap-c-api-concurrency-00.txt>

1.   Status of this Memo

  This document is an Internet-Draft and is in full conformance with all
  provisions of Section 10 of RFC2026.

  This draft document will be submitted to the RFC Editor as a Standards
  Track document. Distribution of this memo is unlimited.  Technical
  discussion of this document will take place on the IETF LDAP Extension
  Working Group mailing list <ietf-ldapext@netscape.com>.  Please send
  editorial comments directly to the author <Kurt@OpenLDAP.org>.

  Internet-Drafts are working documents of the Internet Engineering Task
  Force (IETF), its areas, and its working groups.  Note that other
  groups may also distribute working documents as Internet-Drafts.

  Internet-Drafts are draft documents valid for a maximum of six months
  and may be updated, replaced, or obsoleted by other documents at any
  time.  It is inappropriate to use Internet-Drafts as reference
  material or to cite them other than as "work in progress."

  The list of current Internet-Drafts can be accessed at
  http://www.ietf.org/ietf/1id-abstracts.txt

  The list of Internet-Draft Shadow Directories can be accessed at
  http://www.ietf.org/shadow.html.

  Copyright 1999, The Internet Society.  All Rights Reserved.

  Please see the Copyright section near the end of this document for
  more information.

2.   Abstract

  This document defines extensions to the LDAP C API to support use in
  concurrent execution environments.  The document describes and defines

Zeilenga                                                        [Page 1]

INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999

  requirements for multiple concurrency levels: thread safe, session
  thread safe, and operation thread safe.

  The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  "SHOULD", "SHOULD NOT", "RECOMMENDED",  and "MAY" in this document are
  to be interpreted as described in RFC 2119 [KEYW].

3.   Introduction

  This document extends the LDAP C API [CAPI] specification to support
  use in concurrent execution environments.  The extensions add powerful
  concurrent processing capabilities to the simple to use CAPI.  This
  document provides an overview of different levels of concurrent
  execution support and offers a number of CAPI "features" to provide
  capabilities at these levels.

  The remainder of this section describes three levels of concurrent
  execution: thread safe, session thread safe, operation thread safe
  APIs.

3.1. Thread Safe

  An implementation which allows applications to safely execute in
  concurrent execution environments where the application provides
  necessary synchronization to ensure serialization of CAPI usage is
  considered to be "thread safe."   Applications may execute non-CAPI
  calls in concurrent execution contexts when using thread safe
  implementations.

3.2. Session Thread Safe

  A "thread safe" implementation which allows CAPI calls associated with
  different LDAP sessions to proceed asychronously is considered to be
  "session thread safe."

3.3. Operation Thread Safe

  A "session thread safe" implementation which allows CAPI calls
  associated with different LDAP operations to proceed asychronously is
  considered to be "operation thread safe".

4.   Basic Thread Safe Feature

Zeilenga                                                        [Page 2]

INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999

  This section details requirements for the thread safe CAPI feature.
  Implementations fulfilling these requirements are said to support the
  LDAP_API_FEATURE_THREAD_SAFE feature and SHOULD advertise this support
  as detailed below.  This feature SHOULD be provided by
  implementations.

  Implementations of this feature MUST implement the LDAP error handling
  extension [ERRNO].

  Implementations of this feature MUST allow non-CAPI calls to proceed
  asynchronously.

  Implementations of this feature MUST NOT use any non-thread safe call
  or mechanism provided by C environment or operating system.  An
  example of non-reentrant calls is the UNIX strtok() function.  Example
  of a non-reentrant mechanism is global (i.e.: non-thread specific)
  errno.

5.   Session Thread Safe Feature

  This section details requirements for the session thread safe CAPI
  feature.  Implementations fulfilling these requirements are said to
  support the LDAP_API_FEATURE_SESSION_THREAD_SAFE feature and SHOULD
  advertise this support as detailed below.  This feature is
  RECOMMENDED.

5.1. Prerequisite Features

  Implementations providing this feature MUST provide and advertise both
  LDAP_API_FEATURE_CONTEXT_SPECIFIC_ERRNO [ERRNO] and
  LDAP_API_FEATURE_THREAD_SAFE.

5.2. Atomic Session Handles

  Implementations providing this feature SHOULD ensure that operations
  upon a given session handle are atomic.  Implementations which provide
  atomic session handles SHOULD advertise the feature
  LDAP_API_FEATURE_ATOMIC_SESSION_HANDLES.

5.3. Concurrency Requirements

  Implementations providing this feature MUST not restrict CAPI calls
  acting upon a given LDAP session to a particular execution context.
  Applications MAY use a session handle on any thread.  Applications

Zeilenga                                                        [Page 3]

INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999

  MUST NOT assume that operations upon a session are atomic.

  Implementations providing this feature MUST allow CAPI calls acting
  upon different LDAP sessions to safely proceed asynchronously.

  Implementations providing this feature MUST allow CAPI calls not
  acting upon an LDAP session to safely proceed asynchronously.

6.   Operation Thread Safe Feature

  This section details requirements for the operation thread safe CAPI
  feature based upon a duplicate session handles mechanism.

  Implementations fulfilling these requirements are said to support the
  LDAP_API_FEATURE_DUPLICATE_SESSION_HANDLES feature and SHOULD
  advertise this support as detailed below.  This feature is OPTIONAL.

6.1. Prerequisite Features

  Implementations of this feature MUST provide and advertise
  LDAP_API_FEATURE_CONTEXT_SPECIFIC_ERRNO [ERRNO],
  LDAP_API_FEATURE_THREAD_SAFE, LDAP_API_FEATURE_SESSION_THREAD_SAFE,
  and LDAP_API_FEATURE_ATOMIC_SESSION_HANDLES.

6.2. Duplicated Session Handles

  Implementations of this feature MUST support duplicated session
  handles.

  As defined in CAPI, a session handle refers to an LDAP session
  encompassing connections with one or more servers, associated message
  results, a set of properties (options), and state information.  This
  feature provides a mechanism for a handle to be duplicated.  A session
  handle and its duplicates are considered siblings.  Each sibling
  session handle refers to the same LDAP session and message results.
  Some properties and state are specific to a handle and others shared
  between siblings as detailed below.

  CAPI calls made on a handle are atomic.  Calls made on sibling (or
  other) handles MAY proceed asynchronously.

  Session handles are duplicated using ldap_dup() and destroyed using
  ldap_destroy().  Use of duplicated session handles with CAPI calls
  have the following semantics detailed in the sections below.

Zeilenga                                                        [Page 4]

INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999

6.2.1.    Creating and Destroying duplicated sessions

  Implementations of this feature are required to provide two new
  routines:      LDAP *ldap_dup( ld );      int ldap_destroy( ld );

  Parameters are:      ld      The session handle

  The ldap_dup() function returns a duplicate of a session handle.  The
  returned session handle may be used concurrently with the original
  session handle as described below. ldap_dup returns NULL if it is not
  able to duplicate the session handle and sets LDAP_OPT_ERROR_NUMBER
  and ldap_errno indicating the nature of the failure.

  The ldap_destroy() function destroys the session handle.  If the
  session handle has no siblings, ldap_destroy behaves exactly like
  ldap_unbind.  If the session handle has siblings, the resources
  assocated with the handle are released and the siblings remain valid.
  ldap_destroy() returns LDAP_SUCCESS or an error number indicating the
  nature of failure.  Regardless of returned value, the handle SHOULD be
  considered invalid and MUST not be used in subsequent calls.  Attempts
  to use a destroyed session handle MUST NOT result in
  LDAP_INVALID_SESSION error being reported.  Implementations SHOULD
  report LDAP_PARAM_ERROR in such cases.

6.2.2.    ldap_unbind and siblings

  When ldap_unbind() is called on a session handle with siblings, the
  siblings become invalid.  The siblings must be destroyed using
  ldap_destroy().  All attempts to obtain the siblings'
  LDAP_OPT_ERROR_NUMBER will return LDAP_INVALID_SESSION.  Any use other
  than ldap_destroy() or reading LDAP_OPT_ERROR_NUMBER will fail with an
  LDAP_INVALID_SESSION error being reported.

6.2.3.    ldap_result()

  Message queues are shared between siblings.  Results of operations on
  a duplicated session handles are accessible to all sibling session
  handles.

  Applications desiring results associated with a specific operation
  SHOULD provide the appropriate msgid to ldap_result().  Applications
  SHOULD avoid calling ldap_result() with LDAP_RES_ANY as such may
  "steal" and return results which an operation on a sibling requires to
  complete.

Zeilenga                                                        [Page 5]

INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999

6.2.4.    Session Options

  The following CAPI options access values shared between siblings:

       LDAP_OPT_API_INFO      LDAP_OPT_DESC      LDAP_OPT_REFERRALS
       LDAP_OPT_PROTOCOL_VERSION      LDAP_OPT_API_FEATURE_INFO
       LDAP_OPT_HOST_NAME

  The following CAPI options access values specific to a sibling:

       LDAP_OPT_DEREF      LDAP_OPT_SIZELIMIT      LDAP_OPT_TIMELIMIT
       LDAP_OPT_RESTART      LDAP_OPT_CLIENT_CONTROLS
       LDAP_OPT_SERVER_CONTROLS      LDAP_OPT_ERROR_NUMBER
       LDAP_OPT_ERROR_STRING      LDAP_OPT_MATCHED_DN

6.2.4.1.  LDAP_OPT_SESSION_REFCNT

  In addition, implementations MUST provide the READ-ONLY, shared
  LDAP_OPT_SESSION_REFCNT option.  LDAP_OPT_SESSION_REFCNT returns the
  reference count associated with the supplied session handle argument.
  The session handle argument is required. The outvalue argument should
  be a pointer to an integer.  Example use:

      int refcount(LDAP *ld) {

      #ifdef LDAP_OPT_SESSION_REFCNT

        if(ld != NULL) {
          int refcnt, rc;
          rc = ldap_get_option(ld,
              LDAP_OPT_SESSION_REFCNT, &refcnt);

          if(rc == LDAP_OPT_SUCCESS) {
            return refcnt;
          }
        }

      #endif

        return -1;
      }

7.   Advertising Features

  This document REQUIRES that supported features with the name in the
  form LDAP_API_FEATURE_x be advertised to consumers of the CAPI as

Zeilenga                                                        [Page 6]

INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999

  follows:

       SHOULD provide the macro LDAP_API_FEATURE_x with the value
       of 1000 + revision number of this draft (i.e.: 1000+0 for
       this 0 revision of the draft).

       MUST provide the CAPI extension "x" when returning API
       information upon LDAP_OPT_API_INFO option access, and

       MUST provide feature info for "x" via LDAP_OPT_FEATURE_INFO
       option mechanism.  The feature version provided MUST      match
  the value LDAP_API_FEATURE_x macro

  where x is replaced appropriately.

  As implementations may not provide macros for all features,
  applications SHOULD use LDAP_OPT_API_INFO to determine which features
  are provided by a given implementation.

8.   Changes to the C API specification

8.1. New Symbols

  This extension introduces the following macros:

       LDAP_API_FEATURE_ATOMIC_SESSION_HANDLES
       LDAP_API_FEATURE_DUPLICATE_SESSION_HANDLES
       LDAP_API_FEATURE_SESSION_THREAD_SAFE
       LDAP_API_FEATURE_THREAD_SAFE
       LDAP_API_FEATURE_OPERATION_THREAD_SAFE      LDAP_INVALID_SESSION
       LDAP_OPT_SESSION_REFCNT

  This extension introduces these new functions:

       ldap_destroy()      ldap_dup()

  This extension introduces no new typedefs nor structure names.

8.2. Duplicated Session Handles

  This extension introduces duplicated session handles and requirements
  for handling duplicated session handles.  Semantics of non-duplicated
  session handles are not affected by this introduction.  However, the
  semantics of calls upon duplicate session handles differs as described
  in the extension.

Zeilenga                                                        [Page 7]

INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999

9.   Security Considerations

  None taken, none given.

10.  Copyright

  Copyright 1999, The Internet Society.  All Rights Reserved.

  This document and translations of it may be copied and furnished to
  others, and derivative works that comment on or otherwise explain it
  or assist in its implementation may be prepared, copied, published and
  distributed, in whole or in part, without restriction of any kind,
  provided that the above copyright notice and this paragraph are
  included on all such copies and derivative works.  However, this
  document itself may not be modified in any way, such as by removing
  the copyright notice or references to the Internet Society or other
  Internet organizations, except as needed for the  purpose of
  developing Internet standards in which case the procedures for
  copyrights defined in the Internet Standards process must be followed,
  or as required to translate it into languages other than English.

  The limited permissions granted above are perpetual and will not be
  revoked by the Internet Society or its successors or assigns.

  This document and the information contained herein is provided on an
  "AS IS" basis and THE AUTHORS, THE INTERNET SOCIETY, AND THE INTERNET
  ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

11.  Bibliography

  [CAPI]  M. Smith, T. Howes, A. Herron, M. Wahl, A. Anantha,      "The
  C LDAP Application Program Interface", INTERNET-DRAFT,      <draft-
  ietf-ldapext-ldap-c-api-03.txt> + LDAPext discussions,      June 1999.

  [ERRNO] K. Zeilenga, "LDAP C API Error Reporting Extension",
       INTERNET-DRAFT, <draft-zeilenga-ldap-c-api-errno-00.txt>,
       June 1999.

  [KEYW]  S. Bradner, "Key words for use in RFCs to Indicate
       Requirement Levels", RFC 2119, March 1997.

Zeilenga                                                        [Page 8]

INTERNET-DRAFT      LDAP C API Concurrency Extensions  28 September 1999

  [LDAP]  M. Wahl, T. Howes, S. Kille, "Lightweight Directory
       Access Protocol (v3)", RFC 2251, December 1997.

13.  Author's Address

  Kurt D. Zeilenga
  OpenLDAP Foundation
  <Kurt@OpenLDAP.org>

  This document expires on 28 March 2000.

Zeilenga                                                        [Page 9]

    ---------------------------------------------------------------------

INTERNET-DRAFT                                        Kurt D. Zeilenga
Intended Category: Standards Track                 OpenLDAP Foundation
Extends: draft-ietf-ldapext-ldap-c-api-03.txt
Expires: 28 March 2000
                                                     28 September 1999

                   LDAP C API Error Reporting Extension
                 <draft-zeilenga-ldap-c-api-errno-00.txt>

1.   Status of this Memo

  This document is an Internet-Draft and is in full conformance with all
  provisions of Section 10 of RFC2026.

  This draft document will be submitted to the RFC Editor as a Standards
  Track document. Distribution of this memo is unlimited.  Technical
  discussion of this document will take place on the IETF LDAP Extension
  Working Group mailing list <ietf-ldapext@netscape.com>.  Please send
  editorial comments directly to the author <Kurt@OpenLDAP.org>.

  Internet-Drafts are working documents of the Internet Engineering Task
  Force (IETF), its areas, and its working groups.  Note that other
  groups may also distribute working documents as Internet-Drafts.

  Internet-Drafts are draft documents valid for a maximum of six months
  and may be updated, replaced, or obsoleted by other documents at any
  time.  It is inappropriate to use Internet-Drafts as reference
  material or to cite them other than as ``work in progress.''

  The list of current Internet-Drafts can be accessed at
  http://www.ietf.org/ietf/1id-abstracts.txt

  The list of Internet-Draft Shadow Directories can be accessed at
  http://www.ietf.org/shadow.html.

  Copyright 1999, The Internet Society.  All Rights Reserved.

  Please see the Copyright section near the end of this document for
  more information.

2.   Abstract

  This document defines a manatory extension to the LDAP C API to
  provide error reporting for all API calls.  The mechanism is
  nonintrusive and can, optionally, support concurrent execution
  environments.

Zeilenga                                                        [Page 1]

INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999

  The key words ``MUST'', ``MUST NOT'', ``REQUIRED'', ``SHALL'', ``SHALL
  NOT'', ``SHOULD'', ``SHOULD NOT'', ``RECOMMENDED'',  and ``MAY'' in
  this document are to be interpreted as described in RFC 2119 [KEYW].

3.   Background and Intent of Use

  The LDAP [LDAP] C API [CAPI] provides an interface which (due to
  legacy compatibiity issues) does not provide a consistent mechanism
  for reporting errors.  A large number of the calls within the
  specification have no mechanism to indicate the nature of a failure.
  The usefulness of a CAPI without a consistent, easy to use, error
  reporting mechanism is limited.

  This document defines an mandatory extension to the CAPI.  All
  implementations of the CAPI MUST provide this extension.

  The extension details additional requirements for error reporting.
  Implementations MUST fulfill all other CAPI error reporting
  requirements.

4.   Error Handling Extension

  This extension provides a mechanism that applications MAY use to
  obtain an LDAP error number indicating the nature of the failure
  associated with the last failed CAPI call.

  Implementations MUST provide access to an LDAP error number (CAPI,
  Section 9) resulting from the last failed CAPI call via the symbol
  ldap_errno.  The last failed CAPI call may be within the global
  context or within the current execution context.

  The ldap_errno MUST evaluate to a modifiable lvalue that has type
  'int', the value of which is set to a LDAP error number.  It is
  unspecified whether ldap_errno is a macro or an identifier declared
  with external linkage.  If a macro definition is suppressed in order
  to access an actual object, or a program defines an identifier with
  the name ldap_errno, the behavior is undefined.

  Applications MUST access ldap_errno within the same concurrent
  execution context, commonly a thread, in which the failure occurred.
  The value of ldap_errno is LDAP_SUCCESS (0) if no API failure has
  occurred within the supported context and the user has not assigned a
  value within the supported context.

Zeilenga                                                        [Page 2]

INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999

  Implementations SHALL NOT update the ldap_errno value upon successful
  CAPI call completion.

  Implementations providing a current execution context specific
  ldap_errno MUST advertise the feature LDAP_API_CONTEXT_SPECIFIC_ERRNO
  as described in Section 6.  Implementation of
  LDAP_API_CONTEXT_SPECIFIC_ERRNO is RECOMMENDED.

4.1. Reporting Server Errors

  It is not a CAPI failure for a server to return an error number.
  Implementations SHALL NOT assign error results returned by servers to
  ldap_errno.

4.2. Implementation Specific Reporting

  The CAPI specification stated that the caller may obtain an indication
  of failure of certain calls (see listed below) using implementation
  specific and/or operating system specific requirements.
  Implementations are NOT REQUIRED to support any implementation
  specific and/or operating system mechanism for ANY call detailed by
  the CAPI specification or its extensions.

  Affected calls include ldap_init(), ldap_open(), and ber_*().

4.3. Example

  The following is an example showing how an application may obtain the
  error information resulting from a failed CAPI calls:

    int msgid;
    LDAP *ld = ldap_init("localhost", 389);

    if(ld == NULL) {
      printf("ldap_init failed, ldap_errno=%d (%s)\n",
        ldap_errno, ldap_err2string(ldap_errno));

      printf("unable to initialize LDAP session\n");
      return -1;
    }

    msgid = ldap_simple_bind(ld, NULL, NULL);

    if(msgid == -1) {
      int err = ldap_errno;

      if (err != LDAP_SUCCESS ) {

Zeilenga                                                        [Page 3]

INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999

        /* API failure */
        printf("ldap_simple_bind failure: ldap_errno=%d (%s)\n",
          err, ldap_err2string(err));

      } else {
        int lderr, rc;

        printf("ldap_simple_bind failed\n");

        rc = ldap_get_option(ld,
          LDAP_OPT_ERROR_NUMBER, &lderr);

        if(rc == LDAP_OPT_SUCCESS) {
          printf("  reason=%d (%s)\n",
            lderr, ldap_err2string(lderr));

        } else {
          printf("ldap_get_option failed, ldap_errno=%d (%s)\n",
            ldap_errno, ldap_err2string(ldap_errno));        }
      }

      goto unbind;
    }

    /* ... */

    unbind: if(ldap_unbind(ld) != 0) {
      printf("ldap_unbind failed, ldap_errno=%d (%s)\n",
        ldap_errno, ldap_error2str(ldap_errno));

      return -1;
    }
    return 0;

5.   Advertising Features

  This document REQUIRES that supported features with the name in the
  form LDAP_API_FEATURE_x be advertised to consumers of the CAPI as
  follows:

       SHOULD provide the macro LDAP_API_FEATURE_x with the value
       of 1000 + revision number of this draft (i.e.: 1000+0 for
       this 0 revision of the draft).

       MUST provide the CAPI extension "x" when returning API
       information upon LDAP_OPT_API_INFO option access, and

Zeilenga                                                        [Page 4]

INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999

       MUST provide feature info for "x" via LDAP_OPT_FEATURE_INFO
       option mechanism.  The feature version provided MUST      match
  the value LDAP_API_FEATURE_x macro

  where x is replaced appropriately.

  As implementations may not provide macros for all features,
  applications SHOULD use LDAP_OPT_API_INFO to determine which features
  are provided by a given implementation.

6.   Changes to the LDAP C API

  This section provides a summary of changes to the CAPI specification.

6.1. LDAP_API_VERSION

  LDAP_API_VERSION should be set to the RFC number of this extension if
  and when it is published as a Standards Track RFC.  (see purpose of
  this draft above).

  Until such time as this document is published as an RFC,
  implementations should use the value specified by CAPI plus 100 + 10 *
  the number of this draft.

  For the third draft of CAPI and this 0 revision of draft, the value of
  2103 ((2000+3) + (100+10*0)) should be used.

6.2. New Symbols

  This extension introduces two new symbols:
       LDAP_API_FEATURE_CONTEXT_SPECIFIC_ERRNO      ldap_errno

  LDAP_API_FEATURE_CONTEXT_SPECIFIC_ERRNO is a macro.  ldap_errno MAY be
  a MACRO.

  This extension indroductes no new functions, typedefs, or structure
  names.

6.3. Implementation/System Specific Error Handling

  This extensions removes any requirements that implementations to use
  implementation and/or operating system specific error reporting
  mechanisms.

Zeilenga                                                        [Page 5]

INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999

7.   Security Considerations

  None taken, none given.

8.   Copyright

  Copyright 1999, The Internet Society.  All Rights Reserved.

  This document and translations of it may be copied and furnished to
  others, and derivative works that comment on or otherwise explain it
  or assist in its implementation may be prepared, copied, published and
  distributed, in whole or in part, without restriction of any kind,
  provided that the above copyright notice and this paragraph are
  included on all such copies and derivative works.  However, this
  document itself may not be modified in any way, such as by removing
  the copyright notice or references to the Internet Society or other
  Internet organizations, except as needed for the  purpose of
  developing Internet standards in which case the procedures for
  copyrights defined in the Internet Standards process must be followed,
  or as required to translate it into languages other than English.

  The limited permissions granted above are perpetual and will not be
  revoked by the Internet Society or its successors or assigns.

  This document and the information contained herein is provided on an
  "AS IS" basis and THE AUTHORS, THE INTERNET SOCIETY, AND THE INTERNET
  ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
  INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

9.   Bibliography

  [CAPI]  M. Smith, T. Howes, A. Herron, M. Wahl, A. Anantha,
          "The C LDAP Application Program Interface", INTERNET-DRAFT,
          <draft-ietf-ldapext-ldap-c-api-03.txt> + LDAPext discussions,
       June 1999.

  [KEYW]  S. Bradner, "Key words for use in RFCs to Indicate
          Requirement Levels", RFC 2119, March 1997.

  [LDAP]  M. Wahl, T. Howes, S. Kille, "Lightweight Directory
          Access Protocol (v3)", RFC 2251, December 1997.

Zeilenga                                                        [Page 6]

INTERNET-DRAFT    LDAP C API Error Reporting Extension 28 September 1999

10.  Author's Address

  Kurt D. Zeilenga
  OpenLDAP Foundation
  <Kurt@OpenLDAP.org>

  This document expires on 28 March 2000.

Zeilenga                                                        [Page 7]
alt-openldap11-devel/drafts/draft-sermersheim-ldap-chaining-xx.txt000064400000036717150410163270021176 0ustar00
Internet Draft                                           J. Sermersheim 
Personal Submission                                         R. Harrison 
Intended Category: Standard Track                           Novell, Inc 
Document: draft-sermersheim-ldap-chaining-02.txt               Feb 2004 
                                                                        
 
 
               LDAP Control to Specify Chaining Behavior 
 
 
Status of this Memo 
 
   This document is an Internet-Draft and is in full conformance with 
   all provisions of Section 10 of RFC2026.  
    
   Internet-Drafts are working documents of the Internet Engineering 
   Task Force (IETF), its areas, and its working groups. Note that other 
   groups may also distribute working documents as Internet-Drafts. 
   Internet-Drafts are draft documents valid for a maximum of six months 
   and may be updated, replaced, or obsoleted by other documents at any 
   time. It is inappropriate to use Internet-Drafts as reference 
   material or to cite them other than as "work in progress."  
    
   The list of current Internet-Drafts can be accessed at 
   http://www.ietf.org/ietf/1id-abstracts.txt  
    
   The list of Internet-Draft Shadow Directories can be accessed at 
   http://www.ietf.org/shadow.html. 
    
   Distribution of this memo is unlimited. Technical discussion of this 
   document will take place on the IETF LDAP Extensions Working Group 
   mailing list <ldapext@ietf.org>. Editorial comments may be sent to 
   the author <jimse@novell.com>. 
 
    
Abstract 
    
   This document describes a Lightweight Directory Access Protocol 
   (LDAP) request control that allows specification of chaining behavior 
   for LDAP operations. By using the control with various LDAP 
   operations, a directory client (DUA), or directory server (DSA) 
   specifies whether or not a DSA or secondary DSA chains operations to 
   other DSAs or returns referrals and/or search result references to 
   the client. 
    
    
1. Introduction 
    
   Many directory servers have the ability through the use of various 
   mechanisms to participate in a distributed directory model. A 
   distributed directory is one where the DIT is distributed over 
   multiple DSAs. One operation completion mechanism used by DSAs in a 
   distributed directory is chaining. Chaining is defined in [X.518], 
   and is the act of one DSA communicating a directory operation that 
 
Sermersheim, Harrison    Internet-Draft - Exp. Aug 2004         Page 1 
               LDAP Control to Specify Chaining Behavior 
 
   originated from a DUA to another DSA in a distributed directory. 
   Contrast this with the act of passing referrals (4.1.11 of [RFC2251]) 
   and SearchResultReferences (4.5.2 of [RFC2251]) back to the client. 
   Chaining may happen during the name resolution part of an operation 
   or during other parts of operations like search which apply to a 
   number of entries in a subtree. 
    
   This document does not attempt to define the distributed directory 
   model, nor does it attempt to define the manner in which DSAs chain 
   requests. This document defines a request control that the client can 
   use to specify whether parts of an operation should or should not be 
   chained. 
    
    
2. Conventions 
    
   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" 
   used in this document carry the meanings described in [RFC2119]. 
    
   The term chaining may apply to uni-chaining as well as multi-chaining 
   (see [X.518]) depending on the capabilities and configuration of the 
   DSAs. 
    
    
3. The Control 
    
   Support for the control is advertised by the presence of its 
   controlType in the supportedControl attribute of a server's root DSE. 
    
   This control MAY be included in any LDAP request operation except 
   abandon, unbind, and StartTLS as part of the controls field of the 
   LDAPMessage, as defined in Section 4.1.12 of [RFC2251]: 
    
   The controlType is set to <IANA-ASSIGNED-OID.1>. The criticality MAY 
   be set to either TRUE or FALSE. The controlValue is an OCTET STRING, 
   whose value is the following ChainingBehavior type, BER encoded 
   following the rules in Section 5.1 of [RFC2251]: 
    
   ChainingBehavior ::= SEQUENCE { 
        resolveBehavior         Behavior OPTIONAL, 
        continuationBehavior    Behavior OPTIONAL } 
    
   Behavior :: = ENUMERATED { 
        chainingPreferred       (0), 
        chainingRequired        (1), 
        referralsPreferred      (2), 
        referralsRequired       (3) } 
      
   resolveBehavior instructs the DSA what to do when a referral is 
   encountered during the local name resolution part of an operation. If 
   this field is not specified, other policy dictates the DSA's 
   behavior. 
    

  
Sermersheim, Harrison    Internet-Draft - Exp. Aug 2004         Page 2 
               LDAP Control to Specify Chaining Behavior 
 
   continuationBehavior instructs the DSA what to do when a referral is 
   encountered after the name resolution part of an operation has 
   completed. This scenario occurs during search operations, and may 
   occur during yet to be defined future operations. If this field is 
   not specified, other policy dictates the DSA's behavior. 
      
   Behavior specifies whether the DSA should chain the operation or 
   return referrals when a target object is held by a remote service.  
     
        chainingPreferred indicates that the preference is that 
        chaining, rather than referrals, be used to provide the service. 
        When this value is set, the server attempts to chain the request 
        but if it can't it returns referrals. 
    
        chainingRequired indicates that chaining is to be used rather 
        than referrals to service the request. When this value is set, 
        the server MUST NOT return referrals. It either chains the 
        request or fails. 
         
        referralsPreferred indicates that the client wishes to receive 
        referrals rather than allow the server to chain the operation. 
        When this value is set, the server return referrals and search 
        references when possible, but may chain the operation otherwise. 
    
        referralsRequired indicates that chaining is prohibited. When 
        this value is set, the server MUST NOT chain the request to 
        other DSAs. Instead it returns referrals as necessary, or fails. 
    
   The following list assigns meanings to some of the result codes that 
   may occur due to this control being present: 
    
   - chainingRequired  (IANA-ASSIGNED-1)   Unable to process without 
                                           chaining. 
   - cannotChain       (IANA-ASSIGNED-2)   Unable to chain the request. 
 
    
4. Notes to Implementors 
    
   <todo: add some> 
 
 
4.1 Unbind and Abandon 
    
   Clients MUST NOT include the ChainingBehavior control with an Abandon 
   operation or an Unbind operation. Servers MUST ignore any chaining 
   control on the abandon and unbind requests. Servers that chain 
   operation are responsible to keep track of where an operation was 
   chained to for the purposes of unbind and abandon. 
    
    
4.2 StartTLS 
    
   This operation cannot be chained because the TLS handshake protocol 
   does not allow man-in-the-middle attacks.  
  
Sermersheim, Harrison    Internet-Draft - Exp. Aug 2004         Page 3 
               LDAP Control to Specify Chaining Behavior 
 
    
    
5. Relationship with other Extensions 
    
   This control MAY be used with other controls or with extended 
   operations. When it is used with other controls or with extended 
   operations not listed here, server behavior is undefined unless 
   otherwise specified. 
    
    
5.1 Relationship with ManageDsaIT 
    
   When this control is used along with the ManageDsaIT control, the 
   resolveBehavior value is evaluated. If resolveBehavior is such that 
   chaining is allowed, the DSA is allowed to chain the operation as 
   necessary until the last RDN is found.  
    
   For example: DSA1 holds the naming context <dc=net> and a subordinate 
   reference to <dc=example,dc=net>, DSA2 holds the naming context 
   <dc=example,dc=net> and a subordinate reference to 
   <dc=hostc,dc=example,dc=net>.  
    
   A modify operation accompanied by the ManageDsaIT control alone is 
   sent to DSA1. The base object of the modify operation is set to 
   <dc=hostc,dc=example,dc=net>. Since DSA1 does not hold the 
   <dc=hostc,dc=example,dc=net> IT DSE, a referral is returned for 
   <dc=example,dc=net>.  
    
   Next, the same modify operation is accompanied by both the 
   ManageDsaIT and the ChainingBehavior control where the 
   ChainingBehavior.resolveBehavior is set to chainingPreferred. In this 
   case, DSA1 chains to DSA2 when it encounters <dc=example,dc=net> and 
   DSA2 continues the operation. Since DSA2 holds the IT DSE 
   <dc=hostc,dc=example,dc=net>, the resolve portion completes, and the 
   rest of the operation proceeds. 
    
    
6. Security Considerations 
    
   Because this control directs a DSA to chain requests to other DSAs, 
   it may be used in a denial of service attack. Implementers should be 
   cognizant of this possibility. 
    
   This control may be used to allow access to hosts and portions of the 
   DIT not normally available to clients. Servers supporting this 
   control should provide sufficient policy to prevent unwanted 
   occurrences of this. 
    
    
7. IANA Considerations 
    
   Registration of the following values is requested [RFC3383]. 
    
    
  
Sermersheim, Harrison    Internet-Draft - Exp. Aug 2004         Page 4 
               LDAP Control to Specify Chaining Behavior 
 
7.1. Object Identifiers 
    
   It is requested that IANA register upon Standards Action an LDAP 
   Object Identifier in identifying the protocol elements defined in 
   this technical specification.  The following registration template is 
   suggested: 
    
        Subject: Request for LDAP OID Registration 
        Person & email address to contact for further information: 
                Jim Sermersheim 
                jimse@novell.com 
        Specification: RFCXXXX 
        Author/Change Controller: IESG 
        Comments: 
                One delegation will be made under the assigned OID: 
                 
                IANA-ASSIGNED-OID.1 Chaining Behavior Request Control 
    
    
7.2. LDAP Protocol Mechanism 
    
   It is requested that IANA register upon Standards Action the LDAP 
   protocol mechanism described in this document.  The following 
   registration template is suggested: 
    
        Subject: Request for LDAP Protocol Mechanism Registration 
        Object Identifier: IANA-ASSIGNED-OID.1 
        Description: Chaining Behavior Request Control 
        Person & email address to contact for further information: 
                Jim Sermersheim 
                jimse@novell.com 
        Usage: Control 
        Specification: RFCXXXX 
        Author/Change Controller: IESG 
        Comments: none 
    
    
7.3. LDAP Result Codes 
    
   It is requested that IANA register upon Standards Action the LDAP 
   result codes: 
    
        chainingRequired        (IANA-ASSIGNED-1) 
        cannotChain             (IANA-ASSIGNED-2) 
    
        The following registration template is suggested: 
    
        Subject: LDAP Result Code Registration 
        Person & email address to contact for further information: 
                Jim Sermersheim 
                jimse@novell.com  
        Result Code Name: chainingRequired 
        Result Code Name: cannotChain 
        Specification: RFCXXXX 
  
Sermersheim, Harrison    Internet-Draft - Exp. Aug 2004         Page 5 
               LDAP Control to Specify Chaining Behavior 
 
        Author/Change Controller: IESG 
        Comments:  request consecutive result codes be assigned 
 
 
8. Normative References 
    
   [X.518] 
   ITU-T Rec. X.511, "The Directory: Abstract Service Definition", 1993. 
    
   [RFC2119] 
   Bradner, Scott, "Key Words for use in RFCs to Indicate Requirement 
   Levels", Internet Draft, March 1997.  
   Available as RFC2119. 
    
   [RFC2251] 
   Wahl, M, S. Kille and T. Howes, "Lightweight Directory Access 
   Protocol (v3)", Internet Standard, December, 1997.  
   Available as RFC2251. 
    
    
9. Authors' Addresses 
    
   Jim Sermersheim 
   Novell, Inc. 
   1800 South Novell Place 
   Provo, Utah 84606, USA 
   jimse@novell.com 
   +1 801 861-3088 
    
   Roger Harrison 
   Novell, Inc. 
   1800 South Novell Place 
   Provo, Utah 84606, USA 
   rharrison@novell.com 
   +1 801 861-2642 



















  
Sermersheim, Harrison    Internet-Draft - Exp. Aug 2004         Page 6 
               LDAP Control to Specify Chaining Behavior 
 
Intellectual Property Rights 
 
     The IETF takes no position regarding the validity or scope of any 
     intellectual property or other rights that might be claimed to 
     pertain to the implementation or use of the technology described in 
     this document or the extent to which any license under such rights 
     might or might not be available; neither does it represent that it 
     has made any effort to identify any such rights. Information on the 
     IETF's procedures with respect to rights in standards-track and 
     standards-related documentation can be found in BCP-11. Copies of 
     claims of rights made available for publication and any assurances 
     of licenses to be made available, or the result of an attempt made 
     to obtain a general license or permission for the use of such 
     proprietary rights by implementors or users of this specification 
     can be obtained from the IETF Secretariat. 
 
     The IETF invites any interested party to bring to its attention any 
     copyrights, patents or patent applications, or other proprietary 
     rights which may cover technology that may be required to practice 
     this standard. Please address the information to the IETF Executive 
     Director. 
 
 
Full Copyright Statement 
 
     Copyright (C) The Internet Society (2004). All Rights Reserved. 
      
     This document and translations of it may be copied and furnished to 
     others, and derivative works that comment on or otherwise explain 
     it or assist in its implementation may be prepared, copied, 
     published and distributed, in whole or in part, without restriction 
     of any kind, provided that the above copyright notice and this 
     paragraph are included on all such copies and derivative works. 
     However, this document itself may not be modified in any way, such 
     as by removing the copyright notice or references to the Internet 
     Society or other Internet organizations, except as needed for the 
     purpose of developing Internet standards in which case the 
     procedures for copyrights defined in the Internet Standards process 
     must be followed, or as required to translate it into languages 
     other than English. 
      
     The limited permissions granted above are perpetual and will not be 
     revoked by the Internet Society or its successors or assigns. 
      
     This document and the information contained herein is provided on 
     an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET 
     ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR 
     IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF 
     THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED 
     WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
    



  
Sermersheim, Harrison    Internet-Draft - Exp. Aug 2004         Page 7 

alt-openldap11-devel/drafts/draft-ietf-ldapext-acl-model-xx.txt000064400000244645150410163270020401 0ustar00






Internet-Draft                                     E. Stokes
LDAP Extensions WG                                B. Blakley
Intended Category: Standards Track            Tivoli Systems
Expires: 14 January 2001                        D. Rinkevich
                                                         IBM
                                                    R. Byrne
                                            Sun Microsystems
                                                14 July 2000

              Access Control Model for LDAPv3
           <draft-ietf-ldapext-acl-model-06.txt>

STATUS OF THIS MEMO

This document is an Internet-Draft and is in full
conformance with all provisions of Section 10 of RFC2026.

Internet-Drafts are working documents of the Internet
Engineering Task Force (IETF), its areas, and its working
groups. Note that other groups may also distribute working
documents as Internet-Drafts. Internet-Drafts are draft
documents valid for a maximum of six months and may be
updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as
reference material or to cite them other than as "work in
progress."

The list of current Internet-Drafts can be accessed at
http://www.ietf.org/ietf/1id-abstracts.txt

The list of Internet-Draft Shadow Directories can be
accessed at http://www.ietf.org/shadow.html.

Comments and suggestions on this document are encouraged.
Comments on this document should be sent to the  LDAPEXT
working group discussion list:

          ietf-ldapext@netscape.com

COPYRIGHT NOTICE

Copyright (C) The Internet Society (2000).  All Rights
Reserved.

ABSTRACT

This document describes the access control model for the
Lightweight Directory Application Protocol V3 (LDAPv3)
directory service. It includes a description of the model,
the LDAP controls, and the extended operations to the LDAP
protocol.  The current LDAP APIs are sufficient for most



Stokes, et al      Expires 14 January 2001          [Page 1]





Internet-Draft      Access Control Model        14 July 2000



access control operations.  An API (in a separate document)
is needed for the extended operation getEffectiveAccess.  A
separate requirements document for access control exists
[REQTS].  The access control model used the requirements
documents as a guideline for the development of this
specification and are reflected in this specification to the
extent that the working group could agree on an access
control model.


The key words "MUST", "MUST NOT", "REQUIRED", "SHALL",
"SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  and
"MAY" used in this document are to be interpreted as
described in [Bradner97].



1.  Introduction

The ability to securely access (replicate and distribute)
directory information throughout the network is necessary
for successful deployment.  LDAP's acceptance as an access
protocol for directory information is driving the need to
provide an access control model definition for LDAP
directory content among servers within an enterprise and the
Internet.  Currently LDAP does not define an access control
model, but one is needed to ensure consistent secure access,
replication, and management across heterogeneous LDAP
implementations. The major objective is to provide a simple,
usable, and implementable, but secure and efficient access
control model for LDAP while also providing the appropriate
flexibility to meet the needs of both the Internet and
enterprise environments and policies.  This document defines
the model and the protocol extensions (controls and extended
operations).

This draft does not (and cannot) fully specify the behavior
of the Access Control Model in a distributed environment
(e.g. propagating access control information across servers
and ACI administration) because there is no LDAP standard
defining how to distribute directory data between LDAP
servers.  The behavior of the Access Control Model in
distributed environments is beyond the scope of this draft.



2.  The LDAPv3 Access Control Model

Access Control mechanisms evaluate requests for access to
protected resources and make decisions about whether those
requests should be granted or denied.  In order to make a



Stokes, et al      Expires 14 January 2001          [Page 2]





Internet-Draft      Access Control Model        14 July 2000



grant/deny decision about a request for access to a
protected resource, an access control mechanism needs to
evaluate policy data.  This policy data describes security-
relevant characteristics of the requesting subject and the
rules which govern the use of the target object.

No mechanism is defined in this document for storage of
access control information at the server beyond indicating
that the attribute holding access control information is an
operational attribute.

The access control mechanisms specified in this document are
neutral with respect to policy inheritance mechanisms,
explicit vs. implicit denial, and group nesting.

The access control model defines

   - What flows on the wire for interoperability

     The existing LDAP protocol flows for ldap operations
     are used to manipulate access control information.  A
     set of permissions and their semantics with respect to
     ldap operations is defined.  The permissions parallel
     the types of ldap operations defined.  What is
     transmitted is exactly what is read back.  Encoding of
     access control information on the wire is per the
     LDAPv3 specifications.

     There is an additional LDAP control and extended
     protocol operation defined, getEffectiveRights.  LDAP
     clients use the control and extended operation to
     manage and administer access control policy enforced by
     LDAP servers.

     Servers may store access control information in any way
     they choose. In particular, servers may use the access
     control mechanisms of their datastores to store and
     enforce LDAP access control, or they may implement
     access control managers external to their datastores.
     Datastores and external access control managers MAY
     implement any access control rule syntax and semantics
     they choose, but the semantics MUST be compatible with
     those defined in the section titled "Operational
     Semantics of Access Control Operations".

   - Attributes and classes for application portability of
     access control information

     An access control information attribute (ldapACI) for
     application portability:  This attribute is used as
     input to the LDAP APIs so access control information



Stokes, et al      Expires 14 January 2001          [Page 3]





Internet-Draft      Access Control Model        14 July 2000



     can be addressed uniformly independent of how that
     information is addressed and stored at the server.
     This same attribute appears in LDIF output for
     interchange of access control information.

     An access control information subentry class
     (ldapACISubEntry) and a set of attributes
     (supportedAccessControlSchemes which is used in the
     rootDSE and accessControlSchemes which is used in the
     subentry ldapACISubEntry) to identity the access
     control mechanisms supported by a server and in a given
     part of the namespace, respectively.

   - An attribute in the rootDSE, discloseOnError, to
     control whether it is permissible for the server to
     return the name of an entry or attribute in an error
     (or empty set) operation result.  This closes a hole on
     the ability to discover information you are not
     authorized to discover.

   - A mechanism to control access to access control
     information:  The access control information attribute,
     ldapACI, is used to control access to access control
     information (controls access to itself).  How to get an
     initial ldapACI in the directory is server specific and
     beyond the scope of this model.

Servers can support multiple access control mechanisms, but
MUST be capable of supporting the LDAP Mechanism in the DIT
scoped by the rootDSE (entire server's DIT) for that server
and SHOULD be capable of supporting the LDAP mechanism in an
arbitrary part (subtree) of the DIT.

The accessControlSchemes attribute in the ldapACISubEntry
indicates which access control mechanism is in effect for
the scope of that ldapACISubEntry.  The
supportedAccessControlSchemes attribute in the rootDSE
indicates which acess control mechanisms are supported by
the server; those mechanisms are in effect in that server's
DIT unless overridden by a mechanism defined in a
ldapACISubEntry elsewhere in that DIT.

Changing the value(s) of either the
supportedAccessControlSchemes or accessControlSchemes
attributes changes the mechanism(s) in effect for the scope
of those attributes (where scope is either that of the
rootDSE or ldapACISubEntry).

Through the use of the mechanism rootDSE attribute and
ldapACI subentry, it is possible to run multiple mechanisms
in either the same subtree or separate subtrees.  If two



Stokes, et al      Expires 14 January 2001          [Page 4]





Internet-Draft      Access Control Model        14 July 2000



mechanisms are run in the same subtree, it is desirable that
the result be the same independent of mechanism, but
definition and discussion of this is beyond the scope of
this model.



3.  Access Control Mechanism Attributes

Two attributes are defined to identify which access control
mechanisms are supported by a given server and by a given
subtree:  supportedAccessControlSchemes and
accessControlSchemes.  (We chose these names based on the
X.500 attribute, AccessControlScheme which is single-valued
and defined in X.501).


3.1  Root DSE Attribute for Access Control Mechanism

The server advertises which access control mechanisms it
supports by inclusion of the 'supportedAccessControlSchemes'
attribute in the root DSE.  This attribute is a list of
OIDs, each of which identify an access control mechanism
supported by the server.  By default, these are also the
mechanisms in effect in subtrees beneath the root in that
server unless overridden by a ldapACISubEntry (see section
"Subentry Class Access Control Mechanism").

 (<OID to be assigned>
    NAME      'supportedAccessControlSchemes'
    DESC      list of access control mechanisms supported
                by this directory server
    SYNTAX    LDAPOID
    USAGE     dSAOperation
 )

The access control mechanism defined is:
     LDAPv3     <OID to be assigned>

Other vendor access control mechanisms MAY be defined (by
OID) and are the responsibility of those vendors to provide
the definition and OID.


3.2  Root DSE Attribute for Control of Disclosing Errors

The server specifies whether it is permissible for the name
of an entry or attribute to be disclosed in an error (or
empty) operation result.  This rootDSE attribute is
discloseOnError.  The default for discloseOnError is false
(0) or not to disclose on error.  The lack of this attribute



Stokes, et al      Expires 14 January 2001          [Page 5]





Internet-Draft      Access Control Model        14 July 2000



in the rootDSE is interpreted as the default.

 (<OID to be assigned>
    NAME      'discloseOnError'
    DESC      specify whether to return the name of an
                entry or attribute in an error (or
                empty) operation result; 0=do not
                disclose (default); 1=disclose
    SYNTAX    LDAPString
    USAGE     dSAOperation


3.3  Subentry Class Access Control Mechanism

A given naming context MUST provide information about which
access control mechanisms are in effect for that portion of
the namespace.  This information is contained in a subentry
(ldapACISubEntry class), derived from [SUBENTRY].
ldapACISubEntry MAY be used to define the scope of an access
control mechanism.  The value(s) held in the rootDSE
attribute, supportedAccessControlSchemes, are the mechanisms
in effect in subtrees beneath the root in that server unless
overridden in a ldapACISubEntry further down the tree held
by that server.  The scope of that ldapACISubEntry is to the
end of the subtree held by that server or until another
ldapACISubEntry is encountered in that subtree held by that
server.  The ldapACISubEntry class is defined as:


 ( <OID to be assigned>
     NAME   'ldapACISubEntry'
     DESC   'LDAP ACI Subentry class'
     SUP    ldapSubEntry STRUCTURAL
     MUST   ( accessControlSchemes )
 )

The accessControlSchemes attribute MUST be in each ldap
access control subentry entry associated with a naming
context whose access control mechanism is different from
adjacent naming contexts supported by that directory server.
accessControlSchemes lists the values (list of OIDs) that
define the access control mechanisms in effect for the scope
of that ldap access control subentry.  Although, in general,
this attribute will define only a single mechanism (single
value), more than one mechanism MAY be in effect for the
scope of that subentry.

 (<OID to be assigned>
    NAME      'accessControlSchemes'
    DESC      list of access control mechanisms supported
                in this subtree



Stokes, et al      Expires 14 January 2001          [Page 6]





Internet-Draft      Access Control Model        14 July 2000



    SYNTAX    LDAPOID
    USAGE     dSAOperation
 )



4.  The Access Control Information Attribute (ldapACI)

The access control information attribute, ldapACI, is
defined as:

 (<OID to be assigned>
   NAME      'ldapACI'
   DESC      'ldap access control information'
   EQUALITY  caseIgnoreMatch
   SYNTAX    directoryString
   USAGE     directoryOperation
 )

The intent of the attribute definition is to design a common
interchange format.  Any given LDAP server should be able to
translate the below defined attribute into meaningful
operation requests. Each server should be able to understand
the attribute; there should not be any ambiguity into what
any part of the syntax means.

While the end goal is to have a common behavior model
between different LDAP server implementations, the attribute
definition alone will not ensure identical ACL processing
behavior between servers.  The semantics of how a server
interprets the ACI syntax are defined in the "Operational
Semantics of Access Control" section of this document.
Additionally, while the server must recognize and act on the
attribute when received over the wire, there are no
requirements for the server to physically store this
attribute.

The attribute definition maintains an assumption that the
receiving server supports inheritance within the security
model. If the server does not support inheritance, the
receiving server must expand any inherited information based
on the scope flag.  If the server does not support partial
inheritance and both the entry and subtree scope are used,
then entry is the prevailing scope.  (It is possible for two
values in the ldapACI attribute to have different scopes
given the syntax of ldapACI; one might contain 'entry' and
another might contain 'subtree'.  This implies that some
ldapACI values inherit down the DIT and othersdo not - hence
partial inheritance of the ldapACI attribute.)

The attribute is defined so access control information (ACI)



Stokes, et al      Expires 14 January 2001          [Page 7]





Internet-Draft      Access Control Model        14 July 2000



can be addressed in a server independent of server
implementation.  This attribute is used in typical LDAP APIs
and in LDIF output of ACI. This attribute may be queried or
set on all directory objects.  The BNF and definitions are
given below.


4.1  The BNF


4.1.1  ACI String Representation

 Values of this syntax are encoded according to the
 following BNF which follows the BNF encoding
 conventions described in [ABNF]:

 ldapACI = scope "#" rights "#" attr "#" subject

 scope = "entry" / "subtree"

 rights = (("grant:" / "deny:") permissions) /
          ("grant:" permissions ";deny:" permissions)

 permissions = [permission *("," permission)]

 permission = "a" / ; add
              "d" / ; delete
              "e" / ; export
              "i" / ; import
              "n" / ; renameDN
              "b" / ; browseDN
              "t" / ; returnDN
              "r" / ; read
              "s" / ; search
              "w" / ; write (mod-add)
              "o" / ; obliterate (mod-del)
              "c" / ; compare
              "m" / ; make

 attr = "[all]" / "[entry]" / (attribute *("," attribute))

 attribute = ; OID syntax (1.3.6.1.4.1.1466.115.121.1.38)
             ;     from [ATTR]

 subject = ["authnLevel:" authnLevel ":"]
             (("authzID-" authzID) /
             ("role:" dn) /
             ("group:" dn) /
             ("subtree:" dn) /
             ("ipAddress:" ipAddress) /
             "public:" /



Stokes, et al      Expires 14 January 2001          [Page 8]





Internet-Draft      Access Control Model        14 July 2000



             "this:")

 authnLevel = "any" /
              "simple" /
              sasl

 sasl = "sasl:"
        ("any" /
        mechanism)

 mechanism = ; sasl mechanism from 4.2 of [LDAPv3]

 authzID = ; authzID from [AuthMeth] repeated below
           ;    for convenience

 authzId = dnAuthzId / uAuthzId

 ; distinguished-name-based authz id.
 dnAuthzId  = "dn:" dn

 dn = utf8string ; with syntax defined in [UTF]

 ; unspecified userid, UTF-8 encoded.
 uAuthzId   = "u:" userid
 userid     = utf8string ; syntax unspecified

 ipAddress = printableString
               ; dotted decimal form (e.g. 10.0.0.6)
               ; or use wildcards such as 12.3.45.* to
               ;    specify a specific subnetwork
               ; or 123.45.6.*+255.255.255.115 to
               ;    specify a subnetmask
               ; or use a wildcard domain name such as
               ;    *.airius.com to specify a specific
               ;    DNS domain

 printableString ; printableString syntax from [ATTR]


Note that the colon following the "public" and "this"
subject options exist only to simplify string parsing.

Note also that per [AuthMeth], authzID may be expanded in
the future.

See section titled 'ACI Examples' for examples of the string
representation.







Stokes, et al      Expires 14 January 2001          [Page 9]





Internet-Draft      Access Control Model        14 July 2000



4.1.2  ACI Binary Representation

 The following ASN.1 data type is used to represent this
 syntax when transferred in binary form:

 ldapACI ::= SEQUENCE {
      scope      ENUMERATED {
            entry       (0),
            subtree     (1) },
      rights     SEQUENCE OF CHOICE {
            grant       [0] Permissions,
            deny        [1] Permissions },
      attr       CHOICE {
            all         [0] NULL,
            entry       [1] NULL,
            attributes  [2] SEQUENCE OF Attribute },
      subject    SEQUENCE {
         authnLevel   CHOICE {
            any      [0] NULL,
            simple   [1] NULL,
            sasl     [2] CHOICE {
               any       [0] NULL,
               mechanism [1] LDAPString -- from [LDAPv3]
            }
         },
      subject    CHOICE {
            dn          [0] DN,
            user              [1] utf8String
            role        [1] DN,
            group       [2] DN,
            subtree     [3] DN,
            ipAddress   [4] IPAddress,
            public      [6] NULL,
            this        [7] NULL }, } -- may be expanded
                                          per [AuthMeth]

   Permissions ::= SEQUENCE OF ENUMERATED {
      add        (0),
      delete     (1),
      export     (2),
      import     (3),
      renameDN   (4),
      browseDN   (5),
      returnDN   (6),
      read       (7),
      search     (8),
      write      (9),
      obliterate (10),
      compare    (11),
      make       (12) }




Stokes, et al      Expires 14 January 2001         [Page 10]





Internet-Draft      Access Control Model        14 July 2000



   Attribute ::= AttributeType -- from [LDAPv3]

   IPAddress ::= PrintableString -- (e.g. 10.0.0.6)



4.2  The Components of ldapACI Attribute

This section defines components that comprise the access
control information attribute, ldapACI.


4.2.1  Scope

Two scopes for access control information are defined:

   - entry - the access control information in the ldapACI
     attribute applies only to the entry in which it is
     contained

   - subtree - the access control information in the ldapACI
     attribute applies to each entry down the subtree unless
     it is overridden by an entry-specific ldapACI whose
     values are more specific.

Use of prescriptive ACIs and scoping via use of a
ldapACISubEntry is outside the scope of this document.


4.2.2  Access Rights and Permissions

Access rights can apply to an entire object or to attributes
of the object. Access can be granted or denied.  Either or
both of the actions "grant" | "deny"  may be used when
creating or updating ldapACI.

Each of the LDAP access permissions are discrete. One
permission does not imply another permission.  The
permissions which apply to attributes and the entry parallel
the type of ldap operations that can be performed.

Permissions which apply to attributes:

   r   Read        Read attribute values
   w   Write       Modify-add values
   o   Obliterate  Modify-delete values
   s   Search      Search entries with specified attributes
   c   Compare     Compare attributes
   m   Make        Make attributes on a new entry below
                     this entry




Stokes, et al      Expires 14 January 2001         [Page 11]





Internet-Draft      Access Control Model        14 July 2000



  1.  r  Read

      If granted, permits attributes and values to be
      returned in a read or search operation.

  2.  w  Write

      If granted, permits attributes and values to be added
      in a modify operation.

  3.  o  Obliterate

      If granted, permits attributes and values to be
      deleted in a modify operation.

  4.  s  Search

      If granted, permits attributes and values to be
      included in a search operation.

  5.  c  Compare

      If granted, permites attributes and value to be used
      in a compare operation.

  6.  m  Make

      The attribute permission "m" is required for all
      attributes that are placed on an object when it is
      created. Just as the "w" and "o" permissions are used
      in the Modify operation, the "m" permission is used in
      the Add operation. Additionally, note that "w" and "o"
      have no bearing on the Add operation and "m" has no
      bearing on the Modify operation.  Since a new object
      does not yet exist, the "a" and "m" permissions needed
      to create it must be granted on the new object's
      parent. This differs from "w" and "o" which must be
      granted on the object being modified. The "m"
      permission is distinct and separate from the "w" and
      "o" permissions so that there is no conflict between
      the permissions needed to add new children to an entry
      and the permissions needed to modify existing children
      of the same entry.

Note:  Modify-replace values of an attribute requires "w"
and "o" permission.

Permissions that apply to an entire entry:


   a    Add        Add an entry below this entry



Stokes, et al      Expires 14 January 2001         [Page 12]





Internet-Draft      Access Control Model        14 July 2000



   d    Delete     Delete this entry
   e    Export     Export entry & subordinates to new
                      location
   i    Import     Import entry & subordinates from some
                      location
   n    RenameDN   Rename an entry's DN
   b    BrowseDN   Browse an entry's DN
   t    ReturnDN   Allows DN of entry to be disclosed in
                      an operation result


  1.  a  Add

      If granted, permits creation of an entry in the DIT
      subject to control on all attributes and values to be
      placed in the new entry at time of creation.  In order
      to add an entry, permission must also be granted to
      add at least the mandatory attributes.

  2.  d  Delete

      If granted, permits the entry to be removed from the
      DIT regardless of controls on attributes within the
      entry.

  3.  e  Export

      If granted, permits an entry and its subordinates (if
      any) to be exported; that is, removed from the current
      location and placed in a new location subject to the
      granting of suitable permission at the destination.
      If the last RDN is changed, Rename is also required at
      the current location. In order to export an entry or
      its subordinates, there are no prerequisite
      permissions to contained attributed, including the RDN
      attributes; this is true even when the operation
      causes new attribute values to be added or removed as
      the result of the changes of RDN.

  4.  i  Import

      If granted, permits an entry and its suordinates (if
      any) to be imported; that is, removed from some other
      location and placed a t the location to which the
      permission applies subject to the granting of suitable
      permissions at the source location.  In order to
      import an entry or its subordinates, there are no
      prerequisite permissions to contained attributed,
      including the RDN attributes; this is true even when
      the operation causes new attribute values to be added
      or removed as the result of the changes of RDN.



Stokes, et al      Expires 14 January 2001         [Page 13]





Internet-Draft      Access Control Model        14 July 2000



  5.  n  RenameDN

      Granting Rename is necessary for an entry to be
      renamed with a new RDN, taking into account
      consequential changes to the distinguished names of
      subordinate entries, if any; if the name of the
      superior is unchanged, the grant is sufficient.  In
      order to rename an entry, there are no prerequisite
      permissions to contained attributed, including the RDN
      attributes; this is true even when the operation
      causes new attribute values to be added or removed as
      the result of the changes of RDN.

  6.  b  BrowseDN

      If granted, permits entries to be accessed using
      directory operations which do not explicitly provide
      the name of the entry.

  7.  t  ReturnDN

      If granted, allows the distinguished name of the entry
      to be disclosed in the operation result.

All permissions (for grant and deny) for an attribute/entry
and a given subject MUST be contained within one ldapACI
value, i.e. (in abbreviated form)

 ldapACI:  ...grant OID.attr1 subjectA
 ldapACI:  ...deny OID.attr1 subjectA

must be ldapACI:  ...grant ... deny... OID.attr1 subjectA

Using the defined BNF it is possible for the permission
string to be empty. The ACI

 ldapACI: subtree#grant#OID.attr1#group:cn=Dept XYZ,c=US

 ldapACI: subtree#grant:r,s#[all]#group:cn=Dept XYZ,c=US

means that this group (Dept XYZ) is granted permission to
read and search all attributes except OID.attr1 because
OID.attr1 is more specific than "[all]".


4.2.3  Attributes

Attribute describes an attribute name in the form of a
dotted decimal OID for that <attr>. If the string (OID)
refers to an attribute not defined in the given server's
schema, the server SHOULD report an error. "[entry]" means



Stokes, et al      Expires 14 January 2001         [Page 14]





Internet-Draft      Access Control Model        14 July 2000



the permissions apply to the entire object. This could mean
actions such as delete the object, or add a child object.
"[all]" means the permission set apply to all attributes of
the entry.

If the keyword "[all]" and another attribute are both
specified within an ACI, the more specific permission set
for the attribute overrides the less specific permission set
for "[all]".


4.2.4  Subjects and Associated Authentication

The following subjects are defined and MUST be supported:

   - authzID, defined per [authmeth]

   - group, defined as the distinguished name of a
     groupOfNames or groupOfUniqueNames entry

   - role

   - subtree, defined as the distinguished name of a non-
     leaf node in the DIT

   - ipAddress,

   - public, defined as public access

   - this, defined as the user whose name matches that of
     the entry being accessed

Other parties MAY define other subjects.  It is the
responsibility of those parties to provide the definition.

A subject may be qualified by the type of authentication
required for access to a given attribute(s) or entry.  If no
authnLevel is present, then no specific type of
authentication is additionally required for access.  If
authnLevel is specified, then that type of authentication is
additionally required for access.  The authnLevels parallel
the authentication mechanisms specified for LDAPv3:  simple,
SASL (any type of SASL mechanism), and a SASL-specific
mechanism.  The authnLevel of is not an acceptable mechanism
for this case) as part of obtaining access.


4.3  Grant/Deny Evaluation Rules

The decision whether to grant or deny a client access to a
particular piece of information is based on several pieces



Stokes, et al      Expires 14 January 2001         [Page 15]





Internet-Draft      Access Control Model        14 July 2000



of information found within the ldapaci value.  Throughout
the decision making process, there are guiding principals.

   - Specificity: More specific policies MUST override less
     specific ones (e.g. individual user entry in ACI takes
     precedence over group entry).

   - Deny takes precedence over Grant.

   - When there are conflicting ACI values, deny takes
     precedence over grant.

   - Deny is the default when there is no access control
     information.

Precendence of Scope Types (highest to lowest)

   - entry

   - subtree

Precedence of Subjects within a Scope (highest to lowest):

   - ipAddress

   - authzID, this

   - group, role, this, public

   - subtree, public

Although other types MAY be defined given the BNF, use of
the well-known types aids in interoperability and
operational consistency.

Access Decision algorithm:

  1.  Determine all the ldapACI values which could apply to
      the target DN which is being accessed.  This is the DN
      of the entry which is being queried in a search,
      modified, deleted, etc.  When determining all the
      ldapACI values, the scope field should be used. All
      ldapACI values with a scope of 'entry' take precedence
      over ldapACI values with a scope of 'subtree'.

  2.  Determine which ldapACI (of the set determined in step
      1) apply to the bound DN.  This is determined by
      looking at the subject (combination of subject type
      and subject value) and bind type.  If no bind is in
      effect (this is possible in ldapv3), then treat this
      lack of bind as if bound as anonymous.  Start with the



Stokes, et al      Expires 14 January 2001         [Page 16]





Internet-Draft      Access Control Model        14 July 2000



      most specific subject type.  If at any time, at least
      one ldapACI value exists for a specificity level, then
      processing stops; the exception here is 'this' because
      this may also be combined with group to use power of
      'this'.   Evaluation should take place on set of
      ldapACI values which are all of the same specificity
      level.  Subjects of the same precedence are combined
      using union semantics.

  3.  Evaluate the remaining ldapACI values and determine a
      grant/deny decision.  If conflicting ldapACI value
      exists for the same attribute, or attributes (i.e. one
      ldapACI grants permission and another denies
      permission), then deny takes precedence over grant.
      For example, if one is granted permission to
      "objectclass" in one ldapACI value by being a member
      of group cn=Admin, and denied permission by being a
      member of cn = NontrustedAdmins, then the bound user
      would not receive permission to objectclass.

      The rule of specificity also applies to the
      attributes. If one is denied permission to "[ all ]"
      attributes, but granted permission to "objectclass"
      then the more specific value of  "objectclass" takes
      precedence over the less specific value of "[ all ] ".
      In this case the user would be granted permission to
      "objectclass" but denied permission to all other
      attributes.



5.  Required Permissions for each LDAP Operation

This section defines the required permissions for each LDAP
operation but even if these requirements are satisfied the
server MAY refuse to carry out the operation due to other
implementation specific security considerations. For
example, a server may refuse to modify an entry because the
database where that entry resides is in read only mode.
Another example might be that although the access control is
available to the userPassword attribute a server may refuse
modifications due to some server specific policy governing
access to passwords.

Here, we specify the rights required by a user when
performing an LDAP operation in terms of the LDAP
permissions specified in section 6.1.  Recall that  "a, d,
e, i, n, b,t" are permissions that apply to entries as a
whole while permissions "r, s, w, o, c, m" apply to
attributes within entries.




Stokes, et al      Expires 14 January 2001         [Page 17]





Internet-Draft      Access Control Model        14 July 2000



Required permissions for LDAP extended operations and LDAP
controls are beyond the scope of this draft.

There is a requirement that a user should not be able to
infer the existence of data in the Directory, if the user
does not have the required access rights to that data.  An
example of this requirement would be in a hosting
environment where you would not want any users from the coke
subtree to be able to even discover that the pepsi tree was
hosted on the same server.  This "discloseOnError" feature
will be set once for server in the rootDSE advertised by the
attribute discloseOnError.  The default for discloseOnError
is false (0).  The lack of this attribute in the rootDSE is
interpreted as the default.  The details of its effects are
addressed below, operation by operation.

For the following, assume that the authorization identity of
the user doing the operation is authzID.


5.1  Bind Operation

This draft does not require any permissions to allow a bind
operation to proceed.


5.2  Search Operation

Recall that the parameters of the Search operation per RFC
2251 [LDAPv3] Section 4.5 are:

   SearchRequest ::= [APPLICATION 3] SEQUENCE {
        baseObject      LDAPDN,
        scope           ENUMERATED {
                baseObject              (0),
                singleLevel             (1),
                wholeSubtree            (2) },
        derefAliases    ENUMERATED {
                neverDerefAliases       (0),
                derefInSearching        (1),
                derefFindingBaseObj     (2),
                derefAlways             (3) },
        sizeLimit       INTEGER (0 .. maxInt),
        timeLimit       INTEGER (0 .. maxInt),
        typesOnly       BOOLEAN,
        filter          Filter,
        attributes      AttributeDescriptionList }

Suppose a server is processing a search request from user
authzID with parameters as above and is processing the entry
with dn candidateDN to decide if it may be returned or not.



Stokes, et al      Expires 14 January 2001         [Page 18]





Internet-Draft      Access Control Model        14 July 2000



Then the permissions required by authzID that need to be
evaluated are as follows:


  1.  permission "b" to the entry candidateDN

      If this permission is not granted then the dn
      candidateDN MUST not be returned nor any attribute
      type nor attribute value from this entry.

      If this permission is granted then the dn candidateDN
      MAY be returned.

      Note: The idea of the "b" permission is to say "a user
      has discovery rights" at a certain entry in the
      directory.  Assuming that the further required
      permissions below are satisfied then having "b" right
      is enough to allow the server to return candidateDN.
      Of course candidateDN contains in it's components,
      attributes and attribute values for all the ancestors
      of candidateDN.  This can lead to the slightly odd
      situation that we can discover the naming attribute of
      an entry and that attribute's value by virtue of
      having the required searching permissions to it's
      child but not by searching the entry directly.

  2.  permission "s" to each attribute appearing in a
      presence test during the evaluation of the search
      filter.  permission "r" to each attribute appearing in
      non-presence tests (see rfc1960, section 3:
      equalityMatch, substrings, greaterOrEquial,
      lessOrEqual, present, approxMatch, extensibleMatch)
      during the evaluation of the search filter.

      The above statement covers the case where the
      attributes are being evaluated as part of an
      extensibleMatch (RFC 2251 section 4.5.1) which appears
      in the filter.  In the case where the dnAttributes
      field of the extensibleMatch is true then we do not
      require any access checks to the attributes of the dn
      candidateDN as access to these is taken to be granted
      by the "b" permission, which has already been required
      above.

      If there is an attribute in a filter element to which
      the required permission is not granted then that
      filter element evaluates to "Undefined" of the three-
      valued-logic of X.511(93).

      Note A: Although both "r" and "s" permissions will
      typically be granted to attributes we keep both



Stokes, et al      Expires 14 January 2001         [Page 19]





Internet-Draft      Access Control Model        14 July 2000



      permissions as there are cases where the distinction
      is useful.  For example, the ability to grant the
      right to discover that a user entry contains a
      userPassword attribute, but not to read it's value
      ("s" but not "r").  The converse, granting "r" but not
      "s" permission is less easy to motivate.

      Note B: There is an unusual behaviour with respect to
      naming attributes illustrated in the following
      example:

      Suppose I have "b" rights to cn=fred,o=sun.com and "r"
      rights to attribute objectclass but not "r" rights to
      cn then with search filter (objectclass=*) I get back
      the dn and objectclass (and so can see the value of
      cn), but with a search filter of (cn=fred) I do not
      get anything.

  3.  permission "r" to each attribute in the attribute list

      AttributeDescriptionList (or all attributes in the
      entry candidateDN if AttributeDescriptionList is *)
      whose type and/or value will be returned.

      Note: The presence of an attribute in an entry is only
      ever volunteered by the server if "r" permission is
      granted to it, though a user may infer the presence of
      an attribute with "s" permission by using a presence
      test on that attribute in the search filter.

  4.  permission "t" to the entry candidateDN

      If this permission is not granted then the dn
      candidateDN MUST NOT be returned. If the server knows
      of an alias for the entry, this alias may be returned
      instead. If no alias name is available then the entry
      candidateDN MUST be omitted from the search results.


  5.  Disclose on error for the Search operation

      If every entry in the scope of the search fails to
      satisfy item 1 (browse right on the candidate entry)
      or item 2 (right to use the filter on that entry) and
      if discloseOnError is not granted to the baseObject
      entry then the operation MUST fail with a "no such
      object error" and the matchedDN of the LDAPResult MUST
      be set to "". If every entry in the scope of the
      search fails to satisfy items 1 or 2 above and
      discloseOnError is granted to the baseObject then the
      empty set of results is returned.



Stokes, et al      Expires 14 January 2001         [Page 20]





Internet-Draft      Access Control Model        14 July 2000



5.3  Modify Operation

Recall that the parameters of the Modify operation per
RFC2251 [LDAPv3] Section 4.6 are:

   ModifyRequest ::= [APPLICATION 6] SEQUENCE {
        object          LDAPDN,
        modification    SEQUENCE OF SEQUENCE {
                operation  ENUMERATED {
                                   add     (0),
                                   delete  (1),
                                   replace (2) },
                modification    AttributeTypeAndValues } }


   AttributeTypeAndValues ::= SEQUENCE {
        type    AttributeDescription,
        vals    SET OF AttributeValue }

Then the permissions required by authzID that need to be
evaluated are as follows:


  1.  permission "w" to each attribute being added to object

      If this permission is not granted to such an
      attribute, then the operation MUST fail.  In this
      case, if discloseOnError is not granted to the entry
      then "no such object" error is returned; if
      discloseOnError is granted to the entry and a
      duplicate attribute value is being added then
      "attribute value already exists" error is returned; if
      discloseOnError is granted to the entry and no
      duplicate value is being added then an "insufficient
      access" error is returned.

  2.  permission "o" to each attribute for which a value is
      being deleted from object

      If this permission is not granted to such an attribute
      then the operation MUST fail.  In this case, if
      discloseOnError is not granted to the entry then "no
      such object" error is returned; if discloseOnError is
      granted to the entry and the attribute or one of the
      values to be deleted does not exist then a "no such
      attribute or value" error is returned; if
      discloseOnError is granted to the entry and the
      attribute and all values specified to be deleted exist
      then an "insufficient access" error is returned.





Stokes, et al      Expires 14 January 2001         [Page 21]





Internet-Draft      Access Control Model        14 July 2000



  3.  permissions "o" and "w" to each attribute being
      replaced in object

      If one of these these permissions is not granted to
      such an attribute then the operation MUST fail.  In
      this case, if discloseOnError is not granted to the
      entry then a "no such object" error is returned; if
      discloseOnError is granted to the entry then
      "insufficient access" error is returned.


5.4  Add Operation

Recall that the parameters of the Add operation per RFC2251
[LDAPv3] Section 4.7 are:

   AddRequest ::= [APPLICATION 8] SEQUENCE {
        entry           LDAPDN,
        attributes      AttributeList }


   AttributeList ::= SEQUENCE OF SEQUENCE {
        type    AttributeDescription,
        vals    SET OF AttributeValue }

Then the permissions required by authzID that need to be
evaluated are as follows:

      permission "a" to the parent of entry

      The access rights required for the creation of a root
      entry in the Directory are beyond the scope of this
      document.  They will be vendor specific.

  1.  permission "m" to the parent of entry for each
      attribute being added to entry

If any of these permissions are not granted then the
operation MUST fail.  In this case if discloseOnError is on
and the entry to be added does not already exist then
"insufficient access" is returned.  If it does exist then
"Entry already exists" is returned.  If discloseOnError is
off then "No such object" is returned (meaning the parent
object).

If they are all granted then the operation MAY proceed.

Note: We require "m" permission to each attribute to prevent
an entry from aquiring "unintended" rights (via group or
role membership),  to stop a "rogue" ACI being added that
would prevent even admins deleting the entry and general



Stokes, et al      Expires 14 January 2001         [Page 22]





Internet-Draft      Access Control Model        14 July 2000



consistency with the MODIFY operation.

Note: The access rights required for the creation of the
first entry in the directory are beyond the scope of this
document.


5.5  Delete Operation

Recall that the parameters of the Delete operation per
RFC2251 [LDAPv3] Section 4.10 are:

    DelRequest ::= [APPLICATION 10] LDAPDN

Then the permissions required by authzID that need to be
evaluated are as follows:


  1.  permission "d" to the entry in the Delete request

If this permission is not granted, then the operation MUST
fail.  In this case if discloseOnError is on and the entry
to be deleted exists then "insufficient access" is returned.
If it does not exist then "No such Object" is returned.  If
discloseOnError is off then "No such object" is returned
(meaning the parent object).

If this permission is granted, then the operation MAY
proceed.

Note: One could also require the "o" permission to be
granted to allow the operation to proceed, but customer
experience has shown that the requirement of the additional
permission is not useful nor expected, and X.500 requires
only the "d" permission.


5.6  Modify DN Operation

Recall that the parameters of the Modify DN operation per
RFC2251 [LDAPv3] Section 4.6 are:

   ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
        entry           LDAPDN,
        newrdn          RelativeLDAPDN,
        deleteoldrdn    BOOLEAN,
        newSuperior     [0] LDAPDN OPTIONAL }

Then the permissions required by authzID that need to be
evaluated are as follows:




Stokes, et al      Expires 14 January 2001         [Page 23]





Internet-Draft      Access Control Model        14 July 2000



  1.  If newSuperior is not present (ie. only the RDN is
      being renamed) then permission "n" to entry is
      required.

  2.  If newSuperior is present then permission "e" to entry
      and permission "i" to newSuperior are required.

If any of these permissions are not granted then the
operation MUST fail.  In this case, if discloseOnError is on
then an "insufficient access error" is returned.  Otherwise,
"No  such object" is returned.

If they are all granted then the operation MAY proceed.

Note A: We do not require any additional permissions in the
case where deleteoldrdn is TRUE.

Note B: These permissions allow the naming attribute of an
entry (or entries) to be changed even though "o" and "w"
permissions are not available on the entry.  Distinguishing
the permissions like this allows us to grant permissions for
the ModifyDN operation, but not the Modify operation and
vice versa.


5.7  Compare Operation

Recall that the parameters of the Compare operation per
RFC2251 [LDAPv3] Section 4.10 are:

   CompareRequest ::= [APPLICATION 14] SEQUENCE {
        entry           LDAPDN,
        ava             AttributeValueAssertion }

Then the permissions required by authzID that need to be
evaluated are as follows:


  1.  permission "c" to the attribute in entry on which the
      comparison is being made.

If any of these permissions are not granted then the
operation MUST fail.  In this case, if discloseOnError is on
then an "insufficient access error" is returned.  Otherwise,
"No  such object" is returned.

If they are all granted then the operation MAY proceed.







Stokes, et al      Expires 14 January 2001         [Page 24]





Internet-Draft      Access Control Model        14 July 2000



5.8  Abandon Operation

Recall that the parameters of the Abandon operation per
RFC2251 [LDAPv3] Section 4.6 are:

   AbandonRequest ::= [APPLICATION 16] MessageID

authzID always has the right to send an Abandon Operation
for an operation he previously initiated.


5.9  Extended Operation

Recall that the parameters of the Extended operation per
RFC2251 [LDA{v3] Section 4.12 are:

   ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
        requestName      [0] LDAPOID,
        requestValue     [1] OCTET STRING OPTIONAL }

The access required for an Extended Operation is beyond the
scope of this document.  The required access will normally
be defined by the implementor of the extended request.



6.  Required Permissions for Handling Aliases and References


Use of aliases and referrals are part of LDAPv3.  However,
neither is particularly well-defined.  Alias
objects/attributes are defined in RFC 2256 as derived from
X.500, but LDAPv3 does not explicitly define its semantics
or behavior.  X.500 does define alias semantics and behavior
with respect to access control; we define its behavior in
LDAPv3 based on the X.511, section 7.11.1.  Referrals and
knowledge information are still under design in LDAPv3; they
are defined in X.500, however, X.500 punts on their
semantics and behavior with respect to access control.  We
define their semantics and behavior in LDAPv3 in terms that
should be independent of the future LDAPv3 definition of
referrals and knowledge information.


6.1  ACI Distribution

Currently there is no LDAP standard defining how to
distribute directory data between LDAP servers. Consequently
this draft cannot fully specify the behavior of the Access
Control Model in a distributed environment. The case of
distribution via referrals is treated in the "Referrals"



Stokes, et al      Expires 14 January 2001         [Page 25]





Internet-Draft      Access Control Model        14 July 2000



section below. In the case of chaining (where one LDAP
server forwards a request to another on behalf of a client)
then it is server specific how the access control model
behaves in this environment. Similarly it is server specific
how the server determines whether the chaining of an
operation is permitted in the first place. For example, the
implementation may choose to regard the local naming context
and the remote subordinate naming context as seperate Access
Control Specific Areas, or it may regard the DIT as one
Access Control Specific Area and implement mechanisms to
propagate access control information between the two
servers. The behavior of the Access Control Model in
distributed environments such as these is beyond the scope
of this draft.


6.2  Aliases

There are two things to protect with respect to aliases:
the real name of the aliased object and the location of the
server holding it.

If alias de-referencing is required in the process of
locating a target entry, no specifc permissions are
necessary for alias de-referencing to take place. Access
control is enforced at the object pointed to by the alias.

If alias de-referencing would result in a
continuationReference (e.g. from a search operation), then
browse permission is required to the alias entry and read
permission is required to the 'aliasedObjectName' attribute.
Requiring these permission closes the hole of discovery.


6.3  Referrals

If a referral is to be followed, no specifc permissions are
necessary for the ldap client to follow the referral. Access
control is enforced at the referenced object.  If a referral
is returned, then browse is required on the entry and read
permission is required to the attribute containing the
referral (we cannot name this attribute exactly today
because there are no RFCs on this - only drafts). If the
server implements a default referral, then no special
permissions are required to read and return that referral.
Requiring these permissions closes the hole of discovery.
In the default case, it is assumed that a default referral
is public.






Stokes, et al      Expires 14 January 2001         [Page 26]





Internet-Draft      Access Control Model        14 July 2000



7.  Controlling Access to Access Control Information

The ldapACI attribute is used to specify control for who has
permission to set/change access control information
(ldapACI).  The ldapACI attribute/OID is just another
attribute described with a scope, set of rights and
permissions, and subject as a value of the ldapACI
attribute.  (See the example in the "ACI Examples" section).

If the policy for controlling the ldapACI attribute is not
specified for any object in the tree, behavior is
implementation defined. For instance, if no object anywhere
in the tree defines the access for ldapACI within the
ldapACI attribute, then the server could simply assert that
the 'root DN' is considered the policy owner (controller for
controlling access control) for all objects.



8.  ACI Examples

Note that in the examples, the form "OID.<attrname>" refers
to the OID in dotted decimal form for the attribute
<attrname>.  This shorthand notation is used only for the
examples.  In implementation, the dotted decimal form of the
OID is used.


8.1  Attribute Definition

The following examples show the access required to control
access to the ldapACI attribute.  The first example shows
controlling the access control on an individual entry and
its attributes.  The second example shows controlling the
access control on a subtree.

 ldapACI: entry#grant:r,w#
    OID.ldapACI#authnLevel:any:role:cn=aciAdmin

 ldapACI: subtree#grant:r,w#
    OID.ldapACI#authnLevel:any:role:cn=aciAdmin

The next example shows a ldapACI attribute where a group
"cn=Dept XYZ, c=US" is being given permissions to read,
search, and compare attribute attr1. The permission applies
to the entire subtree below the node containing this ACI.
Authentication of a specified type is not required.

 ldapACI:subtree#grant;r,s,c#
      OID.attr1#group:cn=Dept XYZ,c=US




Stokes, et al      Expires 14 January 2001         [Page 27]





Internet-Draft      Access Control Model        14 July 2000



The next example shows an ACI attribute where a role
"cn=SysAdmins,o=Company" is being given permissions to add
objects below this node and read, search, and compare
attributes attr2 and attr3. The permission applies to the
entire subtree below the node containing this ACI.

 ldapACI: subtree#grant:a#
            [entry]#role:cn=SysAdmins,o=Company

 ldapACI: subtree#grant:r,s,c#
            OID.attr2#role:cn=SysAdmins,o=Company

 ldapACI: subtree#grant:r,s,c#
            OID.attr3#role:cn=SysAdmins,o=Company


8.2  Modifying the ldapACI Values

Modify-Replace works as defined in the ldap operation
modify. If the attribute value does not exist, create the
value. If the attribute does exist, replace the value.  If
the ldapACI value is replaced, all ldapACI values are
replaced.

A given ldapACI for an entry:

 ldapACI: subtree#deny:r,w#[all]#group:cn=Dept ABC

 ldapACI: subtree#grant:r#OID.attr1#group:cn=Dept XYZ

perform the following change:

  dn: cn=someEntry
  changetype: modify
  replace: ldapACI
  ldapACI: subtree#grant:r,w#[all]#group:cn=Dept LMN

The resulting ACI is:

ldapACI: subtree#grant:r,w#[all]#group:cn=Dept LMN

( ldapACI values for Dept XYZ and ABC are lost through the
replace )

During an ldapmodify-add, if the ACI does not exist, the
create the ACI with the specific ldapACI value(s).  If the
ACI does exist, then add the specified values to the given
ldapACI.  For example a given ACI:

ldapACI: subtree#grant:r,w#[all]#group:cn=Dept XYZ




Stokes, et al      Expires 14 January 2001         [Page 28]





Internet-Draft      Access Control Model        14 July 2000



with a modification:

  dn: cn=someEntry
  changetype: modify
  add: ldapACI
  ldapACI: subtree#grant:r#OID.attr1#group:cn=Dept XYZ

would yield an multi-valued ACI of:

 ldapACI: subtree#grant:r,w#[all]#group:cn=Dept XYZ

 ldapACI: subtree#grant:r#OID.attr1#group:cn=Dept XYZ

To delete a particular ACI value, use the regular ldapmodify
- delete syntax

Given an ACI of:

 ldapACI: subtree#grant:r,w#[all]#group:cn=Dept XYZ
 ldapACI: subtree#grant:r#OID.attr1#group:cn=Dept XYZ

  dn: cn = some Entry
  changetype: modify
  delete: ldapACI
  ldapACI: subtree#grant:r#OID.attr1#group:cn=Dept XYZ

would yield a remaining ACI on the server of

ldapACI: subtree#grant:r,w#[all]#group:cn=Dept XYZ

The attributes which are defined for access control
interchange may be used in all LDAP operations.

Within the ldapmodify-delete operation, the entire acl may
be deleted by specifying

 dn: cn = some Entry
 changetype: modify
 delete: ldapACI

In this case, the entry would then inherit its ACI from some
other node in the tree depending on the server inheritance
model.

Similarly, if all values of ldapACI are deleted, then the
access control information for that entry is defined by that
implementation's inheritance model.







Stokes, et al      Expires 14 January 2001         [Page 29]





Internet-Draft      Access Control Model        14 July 2000



8.3  Evaluation

These examples assume that the ldapACI entries listed in
each example are the only ACI which applies to the entry in
question; if backing-store ACI also exists, the effective
policy may be different from that listed in each example.
See section 10 for a discussion of the semantics of ldapACI
entries when backing-store ACI administration is also used.

Assume cn=jsmith is a member of group cn=G1.  Assume
cn=jsmith is a member of group cn=G2.

 Example #1
 dn: o=XYZ, c=US
 ldapACI: subtree#grant:r#attr1
            #authzID-dn:cn=jsmith,ou=ABC,o=XYZ,c=US
 ldapACI: subtree#grant:w#attr1
            #group:cn=G1,ou=ABC,o=XYZ,c=US

 What rights does cn=jsmith have to attr1 of o=XYZ,c=US?
 Read (r) access; authzID is higher precedence than
 group.


 Example #2
 dn: o=XYZ, c=US
 ldapACI: subtree#grant:r#attr2
            #group:cn=G1,ou=ABC,o=XYZ,c=US
 ldapACI: subtree#grant:w#attr2
            #group:cn=G2,ou=ABC,o=XYZ,c=US

 What rights does cn=jsmith have to attr2 of o=XYZ,c=US?
 Read-write (r,w) access; ACI is combined because both
 subjects (group) have same precedence.


 Example #3
 dn: o=XYZ, c=US
 ldapACI: subtree#grant:r,w#attr3
            #group:cn=G1,ou=ABC,o=XYZ,c=US
 ldapACI: subtree#deny:w#attr3#group:cn=G2,ou=ABC,o=XYZ,c=US

 What rights does cn=jsmith have to attr3 of o=XYZ, c=US?
 Read access; write is denied (deny has precedence over
 grant).


 Example #4
 dn: o=XYZ, c=US
 ldapACI: subtree#grant:w#attr4
            #authzID-dn:cn=jsmith,ou=ABC,o=XYZ,c=US



Stokes, et al      Expires 14 January 2001         [Page 30]





Internet-Draft      Access Control Model        14 July 2000



 ldapACI: subtree#grant:r#attr4#subtree:ou=ABC,ou=XYZ,c=US

 What rights does cn=jsmith have to attr4 of o=XYZ, c=US?
 Write (w); rights given to an authzID take precedence
 over those given to a subtree.


 Example #5
 dn: o=XYZ, c=US
 ldapACI: subtree#grant:m#OID.attr5
            #authzID-dn:cn=jsmith,o=ABC,c=US
 ldapACI: subtree#grant:m#OID.cn
            #authzID-dn:cn=jsmith,o=ABC,c=US
 ldapACI: subtree#grant:m#OID.sn
            #authzID-dn:cn=jsmith,o=ABC,c=US
 ldapACI: subtree#grant:a#[entry]
            #authzID-dn:#cn=jsmith,o=ABC,c=US

 What rights does cn=jsmith have to o=XYZ, c=US?
 Make(m) on attributes attr5, cn, and sn and Add(a)
 on the entry.  These are the minimal yet sufficient
 permissions to create a new object,
 cn=New, o=XYZ, c=US with values for the attr5, cn,
 and sn attributes.  This example illustrates how the
 "m" permission can be used to limit the attributes
 that can be created on a new entry.

 Example #6
 dn: c=US
 ldapACI: subtree#grant:m#[all]#subtree:c=US
 dn: o=XYZ, c=US
 ldapACI: subtree#grant:a#[entry]#
            authzID-dn:cn=jsmith,o=ABC,c=US

 What rights does cn=jsmith have to o=XYZ, c=US?
 Make(m) on attributes all attributes and Add(a) on the
 entry. These are sufficient permissions to create a new
 object, cn=New, o=XYZ, c=US with values any desired
 attributes.  For administrators who do not wish to limit
 the attributes that can be created on new entries, this
 example shows how a single ldapACI at the top of the
 domain solves the problem.



9.  Operational Semantics of Access Control Operations

The semantics of access control operations described in this
document are defined operationally in terms of "histories".
A history is a sequence of actions (x1, x2, ..., xN).




Stokes, et al      Expires 14 January 2001         [Page 31]





Internet-Draft      Access Control Model        14 July 2000



9.1  Types of actions

We consider five types of actions:

   - LDAP Access Control Policy Update actions: invocations
     of ldap modify when used to add, delete, or replace the
     aci attribute; invocations of ldap add when used to add
     an entry with an aci attribute.  A LDAP Access Control
     Policy Update action may replace the policy (by
     completely replacing the aci attribute with new policy
     information) or it may grant or deny specific rights
     while leaving others unaffected.

   - LDAP Access Control Policy Query operations:
     invocations of ldap search when used to retrieve the
     aci attribute; invocations of ldap search with the
     getEffectiveRightsRequest control; invocations of the
     ldapGetEffectiveRightsRequest extended operation.

   - Datastore Access Control Policy Update Actions: any
     operation implemented by the server which LDAP is using
     as its datastore which changes the access policy
     enforced with respect to attempts to access LDAP
     directory entries and their attributes.

   - LDAP Access Request operations: invocations of LDAP
     entry or attribute access operations (Read, Update,
     Search, Compare, etc...).

   - Other operations: anything else, including Datastore
     operations which do not change the access policy
     enforced by the server.


9.2  Semantics of Histories

The semantics of histories are defined as follows:

   - LDAP Update (Replace), LDAP Query

     The Query will show that the subject has all rights
     granted by the Update operation, and no rights not
     granted by the Update operation.

   - LDAP Update (Grant), LDAP Query

     The Query will show that the subject has all rights
     granted by the Update operation.  The Query may show
     that the subject also has other rights not granted by
     the Update operation, depending on the policy in force
     before the Update operation.



Stokes, et al      Expires 14 January 2001         [Page 32]





Internet-Draft      Access Control Model        14 July 2000



   - LDAP Update (Deny), LDAP Query

     The Query will show that the subject does not have any
     right denied by the Update operation.  The Query may
     show that the subject has rights not denied by the
     Update operation, depending on the policy in force
     before the Update operation.

   - LDAP Update (Replace), LDAP Access Request

     The Request will succeed if it requires only rights
     granted to the requesting subject by the Update
     operation.  The Request will fail if it requires any
     right not granted by the Update operation.

   - LDAP Update (Grant), LDAP Access Request

     The Request will succeed if it requires only rights
     granted to the requesting subject by the Update
     operation.  The Request may succeed if it requires
     rights not granted by the Update operation, depending
     on the policy in force before the Update operation.

   - LDAP Update (Deny), LDAP Access Request

     The Request will fail if it requires any right denied
     to the requesting subject by the Update operation.  If
     the Request requires only rights which were not denied
     by the Update operation, it may succeed, depending on
     the policy in force before the Update operation.

   - LDAP Update (Replace), Other, LDAP Query

     The Query will show that the subject has all rights
     granted by the Update operation, and no rights not
     granted by the Update operation.

   - LDAP Update (Grant), Other, LDAP Query

     The Query will show that the subject has all rights
     granted by the Update operation.  The Query may show
     that the subject also has other rights not granted by
     the Update operation, depending on the policy in force
     before the Update operation.

   - LDAP Update (Deny), Other, LDAP Query

     The Query will show that the subject does not have any
     right denied by the Update operation.  The Query may
     show that the subject has rights not denied by the
     Update operation, depending on the policy in force



Stokes, et al      Expires 14 January 2001         [Page 33]





Internet-Draft      Access Control Model        14 July 2000



     before the Update operation.

   - LDAP Update (Replace), Other, LDAP Access Request

     The Request will succeed if it requires only rights
     granted to the requesting subject by the Update
     operation.  The Request will fail if it requires any
     right not granted by the Update operation.

   - LDAP Update (Grant), Other, LDAP Access Request

     The Request will succeed if it requires only rights
     granted to the requesting subject by the Update
     operation.  The Request may succeed if it requires
     rights not granted by the Update operation, depending
     on the policy in force before the Update operation.

   - LDAP Update (Deny), Other, LDAP Access Request

     The Request will fail if it requires any right denied
     to the requesting subject by the Update operation.  If
     the Request requires only rights which were not denied
     by the Update operation, it may succeed, depending on
     the policy in force before the Update operation.

   - LDAP Update (Replace), Datastore Policy Update, LDAP
     Query

     The result of the Query is not defined.

   - LDAP Update (Grant), Datastore Policy Update, LDAP
     Query

     The result of the Query is not defined.

   - LDAP Update (Deny), Datastore Policy Update, LDAP Query

     The result of the Query is not defined.

   - LDAP Update (Replace), Datastore Policy Update, LDAP
     Access Request

     The result of the Access Request is not defined.

   - LDAP Update (Grant), Datastore Policy Update, LDAP
     Access Request

     The result of the Access Request is not defined.

   - LDAP Update (Deny), Datastore Policy Update, LDAP
     Access Request



Stokes, et al      Expires 14 January 2001         [Page 34]





Internet-Draft      Access Control Model        14 July 2000



     The result of the Access Request is not defined.



10.  Access Control Parameters for LDAP Controls & Extended
Operations

This section defines the parameters used in the access
control LDAP controls and extended operations in this
document.

targetDN specifies the initial directory entry in DN syntax
on which the control or extended operation is performed.

whichObject specifies whether the access control information
(in the get effective rights control) which is retrieved is
for the target directory entry (ENTRY) or the target
directory entry and its subtree (SUBTREE).

rights in the get effective rights control or extended
operation response is of the form specified in the BNF for
<rights>.

subject is a LDAP string that defines the subject.  Access
control is get/set on a subject.  The syntax of the subject
is the same as the subject field in the BNF.



11.  Access Control Information (ACI) Controls

The access control information controls provide a way to
manipulate access control information in conjunction with a
LDAP operation.  One LDAP control is defined.  This control
allows access control information to be retrieved while
manipulating other directory information for that entry.
The control is:

   - getEffectiveRights to obtain the effective rights for a
     given directory entry(s) for a given subject during a
     ldap_search operation

11.1  getEffectiveRights Control


11.1.1  Request Control

This control may only be included in the ldap_search
message as  part of the controls  field  of the
LDAPMessage, as  defined in  Section  4.1.12 of [LDAPv3].




Stokes, et al      Expires 14 January 2001         [Page 35]





Internet-Draft      Access Control Model        14 July 2000



The controlType is set to <OID to be assigned>. The
criticality MAY be either TRUE or FALSE (where absent is
also equivalent to FALSE) at the client's option.  The
controlValue is an OCTET STRING, whose value is the BER
encoding of a value of the following SEQUENCE:

 getEffectiveRightsRequest ::= SEQUENCE {
   effectiveRightsRequest   SEQUENCE OF SEQUENCE {
       whichObject   ENUMERATED {
                     LDAP_ENTRY (1),
                     LDAP_SUBTREE (2)
                     },
       subject       <see <subject > in BNF> | "*"
       }
 }

The effectiveRightsRequest is a set of sequences that state
the whichObject (entry or entry plus subtree) and specifics
of the control request to be performed. A "*" in the subject
field specifies that all DN types are to be used in
returning the effective rights.  This control is applied to
the filter and scope set by the ldap_search operation, i.e.
base, one-level, subtree.  So the attributes/values returned
are defined by the ldap_search operation.

11.1.2  Response Control

This control is included in the ldap_search_response message
as part of the controls field of the LDAPMessage, as defined
in Section 4.1.12 of [LDAPv3].

The controlType is set to <OID to be assigned>. There is no
need to set the criticality on the response.  The
controlValue is an OCTET STRING, whose value is the BER
encoding of a value of the following SEQUENCE:

 getEffectiveRightsResponse ::= {
   result  ENUMERATED {
      success                       (0),
      operationsError               (1),
      unavailableCriticalExtension (12),
      noSuchAttribute              (16),
      undefinedAttributeType       (17),
      invalidAttributeSyntax       (21),
      insufficientRights           (50),
      unavailable                  (52),
      unwillingToPerform           (53),
      other                        (80)
      }
 }




Stokes, et al      Expires 14 January 2001         [Page 36]





Internet-Draft      Access Control Model        14 July 2000



The effective rights returned are returned with each entry
returned by the search result.  The control response for
ldap_search is:

 PartialEffectiveRightsList ::= SEQUENCE OF SEQUENCE {
    rights        <see <rights> in BNF>,
    whichObject   ENUMERATED {
                      LDAP_ENTRY (1),
                      LDAP_SUBTREE (2)
                      },
    subject       < see <subject> in BNF >
 }

Although this extends the search operation, there are no
incompatibilities between versions.  LDAPv2 cannot send a
control, hence the above structure cannot be returned to a
LDAPv2 client.  A LDAPv3 client cannot send this request to
a LDAPv2 server.  A LDAPv3 server not supporting this
control cannot return the additional data.

11.1.3  Client-Server Interaction

The getEffectiveRightsRequest control requests the rights
that MUST be in effect for requested directory
entry/attribute based on the subject DN.  The server that
consumes the search operation looks up the rights for the
returned directory information based on the subject DN and
returns that rights information.

There are six possible scenarios that may occur as a result
of the getEffectiveRights control being included on the
search request:


  1.  If the server does not support this control and the
      client specified TRUE for the control's criticality
      field, then the server MUST return
      unavailableCriticalExtension as a return code in the
      searchResponse message and not send back any other
      results.  This behavior is specified in section 4.1.12
      of [LDAPv3].

  2.  If the server does not support this control and the
      client specified FALSE for the control's criticality
      field, then the server MUST ignore the control and
      process the request as if it were not present.  This
      behavior is specified in section 4.1.12 of [LDAPv3].

  3.  If the server supports this control but for some
      reason such as cannot process specified family and the
      client specified TRUE for the control's criticality



Stokes, et al      Expires 14 January 2001         [Page 37]





Internet-Draft      Access Control Model        14 July 2000



      field, then the server SHOULD do the following: return
      unavailableCriticalExtension as a return code in the
      searchResult message.

  4.  If the server supports this control but for some
      reason such as cannot process specified family and the
      client specified FALSE for the control's criticality
      field, then the server should process as 'no rights
      returned for that family' and include the result
      Unavailable in the getEffectiveRightsResponse control
      in the searchResult message.

  5.  If the server supports this control and can return the
      rights per the family information, then it should
      include the getEffectiveRightsResponse control in the
      searchResult message with a result of success.

  6.  If the search request failed for any other reason,
      then the server SHOULD omit the
      getEffectiveRightsResponse control from the
      searchResult message.

The client application is assured that the correct rights
are returned for scope of the search operation if and only
if the getEffectiveRightsResponse control returns the
rights.  If the server omits the getEffectiveRightsResponse
control from the searchResult message, the client SHOULD
assume that the control was ignored by the server.

The getEffectiveRightsResponse control, if included by the
server in the searchResponse message, should have the
getEffectiveRightsResult set to either success if the rights
are returned or set to the appropriate error code as to why
the rights could not be returned.

The server may not be able to return a right because it may
not exist in that directory object's attribute; in this
case, the rights request is ignored with success.


12.  Access Control Extended Operation

An extended operation, get effective rights, is defined to
obtain the effective rights for a given directory entry for
a given subject.  This operation may help with the
management of access control information independent of
manipulating other directory information.







Stokes, et al      Expires 14 January 2001         [Page 38]





Internet-Draft      Access Control Model        14 July 2000



12.1  LDAP Get Effective Rights Operation

ldapGetEffectiveRightsRequest ::= [APPLICATION 23] SEQUENCE
{
   requestName      [0] <OID to be assigned>,
   requestValue     [1] OCTET STRING OPTIONAL }

   where

   requestValue ::= SEQUENCE {
      targetDN  LDAPDN,
      updates   SEQUENCE OF SEQUENCE {
                  whichObject   ENUMERATED {
                                  LDAP_ENTRY (1),
                                  LDAP_SUBTREE (2)
                                  },
                  attr SEQUENCE {
                     attr   <see <attr> in BNF >
                     },
                  subject   < see <subject> in BNF > | "*"
                  }
      }


The requestName is a dotted-decimal representation of the
OBJECT IDENTIFIER corresponding to the request. The
requestValue is information in a form defined by that
request, encapsulated inside an OCTET STRING.

The server will respond to this with an LDAPMessage
containing the ExtendedResponse which is a rights list.

ldapGetEffectiveRightsResponse ::= [APPLICATION 24] SEQUENCE
{
   COMPONENTS OF LDAPResult,
   responseName     [10] <OID to be assigned> OPTIONAL,
   effectiveRights  [11] OCTET STRING OPTIONAL }

   where

   effectiveRights ::= SEQUENCE OF SEQUENCE {
      rights        <see <rights> in BNF>,
      whichObject   ENUMERATED {
                       LDAP_ENTRY (1),
                       LDAP_SUBTREE (2)
                       },
      subject       < see <subject> in BNF >
   }

If the server does not recognize the request name, it MUST
return only the response fields from LDAPResult, containing



Stokes, et al      Expires 14 January 2001         [Page 39]





Internet-Draft      Access Control Model        14 July 2000



the protocolError result code.



13.  Security Considerations

This document proposes protocol elements for transmission of
security policy information.  Security considerations are
discussed throughout this draft.  Because subject security
attribute information is used to evaluate decision requests,
it is security-sensitive information and must be protected
against unauthorized modification whenever it is stored or
transmitted.

Interaction of access control with other directory functions
(other than the ones defined in this document) are not
defined in this document, but instead in the documents where
those directory functions are defined.  For example, the
directory replication documents should address the
interaction of access control with the replication function.



14.  References

[LDAPv3] M. Wahl, T. Howes, S. Kille, "Lightweight Directory
Access Protocol (v3)", RFC 2251, December 1997.

[ECMA] ECMA, "Security in Open Systems: A Security
Framework" ECMA TR/46, July 1988.

[REQTS] Stokes, Byrne, Blakley, "Access Control Requirements
for LDAP", RFC 2820, May 2000.

[ATTR] M.Wahl, A, Coulbeck, T. Howes, S. Kille, "Lightweight
Directory Access Protocol (v3)": Attribute Syntax
Definitions, RFC 2252, December 1997.

[UTF] M. Wahl, S. Kille, "Lightweight Directory Access
Protocol (v3)": A UTF-8 String Representation of
Distinguished Names", RFC 2253, December 1997.

[Bradner97] Bradner, Scott, "Key Words for use in RFCs to
Indicate Requirement Levels", RFC 2119.

[AuthMeth] Wahl, M., Alvestrand, H., Hodges, J. and R.
Morgan, "Authentication Methods for LDAP", RFC 2829, May
2000.

[ABNF] D. Crocker, P. Overell, "Augmented BNF for Syntax
Specifications: ABNF", RFC 2234, November 1997.



Stokes, et al      Expires 14 January 2001         [Page 40]





Internet-Draft      Access Control Model        14 July 2000



ACKNOWLEDGEMENT

This is to acknowledge the numerous companies and individuals who have
contributed their valuable help and insights to the development of this
specification.


AUTHOR(S) ADDRESS

 Ellen Stokes                       Bob Blakley
 Tivoli Systems                     Tivoli Systems
 6300 Bridgepoint Parkway           6300 Bridgepoint Parkway
 Austin, TX 78731                   Austin, TX 78731
 USA                                USA
 mail-to: estokes@tivoli.com        mail-to: blakley@tivoli.com
 phone: +1 512 436 9098             phone: +1 512 436 1564
 fax:   +1 512 436 1199             fax:   +1 512 436 1199


 Debbie Rinkevich                   Robert Byrne
 IBM                                Sun Microsystems
 11400 Burnet Rd                    29 Chemin du Vieux Chene
 Austin, TX 78758                   Meylan ZIRST 38240
 USA                                France
 mail-to: djbrink@us.ibm.com        mail-to: rbyrne@france.sun.com
 phone: +1 512 838 1960             phone: +33 (0)4 76 41 42 05
 fax:   +1 512 838 8597



























Stokes, et al      Expires 14 January 2001         [Page 41]





Internet-Draft      Access Control Model        14 July 2000

























































Stokes, et al      Expires 14 January 2001         [Page 42]









                          CONTENTS


 1.  Introduction.......................................   2

 2.  The LDAPv3 Access Control Model....................   2

 3.  Access Control Mechanism Attributes................   5
     3.1   Root DSE Attribute for Access Control
           Mechanism....................................   5
     3.2   Root DSE Attribute for Control of Disclosing
           Errors.......................................   5
     3.3   Subentry Class Access Control Mechanism......   6

 4.  The Access Control Information Attribute
     (ldapACI)..........................................   7
     4.1   The BNF......................................   8
           4.1.1   ACI String Representation   8
           4.1.2   ACI Binary Representation  10
     4.2   The Components of ldapACI Attribute..........  11
           4.2.1   Scope  11
           4.2.2   Access Rights and Permissions  11
           4.2.3   Attributes  14
           4.2.4   Subjects and Associated
                   Authentication  15
     4.3   Grant/Deny Evaluation Rules..................  15

 5.  Required Permissions for each LDAP Operation.......  17
     5.1   Bind Operation...............................  18
     5.2   Search Operation.............................  18
     5.3   Modify Operation.............................  21
     5.4   Add Operation................................  22
     5.5   Delete Operation.............................  23
     5.6   Modify DN Operation..........................  23
     5.7   Compare Operation............................  24
     5.8   Abandon Operation............................  25
     5.9   Extended Operation...........................  25

 6.  Required Permissions for Handling Aliases and
     References.........................................  25
     6.1   ACI Distribution.............................  25
     6.2   Aliases......................................  26
     6.3   Referrals....................................  26

 7.  Controlling Access to Access Control
     Information........................................  27

 8.  ACI Examples.......................................  27
     8.1   Attribute Definition.........................  27
     8.2   Modifying the ldapACI Values.................  28
     8.3   Evaluation...................................  30



                           - i -











 9.  Operational Semantics of Access Control
     Operations.........................................  31
     9.1   Types of actions.............................  32
     9.2   Semantics of Histories.......................  32

10.  Access Control Parameters for LDAP Controls &
     Extended Operations................................  35

11.  Access Control Information (ACI) Controls..........  35
     11.1  getEffectiveRights Control...................  35
           11.1.1  Request Control  35
           11.1.2  Response Control  36
           11.1.3  Client-Server Interaction  37

12.  Access Control Extended Operation..................  38
     12.1  LDAP Get Effective Rights Operation..........  39

13.  Security Considerations............................  40

14.  References.........................................  40


































                           - ii -











Full Copyright Statement

Copyright (C) The Internet Society (2000).á All Rights
Reserved.

This document and translations of it may be copied and
furnished to others, and derivative works that comment on or
otherwise explain it or assist in its implementation may be
prepared, copied, published and distributed, in whole or in
part, without restriction of any kind, provided that the
above copyright notice and this paragraph are included on
all such copies and derivative works.á However, this
document itself may not be modified in any way, such as by
removing the copyright notice or references to the Internet
Society or other Internet organizations, except as needed
for the purpose of developing Internet standards in which
case the procedures for copyrights defined in the Internet
Standards process must be followed, or as required to
translate it into languages other than English.

The limited permissions granted above are perpetual and will
not be revoked by the Internet Society or its successors or
assigns.

This document and the information contained herein is
provided on an "AS IS" basis and THE INTERNET SOCIETY AND
THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT
INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.























                          - iii -




alt-openldap11-devel/drafts/draft-ietf-ldapext-ldapv3-dupent-xx.txt000064400000046171150410163270021224 0ustar00

LDAPEXT Working Group                                    J. Sermersheim 
Internet Draft                                              Novell, Inc 
Document: draft-ietf-ldapext-ldapv3-dupent-08.txt             Sept 2002 
Intended Category: Standard Track                                       
 
 
  LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
1. Status of this Memo 
 
   This document is an Internet-Draft and is in full conformance with 
   all provisions of Section 10 of RFC2026 [1].  
    
   Internet-Drafts are working documents of the Internet Engineering 
   Task Force (IETF), its areas, and its working groups. Note that 
   other groups may also distribute working documents as Internet-
   Drafts. Internet-Drafts are draft documents valid for a maximum of 
   six months and may be updated, replaced, or obsoleted by other 
   documents at any time. It is inappropriate to use Internet- Drafts 
   as reference material or to cite them other than as "work in 
   progress."  
    
   The list of current Internet-Drafts can be accessed at 
   http://www.ietf.org/ietf/1id-abstracts.txt  
    
   The list of Internet-Draft Shadow Directories can be accessed at 
   http://www.ietf.org/shadow.html. 
    
2. Abstract 
    
   This document describes a Duplicate Entry Representation control 
   extension for the LDAP Search operation. By using the control with 
   an LDAP search, a client requests that the server return separate 
   entries for each value held in the specified attribute(s). For 
   instance, if a specified attribute of an entry holds multiple 
   values, the search operation will return multiple instances of that 
   entry, each instance holding a separate single value in that 
   attribute. 
    
3. Introduction 
    
   This document describes controls, which allow duplicate entries to 
   be returned in the result set of search operation. Each duplicated 
   entry represents a distinct value (or combination of values) of the 
   set of specified multi-valued attributes. 
    
   For example, an application may need to produce an ordered list of 
   entries, sorted by a multi-valued attribute, where each attribute 
   value is represented in the list. The Server-Side Sorting control 
   [RFC2891] allows the server to order search result entries based on 
   attribute values (sort keys).  But it does not allow one to specify 
   behavior when an attribute contains multiple values.  The default 

 
Sermersheim       Internet-Draft - Expires Mar 2003            Page 1 
LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
   behavior, as outlined in 7.9 of [X.511], is to use the smallest 
   order value as the sort key. 
    
   In order to produce an ordered list, where each value of a multi-
   valued attribute is sorted into the list, a separate control is 
   needed which causes the set of entries to be expanded sufficiently 
   to represent each attribute value prior to sorting. 
    
    
    
   An example of this would be a sorted list of all telephone numbers 
   in an organization.  Because any entry may have multiple telephone 
   numbers, and the list is to be sorted by telephone number, the list 
   must be able to contain duplicate entries, each with its own unique 
   telephone number. 
    
   Another example would be an application that needs to display an 
   ordered list of all members of a group.  It would use this control 
   to create a result set of duplicate groupOfNames entries, each with 
   a single, unique value in its member attribute. 
    
4. Conventions 
    
   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" 
   used in this document carry the meanings described in [RFC2119]. 
    
   All controlValue data is represented as ASN.1 in this document, and 
   is to be BER encoded as stated in Section 5.1 of [RFC2251]. 
    
5. The Controls 
    
   Support for the controls is advertised by the presence of their OID 
   in the supportedControl attribute of a server's root DSE.  The OID 
   for the request control is "2.16.840.1.113719.1.27.101.1" and the 
   OIDs for the response controls are "2.16.840.1.113719.1.27.101.2" 
   and "2.16.840.1.113719.1.27.101.3". 
    
5.1 Request Control 
    
   This control is included in the searchRequest message as part of the 
   controls field of the LDAPMessage, as defined in Section 4.1.12 of 
   [RFC2251]. 
    
   The controlType is set to "2.16.840.1.113719.1.27.101.1". The 
   criticality MAY be set to either TRUE or FALSE.  The controlValue is 
   defined as the following DuplicateEntryRequest: 
    
   DuplicateEntryRequest ::= SEQUENCE { 
        AttributeDescriptionList, -- from [RFC2251] 
        PartialApplicationAllowed BOOLEAN DEFAULT TRUE } 
         
    
5.1.1 AttributeDescriptionList Semantics 
  
Sermersheim       Internet-Draft - Expires Mar 2003            Page 2 
LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
    
   The AttributeDescriptionList data type is described in 4.1.5 of 
   [RFC2251] and describes a list of zero or more AttributeDescription 
   types as also described in 4.1.5 of [RFC2251]. Both definitions are 
   repeated here for convenience: 
    
        AttributeDescriptionList ::= SEQUENCE OF 
                AttributeDescription 
    
        AttributeDescription ::= LDAPString 
    
   A value of AttributeDescription is based on the following BNF: 
    
        attributeDescription = AttributeType [ ";" <options> ] 
    
   While processing a search request, a server implementation examines 
   this list. If a specified attribute or attribute subtype exists in 
   an entry to be returned by the search operation, and that attribute 
   holds multiple values, the server treats the entry as if it were 
   multiple, duplicate entries -- the specified attributes each holding 
   a single, unique value from the original set of values of that 
   attribute. Note that this may result in search result entries that 
   no longer match the search filter. 
    
   Specifying an attribute supertype has the effect of treating all 
   values of that attribute's subtypes as if they were values of the 
   specified attribute supertype. See Section 6.2 for an example of 
   this. 
    
   When attribute descriptions contain subtyping options, they are 
   treated in the same manner as is described in Section 4.1.5 of 
   [RFC2251]. Semantics are undefined if an attribute description 
   contains a non-subtyping option, and SHOULD NOT be specified by 
   clients. 
    
   When two or more attributes are specified by this control, the 
   number of duplicate entries is the combination of all values in each 
   attribute. Because of the potential complexity involved in servicing 
   multiple attributes, server implementations MAY choose to support a 
   limited number of attributes in the control. 
    
   There is a special case where either no attributes are specified, or 
   an attribute description value of "*" is specified.  In this case, 
   all attributes are used.  (The "*" allows the client to request all 
   user attributes in addition to specific operational attributes). 
    
   If an attribute is unrecognized, that attribute is ignored when 
   processing the control. 
    
5.1.2 PartialApplicationAllowed Semantics 
    
   The PartialApplicationAllowed field is used to specify whether the 
   client will allow the server to apply this control to a subset of 
  
Sermersheim       Internet-Draft - Expires Mar 2003            Page 3 
LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
   the search result set. If TRUE, the server is free to arbitrarily 
   apply this control to no, any, or all search results. If FALSE, the 
   server MUST either apply the control to all search results or fail 
   to support the control at all. 
    
   Client implementations use the DuplicateSearchResult control to 
   discover which search results have been affected by this control. 
    
5.2 Response Controls 
    
   Two response controls are defined to provide feedback while the 
   search results are being processed; DuplicateSearchResult and 
   DuplicateEntryResponseDone.  
    
   The DuplicateSearchResult control is sent with all SearchResultEntry 
   operations that contain search results which have been modified by 
   the DuplicateEntryRequest control. 
    
   The DuplicateEntryResponseDone control is sent with the 
   SearchResultDone operation in order to convey completion 
   information.  
    
5.2.1 The DuplicateSearchResult control 
    
   This control is included in the SearchResultEntry message of any 
   search result that holds an entry that has been modified by the 
   DuplicateEntryRequest control as part of the controls field of the 
   LDAPMessage, as defined in Section 4.1.12 of [RFC2251]. This control 
   is absent on search results that are unaffected by 
   DuplicateEntryRequest control. 
    
   The controlType is set to "2.16.840.1.113719.1.27.101.2". The 
   controlValue is not included. 
    
5.2.2 The DuplicateEntryResponseDone control 
    
   This control is included in the searchResultDone message as part of 
   the controls field of the LDAPMessage, as defined in Section 4.1.12 
   of [RFC2251]. 
    
   The controlType is set to "2.16.840.1.113719.1.27.101.3". The 
   controlValue is defined as the following DuplicateEntryResponseDone: 
    
      DuplicateEntryResponseDone ::= SEQUENCE { 
         resultCode,     -- From [RFC2251] 
         errorMessage    [0] LDAPString OPTIONAL, 
         attribute       [1] AttributeDescription OPTIONAL } 
    
   A resultCode field is provided here to allow the server to convey to 
   the client that an error resulted due to the control being serviced. 
   For example, a search that would ordinarily complete successfully 
   may fail with a sizeLimitExceeded error due to this control being 

  
Sermersheim       Internet-Draft - Expires Mar 2003            Page 4 
LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
   processed. If the operation is successfull, the value will be 
   success (0). 
 
   The errorMessage field MAY be populated with a human-readable string 
   in the event of an erroneous result code. 
    
   The attribute field MAY be set to the value of the first attribute 
   specified by the DuplicateEntryRequest that was in error.  The 
   client MUST ignore the attribute field if the result is success. 
 
6. Protocol Examples 
    
6.1 Simple example 
    
   This example will show this control being used to produce a list of 
   all telephone numbers in the dc=example,dc=net container.  Let's say 
   the following three entries exist in this container; 
    
   dn: cn=User1,dc=example,dc=net 
   telephoneNumber: 555-0123 
    
   dn: cn=User2,dc=example,dc=net 
   telephoneNumber: 555-8854 
   telephoneNumber: 555-4588 
   telephoneNumber: 555-5884 
    
   dn: cn=User3,dc=example,dc=net 
   telephoneNumber: 555-9425 
   telephoneNumber: 555-7992 
    
   First an LDAP search is specified with a baseDN of 
   "dc=example,dc=net", subtree scope, filter set to 
   "(telephoneNumber=*)".  A DuplicateEntryRequest control is attached 
   to the search, specifying "telephoneNumber" as the attribute 
   description, and the search request is sent to the server. 
    
   The set of search results returned by the server would then consist 
   of the following entries: 
    
   dn: cn=User1,dc=example,dc=net 
   telephoneNumber: 555-0123 
   <no DuplicateSearchResult control sent with search result> 
    
   dn: cn=User2,dc=example,dc=net 
   telephoneNumber: 555-8854 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User2,dc=example,dc=net 
   telephoneNumber: 555-4588 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User2,dc=example,dc=net 
   telephoneNumber: 555-5884 
  
Sermersheim       Internet-Draft - Expires Mar 2003            Page 5 
LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User3,dc=example,dc=net 
   telephoneNumber: 555-9425 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User3,dc=example,dc=net 
   telephoneNumber: 555-7992 
   control: 2.16.840.1.113719.1.27.101.2 
    
   All but the first entry are accompanied by the DuplicateSearchResult 
   control when sent from the server. 
    
   Note that it is not necessary to use an attribute in this control 
   that is specified in the search filter.  This example only does so, 
   because the result was to obtain a list of telephone numbers. 
    
6.2 Specifying multiple attributes 
    
   A more complicated example involving multiple attributes will result 
   in more entries. If we assume these entries in the directory: 
    
   dn: cn=User1,dc=example,dc=net 
   cn: User1 
   givenName: User One 
   mail: user1@example.net 
    
   dn: cn=User2,dc=example,dc=net 
   cn: User2 
   givenName: User Two 
   mail: user2@example.net  
   mail: usertwo@example.net 
    
   In this example, we specify mail and name in the attribute list. By 
   specifying name, all attribute subtypes of name will also be 
   considered. Following is the resulting set of entries: 
    
   dn: cn=User1,dc=example,dc=net 
   cn: User1 
   mail: user1@example.net 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User1,dc=example,dc=net 
   givenName: User One 
   mail: user1@example.net 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User2,dc=example,dc=net 
   cn: User2 
   mail: user2@example.net  
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User2,dc=example,dc=net 
  
Sermersheim       Internet-Draft - Expires Mar 2003            Page 6 
LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
   cn: User2 
   mail: usertwo@example.net  
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User2,dc=example,dc=net 
   givenName: User Two 
   mail: user2@example.net  
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=User2,dc=example,dc=net 
   givenName: User Two 
   mail: usertwo@example.net 
   control: 2.16.840.1.113719.1.27.101.2 
 
6.3 Listing the members of a groupOfNames 
    
   This example shows how the controls can be used to turn a single 
   groupOfNames entry into multiple duplicate entries.  Let's say this 
   is our groupOfNames entry: 
    
   dn: cn=Administrators,dc=example,dc=net 
   cn: Administrators 
   member: cn=aBaker,dc=example,dc=net 
   member: cn=cDavis,dc=example,dc=net 
   member: cn=bChilds,dc=example,dc=net 
   member: cn=dEvans,dc=example,dc=net 
    
   We could set our search base to "cn=Administrators,dc=example,dc=net 
   ", filter to "(objectClass=*)", use an object scope (to restrict it 
   to this entry) and send the duplicateEntryRequest control with 
   "member" as its attribute value.  The resulting set would look like 
   this: 
    
   dn: cn=Administrators,dc=example,dc=net 
   member: cn=aBaker,dc=example,dc=net 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=Administrators,dc=example,dc=net 
   member: cn=cDavis,dc=example,dc=net 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=Administrators,dc=example,dc=net  
   member: cn=bChilds,dc=example,dc=net 
   control: 2.16.840.1.113719.1.27.101.2 
    
   dn: cn=Administrators,dc=example,dc=net 
   member: cn=dEvans,dc=example,dc=net 
   control: 2.16.840.1.113719.1.27.101.2 
    
   This list can then be sorted by member and displayed (also by 
   member) in a list. 
    
7. Relationship to other controls 
  
Sermersheim       Internet-Draft - Expires Mar 2003            Page 7 
LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
    
   This control is intended (but not limited) to be used with the 
   Server Side Sorting control [RFC2891].  By pairing this control with 
   the Server Side Sorting control, One can produce a set of entries, 
   sorted by attribute values, where each attribute value is 
   represented in the sorted set.  Server implementations MUST ensure 
   that this control is processed before sorting the result of a 
   search, as this control alters the result set of search. 
    
   This control MAY also be used with the Virtual List View [VLV] 
   control (which has a dependency on the Server Side Sort control). 
   The nature of the dependency between the VLV control and the Sort 
   control is such that the Sorting takes place first. Because the sort 
   happens first, and because this control is processed before the sort 
   control, the impact of this control on the VLV control is minimal. 
   Some server implementations may need to carefully consider how to 
   handle the typedown functionality of the VLV control when paired 
   with this control. The details of this are heavily implementation 
   dependent and are beyond the scope of this document. 
    
8. Notes for Implementers 
    
   Both client and server implementations MUST be aware that using this 
   control could potentially result in a very large set of search 
   results. Servers MAY return an adminLimitExceeded result in the 
   response control due to inordinate consumption of resources. This 
   may be due to some a priori knowledge such as a server restriction 
   of the number of attributes in the request control that it's willing 
   to service, or it may be due to the server attempting to service the 
   control and running out of resources. 
    
   Client implementations MUST be aware that when using this control, 
   search entries returned will contain a subset of the values of any 
   specified attribute. 
    
   If this control is used in a chained environment, servers SHOULD NOT 
   pass this control to other servers. Instead they SHOULD gather 
   results and apply this control themselves. 
    
9. Security Considerations 
    
   This control allows finer control of the result set returned by an 
   LDAP search operation and as such may be used in a denial of service 
   attack. See Section 8 for more information on how this is detected 
   and handled. 
    
10. Acknowledgments 
    
   The author gratefully thanks the input and support of participants 
   of the LDAP-EXT working group. 
    
11. References 
    
  
Sermersheim       Internet-Draft - Expires Mar 2003            Page 8 
LDAP Control for a Duplicate Entry Representation of Search Results 
 
 
   [RFC2251] 
   Wahl, M, S. Kille and T. Howes, "Lightweight Directory Access 
   Protocol (v3)", Internet RFC, December, 1997.  
   Available as RFC 2251. 
    
   [RFC2891] 
   Wahl, M, A. Herron and T. Howes, "LDAP Control Extension for Server 
   Side Sorting of Search Results", Internet RFC, August, 2000. 
   Available as RFC 2891. 
    
   [VLV] 
   Boreham, D, Sermersheim, J, Anantha, A, Armijo, M, "LDAP Extensions 
   for Scrolling View Browsing of Search Results", Internet Draft, 
   April, 2000. 
   Available as draft-ietf-ldapext-ldapv3-vlv-xx.txt. 
    
   [X.511] 
   ITU-T Rec. X.511, "The Directory: Abstract Service Definition", 
   1993. 
    
   [RFC2119] 
   Bradner, Scott, "Key Words for use in RFCs to Indicate Requirement 
   Levels", Internet Draft, March, 1997.  
   Available as RFC 2119. 
    
12. Author's Address 
    
   Jim Sermersheim 
   Novell, Inc. 
   1800 South Novell Place 
   Provo, Utah 84606, USA 
   jimse@novell.com 
   +1 801 861-3088 
 
    


















  
Sermersheim       Internet-Draft - Expires Mar 2003            Page 9 
alt-openldap11-devel/drafts/draft-zeilenga-ldap-dontusecopy-xx.txt000064400000024040150410163270021227 0ustar00





INTERNET-DRAFT                                   Kurt D. Zeilenga
Intended Category: Standard Track                Isode Limited
Expires in six months                            14 February 2007



                     The LDAP Don't Use Copy Control
                 <draft-zeilenga-ldap-dontusecopy-04.txt>


Status of this Memo

  This document is intended to be, after appropriate review and
  revision, submitted to the IESG for consideration as a Standard Track
  document.  Distribution of this memo is unlimited.  Technical
  discussion of this document will take place on the IETF LDAP
  Extensions mailing list <ldapext@ietf.org>.  Please send editorial
  comments directly to the author <Kurt.Zeilenga@Isode.COM>.

  By submitting this Internet-Draft, each author represents that any
  applicable patent or other IPR claims of which he or she is aware have
  been or will be disclosed, and any of which he or she becomes aware
  will be disclosed, in accordance with Section 6 of BCP 79.

  Internet-Drafts are working documents of the Internet Engineering Task
  Force (IETF), its areas, and its working groups. Note that other
  groups may also distribute working documents as Internet-Drafts.

  Internet-Drafts are draft documents valid for a maximum of six months
  and may be updated, replaced, or obsoleted by other documents at any
  time. It is inappropriate to use Internet-Drafts as reference material
  or to cite them other than as "work in progress."

  The list of current Internet-Drafts can be accessed at
  http://www.ietf.org/1id-abstracts.html.

  The list of Internet-Draft Shadow Directories can be accessed at
  http://www.ietf.org/shadow.html.


  Copyright (C) The IETF Trust (2007).  All Rights Reserved.

  Please see the Full Copyright section near the end of this document
  for more information.







Zeilenga               LDAP Don't Use Copy Control              [Page 1]

INTERNET-DRAFT     draft-zeilenga-ldap-dontusecopy-04   14 February 2007


Abstract

  This document defines the Lightweight Directory Access Protocol (LDAP)
  Don't Use Copy control extension which allows a client to specify that
  copied information should not be used in providing service.  This
  control is based upon the X.511 dontUseCopy service control option.


1.  Background and Intended Usage

  This document defines the Lightweight Directory Access Protocol (LDAP)
  [RFC4510] Don't Use Copy control extension.  The control may be
  attached to request messages to indicate that copied (replicated or
  cached) information [X.500] should not be used in providing service.
  This control is based upon the X.511 [X.511] dontUseCopy service
  control option.

  The Don't Use Copy control is intended to be used where the client
  requires the service be provided using original (master) information
  [X.500].


2. Terminology

  DSA stands for Directory System Agent (or server).
  DSE stands for DSA-specific Entry.

  The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  document are to be interpreted as described in BCP 14 [RFC2119].


3.  The Don't Use Copy Control

  The Don't Use Copy control is an LDAP Control [RFC4511] whose
  controlType is IANA-ASSIGNED-OID and controlValue is absent.  The
  criticality MUST be TRUE.  There is no corresponding response control.

  The control is appropriate for both LDAP interrogation operations,
  including Compare and Search operations [RFC4511].  It is
  inappropriate for all other operations, including Abandon, Bind,
  Delete, Modify, ModifyDN, StartTLS, and Unbind operations [RFC4511].

  When the control is attached to an LDAP request, the requested
  operation MUST NOT be performed on copied information.  That is, the
  requested operation MUST be performed on original information.

  If original information for the target or base object of the operation



Zeilenga               LDAP Don't Use Copy Control              [Page 2]

INTERNET-DRAFT     draft-zeilenga-ldap-dontusecopy-04   14 February 2007


  is not available (either locally or through chaining), the server MUST
  either return a referral directing the client to a server believed to
  be better able to service the request or return an appropriate result
  code (e.g., unwillingToPerform).

  Servers implementing this technical specification SHOULD publish the
  object identifier IANA-ASSIGNED-OID as a value of the
  'supportedControl' attribute [RFC4512] in their root DSE.  A server
  MAY choose to advertise this extension only when the client is
  authorized to use it.


4.  Security Considerations

  This control is intended to be provided where providing service using
  copied information might lead to unexpected application behavior.
  Designers of directory applications should consider where it is
  appropriate for clients to provide this control.  Designers should
  consider whether use of copied information, in particular security and
  policy information, may result insecure behavior.

  Security considerations for the base operations [RFC4511] extended by
  this control, as well as general LDAP security considerations
  [RFC4510], generally apply to implementation and use of this
  extension.


5.  IANA Considerations

5.1.  Object Identifier

  It is requested that IANA assign upon Standards Action an LDAP Object
  Identifier [RFC4520] to identify the LDAP Don't Use Copy Control
  defined in this document.

      Subject: Request for LDAP Object Identifier Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Specification: RFC XXXX
      Author/Change Controller: IESG
      Comments:
          Identifies the LDAP Don't Use Copy Control

5.2  LDAP Protocol Mechanism

  Registration of this protocol mechanism [RFC4520] is requested.

      Subject: Request for LDAP Protocol Mechanism Registration



Zeilenga               LDAP Don't Use Copy Control              [Page 3]

INTERNET-DRAFT     draft-zeilenga-ldap-dontusecopy-04   14 February 2007


      Object Identifier: IANA-ASSIGNED-OID
      Description: Don't Use Copy Control
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Usage: Control
      Specification: RFC XXXX
      Author/Change Controller: IESG
      Comments: none



6.  Author's Address

  Kurt D. Zeilenga
  Isode Limited

  Email: Kurt.Zeilenga@Isode.COM


7. References

  [[Note to the RFC Editor: please replace the citation tags used in
  referencing Internet-Drafts with tags of the form RFCnnnn where
  possible.]]


7.1. Normative References

  [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                Requirement Levels", BCP 14 (also RFC 2119), March 1997.

  [RFC4510]     Zeilenga, K. (editor), "LDAP: Technical Specification
                Road Map", RFC 4510, June 2006.

  [RFC4511]     Sermersheim, J. (editor), "LDAP: The Protocol", RFC
                4511, June 2006.

  [RFC4512]     Zeilenga, K. (editor), "LDAP: Directory Information
                Models", RFC 4512, June 2006.


7.2. Informative References

  [X.500]       International Telecommunication Union -
                Telecommunication Standardization Sector, "The Directory
                -- Overview of concepts, models and services,"
                X.500(1993) (also ISO/IEC 9594-1:1994).




Zeilenga               LDAP Don't Use Copy Control              [Page 4]

INTERNET-DRAFT     draft-zeilenga-ldap-dontusecopy-04   14 February 2007


  [X.511]       International Telecommunication Union -
                Telecommunication Standardization Sector, "The
                Directory: Abstract Service Definition", X.511(1993)
                (also ISO/IEC 9594-3:1993).

  [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                (IANA) Considerations for the Lightweight Directory
                Access Protocol (LDAP)", RFC 4520, BCP 64, June 2006.



Intellectual Property

  The IETF takes no position regarding the validity or scope of any
  Intellectual Property Rights or other rights that might be claimed to
  pertain to the implementation or use of the technology described in
  this document or the extent to which any license under such rights
  might or might not be available; nor does it represent that it has
  made any independent effort to identify any such rights.  Information
  on the procedures with respect to rights in RFC documents can be found
  in BCP 78 and BCP 79.

  Copies of IPR disclosures made to the IETF Secretariat and any
  assurances of licenses to be made available, or the result of an
  attempt made to obtain a general license or permission for the use of
  such proprietary rights by implementers or users of this specification
  can be obtained from the IETF on-line IPR repository at
  http://www.ietf.org/ipr.

  The IETF invites any interested party to bring to its attention any
  copyrights, patents or patent applications, or other proprietary
  rights that may cover technology that may be required to implement
  this standard.  Please address the information to the IETF at
  ietf-ipr@ietf.org.



Full Copyright

  Copyright (C) The IETF Trust (2007).

  This document is subject to the rights, licenses and restrictions
  contained in BCP 78, and except as set forth therein, the authors
  retain all their rights.

  This document and the information contained herein are provided on an
  "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND



Zeilenga               LDAP Don't Use Copy Control              [Page 5]

INTERNET-DRAFT     draft-zeilenga-ldap-dontusecopy-04   14 February 2007


  THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.















































Zeilenga               LDAP Don't Use Copy Control              [Page 6]

alt-openldap11-devel/drafts/draft-wahl-ldap-session-xx.txt000064400000104461150410163270017501 0ustar00


Network Working Group                                            M. Wahl
Internet-Draft                                     Informed Control Inc.
Intended status: Standards Track                             May 9, 2007
Expires: November 10, 2007


                     LDAP Session Tracking Control
                       draft-wahl-ldap-session-03

Status of this Memo

   By submitting this Internet-Draft, each author represents that any
   applicable patent or other IPR claims of which he or she is aware
   have been or will be disclosed, and any of which he or she becomes
   aware will be disclosed, in accordance with Section 6 of BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on November 10, 2007.

Copyright Notice

   Copyright (C) The IETF Trust (2007).














Wahl                    Expires November 10, 2007               [Page 1]

Internet-Draft        LDAP Session Tracking Control             May 2007


Abstract

   Many network devices, application servers, and middleware components
   of a enterprise software infrastructure generate some form of session
   tracking identifiers, which are useful when analyzing activity and
   accounting logs to group activity relating to a particular session.
   This document discusses how Lightweight Directory Access Protocol
   version 3 (LDAP) clients can include session tracking identifiers
   with their LDAP requests.  This information is provided through
   controls in the requests the clients send to LDAP servers.  The LDAP
   server receiving these controls can include the session tracking
   identifiers in the log messages it writes, enabling LDAP requests in
   the LDAP server's logs to be correlated with activity in logs of
   other components in the infrastructure.  The control also enables
   session tracking information to be generated by LDAP servers and
   returned to clients and other servers.  Three formats of session
   tracking identifiers are defined in this document.


































Wahl                    Expires November 10, 2007               [Page 2]

Internet-Draft        LDAP Session Tracking Control             May 2007


1.  Introduction

   The majority of directory server implementations produce access logs
   detailing each request they receive.  These logs can be read using
   log parsing tools or specialized log viewer applications.  Typically
   it will be possible, for each request logged by a directory server,
   to determine the bind DN (or possibly another form of authentication
   identity) of the client which sent the request to the server, and
   many servers also log the IP address of the client that sent the
   request.

   In the original OSI architecture, it was envisaged that users might
   interact with a directory service through specialized applications,
   known as Directory User Agents, which were the clients of the
   Directory Access Protocol.  Similarly, in early Internet directory
   deployments, a majority of LDAP clients were desktop applications,
   that used the LDAP protocol to search an enterprise directory for
   address book/contact information.

   Today, the majority of LDAP clients are embedded within middleware
   and server applications.  Legacy address book protocols might be
   gatewayed into LDAP, or a server might consult an LDAP server in
   order to check a user's password or obtain their preferences.  While
   the LDAP requests might result from a user's activity somewhere on
   the network, it is rare for the user to be 'driving' the LDAP client,
   and in most cases the user performing the activity is unaware that
   LDAP requests are being generated on their behalf.

   However, this information is important to directory system
   administrators and auditors.  They may wish to determine who is
   making use of the directory service, or track the source of unusual
   requests.

   When a directory server administrator reviews a log file produced by
   a directory server that has been accessed only by clients that are
   themselves middleware, where the end user does not interact with the
   middleware directly, only through other kinds of servers (e.g.
   application servers or remote access servers), it will be difficult
   to correlate between the directory server's log and the logs of the
   servers which made use of this directory to determine why the LDAP
   requests were made and who were responsible for causing them.

   Reasons for this include:

   o  Directory servers are capable of performing many hundreds of
      requests per second or more, and even with time synchronization
      between the systems on which the directory server and middleware
      are deployed, times of requests might not be logged accurately



Wahl                    Expires November 10, 2007               [Page 3]

Internet-Draft        LDAP Session Tracking Control             May 2007


      enough to be able to correlate based on time: the server's logs
      might be only to 1-second resolution.

   o  A single function on a middleware server, such as "authenticate a
      user", may result in multiple LDAP requests being generated in
      order to perform that request.

   o  Many high performance middleware servers implement connection
      pooling, managing a set of persistent connections to each
      directory server and multiplexing operations across the
      connections.  Each connection will have the same source IP address
      and bind DN.  If a particular activity causes multiple LDAP
      requests to be generated, each LDAP request might be sent on a
      different connection.  Also, as LDAP is an asynchronous protocol,
      middleware servers may have more than one request in progress on
      each connection, asynchronously sending requests to the directory
      server on each connection and processing the responses in whatever
      order they are received.

   This document defines a new control for use in LDAPv3 [1] operation
   requests.  This control contains session tracking information that
   can be used to correlate log information present in the directory
   server's log with the logs of other middleware servers.

   The words "MUST", "SHOULD" and "MAY" are used as defined in RFC 2119
   [2].

1.1.  Motivation for session tracking

   A typical enterprise deployment with an application indirectly
   relying upon the directory might resemble:


       +------+     +--------+       +----------+      +--------+
       | User |     | Appli- |       | Auth./   | LDAP |  LDAP  |
       |      +-----+ cation +-------+ Identity +------+ Server |
       |      |     | Server |       | Provider |      |        |
       |  A   |     |   B    |       |    C     |      |   D    |
       +------+     +--------+       +----------+      +--------+


   In this diagram, a user (A) makes some request of an application
   server (B).  The application server might rely on an integrated or
   external authentication provider in order to check the user's
   authentication credentials, or might use an identity provider to
   obtain profile information about the user.  This request might be
   made through an API or a protocol other than LDAP, e.g.  RADIUS,
   Kerberos, SMB, etc.  The authentication/identity provider (C) would



Wahl                    Expires November 10, 2007               [Page 4]

Internet-Draft        LDAP Session Tracking Control             May 2007


   generate one or more LDAP requests and send them to an LDAP server
   (D).

   The LDAP server has the following information already available to it
   through the LDAP protocol: the IP address and authentication
   credentials of the authentication/identity provider (C).  If the
   provider has included the Proxy Authorization Control [11], then the
   LDAP server might also receive the Distinguished Name or
   authorization identity of either the user (A) or the application
   server (B), depending on how the authentication/identity provider (C)
   uses the directory.  In order to obtain this distinguished name
   however, the authentication/identity provider (C) might need to
   perform one or more LDAP search or bind requests.  If there is no
   entry in the directory corresponding to the identity of the user (A)
   or the application server (B), then there is no way in the base LDAP
   specification or the Proxy Authorization Control for the
   authentication/identity provider (C) to describe the user (A) or the
   application server (B) to the LDAP server (D).

   If either the application server (B) or the authentication/identity
   provider (C) have generated a session identifier for tracking the
   interactions of the user (A) for a particular session, then it is
   useful to include this information with the requests made to the
   directory server, so that this session identifier will show up in the
   directory server's logs.  That is the purpose of the control defined
   in the next section.

























Wahl                    Expires November 10, 2007               [Page 5]

Internet-Draft        LDAP Session Tracking Control             May 2007


2.  Control definition

   There is currently no standard way of describing a session: there are
   many different formats for a session identifier, and each application
   that tracks sessions typically has its own semantics for what a
   session means.  Thus, a control is defined using an extensible model,
   in order to incorporate many different application's concepts and
   formats of a session tracking identifier.

   The value of the session identifier control encapsulates the
   following four pieces of information: sessionSourceIp,
   sessionSourceName, formatOID and sessionTrackingIdentifier.

   The sessionSourceIp field is a US-ASCII string encoding of an IPv4 or
   IPv6 [3] address of the component of the system which has generated a
   session tracking identifier.  The purpose of this field is to enable
   the directory server administrator, even if they do not have a log
   parser that understands a particular session tracking identifier
   format, to at least be able to identify the server that manages the
   session.  Note that there is no guarantee of IP-level connectivity
   between the directory server and the system which generated the
   tracking identifier, and if Network Address Translation is being
   used, the IP address in this field might be from a private use
   address range.

   The sessionSourceName field is a UTF-8 [4] encoded ISO 10646 [5] text
   string.  This field describes the component of the system which has
   generated a session tracking identifier.  The format of this field is
   determined by the formatOID (discussed below); examples of contents
   of a sessionSourceName field might be a hostname, a distinguished
   name, or a web service address.  This contents of this field is not
   intended to identify an end user; instead it identifies the server
   using a name other than the server's IP address.

   The formatOID is a US-ASCII encoded dotted decimal representation of
   an OBJECT IDENTIFIER.  The OBJECT IDENTIFIER indicates the scheme
   that is used to generate the sessionSourceName and
   sessionTrackingIdentifier fields.  As there is currently no standard
   scheme for session information, it is expected that there will be
   many different formats carried within this control.  The OBJECT
   IDENTIFIERs for three formats are presented in this document.

   The sessionTrackingIdentifier field is a UTF-8 encoded ISO 10646
   string.  The session identifier SHOULD be limited to whitespace and
   printable characters; non-printing and control characters SHOULD NOT
   be used, and byte sequences that are not legal UTF-8 MUST NOT be
   used.  The syntax of the session identifier and its semantics (e.g.,
   how values are compared for equality) are governed by the formatOID.



Wahl                    Expires November 10, 2007               [Page 6]

Internet-Draft        LDAP Session Tracking Control             May 2007


   For example, the session identifier might be a simple string encoding
   of a decimal counter, a username, a timestamp, a fragment of XML, or
   it might be something else, depending on the format.

2.1.  Formal definition

   This document defines a single LDAP control.

   The controlType is 1.3.6.1.4.1.21008.108.63.1, the criticality MUST
   be either FALSE or absent, and the controlValue MUST be present.  The
   controlValue OCTET STRING is always present and contains the bytes of
   the BER [6] encoding of a value of the ASN.1 data type
   SessionIdentifierControlValue, defined as follows:

      LDAP-Session-Identifier-Control
      DEFINITIONS IMPLICIT TAGS ::=
      BEGIN

      LDAPString ::= OCTET STRING -- UTF-8 encoded
      LDAPOID ::= OCTET STRING -- Constrained to numericoid

      SessionIdentifierControlValue ::= SEQUENCE {
           sessionSourceIp                 LDAPString,
           sessionSourceName               LDAPString,
           formatOID                       LDAPOID,
           sessionTrackingIdentifier       LDAPString
      }

      END

   The sessionSourceIp element SHOULD NOT be longer than 42 characters
   (the length necessary for a string representation of an IPv6
   address), and MUST NOT be longer than 128 characters.  Each character
   will be encoded into a single byte.  If the IP address of the system
   which generated the session tracking identifier is not known, the
   sessionSourceIp element SHOULD be of zero length.

   The sessionSourceName element SHOULD NOT be longer than 1024
   characters, and MUST NOT be longer than 65536 bytes.  Note that in
   the UTF-8 encoding a character MAY be encoded into more than one
   byte.  If no other addressing information about that system is known
   or relevant to the format, the sessionSourceName element SHOULD be of
   zero length.

   The formatOID element MUST contain only the US-ASCII encodings of the
   ISO 10646 characters FULL STOP and DIGIT ZERO through DIGIT NINE
   (0x2E, 0x30-0x39).  The formatOID element MUST NOT be of zero length,
   and SHOULD NOT be longer than 1024 characters.



Wahl                    Expires November 10, 2007               [Page 7]

Internet-Draft        LDAP Session Tracking Control             May 2007


   The sessionTrackingIdentifier field MAY be of zero length (although
   this might not be useful).  There is no upper bound on the
   sessionTrackingIdentifier, but it is suggested that values SHOULD NOT
   be longer than 65536 characters without prior agreement with the
   directory server administrator.  Note that in the UTF-8 encoding a
   character MAY be encoded into more than one byte.

2.2.  Use in LDAP

   The control MAY be included in any LDAP operation.  The control has
   order-dependent semantics.

   A client might place the control on a message with a bindRequest,
   searchRequest, modifyRequest, addRequest, delRequest, modDNRequest,
   compareRequest or extendedReq.  A client MAY include multiple
   controls of this type in a single request.  This enables the client
   to incorporate multiple distinct session tracking identifiers with
   different formats.

   When a network service is proxying or chaining LDAP, in which the
   service receives an incoming LDAP request from a client and from this
   generates one or more requests to other LDAP servers, the service
   SHOULD include any controls of this type that it received from
   clients in requests it generates, without modification.  A service
   MAY silently remove a control if that control would violate security
   policy.  If the service has its own session state identifier, it
   SHOULD include the session identifier control it generates in the
   Controls SEQUENCE after any session identifier controls received by
   clients.  (If there are multiple proxies involved, each will add
   their own session state to the end of the controls list).

   A server might place the control on message with a bindResponse,
   searchResDone, modifyResponse, addResponse, delResponse,
   modDNResponse, compareResponse, extendedResp or intermediateResponse.
   The server can include the control in the response regardless of
   whether the client included a control in the request or not.  (The
   control in a response is unsolicited, and a client which does not
   recognize the control or a session tracking format can safely ignore
   the control, as discussed in the following section).  A server MAY
   include multiple controls of this type in a response.

2.3.  Extensibility considerations

   The following section of this document defines 3 possible formats,
   and it is expected that applications MAY define their own formats to
   represent session tracking identifiers already implemented.

   An application developer or server developer who wishes to transfer



Wahl                    Expires November 10, 2007               [Page 8]

Internet-Draft        LDAP Session Tracking Control             May 2007


   their implementation's format for session tracking identifier within
   an LDAP control MUST choose a new, unique, OBJECT IDENTIFIER to
   represent this format.

   The format determines the semantics of the sessionSourceName string,
   and the sessionTrackingIdentifier string.

   In general, when an LDAP server that has session tracking logging
   enabled receives one or more of these controls with a request, the
   server SHOULD include all fields of all of the controls with the
   logging information for the request.

   A LDAP server that supports third-party or extensible log parsing
   tools SHOULD NOT reject or ignore a control if the formatOID value is
   not recognized, as it is expected that applications may include
   session tracking identifiers and want to make this information
   available to log parsers for correlation purposes, even if the
   directory server does not need to make any use of this information.

   However, if the LDAP server does not recognize the control, the
   control is not properly formatted, or the LDAP client is not
   authorized to use this control, the LDAP server SHOULD ignore the
   control and process the request as if the control had not been
   included.

   When an LDAP client receives a response that includes this control,
   the behavior depends on the client implementation.  Clients SHOULD
   silently ignore controls with formats they do not recognize, and
   process the response as if the control had not been included.






















Wahl                    Expires November 10, 2007               [Page 9]

Internet-Draft        LDAP Session Tracking Control             May 2007


3.  Session tracking format definitions

   This section defines three session tracking formats that can be used
   within the session tracking control: two for RADIUS accounting, and
   one based on usernames.  Other formats can be defined in other
   documents.

3.1.  Formats for use with RADIUS accounting

   This section defines two possible session tracking formats, that can
   be used in LDAP clients that are part of or used by RADIUS servers
   [7].

   With formatOID set to 1.3.6.1.4.1.21008.108.63.1.1 within the control
   value, the sessionTrackingIdentifier SHOULD contain the value of the
   Acct-Session-Id RADIUS attribute (type 44), as defined in RFC 2866
   [8].  (RFC 2866 section 5.5 states that the Acct-Session-Id SHOULD
   contain UTF-8 encoded ISO 10646 characters.)

   With formatOID set to 1.3.6.1.4.1.21008.108.63.1.2 within the control
   value, the sessionTrackingIdentifier SHOULD contain the value of the
   Acct-Multi-Session-Id RADIUS attribute (type 50), as defined in RFC
   2866 [8].  (RFC 2866 section 5.11 states that the
   Acct-Multi-Session-Id SHOULD contain UTF-8 encoded ISO 10646
   characters.)

   In both of these two formats, the value of the sessionSourceIp field
   SHOULD contain either a string encoding value of the IPv4 address
   from the NAS-IP-Address RADIUS attribute (type 4), or a string
   encoding of the IPv6 address from the value of the NAS-IPv6-Address
   RADIUS attribute (type 95) as defined in RFC 3162 [9].  The value of
   the sessionSourceName field SHOULD contain a string encoding the
   value of the NAS-Identifier RADIUS attribute (type 32), if present,
   or be of zero length if the NAS-Identifier RADIUS attribute was not
   provided or was not in a recognized format.

3.2.  Format for username accounting

   This section defines another possible session tracking format that
   can be used in LDAP clients that are part of applications which
   identify users with simple string usernames.

   With formatOID set to 1.3.6.1.4.1.21008.108.63.1.3 within the control
   value, the sessionTrackingIdentifier SHOULD contain a username that
   has already been authenticated by the application that is generating
   the session.  This format SHOULD NOT be used for purported names,
   where the application has not verified that the username is valid.




Wahl                    Expires November 10, 2007              [Page 10]

Internet-Draft        LDAP Session Tracking Control             May 2007


   The sessionSourceName field SHOULD contain the hostname where that
   application is running, or be of zero length if the hostname is not
   known.

   The username SHOULD be a SASL authorization identity string, as
   described in section 3.4.1 of RFC 4422 [10].  It is expected that
   these usernames are not globally unique, but are only unique within
   the context of a particular application or particular enterprise.  A
   username need not be a distinguished name, and an implementation
   receiving a control in this format MUST NOT assume that the contents
   of the sessionTrackingIdentifier can be parsed as a distinguished
   name.

   A control with this format differs from the Proxied Authorization
   Control as defined in RFC 4370 [11], as the presence of this session
   identifier control on a request SHOULD NOT influence the directory
   server's access control decision of whether or how to perform that
   request.

   Note that this format does not provide any information to
   differentiate between multiple sessions or periods of interaction by
   the same user.  It is primarily intended for deployments which merely
   need to be able to tie each directory operation to they identity of
   the user whose activities caused the operation request to be
   generated, even if the user might not even be represented in the
   directory where the operations are being performed.

3.2.1.  Example

   For example, if an application server "app.example.com" with IPv4
   address "192.0.2.1" had authenticated an user with name "bloggs", and
   then sent a search request to the LDAP directory in order to obtain
   some public information on service configuration intending to provide
   it to that user, the application might include a session identifier
   control.  The SessionIdentifierControlValue would have the following
   ASN.1 value prior to encoding:


      {  -- SEQUENCE
         "192.0.2.1",                    -- sessionSourceIp
         "app.example.com",              -- sessionSourceName
         "1.3.6.1.4.1.21008.108.63.1.3", -- formatOID
         "bloggs"                        -- sessionTrackingIdentifier
      }







Wahl                    Expires November 10, 2007              [Page 11]

Internet-Draft        LDAP Session Tracking Control             May 2007


   The session identifier control would be sent with controlType
   1.3.6.1.4.1.21008.108.63.1, criticality FALSE, and the controlValue
   the BER encoding of the SessionIdentifierControlValue.  The control
   included with the LDAP request would resemble:


      {  -- SEQUENCE
         "1.3.6.1.4.1.21008.108.63.1", -- controlType
         FALSE,                        -- criticality
         '304204093139322e302e322e31040f6170702e6578616d706c652e636f6d
          041c312e332e362e312e342e312e32313030382e3130382e36332e312e33
          0406626c6f676773'H           -- controlValue
      }






































Wahl                    Expires November 10, 2007              [Page 12]

Internet-Draft        LDAP Session Tracking Control             May 2007


4.  Security Considerations

   The session identifier controls used in this document are not
   intended as a security control or proxy authentication mechanism, and
   SHOULD NOT be used within a directory server to influence the
   operation processing behavior.

   Malicious clients might attempt to provide false or misleading
   information in directory server logs through the use of this control.
   LDAP servers SHOULD implement access checks which limit whether
   session identifier information provided by a client is logged.  LDAP
   servers which implement this control SHOULD permit the administrator
   of the directory server to configure that this control is ignored
   unless the request containing the control was received from a client
   that been authenticated.  LDAP servers which implement this control
   SHOULD permit the administrator of the directory server to configure
   that this control is ignored unless the client is authorized to use
   this or related controls, such as the Proxied Authorization Control
   [11].  Session identifier information from clients which do not meet
   the server's access check requirement SHOULD be silently discarded.

   In some formats, session tracking identifiers may contain personal-
   identifiable information, such as usernames or client IP addresses.
   Unless data link, network or transport level encryption is being
   used, this information might be visible to attackers monitoring the
   network segments across which this information is being transmitted.
   Implementations of LDAP clients which include this control in
   requests sent to directory servers SHOULD support the use of
   underlying security services that establish connection
   confidentiality before the control is sent, such as a SASL mechanism
   that negotiates a security layer, or the Start TLS operation.

   Correlation of activities across multiple servers can enable
   administrators and monitoring tools to construct a more accurate
   picture of user behavior.  In particular, this tracking control could
   be used to determine the set of applications and services with which
   a particular user has had interactions.  Thus, this control would not
   be appropriate to deployments intending to anonymize directory
   requests.  Session formats containing personal identifiable
   information SHOULD NOT be used between systems in different
   organizations where there is no existing agreement between those
   organizations on privacy protection.

   A value of the session tracking control might contain internal IP
   addresses, hostnames and other identifiers that reveal the structure
   of an enterprise network.  A network service that generates its own
   sessions SHOULD NOT send a session tracking control to a directory
   server that is under different administration or in a different



Wahl                    Expires November 10, 2007              [Page 13]

Internet-Draft        LDAP Session Tracking Control             May 2007


   security enclave from itself.  A network service that is an LDAP
   client and also either receives requests over another protocol that
   contains session tracking identifiers or is proxying incoming LDAP
   requests SHOULD NOT forward received session tracking identifiers to
   a directory server that is under different administration or in a
   different security enclave from itself.  A packet inspecting firewall
   that permits outgoing LDAP requests from an enterprise network SHOULD
   silently remove any session tracking controls from requests that are
   being sent to directory servers outside of the enterprise network for
   which there is not a preexisting policy configured to allow the
   session tracking control to be sent to that directory server.








































Wahl                    Expires November 10, 2007              [Page 14]

Internet-Draft        LDAP Session Tracking Control             May 2007


5.  IANA Considerations

   This control will be registered as follows:

      Subject: Request for LDAP Protocol Mechanism Registration

      Object Identifier: 1.3.6.1.4.1.21008.108.63.1

      Description: Session Tracking Identifier

      Person & email address to contact for further information:
      Mark Wahl <Mark.Wahl@informed-control.com>

      Usage: Control

      Specification: (I-D) RFC XXXX

      Author/Change Controller: Mark Wahl


   The OBJECT IDENTIFIER for particular session identifier formats
   defined for other applications need not be registered with IANA.





























Wahl                    Expires November 10, 2007              [Page 15]

Internet-Draft        LDAP Session Tracking Control             May 2007


6.  Acknowledgments

   This control was inspired by conversations with Greg Lavender.  Neil
   Wilson provided useful feedback on this document.















































Wahl                    Expires November 10, 2007              [Page 16]

Internet-Draft        LDAP Session Tracking Control             May 2007


7.  References

7.1.  Normative References

   [1]   Zeilenga, K., "Lightweight Directory Access Protocol (LDAP):
         Technical Specification Road Map", RFC 4510, June 2006.

   [2]   Bradner, S., "Key words for use in RFCs to Indicate Requirement
         Levels", RFC 2119, BCP 14, March 1997.

   [3]   Hinden, R., "IP Version 6 Addressing Architecture", RFC 1884,
         January 1996.

   [4]   Yergeau, F., "UTF-8, a transformation format of ISO 10646",
         RFC 3629, November 2003.

   [5]   "Universal Multiple-Octet Coded Character Set (UCS) -
         Architecture and Basic Multilingual Plane, ISO/IEC 10646-1:
         1993".

   [6]   "ITU-T Rec. X.690 (07/2002) | ISO/IEC 8825-1:2002, "Information
         technology - ASN.1 encoding rules: Specification of Basic
         Encoding Rules (BER), Canonical Encoding Rules (CER) and
         Distinguished Encoding Rules (DER)", 2002.".

   [7]   Rigney, C., "Remote Authentication Dial In User Service
         (RADIUS)", RFC 2865, June 2000.

   [8]   Rigney, C., "RADIUS Accounting", RFC 2866, June 2000.

   [9]   Aboba, B., "RADIUS and IPv6", RFC 3162, August 2001.

   [10]  Melnikov, A., "Simple Authentication and Security Layer
         (SASL)", RFC 4422, June 2006.

7.2.  Informative References

   [11]  Weltman, R., "Lightweight Directory Access Protocol (LDAP)
         Proxied Authorization Control", RFC 4370, February 2006.












Wahl                    Expires November 10, 2007              [Page 17]

Internet-Draft        LDAP Session Tracking Control             May 2007


Appendix A.  Copyright

   Copyright (C) The IETF Trust (2007).  This document is subject to the
   rights, licenses and restrictions contained in BCP 78, and except as
   set forth therein, the authors retain all their rights.  This
   document and the information contained herein are provided on an "AS
   IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR
   IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.







































Wahl                    Expires November 10, 2007              [Page 18]

Internet-Draft        LDAP Session Tracking Control             May 2007


Author's Address

   Mark Wahl
   Informed Control Inc.
   PO Box 90626
   Austin, TX  78709
   US

   Email: mark.wahl@informed-control.com










































Wahl                    Expires November 10, 2007              [Page 19]

Internet-Draft        LDAP Session Tracking Control             May 2007


Full Copyright Statement

   Copyright (C) The IETF Trust (2007).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.


Acknowledgment

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).





Wahl                    Expires November 10, 2007              [Page 20]

alt-openldap11-devel/drafts/draft-legg-ldap-transfer-xx.txt000064400000056402150410163270017626 0ustar00INTERNET-DRAFT                                                   S. Legg
draft-legg-ldap-transfer-03.txt                      Adacel Technologies
Intended Category: Standards Track                          16 June 2004
Updates: RFC 2252bis


             Lightweight Directory Access Protocol (LDAP):
                       Transfer Encoding Options

    Copyright (C) The Internet Society (2004). All Rights Reserved.

   Status of this Memo


   This document is an Internet-Draft and is in full conformance with
   all provisions of Section 10 of RFC2026.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as
   Internet-Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress".

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This document is intended to be, after appropriate review and
   revision, submitted to the RFC Editor as a Standard Track document.
   Distribution of this document is unlimited.  Technical discussion of
   this document should take place on the IETF LDAP Revision Working
   Group (LDAPbis) mailing list <ietf-ldapbis@openldap.org>.  Please
   send editorial comments directly to the editor
   <steven.legg@adacel.com.au>.

   This Internet-Draft expires on 16 December 2004.


Abstract

   Each attribute stored in a Lightweight Directory Access Protocol
   (LDAP) directory has a defined syntax (i.e., data type).  A syntax



Legg                    Expires 16 December 2004                [Page 1]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


   definition specifies how attribute values conforming to the syntax
   are normally represented when transferred in LDAP operations.  This
   representation is referred to as the LDAP-specific encoding to
   distinguish it from other methods of encoding attribute values.  This
   document introduces a new category of attribute options, called
   transfer encoding options, which can be used to specify that the
   associated attribute values are encoded according to one of these
   other methods.











































Legg                    Expires 16 December 2004                [Page 2]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
   2.  Conventions. . . . . . . . . . . . . . . . . . . . . . . . . .  3
   3.  Transfer Encoding Options. . . . . . . . . . . . . . . . . . .  4
   4.  Defined Transfer Encoding Options. . . . . . . . . . . . . . .  5
   5.  Attributes Returned in a Search. . . . . . . . . . . . . . . .  6
   6.  Syntaxes Requiring Binary Transfer . . . . . . . . . . . . . .  7
   7.  Security Considerations. . . . . . . . . . . . . . . . . . . .  7
   8.  IANA Considerations. . . . . . . . . . . . . . . . . . . . . .  8
   9.  References . . . . . . . . . . . . . . . . . . . . . . . . . .  9
       9.1.  Normative References . . . . . . . . . . . . . . . . . .  9
       9.2.  Informative References . . . . . . . . . . . . . . . . . 10
   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 10
   Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 10

1.  Introduction

   Each attribute stored in a Lightweight Directory Access Protocol
   (LDAP) directory [ROADMAP] has a defined syntax (i.e., data type)
   which constrains the structure and format of its values.

   The description of each syntax [SYNTAX] specifies how attribute or
   assertion values [MODELS] conforming to the syntax are normally
   represented when transferred in LDAP operations [PROT].  This
   representation is referred to as the LDAP-specific encoding to
   distinguish it from other methods of encoding attribute values.

   This document introduces a new category of attribute options
   [MODELS], called transfer encoding options, that allow attribute and
   assertion values to be transferred using an alternative method of
   encoding.  This document defines several transfer encoding options
   which can be used in an attribute description [MODELS] in an LDAP
   operation to specify that the associated attribute values or
   assertion value are, or are requested to be, encoded according to
   specific Abstract Syntax Notation One (ASN.1) [X680] encoding rules,
   instead of the usual LDAP-specific encoding.  One option in
   particular allows Extensible Markup Language (XML) [XML] encodings.

2.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and  "OPTIONAL" in this
   document are to be interpreted as described in BCP 14, RFC 2119
   [KEYWORD].

   This specification makes use of definitions from the XML Information
   Set (Infoset) [ISET].  In particular, information item property names



Legg                    Expires 16 December 2004                [Page 3]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


   are presented per the Infoset, e.g., [local name].

3.  Transfer Encoding Options

   Transfer encoding options enable attribute and assertion values to be
   transferred using an alternative method of encoding to the default
   LDAP-specific encoding.  In fact, some attribute and assertion
   syntaxes do not have a defined LDAP-specific encoding in which case
   the only way values of those syntaxes can be transferred is by using
   an alternative encoding.

   The binary option [BINARY] is not formally regarded as a transfer
   encoding option, though it has much in common with transfer encoding
   options.  The requirements governing the use of transfer encoding
   options do not apply to the binary option.  The requirements
   governing the use of the binary option are described elsewhere
   [BINARY].

   In terms of the protocol [PROT], a transfer encoding option specifies
   that the contents octets of an associated AttributeValue or
   AssertionValue OCTET STRING are a complete encoding of the relevant
   value according to the encoding method specified by the option.

   Where a transfer encoding option is present in an attribute
   description the associated attribute values or assertion value MUST
   be encoded according to the encoding method corresponding to the
   option.  Note that it is possible for a syntax to be defined such
   that its LDAP-specific encoding is exactly the same as its encoding
   according to some transfer encoding option (e.g., the LDAP-specific
   encoding might be defined to be the same as the BER encoding).

   Transfer encoding options are mutually exclusive.  An attribute
   description SHALL NOT contain more than one transfer encoding option,
   and SHALL NOT contain both a transfer encoding option and the binary
   option.

   Transfer encoding options are not tagging options [MODELS] so the
   presence of a transfer encoding option does not specify an attribute
   subtype.  An attribute description containing a transfer encoding
   option references exactly the same attribute as the same attribute
   description without the transfer encoding option.  The
   supertype/subtype relationships of attributes with tagging options
   are not altered in any way by the presence or absence of transfer
   encoding options.

   An attribute description SHALL be treated as unrecognized if it
   contains a transfer encoding option and the syntax of the attribute
   does not have an associated ASN.1 type [SYNTAX], or if the nominated



Legg                    Expires 16 December 2004                [Page 4]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


   encoding is not supported for that type.

   The presence or absence of a transfer encoding option only affects
   the transfer of attribute and assertion values in protocol; servers
   store any particular attribute value in a single format of their
   choosing.

4.  Defined Transfer Encoding Options

   The attribute option string "transfer-ber" specifies that the
   associated attribute values or assertion value are (to be) encoded
   according to the Basic Encoding Rules [X690] of ASN.1.  This option
   is similar to the binary option [BINARY], however servers are more
   restricted in when they can use "transfer-ber" which leads to more
   predictability in the results returned to clients who request
   "transfer-ber".

   The attribute option string "transfer-der" specifies that the
   associated attribute values or assertion value are (to be) encoded
   according to the Distinguished Encoding Rules [X690] of ASN.1.

   The attribute option string "transfer-gser" specifies that the
   associated attribute values or assertion value are (to be) encoded
   according to the Generic String Encoding Rules (GSER) [RFC3641].

   The attribute option string "transfer-rxer" specifies that the
   associated attribute values or assertion value are (to be) encoded as
   an XML document [XML].  The [local name] of the [document element] of
   the document information item representing the associated value SHALL
   be the identifier of the NamedType [X680] in the LDAP ASN.1
   specification [PROT] defining the associated attribute value or
   assertion value, or "item" if the associated value isn't in a
   NamedType.  This means:

    - for an AttributeValue the identifier is "value" in every case,

    - for an AssertionValue in an AttributeValueAssertion the identifier
      is "assertionValue",

    - for an AssertionValue in a SubstringFilter the identifier is
      "initial", "any" or "final", as appropriate,

    - for an AssertionValue in a MatchingRuleAssertion the identifier is
      "matchValue".

   The [namespace name] of the [document element] SHALL have no value.
   The content of the [document element] is the Robust XML Encoding
   Rules (RXER) [RXER] encoding of the associated attribute or assertion



Legg                    Expires 16 December 2004                [Page 5]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


   value.  Note that the enclosing element for the RXER encoding has the
   form it would take in an XLDAP operation [XLDAP].

   Note that, like all attribute options, the strings representing
   transfer encoding options are case insensitive.

   All future registrations of option strings for transfer encoding
   options should use the "transfer-" prefix so that LDAP clients and
   servers can recognize that an option is a transfer encoding option
   even though the particular encoding rules may be unrecognized.

5.  Attributes Returned in a Search

   An LDAP search request [PROT] contains a list of the attributes (the
   requested attributes list) to be returned from each entry matching
   the search filter.  An attribute description in the requested
   attributes list also implicitly requests all subtypes of the
   attribute type in the attribute description, whether through
   attribute subtyping or attribute tagging option subtyping [MODELS].

   The requested attributes list MAY contain attribute descriptions with
   a transfer encoding option, but MUST NOT contain two attribute
   descriptions with the same attribute type and the same tagging
   options (even if only one of them has a transfer encoding option).  A
   transfer encoding option in an attribute description in the requested
   attributes list implicitly applies to the subtypes of the attribute
   type in the attribute description.

   If the list of attributes in a search request is empty, or contains
   the special attribute description string "*", then all user
   attributes are requested to be returned.

   In general, it is possible for a particular attribute to be
   explicitly requested by an attribute description and/or implicitly
   requested by the attribute descriptions of one or more of its
   supertypes.  In such cases the effective transfer encoding being
   requested for a particular attribute is determined by the transfer
   encoding option (or lack thereof) in the most specific attribute
   description in the requested attributes list that applies to the
   attribute.

   An applicable attribute description with an actual attribute type is
   more specific than the special attribute description string "*".

   If the attribute type of one applicable attribute description is a
   direct or indirect subtype of the attribute type in another
   applicable attribute description then the former attribute
   description is more specific than the latter attribute description.



Legg                    Expires 16 December 2004                [Page 6]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


   If two applicable attribute descriptions have the same attribute type
   and the tagging options of one attribute description are a superset
   of the tagging options of the other attribute description then the
   former attribute description is more specific than the latter
   attribute description.

   Attributes MUST either be returned in the effective transfer encoding
   requested, be returned with no attribute values, or be omitted from
   the results.  An attribute SHALL NOT be returned using an encoding
   other than the effective transfer encoding requested.

   Regardless of the encoding chosen, a particular attribute value is
   returned at most once.

6.  Syntaxes Requiring Binary Transfer

   Certain syntaxes are required to be transferred in the BER encoded
   form.  These syntaxes are said to have a binary transfer requirement.
   The Certificate, Certificate List, Certificate Pair and Supported
   Algorithm syntaxes [PKI] are examples of syntaxes with a binary
   transfer requirement.  These syntaxes also have an additional
   requirement that the exact BER encoding must be preserved.  Note that
   this is a property of the syntaxes themselves, and not a property of
   the binary option or any of the transfer encoding options.

   Transfer encoding options SHALL take precedence over the requirement
   for binary transfer.  For example, if the effective transfer encoding
   requested is say "transfer-gser", then attribute values of a syntax
   with a binary transfer requirement will be GSER encoded.  In the
   absence of a transfer encoding option the normal rules on binary
   transfer and the use of the binary option SHALL apply.

7.  Security Considerations

   There is a requirement on some attribute syntaxes that the exact BER
   encoding of values of that syntax be preserved.  In general, a
   transformation from the BER encoding into some other encoding (e.g.,
   GSER) and back into the BER encoding will not necessarily reproduce
   exactly the octets of the original BER encoding.

   Applications needing the original BER encoding to be preserved, e.g.,
   for the verification of digital signatures, MUST NOT request
   attributes with such a requirement using a transfer encoding option.
   These attributes MUST be requested explicitly or implicitly with the
   binary option, or implicitly without the binary option (or any
   transfer encoding option).

   When interpreting security-sensitive fields, and in particular fields



Legg                    Expires 16 December 2004                [Page 7]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


   used to grant or deny access, implementations MUST ensure that any
   matching rule comparisons are done on the underlying abstract value,
   regardless of the particular encoding used.

8.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) is requested to update
   the LDAP attribute description option registry [BCP64] as indicated
   by the following templates:

      Subject: Request for
        LDAP Attribute Description Option Registration
      Option Name: transfer-ber
      Family of Options: NO
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Specification: RFC XXXX
      Author/Change Controller: IESG
      Comments:

      Subject: Request for
        LDAP Attribute Description Option Registration
      Option Name: transfer-der
      Family of Options: NO
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Specification: RFC XXXX
      Author/Change Controller: IESG
      Comments:

      Subject: Request for
        LDAP Attribute Description Option Registration
      Option Name: transfer-gser
      Family of Options: NO
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Specification: RFC XXXX
      Author/Change Controller: IESG
      Comments:

      Subject: Request for
        LDAP Attribute Description Option Registration
      Option Name: transfer-rxer
      Family of Options: NO
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Specification: RFC XXXX
      Author/Change Controller: IESG



Legg                    Expires 16 December 2004                [Page 8]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


      Comments:

9.  References

9.1.  Normative References

   [KEYWORD]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [BCP64]    Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protcol (LDAP)", BCP 64, RFC 3383, September 2002.

   [ROADMAP]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map",
              draft-ietf-ldapbis-roadmap-xx.txt, a work in progress,
              June 2004.

   [MODELS]   Zeilenga, K., "LDAP: Directory Information Models",
              draft-ietf-ldapbis-models-xx.txt, a work in progress, June
              2004.

   [PROT]     Sermersheim, J., "LDAP: The Protocol",
              draft-ietf-ldapbis-protocol-xx.txt, a work in progress,
              May 2004.

   [SYNTAX]   Legg, S. and K. Dally, "Lightweight Directory Access
              Protocol (LDAP): Syntaxes and Matching Rules",
              draft-ietf-ldapbis-syntaxes-xx.txt, a work in progress,
              May 2004.

   [RFC3641]  Legg, S., "Generic String Encoding Rules (GSER) for ASN.1
              Types", RFC 3641, October 2003.

   [BINARY]   Legg, S., "Lightweight Directory Access Protocol (LDAP):
              The Binary Encoding Option",
              draft-legg-ldap-binary-xx.txt, a work in progress, June
              2004.

   [RXER]     Legg, S. and D. Prager, "Robust XML Encoding Rules for
              ASN.1 Types", draft-legg-xed-rxer-00.txt, a work in
              progress, June 2004.

   [X680]     ITU-T Recommendation X.680 (07/02) | ISO/IEC 8824-1,
              Information technology - Abstract Syntax Notation One
              (ASN.1): Specification of basic notation.

   [X690]     ITU-T Recommendation X.690 (07/02) | ISO/IEC 8825-1,



Legg                    Expires 16 December 2004                [Page 9]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


              Information Technology - ASN.1 encoding rules:
              Specification of Basic Encoding Rules (BER), Canonical
              Encoding Rules (CER) and Distinguished Encoding Rules
              (DER).

   [XML]      Bray, T., Paoli, J., Sperberg-McQueen, C., Maler, E. and
              F. Yergeau, "Extensible Markup Language (XML) 1.0 (Third
              Edition)", W3C Recommendation,
              http://www.w3.org/TR/2004/REC-xml-20040204, February 2004.

   [ISET]     Cowan, J. and R. Tobin, "XML Information Set",
              http://www.w3.org/TR/2001/REC-xml-infoset-20011024,
              October 2001.

9.2.  Informative References

   [XLDAP]    Legg, S. and D. Prager, "The XML Enabled Directory:
              Protocols", draft-legg-xed-protocols-xx.txt, a work in
              progress, May 2004.

Author's Address

   Steven Legg
   Adacel Technologies Ltd.
   250 Bay Street
   Brighton, Victoria 3186
   AUSTRALIA

   Phone: +61 3 8530 7710
     Fax: +61 3 8530 7888
   Email: steven.legg@adacel.com.au

Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property




Legg                    Expires 16 December 2004               [Page 10]

INTERNET-DRAFT       LDAP: Transfer Encoding Options       June 16, 2004


   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Changes in Draft 01

   A transfer encoding option for RXER has been added.

Changes in Draft 02

   The local name of the root element of the XML document representing
   an attribute value encoded according to the transfer-rxer encoding
   option has been changed from "item" to "value" to align with
   revisions to the LDAP protocol specification [PROT].

   The Directory XML Encoding Rules (DXER) have been renamed to the
   Robust XML Encoding Rules (RXER).

Changes in Draft 03

   The special attribute description strings that consist of the
   asterisk character followed by a transfer encoding option, e.g.,
   "*;transfer-ber", "*;transfer-gser", have been removed from this
   specification.  An LDAP control will be defined in a separate
   document to provide equivalent functionality.








Legg                    Expires 16 December 2004               [Page 11]


alt-openldap11-devel/drafts/draft-sermersheim-ldap-subordinate-scope-xx.txt000064400000025522150410163300023026 0ustar00
Network Working Group                                    J;. Sermersheim
Internet-Draft                                               Novell, Inc
Updates: 2251 (if approved)                                    July 2004
Expires: December 30, 2004


               Subordinate Subtree Search Scope for LDAP
              draft-sermersheim-ldap-subordinate-scope-00.txt

Status of this Memo

   This document is an Internet-Draft and is subject to all provisions
   of section 3 of RFC 3667.  By submitting this Internet-Draft, each
   author represents that any applicable patent or other IPR claims of
   which he or she is aware have been or will be disclosed, and any of
   which he or she become aware will be disclosed, in accordance with
   RFC 3668.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as
   Internet-Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on December 30, 2004.

Copyright Notice

   Copyright (C) The Internet Society (2004).

Abstract

   The Lightweight Directory Application Protocol (LDAP) specification
   supports three scope values for the search operation -- namely:
   baseObject, singleLevel, and wholeSubtree.  This document introduces
   a subordinateSubtree scope which constrains the search scope to all
   subordinates of the named base object.

Discussion Forum



Sermersheim            Expires December 30, 2004                [Page 1]

Internet-Draft    Subordinate Subtree Search Scope for LDAP    July 2004


   Technical discussion of this document will take place on the IETF
   LDAP Extensions mailing list <ldapext@ietf.org>.  Please send
   editorial comments directly to the author.

1.  Overview

   There are a number of reasons which have surfaced for introducing a
   Lightweight Directory Application Protocol (LDAP) [RFC3377]
   SearchRequest.scope [RFC2251] which constrains the search scope to
   all subordinates of the named base object, and does not include the
   base object (as wholeSubtree does).  These reasons range from the
   obvious utility of allowing an LDAP client application the ability to
   exclude the base object from a wholeSubtree search scope, to
   distributed operation applications which require this scope for
   progressing search sub-operations resulting from an nssr DSE type
   reference.

   To meet these needs, the subordinateSubtree scope value is
   introduced.

   The subordinateSubtrees cope is applied to the SearchRequest.scope
   field, the <scope> type and alternately the <extension> type of the
   LDAP URL [RFC2255] and may be applied to other specifications which
   include an LDAP search scope.  A mechanism is also given which allows
   LDAP Directory Server Agents (DSA)s to advertise support of this
   search scope.

2.  Application to SearchRequest.scope

   A new item is added to this ENUMERATED type.  The identifier is
   subordinateSubtree and the number is 4.

   A DSA which receives and supports the subordinateSubtree
   SearchRequest.scope constrains the search scope to all subordinate
   objects.

   A DSA which receives but does not support the subordinateSubtree
   SearchRequest.scope returns a protocolError resultCode in the
   SearchResultDone.

3.  LDAP URL applications

   The LDAP URL [RFC2255] specification allows the conveyance of a
   search scope.  This section intoduces two ways in which the
   subordinateScope search scope may be conveyed in an LDAP URL.  One
   way is by allowing a new "subord" scope in the <scope> part.  Another
   way is through the introduction of an LDAP URL extension.  The LDAP
   URL extension method is preferred for its criticality semantics.



Sermersheim            Expires December 30, 2004                [Page 2]

Internet-Draft    Subordinate Subtree Search Scope for LDAP    July 2004


3.1  Application to LDAP URL <scope>

   A new <scope> value of "subord" is added.  Using the <scope> type
   from LDAP URL [RFC2255], the ABNF is as follows:

   scope /= "subord"

   Implementations processing but which do not understand or support the
   "subord" <scope> of an LDAP URL raise an appropriate error.

3.2  Application to LDAP URL <extension>

   An LDAP URL <extension> mechanism is introduced here.  The <extype>
   is IANA-ASSIGNED-OID.1 or the descriptor 'subordScope', and the
   exvalue is omitted.  The extension may be marked as either critical
   or non-critical.

   If supported, the subordScope extension overrides any value set in
   the <scope> field.

4.  DSA Advertisement of support

   A DSA may advertise its support of the subordinateSubtree item in the
   SearchRequest.scope by inclusion of IANA-ASSIGNED-OID.2 in the
   'supportedFeatures' attribute of the root DSE.

5.  Security Considerations

   This specification introduces no security concerns above any
   associated with the existing wholeSubtree search scope value.

   As with the wholeSubtree search scope, this scope specifies that a
   search be applied to an entire subtree hierarchy.  Implementations
   should be aware of the relative cost of using or allowing this scope.

6  Normative References

   [RFC2251]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2255]  Howes, T. and M. Smith, "The LDAP URL Format", RFC 2255,
              December 1997.

   [RFC3377]  Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)



Sermersheim            Expires December 30, 2004                [Page 3]

Internet-Draft    Subordinate Subtree Search Scope for LDAP    July 2004


              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.


Author's Address

   Jim Sermersheim
   Novell, Inc
   1800 South Novell Place
   Provo, Utah  84606
   USA

   Phone: +1 801 861-3088
   EMail: jimse@novell.com

Appendix A.  IANA Considerations

   Registration of the following values is requested [RFC3383].

A.1  LDAP Object Identifier Registrations

   It is requested that IANA register upon Standards Action an LDAP
   Object Identifier in identifying the protocol elements defined in
   this technical specification.  The following registration template is
   provided:

      Subject: Request for LDAP OID Registration
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments:
      2 delegations will be made under the assigned OID:
         IANA-ASSIGNED-OID.1 subordScope LDAP URL extension
         IANA-ASSIGNED-OID.2 subordinateScope Supported Feature

A.2  LDAP Protocol Mechanism Registrations

   It is requested that IANA register upon Standards Action the LDAP
   protocol mechanism described in this document.  The following
   registration templates are given:

      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID.1
      Description: subordScope LDAP URL extension
      Person & email address to contact for further information:




Sermersheim            Expires December 30, 2004                [Page 4]

Internet-Draft    Subordinate Subtree Search Scope for LDAP    July 2004


         Jim Sermersheim
         jimse@novell.com
      Usage: Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none

A.3  LDAP Descriptor Registrations

   It is requested that IANA register upon Standards Action the LDAP
   descriptors described in this document.  The following registration
   templates are given:

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): subordScope
      Object Identifier: IANA-ASSIGNED-OID.1
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: URL Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none




























Sermersheim            Expires December 30, 2004                [Page 5]

Internet-Draft    Subordinate Subtree Search Scope for LDAP    July 2004


Intellectual Property Statement

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.


Disclaimer of Validity

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and
   except as set forth therein, the authors retain all their rights.


Acknowledgment

   Funding for the RFC Editor function is currently provided by the
   Internet Society.




Sermersheim            Expires December 30, 2004                [Page 6]

alt-openldap11-devel/drafts/draft-behera-ldap-password-policy-xx.txt000064400000247252150410163300021450 0ustar00


Network Working Group                                     J. Sermersheim
Internet-Draft                                               Novell, Inc
Intended status: Standards Track                               L. Poitou
Expires: January 19, 2015                               Sun Microsystems
                                                             H. Chu, Ed.
                                                             Symas Corp.
                                                           July 18, 2014


                  Password Policy for LDAP Directories
                  draft-behera-ldap-password-policy-11

Abstract

   Password policy as described in this document is a set of rules that
   controls how passwords are used and administered in Lightweight
   Directory Access Protocol (LDAP) based directories.  In order to
   improve the security of LDAP directories and make it difficult for
   password cracking programs to break into directories, it is desirable
   to enforce a set of rules on password usage.  These rules are made to
   ensure that users change their passwords periodically, passwords meet
   construction requirements, the re-use of old password is restricted,
   and to deter password guessing attacks.

Status of this Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at http://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on January 19, 2015.

Copyright Notice

   Copyright (c) 2014 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents



Sermersheim, et al.     Expires January 19, 2015                [Page 1]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   (http://trustee.ietf.org/license-info) in effect on the date of
   publication of this document.  Please review these documents
   carefully, as they describe your rights and restrictions with respect
   to this document.  Code Components extracted from this document must
   include Simplified BSD License text as described in Section 4.e of
   the Trust Legal Provisions and are provided without warranty as
   described in the Simplified BSD License.












































Sermersheim, et al.     Expires January 19, 2015                [Page 2]

Internet-Draft    Password Policy for LDAP Directories         July 2014


Table of Contents

   1.    Overview . . . . . . . . . . . . . . . . . . . . . . . . . .  4
   2.    Conventions  . . . . . . . . . . . . . . . . . . . . . . . .  5
   3.    Application of Password Policy . . . . . . . . . . . . . . .  6
   4.    Articles of Password Policy  . . . . . . . . . . . . . . . .  7
   4.1.  Password Usage Policy  . . . . . . . . . . . . . . . . . . .  7
   4.2.  Password Modification Policy . . . . . . . . . . . . . . . .  8
   4.3.  Restriction of the Password Policy . . . . . . . . . . . . . 10
   5.    Schema used for Password Policy  . . . . . . . . . . . . . . 12
   5.1.  The pwdPolicy Object Class . . . . . . . . . . . . . . . . . 12
   5.2.  Attribute Types used in the pwdPolicy ObjectClass  . . . . . 12
   5.3.  Attribute Types for Password Policy State Information  . . . 19
   6.    Controls used for Password Policy  . . . . . . . . . . . . . 24
   6.1.  Request Control  . . . . . . . . . . . . . . . . . . . . . . 24
   6.2.  Response Control . . . . . . . . . . . . . . . . . . . . . . 24
   7.    Policy Decision Points . . . . . . . . . . . . . . . . . . . 26
   7.1.  Locked Account Check . . . . . . . . . . . . . . . . . . . . 26
   7.2.  Password Must be Changed Now Check . . . . . . . . . . . . . 26
   7.3.  Password Expiration Check  . . . . . . . . . . . . . . . . . 27
   7.4.  Remaining Grace AuthN Check  . . . . . . . . . . . . . . . . 27
   7.5.  Time Before Expiration Check . . . . . . . . . . . . . . . . 27
   7.6.  Intruder Lockout Check . . . . . . . . . . . . . . . . . . . 27
   7.7.  Intruder Delay Check . . . . . . . . . . . . . . . . . . . . 28
   7.8.  Password Too Young Check . . . . . . . . . . . . . . . . . . 28
   8.    Server Policy Enforcement Points . . . . . . . . . . . . . . 29
   8.1.  Password-based Authentication  . . . . . . . . . . . . . . . 29
   8.2.  Password Update Operations . . . . . . . . . . . . . . . . . 31
   8.3.  Other Operations . . . . . . . . . . . . . . . . . . . . . . 34
   9.    Client Policy Enforcement Points . . . . . . . . . . . . . . 35
   9.1.  Bind Operation . . . . . . . . . . . . . . . . . . . . . . . 35
   9.2.  Modify Operations  . . . . . . . . . . . . . . . . . . . . . 36
   9.3.  Add Operation  . . . . . . . . . . . . . . . . . . . . . . . 37
   9.4.  Compare Operation  . . . . . . . . . . . . . . . . . . . . . 37
   9.5.  Other Operations . . . . . . . . . . . . . . . . . . . . . . 38
   10.   Administration of the Password Policy  . . . . . . . . . . . 39
   11.   Password Policy and Replication  . . . . . . . . . . . . . . 40
   12.   Security Considerations  . . . . . . . . . . . . . . . . . . 42
   13.   IANA Considerations  . . . . . . . . . . . . . . . . . . . . 43
   13.1. Object Identifiers . . . . . . . . . . . . . . . . . . . . . 43
   13.2. LDAP Protocol Mechanisms . . . . . . . . . . . . . . . . . . 43
   13.3. LDAP Descriptors . . . . . . . . . . . . . . . . . . . . . . 43
   13.4. LDAP AttributeDescription Options  . . . . . . . . . . . . . 45
   14.   Acknowledgement  . . . . . . . . . . . . . . . . . . . . . . 46
   15.   Normative References . . . . . . . . . . . . . . . . . . . . 47
         Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 48





Sermersheim, et al.     Expires January 19, 2015                [Page 3]

Internet-Draft    Password Policy for LDAP Directories         July 2014


1.  Overview

   LDAP-based directory services are currently accepted by many
   organizations as the access protocol for directories.  The ability to
   ensure the secure read and update access to directory information
   throughout the network is essential to the successful deployment.
   Most LDAP implementations support many authentication schemes - the
   most basic and widely used is the simple authentication i.e., user DN
   and password.  In this case, many LDAP servers have implemented some
   kind of policy related to the password used to authenticate.  Among
   other things, this policy includes:

   o  Whether and when passwords expire.

   o  Whether failed bind attempts cause the account to be locked.

   o  If and how users are able to change their passwords.

   In order to achieve greater security protection and ensure
   interoperability in a heterogeneous environment, LDAP needs to
   standardize on a common password policy model.  This is critical to
   the successful deployment of LDAP directories.





























Sermersheim, et al.     Expires January 19, 2015                [Page 4]

Internet-Draft    Password Policy for LDAP Directories         July 2014


2.  Conventions

   Imperative keywords defined in [RFC2119] are used in this document,
   and carry the meanings described there.

   All ASN.1 [X.680] Basic Encoding Rules (BER) [X.690] encodings follow
   the conventions found in Section 5.1 of [RFC4511].

   The term "password administrator" refers to a user that has
   sufficient access control privileges to modify users' passwords.  The
   term "password policy administrator" refers to a user that has
   sufficient access control privileges to modify the pwdPolicy object
   defined in this document.  The access control that is used to
   determine whether an identity is a password administrator or password
   policy administrator is beyond the scope of this document, but
   typically implies that the password administrator has 'write'
   privileges to the password attribute.


































Sermersheim, et al.     Expires January 19, 2015                [Page 5]

Internet-Draft    Password Policy for LDAP Directories         July 2014


3.  Application of Password Policy

   The password policy defined in this document can be applied to any
   attribute holding a user's password used for an authenticated LDAP
   bind operation.  In this document, the term "user" represents any
   LDAP client application that has an identity in the directory.

   This policy is typically applied to the userPassword attribute in the
   case of the LDAP simple authentication method [RFC4511] or the case
   of password based SASL [RFC4422] authentication such as CRAM-MD5
   [RFC2195] and DIGEST-MD5 [RFC2831].

   The policy described in this document assumes that the password
   attribute holds a single value.  No considerations are made for
   directories or systems that allow a user to maintain multi-valued
   password attributes.

   Server implementations MAY institute internal policy whereby certain
   identities (such as directory administrators) are not forced to
   comply with any of password policy.  In this case, the password for a
   directory administrator never expires; the account is never locked,
   etc.





























Sermersheim, et al.     Expires January 19, 2015                [Page 6]

Internet-Draft    Password Policy for LDAP Directories         July 2014


4.  Articles of Password Policy

   The following sections explain in general terms each aspect of the
   password policy defined in this document as well as the need for
   each.  These policies are subdivided into the general groups of
   password usage and password modification.  Implementation details are
   presented in Section 8 and Section 9.

4.1.  Password Usage Policy

   This section describes policy enforced when a password is used to
   authenticate.  The general focus of this policy is to minimize the
   threat of intruders once a password is in use.

4.1.1.  Password Validity Policy

   These mechanisms allow account usage to be controlled independent of
   any password expiration policies.  The policy defines the absolute
   period of time for which an account may be used.  This allows an
   administrator to define an absolute starting time after which a
   password becomes valid, and an absolute ending time after which the
   password is disabled.

   A mechanism is also provided to define the period of time for which
   an account may remain unused before being disabled.

4.1.2.  Password Guessing Limit

   In order to prevent intruders from guessing a user's password, a
   mechanism exists to track the number of consecutive failed
   authentication attempts, and take action when a limit is reached.
   This policy consists of several parts:

   o  A counter to track the number of failed authentication attempts.

   o  The amount of time to delay on the first authentication failure.

   o  The maximum amount of time to delay on subsequent failures.

   o  A timeframe in which the limit of consecutive failed
      authentication attempts must happen before action is taken.

   o  A configurable limit on failed authentication attempts.

   o  The action to be taken when the limit is reached.  The action will
      either be nothing, or the account will be locked.





Sermersheim, et al.     Expires January 19, 2015                [Page 7]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   o  An amount of time the account is locked (if it is to be locked).
      This can be indefinite.

   Note that using the account lock feature provides an easy avenue for
   Denial-of-Service (DoS) attacks on user accounts.  While some sites'
   policies require accounts to be locked, this feature is discouraged
   in favor of delaying each failed login attempt.

   The delay time will be doubled on each subsequent failure, until it
   reaches the maximum time configured.

   [TBD: we could also provide a syntax for configuring a backoff
   algorithm.  E.g. "+<int>" for linearly incrementing delay, "x<int>"
   for constant multiplier, "^<int> for geometric.  But it's probably
   overkill to add a calculator language to the server.]

4.2.  Password Modification Policy

   This section describes policy enforced while users are modifying
   passwords.  The general focus of this policy is to ensure that when
   users add or change their passwords, the security and effectiveness
   of their passwords is maximized.  In this document, the term "modify
   password operation" refers to any operation that is used to add or
   modify a password attribute.  Often this is done by updating the
   password attribute during an add or modify operation, but MAY be done
   by other means such as an extended operation.

4.2.1.  Password Expiration, Expiration Warning, and Grace
        Authentications

   One of the key properties of a password is the fact that it is not
   well known.  If a password is frequently changed, the chances of that
   user's account being broken into are minimized.

   Password policy administrators may deploy a password policy that
   causes passwords to expire after a given amount of time - thus
   forcing users to change their passwords periodically.

   As a side effect, there needs to be a way in which users are made
   aware of this need to change their password before actually being
   locked out of their accounts.  One or both of the following methods
   handle this:

   o  A warning may be returned to the user sometime before his password
      is due to expire.  If the user fails to heed this warning before
      the expiration time, his account will be locked.





Sermersheim, et al.     Expires January 19, 2015                [Page 8]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   o  The user may bind to the directory a preset number of times after
      her password has expired.  If she fails to change her password
      during one of her 'grace' authentications, her account will be
      locked.

4.2.2.  Password History

   When the Password Expiration policy is used, an additional mechanism
   may be employed to prevent users from simply re-using a previous
   password (as this would effectively circumvent the expiration
   policy).

   In order to do this; a history of used passwords is kept.  The
   password policy administrator sets the number of passwords to be
   stored at any given time.  Passwords are stored in this history
   whenever the password is changed.  Users aren't allowed to specify
   any passwords that are in the history list while changing passwords.

4.2.3.  Password Minimum Age

   Users may circumvent the Password History mechanism by quickly
   performing a series of password changes.  If they change their
   password enough times, their 'favorite' password will be pushed out
   of the history list.

   This process may be made less attractive to users by employing a
   minimum age for passwords.  If users are forced to wait 24 hours
   between password changes, they may be less likely to cycle through a
   history of 10 passwords.

4.2.4.  Password Quality and Minimum length

   In order to prevent users from creating or updating passwords that
   are easy to guess, a password quality policy may be employed.  This
   policy consists of two general mechanisms - ensuring that passwords
   conform to a defined quality criterion and ensuring that they are of
   a minimum length.

   Forcing a password to comply with the quality policy may imply a
   variety of things including:

   o  Disallowing trivial or well-known words make up the password.

   o  Forcing a certain number of digits be used.

   o  Disallowing anagrams of the user's name.

   The implementation of this policy meets with the following problems:



Sermersheim, et al.     Expires January 19, 2015                [Page 9]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   o  If the password to be added or updated is encrypted by the client
      before being sent, the server has no way of enforcing this policy.
      Therefore, the onus of enforcing this policy falls upon client
      implementations.

   o  There are no specific definitions of what 'quality checking'
      means.  This can lead to unexpected behavior in a heterogeneous
      environment.

4.2.5.  User Defined Passwords

   In some cases, it is desirable to disallow users from adding and
   updating their own passwords.  This policy makes this functionality
   possible.

4.2.6.  Password Change after Reset

   This policy forces the user to update her password after it has been
   set for the first time, or has been reset by a password
   administrator.

   This is needed in scenarios where a password administrator has set or
   reset the password to a well-known value.

4.2.7.  Safe Modification

   As directories become more commonly used, it will not be unusual for
   clients to connect to a directory and leave the connection open for
   an extended period.  This opens up the possibility for an intruder to
   make modifications to a user's password while that user's computer is
   connected but unattended.

   This policy forces the user to prove his identity by specifying the
   old password during a password modify operation.

   {TODO: This allows a dictionary attack unless we specify that this is
   also subject to intruder detection.  One solution is to require users
   to authN prior to changing password.  Another solution is to perform
   intruder detection checks when the password for a non-authenticated
   identity is being updated}

4.3.  Restriction of the Password Policy

   The password policy defined in this document can apply to any
   attribute containing a password.  Password policy state information
   is held in the user's entry, and applies to a password attribute, not
   a particular password attribute value.  Thus the server SHOULD
   enforce that the password attribute subject to password policy,



Sermersheim, et al.     Expires January 19, 2015               [Page 10]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   contains one and only one password value.


















































Sermersheim, et al.     Expires January 19, 2015               [Page 11]

Internet-Draft    Password Policy for LDAP Directories         July 2014


5.  Schema used for Password Policy

   The schema elements defined here fall into two general categories.  A
   password policy object class is defined which contains a set of
   administrative password policy attributes, and a set of operational
   attributes are defined that hold general password policy state
   information for each user.

5.1.  The pwdPolicy Object Class

   This object class contains the attributes defining a password policy
   in effect for a set of users.  Section 10 describes the
   administration of this object, and the relationship between it and
   particular objects.

         ( 1.3.6.1.4.1.42.2.27.8.2.1
         NAME 'pwdPolicy'
         SUP top
         AUXILIARY
         MUST ( pwdAttribute )
         MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdCheckQuality $
         pwdMinLength $ pwdMaxLength $ pwdExpireWarning $
         pwdGraceAuthNLimit $ pwdGraceExpiry $ pwdLockout $
         pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $
         pwdMustChange $ pwdAllowUserChange $ pwdSafeModify $
         pwdMinDelay $ pwdMaxDelay $ pwdMaxIdle ) )

5.2.  Attribute Types used in the pwdPolicy ObjectClass

   Following are the attribute types used by the pwdPolicy object class.

5.2.1.  pwdAttribute

   This holds the name of the attribute to which the password policy is
   applied.  For example, the password policy may be applied to the
   userPassword attribute.

         ( 1.3.6.1.4.1.42.2.27.8.1.1
         NAME 'pwdAttribute'
         EQUALITY objectIdentifierMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )

5.2.2.  pwdMinAge

   This attribute holds the number of seconds that must elapse between
   modifications to the password.  If this attribute is not present, 0
   seconds is assumed.




Sermersheim, et al.     Expires January 19, 2015               [Page 12]

Internet-Draft    Password Policy for LDAP Directories         July 2014


         ( 1.3.6.1.4.1.42.2.27.8.1.2
         NAME 'pwdMinAge'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.3.  pwdMaxAge

   This attribute holds the number of seconds after which a modified
   password will expire.

   If this attribute is not present, or if the value is 0 the password
   does not expire.  If not 0, the value must be greater than or equal
   to the value of the pwdMinAge.

         ( 1.3.6.1.4.1.42.2.27.8.1.3
         NAME 'pwdMaxAge'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.4.  pwdInHistory

   This attribute specifies the maximum number of used passwords stored
   in the pwdHistory attribute.

   If this attribute is not present, or if the value is 0, used
   passwords are not stored in the pwdHistory attribute and thus may be
   reused.

         ( 1.3.6.1.4.1.42.2.27.8.1.4
         NAME 'pwdInHistory'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.5.  pwdCheckQuality

   {TODO: Consider changing the syntax to OID.  Each OID will list a
   quality rule (like min len, # of special characters, etc).  These
   rules can be specified outside this document.}

   {TODO: Note that even though this is meant to be a check that happens
   during password modification, it may also be allowed to happen during
   authN.  This is useful for situations where the password is encrypted



Sermersheim, et al.     Expires January 19, 2015               [Page 13]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   when modified, but decrypted when used to authN.}

   This attribute indicates how the password quality will be verified
   while being modified or added.  If this attribute is not present, or
   if the value is '0', quality checking will not be enforced.  A value
   of '1' indicates that the server will check the quality, and if the
   server is unable to check it (due to a hashed password or other
   reasons) it will be accepted.  A value of '2' indicates that the
   server will check the quality, and if the server is unable to verify
   it, it will return an error refusing the password.

         ( 1.3.6.1.4.1.42.2.27.8.1.5
         NAME 'pwdCheckQuality'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.6.  pwdMinLength

   When quality checking is enabled, this attribute holds the minimum
   number of characters that must be used in a password.  If this
   attribute is not present, no minimum password length will be
   enforced.  If the server is unable to check the length (due to a
   hashed password or otherwise), the server will, depending on the
   value of the pwdCheckQuality attribute, either accept the password
   without checking it ('0' or '1') or refuse it ('2').

         ( 1.3.6.1.4.1.42.2.27.8.1.6
         NAME 'pwdMinLength'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.7.  pwdMaxLength

   When quality checking is enabled, this attribute holds the maximum
   number of characters that may be used in a password.  If this
   attribute is not present, no maximum password length will be
   enforced.  If the server is unable to check the length (due to a
   hashed password or otherwise), the server will, depending on the
   value of the pwdCheckQuality attribute, either accept the password
   without checking it ('0' or '1') or refuse it ('2').







Sermersheim, et al.     Expires January 19, 2015               [Page 14]

Internet-Draft    Password Policy for LDAP Directories         July 2014


         ( 1.3.6.1.4.1.42.2.27.8.1.31
         NAME 'pwdMaxLength'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.8.  pwdExpireWarning

   This attribute specifies the maximum number of seconds before a
   password is due to expire that expiration warning messages will be
   returned to an authenticating user.

   If this attribute is not present, or if the value is 0 no warnings
   will be returned.  If not 0, the value must be smaller than the value
   of the pwdMaxAge attribute.

         ( 1.3.6.1.4.1.42.2.27.8.1.7
         NAME 'pwdExpireWarning'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.9.  pwdGraceAuthNLimit

   This attribute specifies the number of times an expired password can
   be used to authenticate.  If this attribute is not present or if the
   value is 0, authentication will fail.

         ( 1.3.6.1.4.1.42.2.27.8.1.8
         NAME 'pwdGraceAuthNLimit'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.10.  pwdGraceExpiry

   This attribute specifies the number of seconds the grace
   authentications are valid.  If this attribute is not present or if
   the value is 0, there is no time limit on the grace authentications.

         ( 1.3.6.1.4.1.42.2.27.8.1.30
         NAME 'pwdGraceExpire'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27



Sermersheim, et al.     Expires January 19, 2015               [Page 15]

Internet-Draft    Password Policy for LDAP Directories         July 2014


         SINGLE-VALUE )

5.2.11.  pwdLockout

   This attribute indicates, when its value is "TRUE", that the password
   may not be used to authenticate after a specified number of
   consecutive failed bind attempts.  The maximum number of consecutive
   failed bind attempts is specified in pwdMaxFailure.

   If this attribute is not present, or if the value is "FALSE", the
   password may be used to authenticate when the number of failed bind
   attempts has been reached.

         ( 1.3.6.1.4.1.42.2.27.8.1.9
         NAME 'pwdLockout'
         EQUALITY booleanMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
         SINGLE-VALUE )

5.2.12.  pwdLockoutDuration

   This attribute holds the number of seconds that the password cannot
   be used to authenticate due to too many failed bind attempts.  If
   this attribute is not present, or if the value is 0 the password
   cannot be used to authenticate until reset by a password
   administrator.

         ( 1.3.6.1.4.1.42.2.27.8.1.10
         NAME 'pwdLockoutDuration'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.13.  pwdMaxFailure

   This attribute specifies the number of consecutive failed bind
   attempts after which the password may not be used to authenticate.
   If this attribute is not present, or if the value is 0, this policy
   is not checked, and the value of pwdLockout will be ignored.

         ( 1.3.6.1.4.1.42.2.27.8.1.11
         NAME 'pwdMaxFailure'
         EQUALITY integerMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         ORDERING integerOrderingMatch
         SINGLE-VALUE )




Sermersheim, et al.     Expires January 19, 2015               [Page 16]

Internet-Draft    Password Policy for LDAP Directories         July 2014


5.2.14.  pwdFailureCountInterval

   This attribute holds the number of seconds after which the password
   failures are purged from the failure counter, even though no
   successful authentication occurred.

   If this attribute is not present, or if its value is 0, the failure
   counter is only reset by a successful authentication.

         ( 1.3.6.1.4.1.42.2.27.8.1.12
         NAME 'pwdFailureCountInterval'
         EQUALITY integerMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         ORDERING integerOrderingMatch
         SINGLE-VALUE )

5.2.15.  pwdMustChange

   This attribute specifies with a value of "TRUE" that users must
   change their passwords when they first bind to the directory after a
   password is set or reset by a password administrator.  If this
   attribute is not present, or if the value is "FALSE", users are not
   required to change their password upon binding after the password
   administrator sets or resets the password.  This attribute is not set
   due to any actions specified by this document, it is typically set by
   a password administrator after resetting a user's password.

         ( 1.3.6.1.4.1.42.2.27.8.1.13
         NAME 'pwdMustChange'
         EQUALITY booleanMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
         SINGLE-VALUE )

5.2.16.  pwdAllowUserChange

   This attribute indicates whether users can change their own
   passwords, although the change operation is still subject to access
   control.  If this attribute is not present, a value of "TRUE" is
   assumed.  This attribute is intended to be used in the absence of an
   access control mechanism.

         ( 1.3.6.1.4.1.42.2.27.8.1.14
         NAME 'pwdAllowUserChange'
         EQUALITY booleanMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
         SINGLE-VALUE )





Sermersheim, et al.     Expires January 19, 2015               [Page 17]

Internet-Draft    Password Policy for LDAP Directories         July 2014


5.2.17.  pwdSafeModify

   This attribute specifies whether or not the existing password must be
   sent along with the new password when being changed.  If this
   attribute is not present, a "FALSE" value is assumed.

         ( 1.3.6.1.4.1.42.2.27.8.1.15
         NAME 'pwdSafeModify'
         EQUALITY booleanMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
         SINGLE-VALUE )

5.2.18.  pwdMinDelay

   This attribute specifies the number of seconds to delay responding to
   the first failed authentication attempt.  If this attribute is not
   set or is 0, no delays will be used. pwdMaxDelay must also be
   specified if pwdMinDelay is set.

         ( 1.3.6.1.4.1.42.2.27.8.1.24
         NAME 'pwdMinDelay'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.19.  pwdMaxDelay

   This attribute specifies the maximum number of seconds to delay when
   responding to a failed authentication attempt.  The time specified in
   pwdMinDelay is used as the starting time and is then doubled on each
   failure until the delay time is greater than or equal to pwdMaxDelay
   (or a successful authentication occurs, which resets the failure
   counter). pwdMinDelay must be specified if pwdMaxDelay is set.

         ( 1.3.6.1.4.1.42.2.27.8.1.25
         NAME 'pwdMaxDelay'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.2.20.  pwdMaxIdle

   This attribute specifies the number of seconds an account may remain
   unused before it becomes locked.  If this attribute is not set or is
   0, no check is performed.




Sermersheim, et al.     Expires January 19, 2015               [Page 18]

Internet-Draft    Password Policy for LDAP Directories         July 2014


         ( 1.3.6.1.4.1.42.2.27.8.1.26
         NAME 'pwdMaxIdle'
         EQUALITY integerMatch
         ORDERING integerOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
         SINGLE-VALUE )

5.3.  Attribute Types for Password Policy State Information

   Password policy state information must be maintained for each user.
   The information is located in each user entry as a set of operational
   attributes.  These operational attributes are: pwdChangedTime,
   pwdAccountLockedTime, pwdFailureTime, pwdHistory, pwdGraceUseTime,
   pwdReset, pwdPolicySubEntry, pwdStartTime, pwdEndTime,
   pwdLastSuccess.

5.3.1.  Password Policy State Attribute Option

   Since the password policy could apply to several attributes used to
   store passwords, each of the above operational attributes must have
   an option to specify which pwdAttribute it applies to.  The password
   policy option is defined as the following:

   pwd-<passwordAttribute>

   where passwordAttribute is a string following the OID syntax
   (1.3.6.1.4.1.1466.115.121.1.38).  The attribute type descriptor
   (short name) MUST be used.

   For example, if the pwdPolicy object has for pwdAttribute
   "userPassword" then the pwdChangedTime operational attribute, in a
   user entry, will be:

   pwdChangedTime;pwd-userPassword: 20000103121520Z

   This attribute option follows sub-typing semantics.  If a client
   requests a password policy state attribute to be returned in a search
   operation, and does not specify an option, all subtypes of that
   policy state attribute are returned.

5.3.2.  pwdChangedTime

   This attribute specifies the last time the entry's password was
   changed.  This is used by the password expiration policy.  If this
   attribute does not exist, the password will never expire.






Sermersheim, et al.     Expires January 19, 2015               [Page 19]

Internet-Draft    Password Policy for LDAP Directories         July 2014


         ( 1.3.6.1.4.1.42.2.27.8.1.16
         NAME 'pwdChangedTime'
         DESC 'The time the password was last changed'
         EQUALITY generalizedTimeMatch
         ORDERING generalizedTimeOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
         SINGLE-VALUE
         NO-USER-MODIFICATION
         USAGE directoryOperation )

5.3.3.  pwdAccountLockedTime

   This attribute holds the time that the user's account was locked.  A
   locked account means that the password may no longer be used to
   authenticate.  A 000001010000Z value means that the account has been
   locked permanently, and that only a password administrator can unlock
   the account.

         ( 1.3.6.1.4.1.42.2.27.8.1.17
         NAME 'pwdAccountLockedTime'
         DESC 'The time an user account was locked'
         EQUALITY generalizedTimeMatch
         ORDERING generalizedTimeOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
         SINGLE-VALUE
         NO-USER-MODIFICATION
         USAGE directoryOperation )

5.3.4.  pwdFailureTime

   This attribute holds the timestamps of the consecutive authentication
   failures.

         ( 1.3.6.1.4.1.42.2.27.8.1.19
         NAME 'pwdFailureTime'
         DESC 'The timestamps of the last consecutive authentication
         failures'
         EQUALITY generalizedTimeMatch
         ORDERING generalizedTimeOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
         NO-USER-MODIFICATION
         USAGE directoryOperation )

5.3.5.  pwdHistory

   This attribute holds a history of previously used passwords.  Values
   of this attribute are transmitted in string format as given by the
   following ABNF:



Sermersheim, et al.     Expires January 19, 2015               [Page 20]

Internet-Draft    Password Policy for LDAP Directories         July 2014


      pwdHistory = time "#" syntaxOID "#" length "#" data

      time       = GeneralizedTime

      syntaxOID  = numericoid    ; the string representation of the
                                 ; dotted-decimal OID that defines the
                                 ; syntax used to store the password.

      length     = number        ; the number of octets in data.

      data       = <octets representing the password in the format
                    specified by syntaxOID>.

   GeneralizedTime is specified in 3.3.13 of [RFC4517]. numericoid and
   number are specified in 1.4 of [RFC4512].

   This format allows the server to store, and transmit a history of
   passwords that have been used.  In order for equality matching to
   function properly, the time field needs to adhere to a consistent
   format.  For this purpose, the time field MUST be in GMT format.

         ( 1.3.6.1.4.1.42.2.27.8.1.20
         NAME 'pwdHistory'
         DESC 'The history of user s passwords'
         EQUALITY octetStringMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
         NO-USER-MODIFICATION
         USAGE directoryOperation )

5.3.6.  pwdGraceUseTime

   This attribute holds the timestamps of grace authentications after a
   password has expired.

         ( 1.3.6.1.4.1.42.2.27.8.1.21
         NAME 'pwdGraceUseTime'
         DESC 'The timestamps of the grace authentication after the
         password has expired'
         EQUALITY generalizedTimeMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
         NO-USER-MODIFICATION
         USAGE directoryOperation )

5.3.7.  pwdReset

   This attribute holds a flag to indicate (when TRUE) that the password
   has been updated by the password administrator and must be changed by
   the user.



Sermersheim, et al.     Expires January 19, 2015               [Page 21]

Internet-Draft    Password Policy for LDAP Directories         July 2014


         ( 1.3.6.1.4.1.42.2.27.8.1.22
         NAME 'pwdReset'
         DESC 'The indication that the password has been reset'
         EQUALITY booleanMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
         SINGLE-VALUE
         USAGE directoryOperation )

5.3.8.  pwdPolicySubentry

   This attribute points to the pwdPolicy subentry in effect for this
   object.

         ( 1.3.6.1.4.1.42.2.27.8.1.23
         NAME 'pwdPolicySubentry'
         DESC 'The pwdPolicy subentry in effect for this object'
         EQUALITY distinguishedNameMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
         SINGLE-VALUE
         NO-USER-MODIFICATION
         USAGE directoryOperation )

5.3.9.  pwdStartTime

   This attribute specifies the time the entry's password becomes valid
   for authentication.  Authentication attempts made before this time
   will fail.  If this attribute does not exist, then no restriction
   applies.

         ( 1.3.6.1.4.1.42.2.27.8.1.27
         NAME 'pwdStartTime'
         DESC 'The time the password becomes enabled'
         EQUALITY generalizedTimeMatch
         ORDERING generalizedTimeOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
         SINGLE-VALUE
         NO-USER-MODIFICATION
         USAGE directoryOperation )

5.3.10.  pwdEndTime

   This attribute specifies the time the entry's password becomes
   invalid for authentication.  Authentication attempts made after this
   time will fail, regardless of expiration or grace settings.  If this
   attribute does not exist, then this restriction does not apply.






Sermersheim, et al.     Expires January 19, 2015               [Page 22]

Internet-Draft    Password Policy for LDAP Directories         July 2014


         ( 1.3.6.1.4.1.42.2.27.8.1.28
         NAME 'pwdEndTime'
         DESC 'The time the password becomes disabled'
         EQUALITY generalizedTimeMatch
         ORDERING generalizedTimeOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
         SINGLE-VALUE
         NO-USER-MODIFICATION
         USAGE directoryOperation )

   Note that pwdStartTime may be set to a time greater than or equal to
   pwdEndTime; this simply disables the account.

5.3.11.  pwdLastSuccess

   This attribute holds the timestamp of the last successful
   authentication.

         ( 1.3.6.1.4.1.42.2.27.8.1.29
         NAME 'pwdLastSuccess'
         DESC 'The timestamp of the last successful authentication'
         EQUALITY generalizedTimeMatch
         ORDERING generalizedTimeOrderingMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
         SINGLE-VALUE
         NO-USER-MODIFICATION
         USAGE directoryOperation )
























Sermersheim, et al.     Expires January 19, 2015               [Page 23]

Internet-Draft    Password Policy for LDAP Directories         July 2014


6.  Controls used for Password Policy

   This section details the controls used while enforcing password
   policy.  A request control is defined that is sent by a client with a
   request operation in order to elicit a response control.  The
   response control contains various warnings and errors associated with
   password policy.

   {TODO: add a note about advertisement and discovery}

6.1.  Request Control

   This control MAY be sent with any LDAP request message in order to
   convey to the server that this client is aware of, and can process
   the response control described in this document.  When a server
   receives this control, it will return the response control when
   appropriate and with the proper data.

   The controlType is 1.3.6.1.4.1.42.2.27.8.5.1 and the criticality may
   be TRUE or FALSE.  There is no controlValue.

6.2.  Response Control

   If the client has sent a passwordPolicyRequest control, the server
   (when solicited by the inclusion of the request control) sends this
   control with the following operation responses: bindResponse,
   modifyResponse, addResponse, compareResponse and possibly
   extendedResponse, to inform of various conditions, and MAY be sent
   with other operations (in the case of the changeAfterReset error).
   The controlType is 1.3.6.1.4.1.42.2.27.8.5.1 and the controlValue is
   the BER encoding of the following type:

      PasswordPolicyResponseValue ::= SEQUENCE {
         warning [0] CHOICE {
            timeBeforeExpiration [0] INTEGER (0 .. maxInt),
            graceAuthNsRemaining [1] INTEGER (0 .. maxInt) } OPTIONAL,
         error   [1] ENUMERATED {
            passwordExpired             (0),
            accountLocked               (1),
            changeAfterReset            (2),
            passwordModNotAllowed       (3),
            mustSupplyOldPassword       (4),
            insufficientPasswordQuality (5),
            passwordTooShort            (6),
            passwordTooYoung            (7),
            passwordInHistory           (8) } OPTIONAL }

   The timeBeforeExpiration warning specifies the number of seconds



Sermersheim, et al.     Expires January 19, 2015               [Page 24]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   before a password will expire.  The graceAuthNsRemaining warning
   specifies the remaining number of times a user will be allowed to
   authenticate with an expired password.  The passwordExpired error
   signifies that the password has expired and must be reset.  The
   changeAfterReset error signifies that the password must be changed
   before the user will be allowed to perform any operation other than
   bind and modify.  The passwordModNotAllowed error is set when a user
   is restricted from changing her password.  The
   insufficientPasswordQuality error is set when a password doesn't pass
   quality checking.  The passwordTooYoung error is set if the age of
   the password to be modified is not yet old enough.

   Typically, only either a warning or an error will be encoded though
   there may be exceptions.  For example, if the user is required to
   change a password after the password administrator set it, and the
   password will expire in a short amount of time, the control may
   include the timeBeforeExpiration warning and the changeAfterReset
   error.

































Sermersheim, et al.     Expires January 19, 2015               [Page 25]

Internet-Draft    Password Policy for LDAP Directories         July 2014


7.  Policy Decision Points

   Following are a number of procedures used to make policy decisions.
   These procedures are typically performed by the server while
   processing an operation.

   The following sections contain detailed instructions that refer to
   attributes of the pwdPolicy object class.  When doing so, the
   attribute of the pwdPolicy object that governs the entry being
   discussed is implied.

7.1.  Locked Account Check

   A status of true is returned to indicate that the account is locked
   if any of these conditions are met:

   o  The value of the pwdAccountLockedTime attribute is 000001010000Z.

   o  The current time is less than the value of the pwdStartTime
      attribute.

   o  The current time is greater than or equal to the value of the
      pwdEndTime attribute.

   o  The current time is greater than or equal to the value of the
      pwdLastSuccess attribute added to the value of the pwdMaxIdle
      attribute.

   o  The current time is less than the value of the
      pwdAccountLockedTime attribute added to the value of the
      pwdLockoutDuration.

   Otherwise a status of false is returned.

7.2.  Password Must be Changed Now Check

   A status of true is returned to indicate that the password must be
   changed if all of these conditions are met:

   o  The pwdMustChange attribute is set to TRUE.

   o  The pwdReset attribute is set to TRUE.

   Otherwise a status of false is returned.







Sermersheim, et al.     Expires January 19, 2015               [Page 26]

Internet-Draft    Password Policy for LDAP Directories         July 2014


7.3.  Password Expiration Check

   A status of true is returned indicating that the password has expired
   if the current time minus the value of pwdChangedTime is greater than
   the value of the pwdMaxAge.

   Otherwise, a status of false is returned.

7.4.  Remaining Grace AuthN Check

   If the pwdGraceExpiry attribute is present, and the current time is
   greater than the password expiration time plus the pwdGraceExpiry
   value, zero is returned.

   If the pwdGraceUseTime attribute is present, the number of values in
   that attribute subtracted from the value of pwdGraceAuthNLimit is
   returned.  Otherwise zero is returned.  A positive result specifies
   the number of remaining grace authentications.

7.5.  Time Before Expiration Check

   If the pwdExpireWarning attribute is not present a zero status is
   returned.  Otherwise the following steps are followed:

   Subtract the time stored in pwdChangedTime from the current time to
   arrive at the password's age.  If the password's age is greater than
   than the value of the pwdMaxAge attribute, a zero status is returned.
   Subtract the value of the pwdExpireWarning attribute from the value
   of the pwdMaxAge attribute to arrive at the warning age.  If the
   password's age is equal to or greater than the warning age, the value
   of pwdMaxAge minus the password's age is returned.

7.6.  Intruder Lockout Check

   A status of true indicating that an intruder has been detected is
   returned if the following conditions are met:

   o  The pwdLockout attribute is TRUE.

   o  The number of values in the pwdFailureTime attribute that are
      younger than pwdFailureCountInterval is greater or equal to the
      pwdMaxFailure attribute.

   Otherwise a status of false is returned.

   While performing this check, values of pwdFailureTime that are old by
   more than pwdFailureCountInterval are purged and not counted.




Sermersheim, et al.     Expires January 19, 2015               [Page 27]

Internet-Draft    Password Policy for LDAP Directories         July 2014


7.7.  Intruder Delay Check

   If the pwdMinDelay attribute is 0 or not set, zero is returned.

   Otherwise, a delay time is computed based on the number of values in
   the pwdFailureTime attribute.  If the computed value is greater than
   the pwdMaxDelay attribute, the pwdMaxDelay value is returned.

   While performing this check, values of pwdFailureTime that are old by
   more than pwdFailureCountInterval are purged and not counted.

7.8.  Password Too Young Check

   If the Section 7.2 check returned true then this check will return
   false, to allow the password to be changed.

   A status of true indicating that not enough time has passed since the
   password was last updated is returned if:

   o  The value of pwdMinAge is non-zero and pwdChangedTime is present.

   o  The value of pwdMinAge is greater than the current time minus the
      value of pwdChangedTime.

   Otherwise a false status is returned.


























Sermersheim, et al.     Expires January 19, 2015               [Page 28]

Internet-Draft    Password Policy for LDAP Directories         July 2014


8.  Server Policy Enforcement Points

   The server SHOULD enforce that the password attribute subject to a
   password policy as defined in this document, contains one and only
   one password value.

   Note: The case where a single password value is stored in multiple
   formats simultaneously is still considered to be only one password
   value.

   The scenarios in the following operations assume that the client has
   attached a passwordPolicyRequest control to the request message of
   the operation.  In the event that the passwordPolicyRequest control
   was not sent, no passwordPolicyResponse control is returned.  All
   other instructions remain the same.

   For successfully completed operations, unless otherwise stated, no
   passwordPolicyResponse control is returned.

8.1.  Password-based Authentication

   This section contains the policy enforcement rules and policy data
   updates used while validating a password.  Operations that validate
   passwords include, but are not limited to, the Bind operation where
   the simple choice specifies a password, and the Compare operation
   where the attribute being compared holds a password.  Note that while
   the Compare operation does not authenticate a user to the LDAP
   server, it may be used by an external application for purposes of
   authentication.

8.1.1.  Fail if the account is locked

   If the account is locked as specified in Section 7.1, the server
   fails the operation with an appropriate resultCode (i.e.
   invalidCredentials (49) in the case of a bind operation, compareFalse
   (5) in the case of a compare operation, etc.).  The server MAY set
   the error: accountLocked (1) in the passwordPolicyResponse in the
   controls field of the message.

8.1.2.  Validated Password Procedures

   If the validation operation indicates that the password validated,
   these procedures are followed in order:

8.1.2.1.  Policy state updates

   Delete the pwdFailureTime and pwdAccountLockedTime attributes.




Sermersheim, et al.     Expires January 19, 2015               [Page 29]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   Set the value of the pwdLastSuccess attribute to the current time.

   Note: setting pwdLastSuccess is optional, but it is required if the
   policy has pwdMaxIdle defined.

8.1.2.2.  Password must be changed now

   If the decision in Section 7.2 returns true, the server sends to the
   client a response with an appropriate successful resultCode (i.e.
   success (0), compareTrue (6), etc.), and includes the
   passwordPolicyResponse in the controls field of the bindResponse
   message with the warning: changeAfterReset specified.

   For bind, the server MUST then disallow all operations issued by this
   user except modify password, bind, unbind, abandon and StartTLS
   extended operation.

8.1.2.3.  Expired password

   If the password has expired as per Section 7.3, the server either
   returns a success or failure based on the state of grace
   authentications.

8.1.2.3.1.  Remaining Grace Authentications

   If there are remaining grace authentications as per Section 7.4, the
   server adds a new value with the current time in pwdGraceUseTime.
   Then it sends to the client a response with an appropriate successful
   resultCode (i.e. success (0), compareTrue (6), etc.), and includes
   the passwordPolicyResponse in the controls field of the response
   message with the warning: graceAuthNsRemaining choice set to the
   number of grace authentications left.

   Implementor's note: The system time of the host machine may be more
   granular than is needed to ensure unique values of this attribute.
   It is recommended that a mechanism is used to ensure unique
   generalized time values.  The fractional seconds field may be used
   for this purpose.

8.1.2.3.2.  No Remaining Grace Authentications

   If there are no remaining grace authentications, the server fails the
   operation with an appropriate resultCode (invalidCredentials (49),
   compareFalse (5), etc.), and includes the passwordPolicyResponse in
   the controls field of the bindResponse message with the error:
   passwordExpired (0) set.





Sermersheim, et al.     Expires January 19, 2015               [Page 30]

Internet-Draft    Password Policy for LDAP Directories         July 2014


8.1.2.4.  Expiration Warning

   If the result of Section 7.5 is a positive number, the server sends
   to the client a response with an appropriate successful resultCode
   (i.e. success (0), compareTrue (6), etc.), and includes the
   passwordPolicyResponse in the controls field of the bindResponse
   message with the warning: timeBeforeExiration set to the value as
   described above.  Otherwise, the server sends a successful response,
   and omits the passwordPolicyResponse.

8.1.3.  AuthN Failed Procedures

   If the authentication process indicates that the password failed
   validation due to invalid credentials, these procedures are followed:

8.1.3.1.  Policy state update

   Add the current time as a value of the pwdFailureTime attribute.

   Implementor's note: The system time of the host machine may be more
   granular than is needed to ensure unique values of this attribute.
   It is recommended that a mechanism is used to ensure unique
   generalized time values.  The fractional seconds field may be used
   for this purpose.

8.1.3.2.  Handle Intruder Detection

   If the check in Section 7.6 returns a true state, the server locks
   the account by setting the value of the pwdAccountLockedTime
   attribute to the current time.  After locking the account, the server
   fails the operation with an appropriate resultCode
   (invalidCredentials (49), compareFalse (5), etc.), and includes the
   passwordPolicyResponse in the controls field of the message with the
   error: accountLocked (1).

   If the check in Section 7.7 returns a non-zero value, the server
   waits that number of seconds before sending the authentication
   response back to the client.

8.2.  Password Update Operations

   Because the password is stored in an attribute, various operations
   (like add and modify) may be used to create or update a password.
   But some alternate mechanisms have been defined or may be defined,
   such as the LDAP Password Modify Extended Operation [RFC3062].

   While processing a password update, the server performs the following
   steps:



Sermersheim, et al.     Expires January 19, 2015               [Page 31]

Internet-Draft    Password Policy for LDAP Directories         July 2014


8.2.1.  Safe Modification

   If pwdSafeModify is set to TRUE and if there is an existing password
   value, the server ensures that the password update operation includes
   the user's existing password.

   When the LDAP modify operation is used to modify a password, this is
   done by specifying both a delete action and an add or replace action,
   where the delete action specifies the existing password, and the add
   or replace action specifies the new password.  Other password update
   operations SHOULD employ a similar mechanism.  Otherwise this policy
   will fail.

   If the existing password is not specified, the server does not
   process the operation and sends the appropriate response message to
   the client with the resultCode: insufficientAccessRights (50), and
   includes the passwordPolicyResponse in the controls field of the
   response message with the error: mustSupplyOldPassword (4).

8.2.2.  Change After Reset

   If the decision in Section 7.2 returns true, the server ensures that
   the password update operation contains no modifications other than
   the modification of the password attribute.  If other modifications
   exist, the server sends a response message to the client with the
   resultCode: insufficientAccessRights (50), and includes the
   passwordPolicyResponse in the controls field of the response message
   with the error: changeAfterReset (2).

8.2.3.  Rights Check

   Check to see whether the bound identity has sufficient rights to
   update the password.  If the bound identity is a user changing its
   own password, this MAY be done by checking the pwdAllowUserChange
   attribute or using an access control mechanism.  The determination of
   this is implementation specific.  If the user is not allowed to
   update her password, the server sends a response message to the
   client with the resultCode: insufficientAccessRights (50), and
   includes the passwordPolicyResponse in the controls field of the
   response message with the error: passwordModNotAllowed (3).

8.2.4.  Too Early to Update

   If the check in Section 7.8 results in a true status The server sends
   a response message to the client with the resultCode:
   constraintViolation (19), and includes the passwordPolicyResponse in
   the controls field of the response message with the error:
   passwordTooYoung (7).



Sermersheim, et al.     Expires January 19, 2015               [Page 32]

Internet-Draft    Password Policy for LDAP Directories         July 2014


8.2.5.  Password Quality

   Check the value of the pwdCheckQuality attribute.  If the value is
   non-zero, the server:

   o  Ensure that the password meets the quality criteria enforced by
      the server.  This enforcement is implementation specific.  If the
      server is unable to check the quality (due to a hashed password or
      otherwise), the value of pwdCheckQuality is evaluated.  If the
      value is 1, operation continues.  If the value is 2, the server
      sends a response message to the client with the resultCode:
      constraintViolation (19), and includes the passwordPolicyResponse
      in the controls field of the response message with the error:
      insufficientPasswordQuality (5).

      If the server is able to check the password quality, and the check
      fails, the server sends a response message to the client with the
      resultCode: constraintViolation (19), and includes the
      passwordPolicyResponse in the controls field of the response
      message with the error: insufficientPasswordQuality (5).

   o  checks the value of the pwdMinLength attribute.  If the value is
      non-zero, it ensures that the new password is of at least the
      minimum length.

      If the server is unable to check the length (due to a hashed
      password or otherwise), the value of pwdCheckQuality is evaluated.
      If the value is 1, operation continues.  If the value is 2, the
      server sends a response message to the client with the resultCode:
      constraintViolation (19), and includes the passwordPolicyResponse
      in the controls field of the response message with the error:
      passwordTooShort (6).

      If the server is able to check the password length, and the check
      fails, the server sends a response message to the client with the
      resultCode: constraintViolation (19), and includes the
      passwordPolicyResponse in the controls field of the response
      message with the error: passwordTooShort (6).

8.2.6.  Invalid Reuse

   If pwdInHistory is present and its value is non-zero, the server
   checks whether this password exists in the entry's pwdHistory
   attribute or in the current password attribute.  If the password does
   exist in the pwdHistory attribute or in the current password
   attribute, the server sends a response message to the client with the
   resultCode: constraintViolation (19), and includes the
   passwordPolicyResponse in the controls field of the response message



Sermersheim, et al.     Expires January 19, 2015               [Page 33]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   with the error: passwordInHistory (8).

8.2.7.  Policy State Updates

   If the steps have completed without causing an error condition, the
   server performs the following steps in order to update the necessary
   password policy state attributes:

   If the value of either pwdMaxAge or pwdMinAge is non-zero, the server
   updates the pwdChangedTime attribute on the entry to the current
   time.

   If the value of pwdInHistory is non-zero, the server adds the
   previous password (if one existed) to the pwdHistory attribute.  If
   the number of attributes held in the pwdHistory attribute exceeds the
   value of pwdInHistory, the server removes the oldest excess
   passwords.

   If the value the pwdMustChange is TRUE and the modification is
   performed by a password administrator, then the pwdReset attribute is
   set to TRUE.  Otherwise, the pwdReset is removed from the user's
   entry if it exists.

   The pwdFailureTime and pwdGraceUseTime attributes is removed from the
   user's entry if they exist.

8.3.  Other Operations

   For operations other than bind, password update, unbind, abandon or
   StartTLS, if the decision in Section 7.2 returns true, the server
   sends a response message to the client with the resultCode:
   insufficientAccessRights (50), and includes the
   passwordPolicyResponse in the controls field of the response message
   with the error: changeAfterReset (2).

















Sermersheim, et al.     Expires January 19, 2015               [Page 34]

Internet-Draft    Password Policy for LDAP Directories         July 2014


9.  Client Policy Enforcement Points

   These sections illustrate possible scenarios for each LDAP operation
   and define the types of responses that identify those scenarios.

   The scenarios in the following operations assume that the client
   attached a passwordPolicyRequest control to the request message of
   the operation, and thus may receive a passwordPolicyResponse control
   in the response message.  In the event that the passwordPolicyRequest
   control was not sent, no passwordPolicyResponse control is returned.
   All other instructions remain the same.

9.1.  Bind Operation

   For every bind response received, the client checks the resultCode of
   the bindResponse and checks for a passwordPolicyResponse control to
   determine if any of the following conditions are true and MAY prompt
   the user accordingly.

   o  bindResponse.resultCode = insufficientAccessRights (50),
      passwordPolicyResponse.error = accountLocked (1): The password
      failure limit has been reached and the account is locked.  The
      user needs to retry later or contact the password administrator to
      reset the password.

   o  bindResponse.resultCode = success (0),
      passwordPolicyResponse.error = changeAfterReset (2): The user is
      binding for the first time after the password administrator set
      the password.  In this scenario, the client SHOULD prompt the user
      to change his password immediately.

   o  bindResponse.resultCode = success (0),
      passwordPolicyResponse.warning = graceAuthNsRemaining: The
      password has expired but there are remaining grace
      authentications.  The user needs to change it.

   o  bindResponse.resultCode = invalidCredentials (49),
      passwordPolicyResponse.error = passwordExpired (0): The password
      has expired and there are no more grace authentications.  The user
      contacts the password administrator in order to have its password
      reset.

   o  bindResponse.resultCode = success (0),
      passwordPolicyResponse.warning = timeBeforeExpiration: The user's
      password will expire in n number of seconds.






Sermersheim, et al.     Expires January 19, 2015               [Page 35]

Internet-Draft    Password Policy for LDAP Directories         July 2014


9.2.  Modify Operations

9.2.1.  Modify Request

   If the application or client encrypts the password prior to sending
   it in a password modification operation (whether done through
   modifyRequest or another password modification mechanism), it SHOULD
   check the values of the pwdMinLength, and pwdCheckQuality attributes
   and SHOULD enforce these policies.

9.2.2.  Modify Response

   If the modifyRequest operation was used to change the password, or if
   another mechanism is used --such as an extendedRequest-- the
   modifyResponse or other appropriate response MAY contain information
   pertinent to password policy.  The client checks the resultCode of
   the response and checks for a passwordPolicyResponse control to
   determine if any of the following conditions are true and optionally
   notify the user of the condition.

   o  pwdModResponse.resultCode = insufficientAccessRights (50),
      passwordPolicyResponse.error = mustSupplyOldPassword (4): The user
      attempted to change her password without specifying the old
      password but the password policy requires this.

   o  pwdModResponse.resultCode = insufficientAccessRights (50),
      passwordPolicyResponse.error = changeAfterReset (2): The user must
      change her password before submitting any other LDAP requests.

   o  pwdModResponse.resultCode = insufficientAccessRights (50),
      passwordPolicyResponse.error = passwordModNotAllowed (3): The user
      doesn't have sufficient rights to change his password.

   o  pwdModResponse.resultCode = constraintViolation (19),
      passwordPolicyResponse.error = passwordTooYoung (7): It is too
      soon after the last password modification to change the password.

   o  pwdModResponse.resultCode = constraintViolation (19),
      passwordPolicyResponse.error = insufficientPasswordQuality (5):
      The password failed quality checking.

   o  pwdModResponse.resultCode = constraintViolation (19),
      passwordPolicyResponse.error = passwordTooShort (6): The length of
      the password is too short.

   o  pwdModResponse.resultCode = constraintViolation (19),
      passwordPolicyResponse.error = passwordInHistory (8): The password
      has already been used; the user must choose a different one.



Sermersheim, et al.     Expires January 19, 2015               [Page 36]

Internet-Draft    Password Policy for LDAP Directories         July 2014


9.3.  Add Operation

   If a password is specified in an addRequest, the client checks the
   resultCode of the addResponse and checks for a passwordPolicyResponse
   control to determine if any of the following conditions are true and
   may prompt the user accordingly.

   o  addResponse.resultCode = insufficientAccessRights (50),
      passwordPolicyResponse.error = passwordModNotAllowed (3): The user
      doesn't have sufficient rights to add this password.

   o  addResponse.resultCode = constraintViolation (19),
      passwordPolicyResponse.error = insufficientPasswordQuality (5):
      The password failed quality checking.

   o  addResponse.resultCode = constraintViolation (19),
      passwordPolicyResponse.error = passwordTooShort (6): The length of
      the password is too short.

9.4.  Compare Operation

   When a compare operation is used to compare a password, the client
   checks the resultCode of the compareResponse and checks for a
   passwordPolicyResponse to determine if any of the following
   conditions are true and MAY prompt the user accordingly.  These
   conditions assume that the result of the comparison was true.

   o  compareResponse.resultCode = compareFalse (5),
      passwordPolicyResponse.error = accountLocked (1): The password
      failure limit has been reached and the account is locked.  The
      user needs to retry later or contact the password administrator to
      reset the password.

   o  compareResponse.resultCode = compareTrue (6),
      passwordPolicyResponse.warning = graceAuthNsRemaining: The
      password has expired but there are remaining grace
      authentications.  The user needs to change it.

   o  compareResponse.resultCode = compareFalse (5),
      passwordPolicyResponse.error = passwordExpired (0): The password
      has expired and there are no more grace authentications.  The user
      must contact the password administrator to reset the password.

   o  compareResponse.resultCode = compareTrue (6),
      passwordPolicyResponse.warning = timeBeforeExpiration: The user's
      password will expire in n number of seconds.





Sermersheim, et al.     Expires January 19, 2015               [Page 37]

Internet-Draft    Password Policy for LDAP Directories         July 2014


9.5.  Other Operations

   For operations other than bind, unbind, abandon or StartTLS, the
   client checks the result code and control to determine if the user
   needs to change the password immediately.

   o  <Response>.resultCode = insufficientAccessRights (50),
      passwordPolicyResponse.error = changeAfterReset (2) : The user
      needs to change the password immediately.










































Sermersheim, et al.     Expires January 19, 2015               [Page 38]

Internet-Draft    Password Policy for LDAP Directories         July 2014


10.  Administration of the Password Policy

   {TODO: Need to define an administrativeRole (need OID).  Need to
   describe whether pwdPolicy admin areas can overlap}

   A password policy is defined for a particular subtree of the DIT by
   adding to an LDAP subentry whose immediate superior is the root of
   the subtree, the pwdPolicy auxiliary object class.  The scope of the
   password policy is defined by the SubtreeSpecification attribute of
   the LDAP subentry as specified in [RFC3672].

   It is possible to define password policies for different password
   attributes within the same pwdPolicy entry, by specifying multiple
   values of the pwdAttribute.  But password policies could also be in
   separate sub entries as long as they are contained under the same
   LDAP subentry.

   Only one policy may be in effect for a given password attribute in
   any entry.  If multiple policies exist which overlap in the range of
   entries affected, the resulting behavior is undefined.

   Modifying the password policy MUST NOT result in any change in users'
   entries to which the policy applies.

   It SHOULD be possible to overwrite the password policy for one user
   by defining a new policy in a subentry of the user entry.

   Each object that is controlled by password policy advertises the
   subentry that is being used to control its policy in its
   pwdPolicySubentry attribute.  Clients wishing to examine or manage
   password policy for an object may interrogate the pwdPolicySubentry
   for that object in order to arrive at the proper pwdPolicy subentry.



















Sermersheim, et al.     Expires January 19, 2015               [Page 39]

Internet-Draft    Password Policy for LDAP Directories         July 2014


11.  Password Policy and Replication

   {TODO: This section needs to be changed to highlight the pitfalls of
   replication, suggest some implementation choices to overcome those
   pitfalls, but remove prescriptive language relating to the update of
   state information}

   The pwdPolicy object defines the password policy for a portion of the
   DIT and MUST be replicated on all the replicas of this subtree, as
   any subentry would be, in order to have a consistent policy among all
   replicated servers.

   The elements of the password policy that are related to the users are
   stored in the entry themselves as operational attributes.  As these
   attributes are subject to modifications even on a read-only replica,
   replicating them must be carefully considered.

   The pwdChangedTime attribute MUST be replicated on all replicas, to
   allow expiration of the password.

   The pwdReset attribute MUST be replicated on all replicas, to deny
   access to operations other than bind and modify password.

   The pwdHistory attribute MUST be replicated to writable replicas.  It
   doesn't have to be replicated to a read-only replica, since the
   password will never be directly modified on this server.

   The pwdAccountLockedTime, pwdFailureTime and pwdGraceUseTime
   attributes SHOULD be replicated to writable replicas, making the
   password policy global for all servers.  When the user entry is
   replicated to a read-only replica, these attributes SHOULD NOT be
   replicated.  This means that the number of failures, of grace
   authentications and the locking will take place on each replicated
   server.  For example, the effective number of failed attempts on a
   user password will be N x M (where N is the number of servers and M
   the value of pwdMaxFailure attribute).  Replicating these attributes
   to a read-only replica MAY reduce the number of tries globally but
   MAY also introduce some inconstancies in the way the password policy
   is applied.

   Note: there are some situations where global replication of these
   state attributes may not be desired.  For example, if two clusters of
   replicas are geographically remote and joined by a slow network link,
   and their users only login from one of the two locations, it may be
   unnecessary to propagate all of the state changes from one cluster to
   the other.  Servers SHOULD allow administrators to control which
   attributes are replicated on a case-by-case basis.




Sermersheim, et al.     Expires January 19, 2015               [Page 40]

Internet-Draft    Password Policy for LDAP Directories         July 2014


   Servers participating in a loosely consistent multi-master
   replication agreement SHOULD employ a mechanism which ensures
   uniqueness of values when populating the attributes pwdFailureTime
   and pwdGraceUseTime.  The method of achieving this is a local matter
   and may consist of using a single authoritative source for the
   generation of unique time values, or may consist of the use of the
   fractional seconds part to hold a replica identifier.












































Sermersheim, et al.     Expires January 19, 2015               [Page 41]

Internet-Draft    Password Policy for LDAP Directories         July 2014


12.  Security Considerations

   This document defines a set of rules to implement in an LDAP server,
   in order to mitigate some of the security risks associated with the
   use of passwords and to make it difficult for password cracking
   programs to break into directories.

   Authentication with a password MUST follow the recommendations made
   in [RFC4513].

   Modifications of passwords SHOULD only occur when the connection is
   protected with confidentiality and secure authentication.

   Access controls SHOULD be used to restrict access to the password
   policy attributes.  The attributes defined to maintain the password
   policy state information SHOULD only be modifiable by the password
   administrator or higher authority.  The pwdHistory attribute MUST be
   subject to the same level of access control as the attrbute holding
   the password.

   As it is possible to define a password policy for one specific user
   by adding a subentry immediately under the user's entry, Access
   Controls SHOULD be used to restrict the use of the pwdPolicy object
   class or the LDAP subentry object class.

   When the intruder detection password policy is enforced, the LDAP
   directory is subject to a denial of service attack.  A malicious user
   could deliberately lock out one specific user's account (or all of
   them) by sending bind requests with wrong passwords.  There is no way
   to protect against this kind of attack.  The LDAP directory server
   SHOULD log as much information as it can (such as client IP address)
   whenever an account is locked, in order to be able to identify the
   origin of the attack.  Denying anonymous access to the LDAP directory
   is also a way to restrict this kind of attack.  Using the login delay
   instead of the lockout mechanism will also help avoid this denial of
   service.

   Returning certain status codes (such as passwordPolicyResponse.error
   = accountLocked) allows a denial of service attacker to know that it
   has successfully denied service to an account.  Servers SHOULD
   implement additional checks which return the same status when it is
   sensed that some number of failed authentication requests has occured
   on a single connection, or from a client address.  Server
   implementors are encouraged to invent other checks similar to this in
   order to thwart this type of DoS attack.






Sermersheim, et al.     Expires January 19, 2015               [Page 42]

Internet-Draft    Password Policy for LDAP Directories         July 2014


13.  IANA Considerations

   In accordance with [RFC4520] the following registrations are
   requested.

13.1.  Object Identifiers

   The OIDs used in this specification are derived from iso(1)
   identified-organization(3) dod(6) internet(1) private(4)
   enterprise(1) Sun(42) products(2) LDAP(27) ppolicy(8).  These OIDs
   have been in use since at least July 2001 when version 04 of this
   draft was published.  No additional OID assignment is being
   requested.

13.2.  LDAP Protocol Mechanisms

   Registration of the protocol mechanisms specified in this document is
   requested.

      Subject: Request for LDAP Protocol Mechanism Registration

      Object Identifier: 1.3.6.1.4.1.42.2.27.8.5.1

      Description: Password Policy Request and Response Control

      Person & email address to contact for further information:

         Howard Chu <hyc@symas.com>

      Usage: Control

      Specification: (I-D) draft-behera-ldap-password-policy

      Author/Change Controller: IESG

      Comments:

13.3.  LDAP Descriptors

   Registration of the descriptors specified in this document is
   requested.

      Subject: Request for LDAP Descriptor Registration

      Descriptor (short name): see table

      Object Identifier: see table




Sermersheim, et al.     Expires January 19, 2015               [Page 43]

Internet-Draft    Password Policy for LDAP Directories         July 2014


      Description: see table

      Person & email address to contact for further information:

         Howard Chu <hyc@symas.com>

      Specification: (I-D) draft-behera-ldap-password-policy

      Author/Change Controller: IESG

      Comments:

      Name                    Type  OID
      ----------------------- ----  ------------------------------
      pwdPolicy               O     1.3.6.1.4.1.42.2.27.8.2.1
      pwdAttribute            A     1.3.6.1.4.1.42.2.27.8.1.1
      pwdMinAge               A     1.3.6.1.4.1.42.2.27.8.1.2
      pwdMaxAge               A     1.3.6.1.4.1.42.2.27.8.1.3
      pwdInHistory            A     1.3.6.1.4.1.42.2.27.8.1.4
      pwdCheckQuality         A     1.3.6.1.4.1.42.2.27.8.1.5
      pwdMinLength            A     1.3.6.1.4.1.42.2.27.8.1.6
      pwdMaxLength            A     1.3.6.1.4.1.42.2.27.8.1.31
      pwdExpireWarning        A     1.3.6.1.4.1.42.2.27.8.1.7
      pwdGraceAuthNLimit      A     1.3.6.1.4.1.42.2.27.8.1.8
      pwdGraceExpiry          A     1.3.6.1.4.1.42.2.27.8.1.30
      pwdLockout              A     1.3.6.1.4.1.42.2.27.8.1.9
      pwdLockoutDuration      A     1.3.6.1.4.1.42.2.27.8.1.10
      pwdMaxFailure           A     1.3.6.1.4.1.42.2.27.8.1.11
      pwdFailureCountInterval A     1.3.6.1.4.1.42.2.27.8.1.12
      pwdMustChange           A     1.3.6.1.4.1.42.2.27.8.1.13
      pwdAllowUserChange      A     1.3.6.1.4.1.42.2.27.8.1.14
      pwdSafeModify           A     1.3.6.1.4.1.42.2.27.8.1.15
      pwdMinDelay             A     1.3.6.1.4.1.42.2.27.8.1.24
      pwdMaxDelay             A     1.3.6.1.4.1.42.2.27.8.1.25
      pwdMaxIdle              A     1.3.6.1.4.1.42.2.27.8.1.26
      pwdChangedTime          A     1.3.6.1.4.1.42.2.27.8.1.16
      pwdAccountLockedTime    A     1.3.6.1.4.1.42.2.27.8.1.17
      pwdFailureTime          A     1.3.6.1.4.1.42.2.27.8.1.19
      pwdHistory              A     1.3.6.1.4.1.42.2.27.8.1.20
      pwdGraceUseTime         A     1.3.6.1.4.1.42.2.27.8.1.21
      pwdReset                A     1.3.6.1.4.1.42.2.27.8.1.22
      pwdPolicySubEntry       A     1.3.6.1.4.1.42.2.27.8.1.23
      pwdStartTime            A     1.3.6.1.4.1.42.2.27.8.1.27
      pwdEndTime              A     1.3.6.1.4.1.42.2.27.8.1.28
      pwdLastSuccess          A     1.3.6.1.4.1.42.2.27.8.1.29






Sermersheim, et al.     Expires January 19, 2015               [Page 44]

Internet-Draft    Password Policy for LDAP Directories         July 2014


      Legend
      --------------------
      A => Attribute Type
      O => Object Class

13.4.  LDAP AttributeDescription Options

   Registration of the AttributeDescription option specified in this
   document is requested.

      Subject: Request for LDAP Attribute Description Option
      Registration

      Option Name: pwd-

      Family of Options: YES

      Person & email address to contact for further information:

         Howard Chu <hyc@symas.com>

      Specification: (I-D) draft-behera-ldap-password-policy

      Author/Change Controller: IESG

      Comments:

         Used with policy state attributes to specify to which password
         attribute the state belongs.






















Sermersheim, et al.     Expires January 19, 2015               [Page 45]

Internet-Draft    Password Policy for LDAP Directories         July 2014


14.  Acknowledgement

   This document is based in part on prior work done by Valerie Chu from
   Netscape Communications Corp, published as
   draft-vchu-ldap-pwd-policy-00.txt (December 1998).  Prasanta Behera
   participated in early revisions of this document.













































Sermersheim, et al.     Expires January 19, 2015               [Page 46]

Internet-Draft    Password Policy for LDAP Directories         July 2014


15.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2195]  Klensin, J., Catoe, R., and P. Krumviede, "IMAP/POP
              AUTHorize Extension for Simple Challenge/Response",
              RFC 2195, September 1997.

   [RFC2831]  Leach, P. and C. Newman, "Using Digest Authentication as a
              SASL Mechanism", RFC 2831, May 2000.

   [RFC3062]  Zeilenga, K., "LDAP Password Modify Extended Operation",
              RFC 3062, February 2001.

   [RFC3672]  Zeilenga, K., "Subentries in the Lightweight Directory
              Access Protocol (LDAP)", RFC 3672, December 2003.

   [RFC4422]  Melnikov, A. and K. Zeilenga, "Simple Authentication and
              Security Layer (SASL)", RFC 4422, June 2006.

   [RFC4511]  Sermersheim, J., "Lightweight Directory Access Protocol
              (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512,
              June 2006.

   [RFC4513]  Harrison, R., "Lightweight Directory Access Protocol
              (LDAP): Authentication Methods and Security Mechanisms",
              RFC 4513, June 2006.

   [RFC4517]  Legg, S., "Lightweight Directory Access Protocol (LDAP):
              Syntaxes and Matching Rules", RFC 4517, June 2006.

   [RFC4520]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [X.680]    International Telecommunications Union, "Abstract Syntax
              Notation One (ASN.1): Specification of basic notation",
              ITU-T Recommendation X.680, July 2002.

   [X.690]    International Telecommunications Union, "Information
              Technology - ASN.1 encoding rules: Specification of Basic
              Encoding Rules (BER),  Canonical Encoding Rules (CER) and
              Distinguished Encoding Rules (DER)", ITU-T
              Recommendation X.690, July 2002.



Sermersheim, et al.     Expires January 19, 2015               [Page 47]

Internet-Draft    Password Policy for LDAP Directories         July 2014


Authors' Addresses

   Jim Sermersheim
   Novell, Inc
   1800 South Novell Place
   Provo, Utah  84606
   US

   Phone: +1 801 861-3088
   Email: jimse@novell.com


   Ludovic Poitou
   Sun Microsystems
   180, Avenue de l'Europe
   Zirst de Montbonnot, Saint Ismier cedex  38334
   FR

   Phone: +33 476 188 212
   Email: ludovic.poitou@sun.com


   Howard Chu (editor)
   Symas Corp.
   18740 Oxnard Street, Suite 313A
   Tarzana, California  91356
   US

   Phone: +1 818 757-7087
   Email: hyc@symas.com





















Sermersheim, et al.     Expires January 19, 2015               [Page 48]

alt-openldap11-devel/drafts/draft-sermersheim-ldap-distproc-xx.txt000064400000244427150410163300021236 0ustar00
Network Working Group                                     J. Sermersheim
Internet-Draft                                               Novell, Inc
Expires: August 26, 2005                               February 22, 2005



               Distributed Procedures for LDAP Operations
                 draft-sermersheim-ldap-distproc-02.txt


Status of this Memo


   This document is an Internet-Draft and is subject to all provisions
   of Section 3 of RFC 3667.  By submitting this Internet-Draft, each
   author represents that any applicable patent or other IPR claims of
   which he or she is aware have been or will be disclosed, and any of
   which he or she become aware will be disclosed, in accordance with
   RFC 3668.


   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as
   Internet-Drafts.


   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."


   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.


   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.


   This Internet-Draft will expire on August 26, 2005.


Copyright Notice


   Copyright (C) The Internet Society (2005).


Abstract


   This document provides the data types and procedures used while
   servicing Lightweight Directory Access Protocol (LDAP) user
   operations in order to participate in a distributed directory.  In
   particular, it describes the way in which an LDAP user operation in a
   distributed directory environment finds its way to the proper DSA(s)
   for servicing.





Sermersheim              Expires August 26, 2005                [Page 1]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



Discussion Forum


   Technical discussion of this document will take place on the IETF
   LDAP Extensions mailing list <ldapext@ietf.org>.  Please send
   editorial comments directly to the author.


Table of Contents


   1.   Distributed Operations Overview  . . . . . . . . . . . . . .   3
   2.   Conventions  . . . . . . . . . . . . . . . . . . . . . . . .   4
   3.   Distributed Operation Data Types . . . . . . . . . . . . . .   5
   3.1  ContinuationReference  . . . . . . . . . . . . . . . . . . .   5
   3.2  ChainedRequest . . . . . . . . . . . . . . . . . . . . . . .   9
   3.3  Chained Response . . . . . . . . . . . . . . . . . . . . . .  11
   4.   Distributed Procedures . . . . . . . . . . . . . . . . . . .  14
   4.1  Name resolution  . . . . . . . . . . . . . . . . . . . . . .  14
   4.2  Operation Evaluation . . . . . . . . . . . . . . . . . . . .  16
   4.3  Populating the ContinuationReference . . . . . . . . . . . .  19
   4.4  Sending a ChainedRequest . . . . . . . . . . . . . . . . . .  21
   4.5  Emulating the Sending of a ChainedRequest  . . . . . . . . .  23
   4.6  Receiving a ChainedRequest . . . . . . . . . . . . . . . . .  24
   4.7  Returning a Chained Response . . . . . . . . . . . . . . . .  25
   4.8  Receiving a Chained Response . . . . . . . . . . . . . . . .  26
   4.9  Returning a Referral or Intermediate Referral  . . . . . . .  27
   4.10 Acting on a Referral or Intermediate Referral  . . . . . . .  30
   4.11 Ensuring non-existence of an entry under an nssr . . . . . .  31
   4.12 Mapping a referralURI to an LDAP URI . . . . . . . . . . . .  31
   4.13 Using the ManageDsaIT control  . . . . . . . . . . . . . . .  32
   5.   Security Considerations  . . . . . . . . . . . . . . . . . .  33
   6.   Normative References . . . . . . . . . . . . . . . . . . . .  33
        Author's Address . . . . . . . . . . . . . . . . . . . . . .  34
   A.   IANA Considerations  . . . . . . . . . . . . . . . . . . . .  35
   A.1  LDAP Object Identifier Registrations . . . . . . . . . . . .  35
   A.2  LDAP Protocol Mechanism Registrations  . . . . . . . . . . .  35
   A.3  LDAP Descriptor Registrations  . . . . . . . . . . . . . . .  37
   A.4  LDAP Result Code Registrations . . . . . . . . . . . . . . .  38
        Intellectual Property and Copyright Statements . . . . . . .  39















Sermersheim              Expires August 26, 2005                [Page 2]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



1.  Distributed Operations Overview


   One characteristic of X.500-based directory systems [X500] is that,
   given a distributed Directory Information Tree (DIT), a user should
   potentially be able to have any service request satisfied (subject to
   security, access control, and administrative policies) irrespective
   of the Directory Service Agent (DSA) to which the request was sent.
   To accommodate this requirement, it is necessary that any DSA
   involved in satisfying a particular service request have some
   knowledge (as specified in {TODO: Link to future Distributed Data
   Model doc}) of where the requested information is located and either
   return this knowledge to the requester or attempt to satisfy the
   request satisfied on the behalf of the requester (the requester may
   either be a Directory User Agent (DUA) or another DSA).


   Two modes of operation distribution are defined to meet these
   requirements, namely "chaining" and "returning referrals".
   "Chaining" refers to the attempt by a DSA to satisfy a request by
   sending one or more chained operations to other DSAs.  "Returning
   referrals", is the act of returning distributed knowledge information
   to the requester, which may then itself interact with the DSA(s)
   identified by the distributed knowledge information.  It is a goal of
   this document to provide the same level of service whether the
   chaining or referral mechanism is used to distribute an operation.


   The processing of an operation is talked about in two major phases,
   namely "name resolution", and "operation evaluation".  Name
   resolution is the act of locating a local DSE held on a DSA given a
   distinguished name (DN).  Operation evaluation is the act of
   performing the operation after the name resolution phase is complete.


   While distributing an operation, a request operation may be
   decomposed into several sub-operations.


   The distributed directory operation procedures described in this
   document assume the absense of the ManageDsaIT control defined in
   [RFC3296] and described in Section 4.13.















Sermersheim              Expires August 26, 2005                [Page 3]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



2.  Conventions


   Imperative keywords defined in [RFC2119] are used in this document,
   and carry the meanings described there.


   All Basic Encoding Rules (BER) [X690] encodings follow the
   conventions found in Section 5.1 of [RFC2251].













































Sermersheim              Expires August 26, 2005                [Page 4]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



3.  Distributed Operation Data Types


   The data types in this section are used by the chaining and referral
   distributed operation mechanisms described in Section 4


3.1  ContinuationReference


   As an operation is being processed by a DSA, it is useful to group
   the information passed between various procedures as a collection of
   data.  The ContinuationReference data type is introduced for this
   purpose.  This data type is populated and consumed by various
   procedures discussed in various sections of this document.  In
   general, a ContinuationReference is used when indicating that
   directory information being acted on is not present locally, but may
   be present elsewhere.


   A ContinuationReference consists of one or more addresses which
   identify remote DSAs along with other information pertaining both to
   the distributed knowledge information held on the local DSA as well
   as information relevant to the operation.  This data type is
   expressed here in Abstract Syntax Notation One (ASN.1) [X680].


      ContinuationReference ::= SET {
         referralURI      [0] SET SIZE (1..MAX) OF URI,
         localReference   [2] LDAPDN,
         referenceType    [3] ReferenceType,
         remainingName    [4] RelativeLDAPDN OPTIONAL,
         searchScope      [5] SearchScope OPTIONAL,
         searchedSubtrees [6] SearchedSubtrees OPTIONAL,
         failedName       [7] LDAPDN OPTIONAL,
         ...  }


   <Editor's Note: Planned for addition is a searchCriteria field which
   is used both for assuring that the remote object is in fact the
   object originally pointed to (this mechanism provides a security
   measure), and also to allow moved or renamed remote entries to be
   found.  Typically the search criteria would have a filter value of
   (entryUUID=<something>)>


   URI ::= LDAPString     -- limited to characters permitted in URIs
   [RFC2396].


      ReferenceType ::= ENUMERATED {
         superior               (0),
         subordinate            (1),
         cross                  (2),
         nonSpecificSubordinate (3),





Sermersheim              Expires August 26, 2005                [Page 5]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



         suplier                (4),
         master                 (5),
         immediateSuperior      (6),
         self                   (7),
         ...  }
      SearchScope ::= ENUMERATED {
         baseObject         (0),
         singleLevel        (1),
         wholeSubtree       (2),
         subordinateSubtree (3),
         ...  }


   SearchedSubtrees ::= SET OF RelativeLDAPDN


   LDAPDN, RelativeLDAPDN, and LDAPString, are defined in [RFC2251].


   The following subsections introduce the fields of the
   ContinuationReference data type, but do not provide in-depth
   semantics or instructions on the population and consumption of the
   fields.  These topics are discussed as part of the procedural
   instructions.


3.1.1  ContinuationReference.referralURI


   The list of referralURI values is used by the receiver to progress
   the operation.  Each value specifies (at minimum) the protocol and
   address of one or more remote DSA(s) holding the data sought after.
   URI values which are placed in ContinuationReference.referralURI must
   allow for certain elements of data to be conveyed.  Section 3.1.1.1
   describes these data elements.  Furthermore, a mapping must exist
   which relates the parts of a specified URI to these data elements.
   This document provides such a mapping for the LDAP URL [RFC2255] in
   Section 4.12.


   In some cases, a referralURI will contain data which has a
   counterpart in the fields of the ContinuationReference (an example is
   where the referralURI is an LDAP URL, holds a <scope> value, and the
   ContinuationReference.searchScope field is also present).  In these
   cases, the data held on the referralURI overrides the field in the
   ContinuationReference.  Specific examples of this are highlighted in
   other sections.  Providing a means for these values to exist as
   fields of the ContinuationReference allows one value to be applied to
   all values of referralURI (as opposed to populating duplicate data on
   all referralURI values).


   If a referralURI value identifies an LDAP-enabled DSA [RFC3377], the
   LDAP URL form is used.





Sermersheim              Expires August 26, 2005                [Page 6]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



3.1.1.1  Elements of referralURI Values


   The following data elements must be allowed and identified for a
   specified URI type to be used to convey referral information.  Each
   element is given a name which begins with 'referralURI.' for clarity
   when referencing the elements conceptually in other parts of this
   document.


   o  referralURI.protocolIdentifier.  There must be an indication of
      the protocol to be used to contact the DSA identified by the URI.
   o  referralURI.accessPoint.  The URI must identify a DSA in a manner
      that can be used to contact it using the protocol specified in
      protocolIdentifier.
   o  referralURI.targetObject.  Holds the name to be used as the base
      DN of the operation being progressed.  This field must be allowed
      by the URI specification, but may be omitted in URI instances for
      various reasons.
   o  referralURI.localReference.  See Section 3.1.2.  This field must
      be allowed by the URI specification, but may be omitted in URI
      instances for various reasons.
   o  referralURI.searchScope.  See Section 3.1.5.  This field must be
      allowed by the URI specification, but may be omitted in URI
      instances for various reasons.
   o  referralURI.searchedSubtrees.  See Section 3.1.6.  This field must
      be allowed by the URI specification, but may be omitted in URI
      instances for various reasons.
   o  referralURI.failedName.  See Section 3.1.7.  This field must be
      allowed by the URI specification, but may be omitted in URI
      instances for various reasons.


3.1.2  ContinuationReference.localReference


   This names the DSE which was found to hold distributed knowledge
   information, and thus which caused the ContinuationReference to be
   formed.  This field is primarily used to help convey the new target
   object name, but may also be used for purposes referential integrity
   (not discussed here).  In the event that the root object holds the
   distributed knowledge information, this field is present and is
   populated with an empty DN.


3.1.3  ContinuationReference.referenceType


   Indicates the DSE Type of the ContinuationReference.localReference.
   This field may be used to determine how to progress an operations
   (i.e.  if the value is nonSpecificSubordinate, a search continuation
   will exclude the ContinuationReference.referenceType).






Sermersheim              Expires August 26, 2005                [Page 7]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



3.1.4  ContinuationReference.remainingName


   In certain scenarios, the localReference does not completely name the
   DSE to be used as the new target object name.  In these cases,
   remainingName is populated with the RDNSequence relative to the
   localReference of the target object name being resolved.  Some
   examples of these scenarios include (but are not restricted to):


   o  During name resolution, the name is not fully resolved, but a DSE
      holding distributed knowledge information is found, causing a
      ContinuationReference to be generated.
   o  While searching, an alias is dereferenced.  The aliasedObjectName
      points to a DSE of type glue which is subordinate to a DSE holding
      distributed knowledge information.


3.1.5  ContinuationReference.searchScope


   Under certain circumstances, when progressing a search operation, a
   search scope different than that of the original search request must
   be used.  This field facilitates the conveyance of the proper search
   scope to be used when progressing the distributed operation.


   The scope of subordinateSubtree has been added to the values allowed
   by the LDAP SearchRequest.scope field.  This scope includes the
   subtree of entries below the base DN, but does not include the base
   DN itself.  This is used here when progressing distributed search
   operations caused by the existence of a DSE of type nssr.


   If a referralURI.searchScope is present, it overrides this field
   while that referralURI is being operated upon.


3.1.6  ContinuationReference.searchedSubtrees


   For ContinuationReferences generated while processing a search
   operation with a scope of wholeSubtree, each value of this field
   indicates that a particular subtree below the target object has
   already been searched.  Consumers of this data use it to cause the
   progression of the search operation to exclude these subtrees as a
   mechanism to avoid receiving duplicate entries.


   If a referralURI.searchedSubtrees is present, it overrides this field
   while that referralURI is being operated upon.


3.1.7  ContinuationReference.failedName


   When an operation requires that multiple names be resolved (as is the
   case with the ModifyDN operation), this field is used to specify
   which name was found to be non-local.




Sermersheim              Expires August 26, 2005                [Page 8]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   If a referralURI.failedName is present, it overrides this field while
   that referralURI is being operated upon.


3.2  ChainedRequest


   The Chained Request is sent as an LDAP extended operation.  The
   requestName is IANA-ASSIGNED-OID.1.  The requestValue is the BER
   encoding of the following ChainedRequestValue ASN.1 definition:


      ChainedRequestValue ::= SEQUENCE {


         chainingArguments ChainingArguments,
         operationRequest  OperationRequest }


      ChainingArguments ::= SEQUENCE {


         targetObject     [0] LDAPDN OPTIONAL,
         referenceType    [1] ReferenceType,
         traceInformation [2] ChainingTraceInformation,
         searchScope      [3] SearchScope OPTIONAL,
         searchedSubtrees [4] SearchedSubtrees OPTIONAL}


      ChainingTraceInformation ::= SET OF LDAPURL


      OperationRequest ::= SEQUENCE {


         Request ::= CHOICE {


            bindRequest    BindRequest,
            searchRequest  SearchRequest,
            modifyRequest  ModifyRequest,
            addRequest     AddRequest,
            delRequest     DelRequest,
            modDNRequest   ModifyDNRequest,
            compareRequest CompareRequest,
            extendedReq    ExtendedRequest,
            ...  },
         controls       [0] Controls COPTIONAL }


   BindRequest, SearchRequest, ModifyRequest, AddRequest, DelRequest,
   ModifyDNRequest, CompareRequest, ExtendedRequest and Controls are
   defined in [RFC2251].


3.2.1  ChainedRequestValue.chainingArguments


   In general, these fields assist in refining the original operation as
   it is to be executed on the receiving DSA.





Sermersheim              Expires August 26, 2005                [Page 9]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



3.2.1.1  ChainedRequestValue.chainingArguments.targetObject


   This field contains the new target (or base) DN for the operation.


   The sending DSA populates this under different scenarios including
   the case where an alias has been dereferenced while resolving the DN,
   and also the case where a referral carries a target name different
   from the reference object that caused the referral.


   This field can be omitted only if it would be the the same value as
   the object or base object parameter in the
   ChainedRequestValue.operationRequest, in which case its implied value
   is that value.


   The receiving DSA examines this field and (if present) uses it rather
   than the base DN held in the ChainedRequestValue.operationRequest.


3.2.1.2  ChainedRequestValue.chainingArguments.referenceType


   See Section 3.1.3.


   If the receiver encounters a value of nonSpecificSubordinate in this
   field, it indicates that the operation is being chained due to DSE of
   type nssr.  In this case, the receiver allows (and expects) the base
   DN to name the immediate superior of a context prefix.


3.2.1.3  ChainedRequestValue.chainingArguments.traceInformation


   This contains a set of URIs.  Each value represents the address of a
   DSA and DN that has already been contacted while attempting to
   service the operation.  This field is used to detect looping while
   servicing a distributed operation.


   The sending DSA populates this with its own URI, and also the URIs of
   any DSAs that have already been chained to.  The receiving DSA
   examines this list of URIs and returns a loopDetect error if it finds
   that any of the addresses and DNs in the listed URI's represent it's
   own.


3.2.1.4  ChainedRequestValue.chainingArguments.searchScope


   See Section 3.1.5.


3.2.1.5  ChainedRequestValue.chainingArguments.searchedSubtrees


   See Section 3.1.6.






Sermersheim              Expires August 26, 2005               [Page 10]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



3.2.2  ChainedRequestValue.operationRequest


   This holds the original LDAP operation request.  This is restricted
   to a subset of all LDAP operations.  Namely, the following LDAP
   operation types are not allowed:


   o  Abandon/Cancel operations.  When an abandon or cancel operation
      needs to be chained, it is sent to the remote DSA as-is.  This is
      because there is no need to track it for loop detection or pass on
      any other information normally found in ChainingArguments.
   o  Unbind.  Again, there is no need to send chaining-related
      information to a DSA to perform an unbind.  DSAs which chain
      operations maintain connections as they see fit.
   o  Chained Operation.  When a DSA receives a chained operation, and
      must again chain that operation to a remote DSA, it sends a
      ChainedRequest where the ChainedRequestValue.operationRequest is
      that of the incoming ChainedRequestValue.operationRequest.


3.3  Chained Response


   The Chained Response is sent as an LDAP IntermediateResponse
   [RFC3771], or LDAP ExtendedResponse [RFC2251], depending on whether
   the operation is complete or not.  In either case, the responseName
   is omitted.  For intermediate responses, the
   IntermediateResponse.responseValue is the BER encoding of the
   ChainedIntermediateResponseValue ASN.1 definition.  For completed
   operations, the ExtendedResponse.value is the BER encoding of the
   ChainedFinalResponseValue ASN.1 definition.


      ChainedIntermediateResponseValue ::= SEQUENCE {


         chainedResults    ChainingResults,
         operationResponse IntermediateResponse }


      ChainedFinalResponseValue ::= SEQUENCE {


         chainedResults    ChainingResults,
         operationResponse FinalResponse }


      ChainingResults ::= SEQUENCE {


         searchedSubtrees [0] SearchedSubtrees OPTIONAL,
         ...  }


      IntermediateResponse ::= SEQUENCE {


         Response ::= CHOICE {





Sermersheim              Expires August 26, 2005               [Page 11]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005




            searchResEntry       SearchResultEntry,
            searchResRef         SearchResultReference,
            intermediateResponse IntermediateResponse
            ...  },
         controls [0] Controls COPTIONAL }


      FinalResponse ::= SEQUENCE {


         Response ::= CHOICE {


            bindResponse    BindResponse,
            searchResDone   SearchResultDone,
            modifyResponse  ModifyResponse,
            addResponse     AddResponse,
            delResponse     DelResponse,
            modDNResponse   ModifyDNResponse,
            compareResponse CompareResponse,
            extendedResp    ExtendedResponse,
            ...  },
         controls [0] Controls COPTIONAL }


   BindResponse, SearchResultEntry, SearchResultDone,
   SearchResultReference, ModifyResponse, AddResponse, DelResponse,
   ModifyDNResponse, CompareResponse, ExtendedResponse, and Controls are
   defined in [RFC2251].  IntermediateResponse is defined in [RFC3771].


3.3.1  ChainingResults


   In general, this is used to convey additional information that may
   needed in the event that the operation needs to be progressed
   further.


3.3.1.1  ChainingResults.searchedSubtrees


   Each value of this field indicates that a particular subtree below
   the target object has already been searched.  This is particularly
   useful while chaining search operations during operation evaluation
   caused by the presence of a DSA of type nssr.  Each DSA referenced by
   the nssr holds one or more naming contexts subordinate to the nssr
   DSE.  The ChainingResults.searchedSubtrees field allows the DSA being
   chained to, to inform the sending DSA which subordinate naming
   contexts have been searched.  This information may be passed to
   further DSAs listed on the nssr in order to reduce the possibility of
   duplicate entries being returned.







Sermersheim              Expires August 26, 2005               [Page 12]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



3.3.2  ChainedIntermediateResponseValue.intermediateResponse and
      ChainedFinalResponseValue.finalResponse


   This holds the directory operation response message tied to the
   ChainedRequestValue.operationRequest.















































Sermersheim              Expires August 26, 2005               [Page 13]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



4.  Distributed Procedures


   For the purposes of describing a distributed operation, operations
   are said to consist of two major phases -- name resolution and
   operation evaluation.  These terms are adopted from [X518].  Name
   resolution is the act of locating a DSE said to be held locally by a
   DSA given a distinguished name (DN).  Operation evaluation is the act
   of performing the operation after the name resolution phase is
   complete.


   Furthermore, there are two modes of distributing an operation --
   chaining, and returning referrals.  Chaining is the act of forwarding
   an unfinished operation to another DSA for completion (this may
   happen during name resolution or operation evaluation).  In this
   case, the forwarding DSA sends a chained operation to a receiving
   DSA, which attempts to complete the operation.  Alternately, the DSA
   may return a referral (or intermediate referral), and the client may
   use that referral in order to forward the unfinished operation to
   another DSA.  Whether the operation is distributed via chaining or
   referrals is a decision left to the DSA and or DUA.


   The term 'intermediate referral' describes a referral returned during
   the operation evaluation phase of an operation.  These include
   searchResultReferences, referrals returned with an
   intermediateResponse [RFC3771], or future referrals which indicate
   that they are intermediate referrals.


   An operation which is distributed while in the operation evaluation
   phase is termed a 'sub-operation'.


   This document inserts a step between the two distributed operation
   phases in order to commonize the data and processes followed prior to
   chaining an operation or returning a referral.  This step consists of
   populating a ContinuationReference data type.


4.1  Name resolution


   Before evaluating (enacting) most directory operations, the DSE named
   by the target (often called the base DN) of the operation must be
   located .  This is done by evaluating the RDNs of the target DN one
   at a time, starting at the rootmost RDN.  Each RDN is compared to the
   DSEs held by the DSA until the set of RDNs is exhausted, or an RDN
   cannot be found.


   If the DSE named by the target is found to be local, the name
   resolution phase of the operation completes and the operation
   evaluation phase begins.





Sermersheim              Expires August 26, 2005               [Page 14]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   If it is found that the target does not name a local DSE nor a DSE
   that may held by another DSA, it is said that the target does not
   exist, and the operation fails with noSuchObject (subject to local
   policy).


   If it is found that the DSE named by the target is non-local to the
   DSA, but may reside elsewhere, name resolution is said to be
   incomplete.  In this case, the operation may be distributed by
   creating a ContinuationReference (Section 4.3) and either chaining
   the operation (Section 4.4 and Section 4.5)or returning a referral
   (Section 4.9).


4.1.1  Determining that a named DSE is local to a DSA


   If a DSE held by a DSA falls within a naming context held by the DSA,
   or is the root DSE on a first-level DSA, it is said to be local to
   that DSA


4.1.2  Determining that a named DSE does not exist


   A named DSE is said to not exist if, during name resolution the DSE
   is not found, but if found it would fall within a naming context held
   by the DSA.


4.1.3  Determining that a named DSE is non-local


   If a named DSE is niether found to be local to the DSA, nor found to
   not exist, it is said to be non-local to a DSA.  In this case, it is
   indeterminate whether the named DSE exists.


   When a named DSE is found to be non-local, there should be
   distributed knowledge information available to be used to either
   return a referral or chain the operation.


4.1.3.1  Locating distributed knowledge information for a non-local
        target


   If it has been determined that a target names a non-local DSE,
   distributed knowledge information may be found by first examining the
   DSE named by the target, and subsequently all superior DSEs beginning
   with the immediate superior and ending with the root, until an
   examined DSE is one of types:


   {TODO: should DSE types be all caps? It would be easier to read.}
   o  subr
   o  supr
   o  immsupr





Sermersheim              Expires August 26, 2005               [Page 15]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   o  xr
   o  nssr


   The examined DSE which is of one of these types holds the distributed
   knowledge information for the non-local named target.  This DSE is
   said to be the found distributed knowledge information of the
   non-local target.  This found distributed knowledge information may
   then be used to distribute the operation.


   If no examined DSEs are of any of these types, the distributed
   knowledge information is mis-configured, and the error
   invalidReference is returned.


4.1.4  Special case for the Add operation


   During the name resolution phase of the Add operation, the immediate
   parent of the base DN is resolved.


   If the immediate parent of the entry to be added is a DSE of type
   nssr, then further interrogation is needed to ensure that the entry
   to be added does not exist.  Methods for doing this are found in
   Section 4.11.  {TODO: don't make this mandatory.  Also, it doesn't
   work without transaction semantics.  Same prob in the mod dn below.}.


4.1.5  Special case for the ModifyDN operation


   When the modifyDN operation includes a newSuperior name, it must be
   resolved as well as the base DN being modified.  If either of these
   result in a non-local name, the name causing the operation to be
   distributed should be conveyed (Section 4.3.5).  {TODO: also mention
   access control problems, and mention (impl detail) that
   affectsmultidsa can be used.}


   If during operation evaluation of a ModifyDN operation, the
   newSuperior names a DSE type of nssr, then further interrogation is
   needed to ensure that the entry to be added does not exist.  Methods
   for doing this are found in Section 4.11.


4.2  Operation Evaluation


   Once name resolution has completed.  The DSE named in the target has
   been found to be local to a DSA.  At this point the operation can be
   carried out.  During operation evaluation distributed knowledge
   information may be found that may cause the DSA to distribute the
   operation.  When this happens, the operation may be distributed by
   creating a ContinuationReference (Section 4.3) and either chaining
   the operation (Section 4.4 and Section 4.5)or returning a referral
   (Section 4.9).




Sermersheim              Expires August 26, 2005               [Page 16]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   If, during the location of the distributed knowledge information, the
   distributed knowledge information is found to be mis-configured,
   operation semantics are followed (some operations may call for an
   error to be returned, while others call for the error to be ignored).
   {TODO: either make this more specific, or less specific, or just toss
   it out.}


4.2.1  Search operation


   During operation evaluation of a search operation, the DSA must
   determine whether there is distributed knowledge information in the
   scope of the search.  Any DSE in the search scope which is of the
   following types is considered to be 'found distributed knowledge
   information' {TODO: use a better term than found distributed
   knowledge information} in the search scope:


   o  subr
   o  nssr (see nssr note)
   o  xr {TODO: I think xr only qualifies when an alias is dereferenced
      to an xr.  Otherwisw, there should always be a subr above the xr
      if it falls in the search scope.}


   Note that due to alias dereferencing, the search scope may expand to
   include entries outside of the scope originally specified in the
   search operation.  {TODO: note that an aliased object may be glue
   which needs to result in any subr or xr above it to be found}


   Nssr Note: A DSE of type nssr is only considered to be found
   distributed knowledge information when the scope of the search
   includes entries below it.  For example, when the search scope is
   wholeSubtree or subordinateSubtree and a DSE of type nssr is found in
   the scope, or if the search scope is singleLevel and the target
   object names a DSE of type nsssr.


   {TODO: The following sections are talking about how the continuation
   reference is to be populated.  Move to next secion.  Can probably
   just say that whole subtree or subordinare subtree encountering nssr,
   and single level rooted at nssr result in a continuation reference.
   base at, and single level above do not result in a continuation
   reference.}


4.2.1.1  Search operation with singleLevel scope


   If distributed knowledge information is found during operation
   evaluation of a search with a singleLevel scope, it will cause the
   resulting ContinuationReference.searchScope to be set to baseObject.






Sermersheim              Expires August 26, 2005               [Page 17]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



4.2.1.2  Search operation encountering nssr knowledge reference


   When a search operation encounters distributed knowledge information
   which is a DSE type of nssr during operation evaluation, the
   following instructions are followed:


   Note that when a search operation is being progressed due to nssr
   knowledge information, the subsequent distributed progression of the
   search is caused to be applied to each DSA listed as non-specific
   knowledge information (This is talked about in Section 4.3.2).  In
   the event that multiple DSAs listed in the knowledge information hold
   copies of the same directory entries, the 'already searched' and
   'duplicate elimination' mechanisms SHOULD be used to prevent
   duplicate search result entries from ultimately being returned.


4.2.1.2.1  wholeSubtree search scope


   When the search scope is wholeSubtree, the
   ContinuationReference.searchScope is set to subordinateSubtree.
   Because the ContinuationReference.referrenceType is set to
   nonSpecificSubordinate, the receiving protocol peer allows (and
   expects) name resolution to stop at an immsupr DSE type which is
   treated as a local DSE.  The subordinateSubtree scope instructs the
   receiving protocol peer to exclude the target object from the
   sub-search.


4.2.1.2.2  singleLevel search scope


   When the search scope is singleLevel, and the base DN is resolved to
   a DSE of type nssr, subsequent distributed progressions of the search
   are caused to use the same base DN, and a scope of singleLevel.
   Receiving protocol peers will only apply the search to entries below
   the target object.


   When the search scope is singleLevel and an evaluated DSE is of type
   nssr, no special handling is required.  The search is applied to that
   DSE if it is of type entry.


4.2.1.2.3  baseObject search scope


   No special handling is needed when the search scope is baseObject and
   the base DN is an nssr DSEType.  The search is applied to that DSE if
   it is of type entry.


4.2.1.3  Search operation rooted at an nssr DSE type


   (TODO: a subordinateSubtree scope needs to change to wholeSubtree if
   references are found.)




Sermersheim              Expires August 26, 2005               [Page 18]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



4.3  Populating the ContinuationReference


   When an entry is found to be non-local to a DSA (whether during name
   resolution or operation evaluation), the DSA prepares for operation
   distribution by generating a ContinuationReference.  This is a
   conceptual step, given to help explain the interactions that occur
   between discovering that an operation must be distributing, and
   actually invoking the operation distribution mechanism.
   Implementations are not required to perform this step, but will
   effectively work with the same information.


   After the ContinuationReference has been created, the DSA may choose
   to chain the operation or return a referral (or intermediate
   referral(s)).


   the ContinuationReference is made up of data held on the found
   distributed knowledge information, as well as state information
   gained during name resolution or operation evaluation.


4.3.1  Conveying the Target Object


   The consumer of the ContinuationReference will examine various fields
   in order to determine the target object name of the operation being
   progressed.  The fields examined are the localReference and
   remainingName.


   If name resolution did not complete, and the found distributed
   knowledge information names the same DSE as the base DN of the
   operation, the ContinuationReference MAY omit the localReference
   and/or remainingName fields.


   localReference is populated with the name of the found distributed
   knowledge information DSE.  In the event that the root object holds
   the distributed knowledge information, this field will be populated
   with an empty DN.  Contrast this with the omission of this field.


   referenceType is populated with a value reflecting the reference type
   of the localReference DSE.


   remainingName is populated with the RDNSequence which has not yet
   been resolved.  This is the difference between the localReference
   value and the name of the DSE to be resolved.


   In cases where the DSE named by the {TODO, use a dash or different
   term to make 'found distributed knowledge' more like a single term}
   found distributed knowledge is not the same as the base DN of the
   operation, the ContinuationReference must contain the localReference
   and/or remainingName fields.  Such cases include but are not limited




Sermersheim              Expires August 26, 2005               [Page 19]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   to:


   o  Distributed knowledge information is found during operation
      evaluation.
   o  Aliases were dereferenced during name resolution.
   o  Name resolution did not complete and there were remaining RDNs to
      be resolved.


4.3.2  Conveying the Remote DSA


   The referralURI field must contain at least one value.  Each
   referralURI value must hold a referralURI.accessPoint.  Other
   requirements on this field as noted may also apply.


   Note for nssr DSE types: During operation evaluation, if a DSE of
   type nssr causes the operation to be distributed (the scenarios in
   Section 4.2.1.2 are an example), then an intermediate referral {TODO:
   this is talking about referral/intermediate referral, but this
   section is only dealing with populating continuation reference} is
   returned for each value of the ref attribute, where each intermediate
   referral only holds a single referralURI value.


4.3.3  Conveying new search scope


   During the evaluation of the search operation, the instructions in
   Section 4.2.1.2.1 and Section 4.2.1.2.2 are followed and the
   searchScope field is updated with the new search scope.


4.3.4  Preventing duplicates


   In order to prevent duplicate entries from being evaluated while
   progressing a search operation, the searchedSubtrees field is
   populated with any naming context below the
   ContinuationReference.targetObject which have been fully searched.


   During the evaluation of the search operation, if the scope is
   wholeSubtree, it is possible that the DSA may search the contents of
   a naming context which is subordinate to another naming context which
   is subordinate to the search base (See figure).













Sermersheim              Expires August 26, 2005               [Page 20]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



                        O X
                       / \
                      /   \
                     /     \
                    /       \
                    \_______O Y
                           /|\
                          / | \
                         /  |  \
                        /   |   \
                       A    B    O C
                                / \
                               /   \
                              /     \
                             /       \
                             \_______/


   In this figure, the DSA holds the naming context X and C,Y,X, but not
   Y,X.  If the search base was X, an intermediate referral would be
   returned for Y,X.  The DSA holding Y,X may also hold a copy of C,Y,X.
   In this case, the receiver of the ContinuationReference benefits by
   knowing that the DSA already searched C,Y,X so that it can prevent
   other DSAs from returning those entries again.


   Data already searched is in the form of an RDNSequence, consisting of
   the RDNs relative to the target object.


4.3.5  Conveying the Failed Name


   At least one DS operation (modifyDN) requires that multiple DNs be
   resolved (the entry being modified and the newSuperior entry).  In
   this case, the failedName field will be populated with the DN being
   resolved which failed name resolution.  This may aid in the
   determination of how the operation is to be progressed.  If both
   names are found to be non-local, this field is omitted.


4.4  Sending a ChainedRequest


   When an entry is found to be non-local to a DSA (whether during name
   resolution or operation evaluation), the DSA may progress the
   operation by sending a chained operation to another DSA (or DSAs).
   The instructions in this section assume that a ContinuationReference
   has been generated which will be used to form the ChainedRequest.  It
   is also assumed that it can be determined whether the operation is
   being progressed due to name resolution or due to operation
   evaluation.


   A DSA which is able to chain operations may advertise this by




Sermersheim              Expires August 26, 2005               [Page 21]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   returning a value of IANA-ASSIGNED-OID.2; in the supportedFeatures
   attribute on the root DSE.  {TODO: does this and discovery of the
   extended op belong in a new 'discovery mechanisms' sections.}


4.4.1  Forming a ChainedRequest


   The following fields are populated as instructed:


4.4.1.1  ChainedRequestValue.chainingArguments.targetObject


   The ContinuationReference may convey a new target object.  If
   present, the ContinuationReference.localReference field becomes the
   candidate target object.  Otherwise the candidate target object is
   assumed to be that of the original directory operation.  Note that an
   empty value in the ContinuationReference.localReference field denotes
   the root object.


   After performing the above determination as to the candidate target
   object, any RDNSequence in ContinuationReference.remainingName is
   prepended to the determined candidate target object.  This value
   becomes the ChainedRequestValue.chainingArguments.targetObject.  If
   this value matches the value of the original operation, this field
   may be omitted.


4.4.1.2  ChainedRequestValue.chainingArguments.referenceType


   This is populated with the
   ContinuationReference.referralURI.referenceType.


4.4.1.3  ChainedRequestValue.chainingArguments.traceInformation


   This is populated as specified in Section 3.2.1.3.


4.4.1.4  ChainedRequestValue.chainingArguments.searchScope


   This is populated with the
   ContinuationReference.referralURI.searchScope if present, otherwise
   by the ContinuationReference.searchScope if present, and not
   populated otherwise.


4.4.1.5  ChainedRequestValue.chainingArguments.searchedSubtrees


   This is populated with ContinuationReference.searchedSubtrees, as
   well as any previously received values of
   ChainedFinalResponseValue.chainingResults.searchedSubtrees or
   ChainedIntermediateResponseValue.chainingResults.searchedSubtrees
   which are subordinate, relative to the target object.  (If thsi is
   relative to the target object, it can't contain non-relative




Sermersheim              Expires August 26, 2005               [Page 22]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   subtrees)


4.4.1.6  ChainedRequestValue.operationRequest


   This is populated with the original directory operation request.


4.4.2  Attempting Each Referral URI


   A ContinuationReference consists of one or more referralURIs which
   represent(s a) remote DSA(s).  The chaining DSA attempts to chain to
   each of these DSAs until one succeeds in completing the operation.
   An operation is considered to be completed if it reaches the remote
   DSA and a response is sent back that indicates that the operation was
   executed.  Operations which are sent to the remote DSA, but don't
   complete are indicated by a result code of unavailable or busy.  A
   result code of protocolError may indicate that the DSA does not
   support the chained operation, and in this case, it is also treated
   as an uncompleted operation.  Other errors may in the future specify
   that they also indicate non-completion.  Note that the response may
   itself contain referral(s), these are still considered completed
   operations and thus would subsequently be handled and chained.
   {TODO: could use soft/hard, or transient/permanent
   referral/non-referral error terms here.}


4.4.3  Loop Prevention


   Prior to sending a ChainedRequest, the DSA may attempt to prevent
   looping scenarios by comparing {TODO: what matching rule is used?
   Suggest we don't convert dns names to ip addresses due to NATs} the
   address of the remote DSA and target object to the values of
   ChainedRequestValue.chainingArguments.traceInformation.  If a match
   is found, the DSA returns a loopDetect error.  Note that while this
   type of loop prevention aids in detecting loops prior to sending data
   to a remote DSA, it is not a substitute for loop detection (Section
   Section 4.6.2).  This is because the sending DSA is only aware of a
   single address on which the receiving DSA accepts connections.


4.5  Emulating the Sending of a ChainedRequest


   When it is determined that the operation cannot be distributed by
   means of the ChainedRequest, the chaining DSA may instead emulate the
   steps involved in chaining the operation.  These steps consist of
   performing loop prevention, forming a new directory operation request
   from the original request and possibly updating the base DN, search
   scope, and search filter(in order to emulate searchedSubtrees), and,
   similar to the steps in Section 4.4.2, attempting to send the
   operation request to each DSA listed in the
   ContinuationReference.referralURI until one succeeds in completing




Sermersheim              Expires August 26, 2005               [Page 23]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   the operation.


   {TODO: We need a way (control) to tell the receiver to allow name
   resolution to end on the parent of a cp (typically an immsupr).  This
   would be sent when the ContinuationReference.referenceType is
   nonSpecificSubordinate}


4.5.1  Emulated Loop Detection


   For this step, the loop prevention instructions in Section 4.4.3 are
   followed.  Note that this method of loop detection may actually allow
   some looping to occur before the loop is detected.


4.5.2  Forming the New Request


   The new directory operation request is formed from the fields of the
   original request, and the following fields may be updated:


   o  The base DN is formed from the new target object as determined by
      following the instructions in Section 4.4.1.1 and using the value
      which would have been placed in
      ChainedRequestValue.chainingArguments.targetObject.
   o  For the search operation, the scope is populated with
      ContinuationReference.searchScope if present, otherwise the scope
      of the original operation request is used.
   o  For the search operation, if the
      ContinuationReference.searchedSubtrees field is present, causes
      the search filter to be augmented by adding a filter item of the
      'and' CHOICE.  The filter consists of {TODO: weasel Kurt into
      finishing his entryDN draft and reference the appropriate section
      there.  See
      <http://www.openldap.org/lists/ietf-ldapext/200407/msg00000.html>
      for context}
   o  Other fields (such as the messageID, and non-critical controls)
      may also need to be updated or excluded.


   If the service being chained to does not support directory
   operations, other operations may be used as long as they provide the
   same level as service as those provided by the analogous directory
   operation.


4.6  Receiving a ChainedRequest


   A DSA which is able to receive and service a ChainedRequest may
   advertise this feature by returning a value of IANA-ASSIGNED-OID.1 in
   the supportedExtension attribute of the root DSE.  {TODO: move?}


   The ChainedRequestValue data type is the requestValue of an




Sermersheim              Expires August 26, 2005               [Page 24]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   extendedRequest.


   In general, receiving and servicing a ChainedRequest consists of
   performing loop detection and, using components of the
   ChainedRequestType.chainingArguments along with the
   ChainedRequestType.operationRequest, service the request.


4.6.1  Target Object determination


   Prior to checking for a loop condition, the target object must be
   determined.  If the ChainedRequestType.chainingArguments.targetObject
   field is present, its value becomes the target object.  Otherwise,
   the base DN found in the ChainedRequestType.operationRequest becomes
   the target object.


4.6.2  Loop Detection


   The loop detection check happens when a DSA receives a chained
   operation, prior to acting on the operation.  The DSA compares {TODO:
   matching rule? DNS expansion?} each value of
   ChainedRequestValue.traceInformation to the list of addresses at
   which it accepts directory communications.  A value of
   ChainedRequestValue.traceInformation matches when the DSA accepts
   directory communications on the address found in the
   ChainedRequestValue.traceInformation value, and the target object (as
   determined in Section 4.6.1 matches the DN {TODO: using DN matching?}
   value found in the ChainedRequestValue.traceInformation value.  If a
   match is found the DSA returns a loopDetect result.


4.6.3  Processing the ChainedRequestValue.operationRequest


   In processing the operationRequest, the DSA uses the target object
   determined in Section 4.6.1.  For search operations, it uses the
   scope found in ChainedRequestValue.chainingArguments.searchScope, and
   excludes any subtrees relative to the target object indicated in
   ChainedRequestValue.chainingArguments.searchedSubtrees.


   Responses are returned in the form of a Chained Response.


4.7  Returning a Chained Response


   When returning responses to a ChainedRequest, the Chained Response as
   documented in Section 3.3 is used.  If the
   ChainedFinalResponseValue.operationResponse is a searchResultDone,
   the ChainedFinalResponseValue.chainingResults.searchedSubtrees field
   is populated with values consisting of the RDNSequence relative to
   the target object of naming contexts that the DSA searched.  See
   Section 3.3.1.1 for details on why this is done.




Sermersheim              Expires August 26, 2005               [Page 25]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



4.7.1  Chained Response resultCode


   The resultCode for the Chained Response is distinct from the result
   code of the ChainedIntermediateResponseValue.intermediateResponse or
   ChainedFinalResponseValue.finalResponse.  If the act of chaining the
   operation completed, then this value will be success.  Other result
   codes refer to the chained operation itself, and not the result of
   the embedded operation.


4.7.2  Returning referrals in the Chained Response


   {TODO: it would be less complicated if rather than using the simple
   LDAP URL, we used the ContinuationReference type to return referrals
   and intermediate referrals.} {TODO: We need an example of why we
   should allow referrals on a chained response.  Why not just use the
   referral field in the operation?}


4.8  Receiving a Chained Response


   Processing a received Chained Response is generally straight forward
   -- typically the response is simply extracted and returned, but there
   are some extra steps to be taken when chaining sub-operations.


4.8.1  Handling Sub-operation controls and result codes


   When sub-operations are chained, there is the possibility that
   different result codes will be encountered.  Similarly, if controls
   which elicit response controls were attached to the operation, it's
   possible that multiple response controls will be encountered.  Both
   of these possibilities require that the chaining DSA take appropriate
   steps to ensure that the response being returned is correct.


   In general, when a result code indicating an error is received, the
   operation will terminate and the error will be returned.  In cases
   where multiple sub-operations are being concurrently serviced, the
   operation will terminate and the most relevant, or first received
   result code is returned -- determining the result code to be returned
   in this case is a local matter.


   A DSA which chains an operation having a control (or controls)
   attached must ensure that a properly formed response is returned.
   This requires that the DSA understand and know how to aggrigate the
   results of all controls which it allows to remain attached to an
   operation being chained.  If the DSA does not understand or support a
   control which is marked non-critical, it removes the control prior to
   chaining the operation.  The DSA may return
   unavailableCriticalExtension for critical controls that it cannot or
   will not chain.  {TODO: give SSS as an example?}




Sermersheim              Expires August 26, 2005               [Page 26]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



4.8.1.1  Handling referrals during sub-operations


   If a referral is returned in response to a sub-operation, the sending
   DSA may attempt to further chain the operation.  In the event that
   the DSA does not further chain the sub-operation, it will use the
   referral to construct an intermediate referral, and return it
   appropriately.  When using a referral to construct an intermediate
   referral, certain transformations may have to happen.  For example,
   when using a referral to construct a searchResultReference, it must
   be assured that the <dn> field is present, and that the <scope> field
   is properly updated.


4.8.2  Duplicate Elimination


   When search result references cause the DSA to chain a search, it is
   possible that duplicate objects will be returned by different remote
   DSAs.  These duplicate objects must be sensed and not returned.


   {TODO: Even though there are costs associated with returning
   duplicates, is it a worthy exercise to build in an allowance for them
   to be returned? In other words, do we want to add a way for a client
   (or administrator) to say "it's ok, return the duplicates, let the
   client deal with them"? Allowing is seen as a cost benefit to the
   DSA.}


4.9  Returning a Referral or Intermediate Referral


   There are two ways in which the fields of the ContinuationReference
   may be conveyed in a response containing or consisting of referral or
   intermediate referral.  A paired control is introduced for the
   purpose of soliciting and returning a ContinuationReference.  In
   absence of this control, a referral or intermediate referral may be
   returned which conveys the information present in the
   ContinuationReference.  A method of converting a
   ContinuationReference to an LDAP URL is provided for referrals and
   intermediate referrals which identify LDAP-enabled DSAs.  Methods for
   converting a ContinuationReference to URIs which identify non-LDAP
   servers is not provided here, but may be specified in future
   documents, as long as they can represent the data needed to provide
   the same level of service.


4.9.1  ReturnContinuationReference controls


   This control is sent when a client wishes to receive a
   ContinuationReference in the event that a referral or intermediate
   referral is being returned.  If returned, the ContinuationReference
   will hold all data but the referralURI field.  the referralURI values
   will be held in the referral or intermediate referral (Referral,




Sermersheim              Expires August 26, 2005               [Page 27]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   SearchResultReference, etc.).


4.9.1.1  ReturnContinuationReference request control


   Solicits the return of a ReturnContinuationReference response control
   on messages consisting of (or carrying) a referral or intermediate
   referral.  The controlType is IANA-ASSIGNED-OID.3, the criticality is
   set at the sender's discretion, the controlValue is omitted.


4.9.1.2  ReturnContinuationReference response control


   In response to the ReturnContinuationReference request control, this
   holds a ContinuationReference for messages consisting of (or
   carrying) a referral or intermediate referral.  The controlType is
   IANA-ASSIGNED-OID.3, the controlValue is the BER-encoding of a
   ContinuationReference.  Note that the referralURI field is optionally
   omitted when the ContinuationReference is sent in this control value.
   In this event, the URI(s) found in the referral or intermediate
   referral (Referral, SearchContinuationReference, etc.) are to be used
   in its stead.  {TODO: is returining the referralURI outside an
   unneeded complication?}


4.9.2  Converting a ContinuationReference to an LDAP URL


   This section details the way in which an LDAP URL (from the referral
   or intermediate referral) is used to convey the fields of a
   ContinuationReference.  Where existing LDAP URL fields are
   insufficient, extensions are introduced.  Note that further
   extensions to the ContinuationReference type require further
   specifications here.  {TODO: explain that each ldap url in the
   continuation refrerence is examined and converted}


   These instructions must be applied to each LDAP URL value within the
   referral or intermediate referral.


4.9.2.1  Conveying the target name


   If the <dn> part of the LDAP URL is already present, it is determined
   to be the candidate target object.  Otherwise, the candidate target
   object comes from the ContinuationReference.localReference.  Once the
   candidate target object is determined, the value of
   ContinuationReference.remainingName is prepended to the candidate
   target object.  This new value becomes the target object and its
   string value (as specified by <distinguishedName> in [RFC2253]) is
   placed in the <dn> part of the LDAP URL.







Sermersheim              Expires August 26, 2005               [Page 28]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



4.9.2.2  ContinuationReference.localReference


   This is conveyed as an extension.  The extype is IANA-ASSIGNED-OID.4
   or the descriptor 'localReference', and the exvalue is the string DN
   encoding (as specified by <distinguishedName> in [RFC2253]) of the
   ContinuationReference.localReference value.


4.9.2.3  ContinuationReference.referenceType


   This is conveyed as an extension.  The extype is IANA-ASSIGNED-OID.5
   or the descriptor 'referenceType'.  If the
   ContinuationReference.referenceType is one of superior, subordinate,
   cross, nonSpecificSubordinate, suplier, master, immediateSuperior, or
   self, the exvalue 'superior', 'subordinate', 'cross',
   'nonSpecificSubordinate', 'suplier', 'master', 'immediateSuperior',
   or 'self' respectively.


4.9.2.4  ContinuationReference.searchScope


   If the search scope is one of baseObject, singleLevel, or
   wholeSubtree, then it may be conveyed in the 'scope' part of the LDAP
   URL as 'base', 'one', or 'sub' respectively.  If the search scope is
   subordinateSubtree, then it may be conveyed in the <extension> form
   as documented in [LDAP-SUBORD].  If this extension is present, it
   MUST be marked critical.  This ensures that a receiver which is
   unaware of this extension uses the proper search scope, or fails to
   progress the operation.


4.9.2.5  ContinuationReference.searchedSubtrees


   This field is conveyed as an extension.  The extype is
   IANA-ASSIGNED-OID.6 or the descriptor 'searchedSubtrees', and the
   exvalue is the ContinuationReference.searchedSubtree value encoded
   according to the following searchedSubtrees ABNF:


      searchedSubtrees = 1*(LANGLE searchedSubtree RANGLE)
      searchedSubtree = <distinguishedName> from [RFC2253]
      LANGLE  = %x3C ; left angle bracket ("<")
      RANGLE  = %x3E ; right angle bracket (">")


   Each searchedSubtree represents one RDNSequence value in the
   ContinuationReference.searchedSubtree field.  An example of a
   searchedSubtrees value containing two searched subtrees is:
   <dc=example,dc=com><cn=ralph,dc=users,dc=example,dc=com>.


4.9.2.6  ContinuationReference.failedName


   This field is conveyed as an extension.  The extype is




Sermersheim              Expires August 26, 2005               [Page 29]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   IANA-ASSIGNED-OID.7 or the descriptor 'failedName', and the exvalue
   is the string DN encoding (as specified in [RFC2253]) of the
   ContinuationReference.failedName value.


4.10  Acting on a Referral or Intermediate Referral


   When a protocol peer receives a referral or intermediate referral, it
   may distribute the operation either by sending a ChainedRequest, or
   by emulating the ChainedRequest.  Prior to taking these steps, the
   protocol peer effectively converts the referral or intermediate
   referral into a ContinuationReference.  Then, acting in the same
   manner as a DSA would, follows the directions in Section 4.4 if
   sending a ChainedRequest, or Section 4.5 otherwise.


4.10.1  Converting a Referral or Intermediate Referral to a
       ContinuationReference


   A referral or intermediate referral may be converted (or conceptually
   converted) to a ContinuationReference type in order to follow the
   distributed operation procedures in Section 4.4, or Section 4.5.  The
   following steps may only be used to convert a referral or
   intermediate referral containing LDAP URL values.  Converting other
   types of URIs may be specified in future documents as long as the
   conversion provides the same level of service found here.


   o  The ContinuationReference.referralURI is populated with all LDAP
      URL values in the referral or intermediate referral.
   o  The ContinuationReference.localReference populate with the value
      of the localReference extension value (Section 4.9.2.2) if one
      exists.  Otherwise it is omitted.
   o  The ContinuationReference.referenceType populate with the value of
      the referenceType extension value (Section 4.9.2.3) if one exists.
      Otherwise it is omitted.
   o  The ContinuationReference.remainingName is omitted.
   o  The ContinuationReference.searchScope is populated with
      subordinateSubtree if the subordScope LDAP URL extension
      [LDAP-SUBORD] is present.  If the <scope> field contains te value
      'base', 'one', 'sub', or 'subordinates', this filed is populated
      with baseObject, singleLevel, wholeSubtree, or subordinateSubtree
      respectively.  Otherwise this field is omitted.
   o  The ContinuationReference.searchedSubtrees is populated with any
      searchedSubtrees LDAP URI extension Section 4.9.2.5 value found on
      an LDAP URI in the referral or intermediate referral.  If none
      exist, this field is omitted.
   o  The ContinuationReference.failedName is populated with any
      failedName LDAP URI extension Section 4.9.2.6 value found on an
      LDAP URI in the referral or intermediate referral.  If none exist,
      this field is omitted.




Sermersheim              Expires August 26, 2005               [Page 30]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   Note that many fields are simply omitted.  This is either because
   they are conveyed within the LDAP URL values themselves, and
   subsequent instructions will check for their presence, or because
   they are not needed (they are redundant or not used in further
   instructions).


4.11  Ensuring non-existence of an entry under an nssr


   {TODO: add a huge disclaimer here that says without transactional
   semantics, you can never be sure that the entry didn't get added.
   Maybe we should just punt on this and say it's a local matter} In
   order to ensure there are no entries matching the name of the entry
   to be added or renamed immediately subordinate to an nssr, these
   steps may be followed.


   If the DSA is able and allowed to chain operations, it may contact
   each of the DSAs listed as access points in the nssr (in the ref
   attribute) and using a base-level search operation it will determine
   whether or not the object to be added exists.  Note that access
   control or other policies may hide the entry from the sending DSA.
   If the entry does not exist on any of the DSAs listed in the nssr,
   the operation may progress on the local DSA.


   If the DSA cannot make this determination, the operation fails with
   affectsMultipleDSAs.


4.12  Mapping a referralURI to an LDAP URI


   As with any URI specification which is intended to be used as a URI
   which conveys referral information, the LDAP URI specification is
   given a mapping to the elements of a referralURI as specified in.
   Section 3.1.1.1.  These mappings are given here using the ABNF
   identifiers given in [RFC2255].


   referralURI to LDAP URI mapping:


   +---------------------------------+---------------------------------+
   | referralURI element             | LDAP URL element                |
   +---------------------------------+---------------------------------+
   | protocolIdentifier              | <scheme>                        |
   |                                 |                                 |
   | accessPoint                     | <hostport>                      |
   |                                 |                                 |
   | targetObject                    | <dn>. This must be encoded as a |
   |                                 | <distinguishedName> as          |
   |                                 | specified in [RFC2253]          |
   |                                 |                                 |
   | localReference                  | LDAP URL localReference         |




Sermersheim              Expires August 26, 2005               [Page 31]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   |                                 | extension as specified in       |
   |                                 | Section 4.9.2.2                 |
   |                                 |                                 |
   | referenceType                   | LDAP URL referenceType          |
   |                                 | extension as specified in       |
   |                                 | Section 4.9.2.3                 |
   |                                 |                                 |
   | searchScope                     | <scope> or LDAP URL subordScope |
   |                                 | extension as specified in       |
   |                                 | Section 4.9.2.4                 |
   |                                 |                                 |
   | searchedSubtrees                | LDAP URL searchedSubtrees       |
   |                                 | extension as specified in       |
   |                                 | Section 4.9.2.5                 |
   |                                 |                                 |
   | failedName                      | LDAP URL failedName extension   |
   |                                 | as specified in Section 4.9.2.6 |
   +---------------------------------+---------------------------------+



 4.13   Using the ManageDsaIT control


   This control, defined in [RFC3296], allows the management of the
   distributed knowledge information held by a DSA, and thus overrides
   the determinations made during name resolution and operation
   evaluation.  When this control is attached to an operation, all
   resolved and acted upon DSEs are treated as being local to the DSA.
   This is true regardless of the phase the operation is in.  Thus
   referrals are never returned and chaining never occurs.























Sermersheim              Expires August 26, 2005               [Page 32]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



5.  Security Considerations


   This document introduces a mechanism (chaining) which can be used to
   propagate directory operation requests to servers which may be
   inaccessible otherwise.  Implementers and deployers of this
   technology should be aware of this and take appropriate steps such
   that firewall mechanisms are not compromised.


   This document introduces the ability to return auxiliary data when
   returning referrals.  Measures should be taken to ensure proper
   protection of his data.


   Implementers must ensure that any specified time, size, and
   administrative limits are not circumvented due to the mechanisms
   introduced here.


6.  Normative References


   [LDAP-SUBORD]
              Sermersheim, J., "Subordinate Subtree Search Scope for
              LDAP",
              Internet-Draft draft-sermersheim-ldap-subordinate-scope,
              July 2004.


   [RFC2079]  Smith, M., "Definition of an X.500 Attribute Type and an
              Object Class to Hold Uniform Resource Identifiers (URIs)",
              RFC 2079, January 1997.


   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.


   [RFC2251]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.


   [RFC2253]  Wahl, M., Kille, S. and T. Howes, "Lightweight Directory
              Access Protocol (v3): UTF-8 String Representation of
              Distinguished Names", RFC 2253, December 1997.


   [RFC2255]  Howes, T. and M. Smith, "The LDAP URL Format", RFC 2255,
              December 1997.


   [RFC2396]  Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform
              Resource Identifiers (URI): Generic Syntax", RFC 2396,
              August 1998.


   [RFC3296]  Zeilenga, K., "Named Subordinate References in Lightweight
              Directory Access Protocol (LDAP) Directories", RFC 3296,
              July 2002.




Sermersheim              Expires August 26, 2005               [Page 33]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



   [RFC3377]  Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.


   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.


   [RFC3771]  Harrison, R. and K. Zeilenga, "The Lightweight Directory
              Access Protocol (LDAP) Intermediate Response Message",
              RFC 3771, April 2004.


   [X500]     International Telephone and Telegraph Consultative
              Committee, "The Directory - overview of concepts, models
              and services", ITU-T Recommendation X.500, November 1993.


   [X518]     International Telephone and Telegraph Consultative
              Committee, "The Directory - The Directory: Procedures for
              distributed operation", ITU-T Recommendation X.518,
              November 1993.


   [X680]     International Telecommunications Union, "Abstract Syntax
              Notation One (ASN.1): Specification of basic notation",
              ITU-T Recommendation X.680, July 2002.


   [X690]     International Telecommunications Union, "Information
              Technology - ASN.1 encoding rules: Specification of Basic
              Encoding Rules (BER), Canonical Encoding Rules (CER) and
              Distinguished Encoding Rules (DER)", ITU-T Recommendation
              X.690, July 2002.



Author's Address


   Jim Sermersheim
   Novell, Inc
   1800 South Novell Place
   Provo, Utah  84606
   USA


   Phone: +1 801 861-3088
   Email: jimse@novell.com










Sermersheim              Expires August 26, 2005               [Page 34]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



Appendix A.  IANA Considerations


   Registration of the following values is requested [RFC3383].


A.1  LDAP Object Identifier Registrations


   It is requested that IANA register upon Standards Action an LDAP
   Object Identifier in identifying the protocol elements defined in
   this technical specification.  The following registration template is
   provided:


      Subject: Request for LDAP OID Registration
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments:
      Seven delegations will be made under the assigned OID:
      IANA-ASSIGNED-OID.1 ChainedRequest LDAP Extended Operation
      IANA-ASSIGNED-OID.2 Supported Feature: Can Chain Operations
      IANA-ASSIGNED-OID.3 ReturnContinuationReference LDAP Controls
      IANA-ASSIGNED-OID.4 localReference: LDAP URL Extension
      IANA-ASSIGNED-OID.6 searchedSubtree: LDAP URL Extension
      IANA-ASSIGNED-OID.7 failedName: LDAP URL Extension


A.2  LDAP Protocol Mechanism Registrations


   It is requested that IANA register upon Standards Action the LDAP
   protocol mechanism described in this document.  The following
   registration templates are given:


      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID.1
      Description: ChainedRequest LDAP Extended Operation
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID.2
      Description: Can Chain Operations Supported Feature
      Person & email address to contact for further information:





Sermersheim              Expires August 26, 2005               [Page 35]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



         Jim Sermersheim
         jimse@novell.com
      Usage: Feature
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID.3
      Description: ReturnContinuationReference LDAP Controls
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: Control
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID.4
      Description: localReference LDAP URL Extension
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID.5
      Description: referenceType LDAP URL Extension
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID.6
      Description: searchedSubtree LDAP URL Extension
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: Extension





Sermersheim              Expires August 26, 2005               [Page 36]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID.7
      Description: failedName LDAP URL Extension
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


A.3  LDAP Descriptor Registrations


   It is requested that IANA register upon Standards Action the LDAP
   descriptors described in this document.  The following registration
   templates are given:


      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): localReference
      Object Identifier: IANA-ASSIGNED-OID.4
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: URL Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): referenceType
      Object Identifier: IANA-ASSIGNED-OID.5
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: URL Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): searchedSubtree
      Object Identifier: IANA-ASSIGNED-OID.6
      Person & email address to contact for further information:





Sermersheim              Expires August 26, 2005               [Page 37]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



         Jim Sermersheim
         jimse@novell.com
      Usage: URL Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): failedName
      Object Identifier: IANA-ASSIGNED-OID.7
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: URL Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none


A.4  LDAP Result Code Registrations


   It is requested that IANA register upon Standards Action the LDAP
   result codes described in this document.  The following registration
   templates are given:


      Subject: Request for LDAP Result Code Registration
      Result Code Name: invalidReference
      Person & email address to contact for further information:
         Jim Sermersheim
         jimse@novell.com
      Usage: URL Extension
      Specification: RFCXXXX
      Author/Change Controller: IESG
      Comments: none



















Sermersheim              Expires August 26, 2005               [Page 38]
Internet-Draft    Distributed Procedures for LDAP Operations  February 2005



Intellectual Property Statement


   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.


   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.


   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.



Disclaimer of Validity


   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.



Copyright Statement


   Copyright (C) The Internet Society (2005).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and
   except as set forth therein, the authors retain all their rights.



Acknowledgment


   Funding for the RFC Editor function is currently provided by the
   Internet Society.





Sermersheim              Expires August 26, 2005               [Page 39]alt-openldap11-devel/drafts/draft-legg-ldap-acm-bac-xx.txt000064400000300027150410163300017252 0ustar00
INTERNET-DRAFT                                                   S. Legg
draft-legg-ldap-acm-bac-03.txt                       Adacel Technologies
Intended Category: Standards Track                         June 16, 2004
Updates: RFC 2252


             Lightweight Directory Access Protocol (LDAP):
                  Basic and Simplified Access Control

    Copyright (C) The Internet Society (2004). All Rights Reserved.

   Status of this Memo


   This document is an Internet-Draft and is in full conformance with
   all provisions of Section 10 of RFC2026.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as
   Internet-Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress".

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   Distribution of this document is unlimited.  Comments should be sent
   to the author.

   This Internet-Draft expires on 16 December 2004.


Abstract

   An access control scheme describes the means by which access to
   directory information and potentially to access rights themselves may
   be controlled.  This document adapts the X.500 directory Basic Access
   Control and Simplied Access Control schemes for use by the
   Lightweight Directory Access Protocol.





Legg                    Expires 16 December 2004                [Page 1]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
   2.  Conventions. . . . . . . . . . . . . . . . . . . . . . . . . .  3
   3.  Basic Access Control . . . . . . . . . . . . . . . . . . . . .  4
       3.1.  Permissions. . . . . . . . . . . . . . . . . . . . . . .  5
             3.1.1.  Read . . . . . . . . . . . . . . . . . . . . . .  5
             3.1.2.  Compare. . . . . . . . . . . . . . . . . . . . .  6
             3.1.3.  Browse . . . . . . . . . . . . . . . . . . . . .  6
             3.1.4.  ReturnDN . . . . . . . . . . . . . . . . . . . .  6
             3.1.5.  FilterMatch. . . . . . . . . . . . . . . . . . .  6
             3.1.6.  Modify . . . . . . . . . . . . . . . . . . . . .  6
             3.1.7.  Add. . . . . . . . . . . . . . . . . . . . . . .  6
             3.1.8.  Remove . . . . . . . . . . . . . . . . . . . . .  7
             3.1.9.  DiscloseOnError. . . . . . . . . . . . . . . . .  7
             3.1.10. Rename . . . . . . . . . . . . . . . . . . . . .  7
             3.1.11. Export . . . . . . . . . . . . . . . . . . . . .  7
             3.1.12. Import . . . . . . . . . . . . . . . . . . . . .  8
             3.1.13. Invoke . . . . . . . . . . . . . . . . . . . . .  8
       3.2.  Representation of Access Control Information . . . . . .  8
             3.2.1.  Identification Tag . . . . . . . . . . . . . . . 11
             3.2.2.  Precedence . . . . . . . . . . . . . . . . . . . 11
             3.2.3.  Authentication Level . . . . . . . . . . . . . . 11
             3.2.4.  itemFirst and userFirst Components . . . . . . . 12
             3.2.5.  Determining Group Membership . . . . . . . . . . 16
       3.3.  ACI Operational Attributes . . . . . . . . . . . . . . . 17
             3.3.1.  Prescriptive ACI . . . . . . . . . . . . . . . . 17
             3.3.2.  Entry ACI. . . . . . . . . . . . . . . . . . . . 17
             3.3.3.  Subentry ACI . . . . . . . . . . . . . . . . . . 18
             3.3.4.  Protecting the ACI . . . . . . . . . . . . . . . 18
       3.4.  Access Control Decision Points for LDAP Operations . . . 18
             3.4.1.  Common Elements of Procedure . . . . . . . . . . 19
                     3.4.1.1.  Alias Dereferencing. . . . . . . . . . 19
                     3.4.1.2.  Return of Names in Errors. . . . . . . 19
                     3.4.1.3.  Non-disclosure of Entry Existence. . . 20
             3.4.2.  Compare Operation Decision Points. . . . . . . . 20
             3.4.3.  Search Operation Decision Points . . . . . . . . 20
             3.4.4.  Add Operation Decision Points. . . . . . . . . . 23
             3.4.5.  Delete Operation Decision Points . . . . . . . . 24
             3.4.6.  Modify Operation Decision Points . . . . . . . . 24
             3.4.7.  Modify DN Operation Decision Points. . . . . . . 25
       3.5.  Access Control Decision Function . . . . . . . . . . . . 26
             3.5.1.  Inputs . . . . . . . . . . . . . . . . . . . . . 26
             3.5.2.  Tuples . . . . . . . . . . . . . . . . . . . . . 26
             3.5.3.  Discarding Irrelevant Tuples . . . . . . . . . . 27
             3.5.4.  Highest Precedence and Specificity . . . . . . . 28
   4.  Simplified Access Control. . . . . . . . . . . . . . . . . . . 28
   5.  Security Considerations. . . . . . . . . . . . . . . . . . . . 29



Legg                    Expires 16 December 2004                [Page 2]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   6.  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 29
   7.  IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 29
   Appendix A. LDAP Specific Encoding for the ACI Item Syntax . . . . 30
   Normative References . . . . . . . . . . . . . . . . . . . . . . . 39
   Informative References . . . . . . . . . . . . . . . . . . . . . . 40
   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 40
   Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 40

1.  Introduction

   An access control scheme describes the means by which access to
   directory information and potentially to access rights themselves may
   be controlled.  Control of access to information means the prevention
   of unauthorized detection, disclosure, or modification of that
   information.  The definition of an access control scheme in the
   context of a Lightweight Directory Access Protocol (LDAP) [RFC3371]
   directory includes methods to specify Access Control Information
   (ACI), and to enforce access rights defined by that ACI.

   This document adapts the X.500 Basic Access Control and Simplied
   Access Control schemes [X501] for use in LDAP.  Both schemes conform
   to, and make use of, the access control administrative framework for
   LDAP [ACA].

   Section 3 describes the Basic Access Control scheme and defines how
   it applies to LDAP operations [RFC2251].

   Simplified Access Control is a functional subset of the Basic Access
   Control scheme.  This subset is described in Section 4.

   As a matter of security policy, an implementation supporting Basic
   Access Control or Simplified Access Control is permitted to grant or
   deny any form of access to particular attributes (e.g., password
   attributes) irrespective of access controls which may otherwise
   apply.  However, since such security policy has no standardized
   representation, it cannot be propagated in replicated information.

   This document is derived from, and duplicates substantial portions
   of, Section 8 of X.501 [X501], and selected extracts from X.511
   [X511].

2.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and  "OPTIONAL" in this
   document are to be interpreted as described in BCP 14, RFC 2119
   [RFC2119].




Legg                    Expires 16 December 2004                [Page 3]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   Schema definitions are provided using LDAP description formats
   [RFC2252].  Note that the LDAP descriptions have been rendered with
   additional white-space and line breaks for the sake of readability.

3.  Basic Access Control

   This section describes the functionality of the Basic Access Control
   scheme.

   When Basic Access Control is used, the accessControlScheme
   operational attribute [ACA] SHALL have the value basic-access-control
   (2.5.28.1).

   This LDAP profile for Basic Access Control defines, for every LDAP
   operation, one or more points at which access control decisions take
   place.  An access control decision will involve a requestor,
   protected items, and permissions.

   A requestor is the user requesting the operation.  Basic Access
   Control requires a user's authorization identity to be represented as
   a distinguished name (with an optional unique identifier).  The
   mapping of the authentication identity to an authorization identity,
   and the mapping of the authorization identity to a distinguished name
   and optional unique identifier, are outside the scope of this
   document.

   A protected item is the element of directory information being
   accessed.  The protected items are entries, attributes, attribute
   values and distinguished names.  Access to each protected item can be
   separately controlled through ACI.

   A permission is a particular right necessary to complete a portion of
   the operation.

   The Access Control Information, which is used to make access control
   decisions, associates protected items and user classes with
   permissions.  ACI is represented in the directory as values of
   operational attributes with the ACI Item syntax [RFC2252].  Each such
   value is referred to as an ACI item.

   The scope of access controls can be a single entry or a collection of
   entries that are logically related by being within the scope of an
   access control subentry of an administrative point (see [ACA]).

   The Access Control Decision Function (ACDF) (Section 3.5) is used to
   decide whether a particular requestor has a particular access right
   by virtue of applicable ACI items.




Legg                    Expires 16 December 2004                [Page 4]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   Access to DSEs and operational attributes is controlled in the same
   way as for entries and user attributes.

   For query purposes, collective attributes [COLLECT] that are
   associated with an entry are protected precisely as if they were
   attributes actually stored in that entry.

   For the purposes of modification, collective attributes are
   associated with the subentry that holds them, not with entries within
   the scope of the subentry.  Modify-related access controls are
   therefore not relevant to collective attributes, except when they
   apply to the collective attribute and its values within the subentry.

3.1.  Permissions

   Access is controlled by granting or denying permissions.  Access is
   allowed only when there is an explicitly provided grant present in
   the ACI used to make the access control decision.  The only default
   access decision provided in the model is to deny access in the
   absence of explicit ACI that grants access.  All other factors being
   equal, a denial specified in ACI always overrides a grant.

   Certain combinations of grants or denials are illogical, but it is
   the responsibility of directory clients, rather than the directory
   server, to ensure that such combinations are absent.

   The decision whether or not to permit access to an entry or its
   contents is strictly determined by the position of the entry in the
   Directory Information Tree (DIT), in terms of its distinguished name,
   and is independent of how the directory server locates that entry.

   The following sections introduce the permissions by indicating the
   intent associated with the granting of each.  The actual influence of
   a particular granted permission on access control decisions are,
   however, determined by the ACDF and the access control decision
   points for each LDAP operation, described in detail in Section 3.4.

3.1.1.  Read

   If granted for an entry, Read permits the entry to be accessed using
   LDAP Compare and baseObject Search operations, but does not imply
   access to all the attributes and values.

   If granted for an attribute type, Read permits the attribute type to
   be returned as entry information in a Search result.  Read or Browse
   permission for the entry is a prerequisite.

   If granted for an attribute value, Read permits the attribute value



Legg                    Expires 16 December 2004                [Page 5]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   to be returned as entry information in a Search result.  Read or
   Browse permission for the entry and Read permission for the attribute
   type are prerequisites.

3.1.2.  Compare

   If granted for an attribute type, Compare permits the attribute type
   to be tested by the assertion in an LDAP Compare operation.  Read
   permission for the entry is a prerequisite.

   If granted for an attribute value, Compare permits the value to be
   tested by the assertion in an LDAP Compare operation.  Read
   permission for the entry and Compare permission for the attribute
   type are prerequisites.

3.1.3.  Browse

   If granted for an entry, Browse permits the entry to be accessed by
   the LDAP Search operation, including baseObject searches, but does
   not imply access to all the attributes and values.

3.1.4.  ReturnDN

   If granted for an entry, ReturnDN allows the distinguished name of
   the entry to be disclosed in a search result.

3.1.5.  FilterMatch

   If granted for an attribute type, Filtermatch permits the attribute
   type to satisfy a Filter item.

   If granted for an attribute value, Filtermatch permits the attribute
   value to satisfy a Filter item.  FilterMatch permission for the
   attribute type is a prerequisite.

3.1.6.  Modify

   If granted for an entry, Modify permits the information contained
   within an entry to be modified by the LDAP Modify operation, subject
   to controls on the attribute types and values.

3.1.7.  Add

   If granted for an entry, Add permits creation of an entry in the DIT,
   subject to being able to add all specified attributes and attribute
   values.  Add permission granted for an entry is ineffective if Add
   permission is not also granted for at least the mandatory attributes
   and their values.  There is no specific "add subordinate permission".



Legg                    Expires 16 December 2004                [Page 6]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   Permission to add an entry is controlled using prescriptive ACI.

   If granted for an attribute type, Add permits adding a new attribute,
   subject to being able to add all specified attribute values.  Add or
   Modify permission for the entry is a prerequisite.

   If granted for an attribute value, Add permits adding that value to
   an existing attribute.  Add or Modify permission for the entry is a
   prerequisite.

3.1.8.  Remove

   If granted for an entry, Remove permits the entry to be removed from
   the DIT regardless of controls on attributes or attribute values
   within the entry.

   If granted for an attribute, Remove permits removing an attribute,
   subject to being able to remove any explicitly specified attribute
   values.  Remove permission for values not explicitly specified is not
   required.

   If granted for an attribute value, Remove permits the attribute value
   to be removed from an existing attribute.

3.1.9.  DiscloseOnError

   If granted for an entry, DiscloseOnError permits the name of an entry
   to be disclosed in an error result.

   If granted for an attribute, DiscloseOnError permits the presence of
   the attribute to be disclosed by an error.

   If granted for an attribute value, DiscloseOnError permits the
   presence of the attribute value to be disclosed by an error.

3.1.10.  Rename

   If granted for an entry, Rename permits an entry to be renamed with a
   new RDN.  No permissions are required for the attributes and values
   altered by the operation, even if they are added or removed as a
   result of the changes to the RDN.

3.1.11.  Export

   If granted for an entry, Export permits the entry and its
   subordinates, if any, to be removed from the current location and
   placed in a new location, subject to the granting of Import
   permission at the destination.



Legg                    Expires 16 December 2004                [Page 7]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   If the last RDN is changed, Rename permission at the current location
   is also required

3.1.12.  Import

   If granted for an entry, Import permits an entry and its
   subordinates, if any, to be placed at the location to which the
   permission applies, subject to the granting of Export permission at
   the source location.

3.1.13.  Invoke

   Invoke, if granted for an operational attribute, or value thereof,
   permits the directory server to carry out some function associated
   with the operational attribute on behalf of the user.  The specific
   function carried out by invocation depends on the attribute.  No
   other permissions are required by user for the operational attribute,
   or on the entry/subentry that holds it, in order for it to be
   "invoked".

3.2.  Representation of Access Control Information

   Access Control Information is represented as a set of ACI items,
   where each ACI item grants or denies permissions in regard to certain
   specified users and protected items.

   An ACI item is represented as a value of an operational attribute
   with the ACI Item syntax (1.3.6.1.4.1.1466.115.121.1.1) [RFC2252].

   This document updates [RFC2252] by specifying a human-readable
   LDAP-specific encoding for ACI items.  The LDAP-specific encoding of
   values of the ACI Item syntax is defined by the Generic String
   Encoding Rules [GSER].  Appendix A provides an equivalent ABNF for
   this syntax.

   For convenience in specifying access control policies, the ACI Item
   syntax provides the means to identify collections of related items,
   such as attributes in an entry or all attribute values of a given
   attribute, and to specify a common protection for them.

   The ACI Item syntax corresponds to the ACIItem ASN.1 [ASN1] type
   defined in X.501 [X501].  It is reproduced here for convenience:

   ACIItem ::= SEQUENCE {
       identificationTag   DirectoryString { ub-tag },
       precedence          Precedence,
       authenticationLevel AuthenticationLevel,
       itemOrUserFirst     CHOICE {



Legg                    Expires 16 December 2004                [Page 8]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


           itemFirst   [0] SEQUENCE {
               protectedItems  ProtectedItems,
               itemPermissions SET OF ItemPermission },
           userFirst   [1] SEQUENCE {
               userClasses     UserClasses,
               userPermissions SET OF UserPermission } } }

   Precedence ::= INTEGER (0..255)

   ProtectedItems ::= SEQUENCE {
       entry                   [0] NULL OPTIONAL,
       allUserAttributeTypes   [1] NULL OPTIONAL,
       attributeType           [2] SET SIZE (1..MAX) OF
                                       AttributeType OPTIONAL,
       allAttributeValues      [3] SET SIZE (1..MAX) OF
                                       AttributeType OPTIONAL,
       allUserAttributeTypesAndValues  [4] NULL OPTIONAL,
       attributeValue          [5] SET SIZE (1..MAX) OF
                                       AttributeTypeAndValue OPTIONAL,
       selfValue               [6] SET SIZE (1..MAX) OF
                                       AttributeType OPTIONAL,
       rangeOfValues           [7] Filter OPTIONAL,
       maxValueCount           [8] SET SIZE (1..MAX) OF
                                       MaxValueCount OPTIONAL,
       maxImmSub               [9] INTEGER OPTIONAL,
       restrictedBy           [10] SET SIZE (1..MAX) OF
                                       RestrictedValue OPTIONAL,
       contexts               [11] SET SIZE (1..MAX) OF
                                       ContextAssertion OPTIONAL,
       classes                [12] Refinement OPTIONAL }

   MaxValueCount ::= SEQUENCE {
       type        AttributeType,
       maxCount    INTEGER }

   RestrictedValue ::= SEQUENCE {
       type        AttributeType,
       valuesIn    AttributeType }

   UserClasses ::= SEQUENCE {
       allUsers    [0] NULL OPTIONAL,
       thisEntry   [1] NULL OPTIONAL,
       name        [2] SET SIZE (1..MAX) OF NameAndOptionalUID OPTIONAL,
       userGroup   [3] SET SIZE (1..MAX) OF NameAndOptionalUID OPTIONAL,
           -- dn component shall be the name of an
           -- entry of GroupOfUniqueNames
       subtree     [4] SET SIZE (1..MAX) OF
                           SubtreeSpecification OPTIONAL }



Legg                    Expires 16 December 2004                [Page 9]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   NameAndOptionalUID ::= SEQUENCE {
       dn      DistinguishedName,
       uid     UniqueIdentifier OPTIONAL }

   UniqueIdentifier ::= BIT STRING

   ItemPermission ::= SEQUENCE {
       precedence          Precedence OPTIONAL,
           -- defaults to precedence in ACIItem
       userClasses         UserClasses,
       grantsAndDenials    GrantsAndDenials }

   UserPermission ::= SEQUENCE {
       precedence Precedence OPTIONAL,
           -- defaults to precedence in ACIItem
       protectedItems ProtectedItems,
       grantsAndDenials GrantsAndDenials }

   AuthenticationLevel ::= CHOICE {
       basicLevels     SEQUENCE {
           level           ENUMERATED { none(0), simple(1), strong(2) },
           localQualifier  INTEGER OPTIONAL,
           signed          BOOLEAN DEFAULT FALSE },
       other           EXTERNAL }

   GrantsAndDenials ::= BIT STRING {
       -- permissions that may be used in conjunction
       -- with any component of ProtectedItems
       grantAdd             (0),
       denyAdd              (1),
       grantDiscloseOnError (2),
       denyDiscloseOnError  (3),
       grantRead            (4),
       denyRead             (5),
       grantRemove          (6),
       denyRemove           (7),
       -- permissions that may be used only in conjunction
       -- with the entry component
       grantBrowse          (8),
       denyBrowse           (9),
       grantExport         (10),
       denyExport          (11),
       grantImport         (12),
       denyImport          (13),
       grantModify         (14),
       denyModify          (15),
       grantRename         (16),
       denyRename          (17),



Legg                    Expires 16 December 2004               [Page 10]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


       grantReturnDN       (18),
       denyReturnDN        (19),
       -- permissions that may be used in conjunction
       -- with any component, except entry, of ProtectedItems
       grantCompare        (20),
       denyCompare         (21),
       grantFilterMatch    (22),
       denyFilterMatch     (23),
       grantInvoke         (24),
       denyInvoke          (25) }

   AttributeTypeAndValue ::= SEQUENCE {
       type    ATTRIBUTE.&id ({SupportedAttributes}),
       value   ATTRIBUTE.&Type ({SupportedAttributes}{@type}) }

   The SubtreeSpecification and Refinement ASN.1 types are defined in
   X.501 [X501], and separately described for LDAP [SUBENTRY].

   The following sections describe the components of ACIItem.

3.2.1.  Identification Tag

   identificationTag is used to identify a particular ACI item.  This is
   used to discriminate among individual ACI items for the purposes of
   protection and administration.

3.2.2.  Precedence

   Precedence is used to control the relative order in which ACI items
   are considered during the course of making an access control decision
   using the ACDF.  ACI items having higher precedence values prevail
   over others with lower precedence values, other factors being equal.
   Precedence values are integers and are compared as such.

3.2.3.  Authentication Level

   AuthenticationLevel defines the minimum requestor authentication
   level required for this ACI item.  It has two forms:

   1) basicLevels: which indicates the level of authentication,
      optionally qualified by positive or negative integer
      localQualifier.

   2) other: an externally defined measure.

   When basicLevels is used, an AuthenticationLevel consisting of a
   level and optional localQualifier SHALL be assigned to the requestor
   by the directory server according to local policy.  For a requestor's



Legg                    Expires 16 December 2004               [Page 11]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   authentication level to meet or exceed the minimum requirement, the
   requestor's level must meet or exceed that specified in the ACI item,
   and in addition the requestor's localQualifier must be arithmetically
   greater than or equal to that of the ACI item.  Strong authentication
   of the requestor is considered to exceed a requirement for simple or
   no authentication, and simple authentication exceeds a requirement
   for no authentication.  For access control purposes, the "simple"
   authentication level requires at least a password; the case of
   identification only, with no password supplied, is considered "none".
   If a localQualifier is not specified in the ACI item, then the
   requestor need not have a corresponding value (if such a value is
   present it is ignored).

   The signed component of basicLevels is ignored for LDAP.

   When other is used, an appropriate AuthenticationLevel shall be
   assigned to the requestor by the directory server according to local
   policy.  The form of this AuthenticationLevel and the method by which
   it is compared with the AuthenticationLevel in the ACI is a local
   matter.

   An authentication level associated with an explicit grant indicates
   the minimum level to which a requestor shall be authenticated in
   order to be granted access.

   An authentication level associated with an explicit deny indicates
   the minimum level to which a requestor shall be authenticated in
   order not to be denied access.  For example, an ACI item that denies
   access to a particular user class and requires strong authentication
   will deny access to all requestors who cannot prove, by means of a
   strongly authenticated identity, that they are not in that user
   class.

   The directory server may base authentication level on factors other
   than values received in protocol exchanges.

3.2.4.  itemFirst and userFirst Components

   Each ACI item contains a choice of itemFirst or userFirst.  The
   choice allows grouping of permissions depending on whether they are
   most conveniently grouped by user classes or by protected items.  The
   itemFirst and userFirst components are equivalent in the sense that
   they capture the same access control information; however, they
   organize that information differently.  The choice between them is
   based on administrative convenience.  The subcomponents of itemFirst
   and userFirst are described below.

   a) ProtectedItems defines the items to which the specified access



Legg                    Expires 16 December 2004               [Page 12]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      controls apply.  It is defined as a set selected from the
      following:

      - entry means the entry contents as a whole.  It does not
        necessarily include the information in these entries.  This
        element SHALL be ignored if the classes component is present,
        since this latter element selects protected entries on the basis
        of their object class.

      - allUserAttributeTypes means all user attribute type information
        associated with the entry, but not values associated with those
        attributes.

      - allUserAttributeTypesAndValues means all user attribute
        information associated with the entry, including all values of
        all user attributes.

        The allUserAttributeTypes and allUserAttributeTypesAndValues
        components do not include operational attributes, which MUST be
        specified on a per attribute basis, using attributeType,
        allAttributeValues or attributeValue.

      - attributeType means attribute type information pertaining to
        specific attributes but not values associated with the type.

      - allAttributeValues means all attribute value information
        pertaining to specific attributes.

      - attributeValue means specific values of specific attribute
        types.

      - selfValue means the attribute values of the specified attribute
        types that match the distinguished name (and unique identifier)
        of the requestor.  It can only apply in the specific case where
        the attribute specified is of DN syntax
        (1.3.6.1.4.1.1466.115.121.1.12) or Name And Optional UID syntax
        (1.3.6.1.4.1.1466.115.121.1.34) [RFC2252].

      - rangeOfValues means any attribute value which matches the
        specified filter, i.e., for which the specified filter evaluated
        on that attribute value would return TRUE.  The filter is not
        evaluated on any entries in the DIB, rather it is evaluated
        using the semantics defined in 7.8 of [X511], operating on a
        fictitious entry that contains only the single attribute value
        which is the protected item.  Note that the filter is an X.500
        search Filter.  It has a different syntax from the LDAP search
        Filter, but the same semantics.




Legg                    Expires 16 December 2004               [Page 13]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      The following items provide constraints that may disable the
      granting of certain permissions to protected items in the same
      value of ProtectedItems:

      - maxValueCount restricts the maximum number of attribute values
        allowed for a specified attribute type.  It is examined if the
        protected item is an attribute value of the specified type and
        the permission sought is Add.  Values of that attribute in the
        entry are counted, without regard to attribute options and
        access control, as though the operation which is attempting to
        add the values is successful.  If the number of values in the
        attribute exceeds maxCount, the ACI item is treated as not
        granting Add permission.

      - maxImmSub restricts the maximum number of immediate subordinates
        of the superior entry to an entry being added or imported.  It
        is examined if the protected item is an entry, the permission
        sought is Add or Import, and the immediate superior entry is in
        the same server as the entry being added or imported.  Immediate
        subordinates of the superior entry are counted, without regard
        to access control, as though the entry addition or importing is
        successful.  If the number of subordinates exceeds maxImmSub,
        the ACI item is treated as not granting Add or Import
        permission.

      - restrictedBy restricts values added to the attribute type to
        being values that are already present in the same entry as
        values of the attribute identified by the valuesIn component.
        It is examined if the protected item is an attribute value of
        the specified type and the permission sought is Add.  Values of
        the valuesIn attribute are checked, without regard to attribute
        options and access control, as though the operation which adds
        the values is successful.  If the value to be added is not
        present in valuesIn the ACI item is treated as not granting Add
        permission.

      - contexts is not used in this version of the LDAP profile for
        Basic Access Control.

      - classes means the contents of entries that have object class
        values that satisfy the predicate defined by Refinement (see
        [SUBENTRY]).

   b) UserClasses defines a set of zero or more users the permissions
      apply to.  The set of users is selected from the following:

      - allUsers means every directory user (with possible requirements
        for AuthenticationLevel).



Legg                    Expires 16 December 2004               [Page 14]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      - thisEntry means the user with the same distinguished name as the
        entry being accessed.

      - name is the set of users with the specified distinguished names
        (each with an optional unique identifier).

      - userGroup is the set of users who are members of the groups
        (i.e., groupOfNames or groupOfUniqueNames entries [RFC2256])
        identified by the specified distinguished names (each with an
        optional unique identifier).  Members of a group of unique names
        are treated as individual user distinguished names, and not as
        the names of other groups of unique names.  How group membership
        is determined is described in 5.2.5.

      - subtree is the set of users whose distinguished names fall
        within the scope of the unrefined subtrees (specificationFilter
        components SHOULD NOT be used - they SHALL be ignored if
        present).

   c) SubtreeSpecification is used to specify a subtree relative to the
      root DSE, and is not constrained by administrative areas.  The
      specificationFilter component SHOULD NOT be used.  It SHALL be
      ignored if present.

      A subtree refinement is not allowed because membership in a
      subtree whose specification includes only base and/or a
      ChopSpecification can be evaluated in isolation, whereas
      membership in a subtree definition using specificationFilter can
      only be evaluated by obtaining information from the user's entry,
      which is potentially in another directory server.  Basic Access
      Control is designed to avoid remote operations in the course of
      making an access control decision.

   d) ItemPermission contains a collection of users and their
      permissions with respect to ProtectedItems within an itemFirst
      specification.  The permissions are specified in grantsAndDenials
      as discussed in item f).  Each of the permissions specified in
      grantsAndDenials is considered to have the precedence level
      specified in precedence for the purpose of the ACDF.  If
      precedence is omitted within ItemPermission, then precedence is
      taken from the precedence specified for ACIItem.

   e) UserPermission contains a collection of protected items and the
      associated permissions with respect to userClasses within a
      userFirst specification.  The associated permissions are specified
      in grantsAndDenials as discussed in item f).  Each of the
      permissions specified in grantsAndDenials is considered to have
      the precedence level specified in precedence for the purpose of



Legg                    Expires 16 December 2004               [Page 15]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      the ACDF.  If precedence is omitted within UserPermission, the
      precedence is taken from the precedence specified for ACIItem.

   f) GrantsAndDenials specify the access rights that are granted or
      denied by the ACI item.

   g) UniqueIdentifier may be used by the authentication mechanism to
      distinguish between instances of distinguished name reuse.  If
      this component is present, then for a requestor's name to match
      the UserClasses of an ACIItem that grants permissions, in addition
      to the requirement that the requestor's distinguished name match
      the specified distinguished name, the authentication of the
      requestor shall yield an associated unique identifier, and that
      value shall match for equality with the specified value.

3.2.5.  Determining Group Membership

   Determining whether a given requestor is a group member requires
   checking two criteria.  The determination may also be constrained if
   the group definition is not known locally.  The criteria for
   membership and the treatment of non-local groups are discussed below.

   a) A directory server is not required to perform a remote operation
      to determine whether the requestor belongs to a particular group
      for the purposes of Basic Access Control.  If membership in the
      group cannot be evaluated, the server shall assume that the
      requestor does not belong to the group if the ACI item grants the
      permission sought, and does belong to the group if it denies the
      permission sought.

      Access control administrators should beware of basing access
      controls on membership of non-locally available groups or groups
      which are available only through replication (and which may,
      therefore, be out of date).

   b) In order to determine whether the requestor is a member of a
      userGroup user class, the following criteria apply:

      - The entry named by the userGroup specification is an instance of
        the object class groupOfNames or groupOfUniqueNames.

      - The name of the requestor is a value of the member or
        uniqueMember attribute of that entry.

      Values of the member or uniqueMember attribute that do not match
      the name of the requestor are ignored, even if they represent the
      names of groups of which the originator could be found to be a
      member.  Hence, nested groups are not supported when evaluating



Legg                    Expires 16 December 2004               [Page 16]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      access controls.

3.3.  ACI Operational Attributes

   ACI is stored as values of operational attributes of entries and
   subentries.  The operational attributes are multi-valued, which
   allows ACI to be represented as a set of ACI items.

3.3.1.  Prescriptive ACI

   The prescriptiveACI attribute is defined as an operational attribute
   of an access control subentry.  It contains prescriptive ACI
   applicable to entries within that subentry's scope.

   The LDAP description [RFC2252] for the prescriptiveACI operational
   attribute is:

      ( 2.5.24.4 NAME 'prescriptiveACI'
          EQUALITY directoryStringFirstComponentMatch
          SYNTAX 1.3.6.1.4.1.1466.115.121.1.1
          USAGE directoryOperation )

   The directoryStringFirstComponentMatch matching rule is described in
   [SCHEMA].

   Prescriptive ACI within the subentries of a particular administrative
   point never applies to the same or any other subentry of that
   administrative point, but can be applicable to the subentries of
   subordinate administrative points.

   Note that prescriptiveACI attributes are not collective attributes.
   Although the values of a prescriptiveACI attribute contribute to
   access control decisions for each entry within the scope of the
   subentry that holds the attribute, the prescriptiveACI attribute does
   not appear as part of those entries.

3.3.2.  Entry ACI

   The entryACI attribute is defined as an operational attribute of an
   entry or subentry (not just access control subentries).  It contains
   entry ACI applicable to the entry or subentry in which it appears,
   and that (sub)entry's contents.

   The LDAP description [RFC2252] for the entryACI operational attribute
   is:

      ( 2.5.24.5 NAME 'entryACI'
          EQUALITY directoryStringFirstComponentMatch



Legg                    Expires 16 December 2004               [Page 17]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


          SYNTAX 1.3.6.1.4.1.1466.115.121.1.1
          USAGE directoryOperation )

3.3.3.  Subentry ACI

   The subentryACI attribute is defined as an operational attribute of
   administrative entries [ADMIN] (for any aspect of administration).
   It contains subentry ACI that applies to each of the subentries of
   the administrative entry in which it appears.  Only administrative
   entries are permitted to contain a subentryACI attribute.

   The LDAP description [RFC2252] for the subentryACI operational
   attribute is:

      ( 2.5.24.6 NAME 'subentryACI'
          EQUALITY directoryStringFirstComponentMatch
          SYNTAX 1.3.6.1.4.1.1466.115.121.1.1
          USAGE directoryOperation )

3.3.4.  Protecting the ACI

   ACI operational attributes are subject to the same protection
   mechanisms as other attributes.

   The identificationTag provides an identifier for each ACI item.  This
   tag can be used to remove a specific ACI item value, or to protect it
   by prescriptive ACI, entry ACI or subentry ACI.  Directory rules
   ensure that only one ACI item per access control operational
   attribute possesses any specific identificationTag value.

   The creation of subentries for an administrative entry may be
   controlled by means of the subentryACI operational attribute in the
   administrative entry.  The right to create prescriptive access
   controls may also be governed directly by security policy; this
   provision is required to create access controls in new autonomous
   administrative areas [ADMIN].

3.4.  Access Control Decision Points for LDAP Operations

   Each LDAP operation involves making a series of access control
   decisions on the various protected items that the operation accesses.

   For some operations (e.g., the Modify operation), each such access
   control decision must grant access for the operation to succeed; if
   access is denied to any protected item, the whole operation fails.
   For other operations (e.g., the Search operation), protected items to
   which access is denied are simply omitted from the operation result
   and processing continues.



Legg                    Expires 16 December 2004               [Page 18]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   If the requested access is denied, further access control decisions
   may be needed to determine if the user has DiscloseOnError
   permissions to the protected item.  Only if DiscloseOnError
   permission is granted may the server respond with an error that
   reveals the existence of the protected item.  In all other cases, the
   server MUST act so as to conceal the existence of the protected item.

   The permissions required to access each protected item, are specified
   for each operation in the following sections.  The algorithm by which
   a permission is determined to be granted or not granted is specified
   in Section 3.5.

3.4.1.  Common Elements of Procedure

   This section defines the elements of procedure that are common to all
   LDAP operations when Basic Access Control is in effect.

3.4.1.1.  Alias Dereferencing

   If, in the process of locating a target object entry (nominated in an
   LDAP request), alias dereferencing is required, no specific
   permissions are necessary for alias dereferencing to take place.
   However, if alias dereferencing would result in a referral being
   returned, the following sequence of access controls applies.

   1) Read permission is required to the alias entry.  If permission is
      not granted, the operation fails in accordance to the procedure
      described in 5.4.1.3.

   2) Read permission is required to the aliasedEntryName attribute and
      to the single value that it contains.  If permission is not
      granted, the operation fails and the resultCode
      aliasDereferencingProblem SHALL be returned.  The matchedDN field
      of the LDAPResult SHALL contain the name of the alias entry.

   In addition to the access controls described above, security policy
   may prevent the disclosure of knowledge of other servers which would
   otherwise be conveyed in a referral.  If such a policy is in effect
   the resultCode insufficientAccessRights SHALL be returned.

3.4.1.2.  Return of Names in Errors

   Certain LDAP result codes, i.e., noSuchObject, aliasProblem,
   invalidDNSyntax and aliasDereferencingProblem, provide the name of an
   entry in the matchedDN field of an LDAPResult.  The DN of an entry
   SHALL only be provided in the matchedDN field if DiscloseOnError
   permission is granted to that entry, otherwise, the matchedDN field
   of the LDAPResult SHALL either contain the name of the next superior



Legg                    Expires 16 December 2004               [Page 19]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   entry to which DiscloseOnError permission is granted, or, if
   DiscloseOnError permission is not granted to any superior entry, the
   name of the root DSE (i.e., a zero-length LDAPDN).

3.4.1.3.  Non-disclosure of Entry Existence

   If, while performing an LDAP operation, the necessary entry level
   permission is not granted to the specified target object entry -
   e.g., the entry to be modified - the operation fails; if
   DiscloseOnError permission is granted to the target entry, the
   resultCode insufficientAccessRights SHALL be returned, otherwise, the
   resultCode noSuchObject SHALL be returned.  The matchedDN field of
   the LDAPResult SHALL either contain the name of the next superior
   entry to which DiscloseOnError permission is granted, or, if
   DiscloseOnError permission is not granted to any superior entry, the
   name of the root DSE (i.e., a zero-length LDAPDN).

   Additionally, whenever the server detects an operational error
   (including a referral resultCode), it shall ensure that in returning
   that error it does not compromise the existence of the named target
   entry and any of its superiors.  For example, before returning a
   resultCode of timeLimitExceeded or notAllowedOnNonLeaf, the server
   verifies that DiscloseOnError permission is granted to the target
   entry.  If it is not, the procedure described in the paragraph above
   SHALL be followed.

3.4.2.  Compare Operation Decision Points

   The following sequence of access controls applies for an entry being
   compared.

   1) Read permission for the entry to be compared is required.  If
      permission is not granted, the operation fails in accordance with
      5.4.1.3.

   2) Compare permission for the attribute to be compared is required.
      If permission is not granted, the operation fails: if
      DiscloseOnError permission is granted to the attribute being
      compared, a resultCode of insufficientAccessRight SHALL be
      returned, otherwise, the resultCode noSuchAttribute SHALL be
      returned.

   3) If there exists a value within the attribute being compared that
      matches the purported argument and for which Compare permission is
      granted, the operation returns the resultCode compareTrue,
      otherwise the operation returns the resultCode compareFalse.

3.4.3.  Search Operation Decision Points



Legg                    Expires 16 December 2004               [Page 20]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   The following sequence of access controls applies for a portion of
   the DIT being searched.

   1) No specific permission is required to the entry identified by the
      baseObject argument in order to initiate a search.  However, if
      the baseObject is within the scope of the SearchArgument (i.e.,
      when the subset argument specifies baseObject or wholeSubtree) the
      access controls specified in 2) through 5) will apply.

   2) Browse or Read permission is required for the single entry within
      the scope of a baseObject search.  An entry for which neither of
      these permissions is granted is ignored.

      This differs from the X.500 DAP Search operation where the Browse
      permission alone is required.  An entry with Read permission but
      not Browse permission cannot be searched but can still be examined
      with an X.500 DAP Read operation.  LDAP relies on baseObject
      search operations to provide the functionality of the DAP Read
      operation.  Accepting Read permission for the target entry in a
      baseObject search gives an LDAP baseObject search the same access
      rights to the entry as the DAP Read operation.

   3) Browse permission is required for an entry within the scope of a
      singleLevel or wholeSubtree search to be a candidate for
      consideration.  Entries for which this permission is not granted
      are ignored.

   4) The filter argument is applied to each entry left to be considered
      after taking 2) and 3) into account, in accordance with the
      following:

      a) For a present Filter item, if there exists an attribute value
         such that the attribute type of the value (possibly a subtype
         of the attribute type in the FilterItem) satisfies the Filter
         item and FilterMatch permission is granted for the value and
         for the attribute type then the FilterItem evaluates to TRUE,
         otherwise, it evaluates to FALSE.

         If a directory server does not support True/False filters
         [FILTER] on LDAP searches, or if directory clients do not
         exploit this capability, then access control administrators
         SHOULD grant FilterMatch permission for the objectClass
         attribute over entries where Read permission is also granted so
         that an LDAP baseObject search with a filter testing for the
         presence of the objectClass attribute will have the same access
         rights to the target entry as the DAP Read operation.  An LDAP
         baseObject search with a True filter does not require
         FilterMatch permission for any particular attribute type.



Legg                    Expires 16 December 2004               [Page 21]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      b) For an equalityMatch, substrings, greaterOrEqual, lessOrEqual,
         approxMatch or extensibleMatch Filter item, if there exists an
         attribute value such that the value satisfies the Filter item
         and FilterMatch permission is granted for the value and for its
         attribute type (possibly a subtype of the attribute type in the
         FilterItem) then the FilterItem evaluates to TRUE, otherwise,
         it evaluates to FALSE.

   Once the access controls defined in 2) through 4) have been applied,
   an entry is either selected or discarded.

   5) For each selected entry the information returned is as follows:

      a) ReturnDN permission for an entry is required in order to return
         its distinguished name in a SearchResultEntry response.  If
         this permission is not granted, the server SHALL either, return
         the name of a valid alias to the entry, or, omit the entry from
         the search result.

         If the base entry of the search was located using an alias,
         then that alias is known to be a valid alias.  Otherwise, how
         it is ensured that the alias is valid is outside the scope of
         this specification.

         Where a server has a choice of alias names available to it for
         return, it is RECOMMENDED that where possible it choose the
         same alias name for repeated requests by the same client, in
         order to provide a consistent service.

      b) If the typesOnly field of the SearchRequest is TRUE then, for
         each attribute type that is to be returned, Read permission for
         the attribute type and Read permission for at least one value
         of the attribute is required.  If permission is not granted,
         the attribute type is omitted from the attribute list in the
         SearchResultEntry.  If as a consequence of applying these
         controls no attribute type information is selected, the
         SearchResultEntry is returned but no attribute type information
         is conveyed with it (i.e., the attribute list is empty).

      c) If the typesOnly field of the SearchRequest is FALSE then Read
         permission is required for each attribute type and for each
         attribute value that is to be returned.  If permission to an
         attribute type is not granted, the attribute is omitted from
         the SearchResultEntry.  If permission to an attribute value is
         not granted, the value is omitted from its corresponding
         attribute.  If all values of an attribute are omitted then the
         attribute type is omitted from the attribute list in the
         SearchResultEntry.  If as a consequence of applying these



Legg                    Expires 16 December 2004               [Page 22]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


         controls no attribute information is selected, the
         SearchResultEntry is returned but no attribute information is
         conveyed with it (i.e., the attribute list is empty).

   6) If as a consequence of applying the above controls to the entire
      scoped subtree the search result contains no entries (excluding
      any SearchResultReferences) and if DiscloseOnError permission is
      not granted to the entry identified by the baseObject argument,
      the operation fails and the resultCode noSuchObject SHALL be
      returned.  The matchedDN field of the LDAPResult SHALL either
      contain the name of the next superior entry to which
      DiscloseOnError permission is granted, or the name of the root DSE
      (i.e., a zero-length LDAPDN).  Otherwise, the operation succeeds
      but no subordinate information is conveyed with it.

   Security policy may prevent the disclosure of knowledge of other
   servers which would otherwise be conveyed as SearchResultReferences.
   If such a policy is in effect SearchResultReferences are omitted from
   the search result.

   No specific permissions are necessary to allow alias dereferencing to
   take place in the course of a search operation.  However, for each
   alias entry encountered, if alias dereferencing would result in a
   SearchResultReference being returned, the following access controls
   apply: Read permission is required to the alias entry, the
   aliasedEntryName attribute and to the single value that it contains.
   If any of these permissions is not granted, the SearchResultReference
   SHALL be omitted from the search result.

3.4.4.  Add Operation Decision Points

   The following sequence of access controls apply for an entry being
   added.

   1) No specific permission is required for the immediate superior of
      the entry identified by the entry field of the AddRequest.

   2) If an entry already exists with a distinguished name equal to the
      entry field the operation fails; if DiscloseOnError or Add
      permission is granted to the existing entry, the resultCode
      entryAlreadyExists SHALL be returned, otherwise, the procedure
      described in 5.4.1.3 is followed with respect to the entry being
      added.

   3) Add permission is required for the new entry being added.  If this
      permission is not granted, the operation fails; the procedure
      described in 5.4.1.3 is followed with respect to the entry being
      added.



Legg                    Expires 16 December 2004               [Page 23]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      The Add permission is provided as prescriptive ACI when attempting
      to add an entry and as prescriptive ACI or subentry ACI when
      attempting to add a subentry.  Any values of the entryACI
      attribute in the entry being added SHALL be ignored.

   4) Add permission is required for each attribute type and for each
      value that is to be added.  If any permission is absent, the
      operation fails and the resultCode insufficientAccessRights SHALL
      be returned.

3.4.5.  Delete Operation Decision Points

   The following sequence of access controls apply for an entry being
   removed.

   1) Remove permission is required for the entry being removed.  If
      this permission is not granted, the operation fails in accordance
      with 5.4.1.3.

   2) No specific permissions are required for any of the attributes and
      attribute values present within the entry being removed.

3.4.6.  Modify Operation Decision Points

   The following sequence of access controls apply for an entry being
   modified.

   1) Modify permission is required for the entry being modified.  If
      this permission is not granted, the operation fails in accordance
      with 5.4.1.3.

   2) For each of the specified modification arguments applied in
      sequence, the following permissions are required:

      a) Add permission is required for each of the attribute values
         specified in an add modification.  If the attribute does not
         currently exist then Add permission for the attribute type is
         also required.  If these permissions are not granted, or any of
         the attribute values already exist, the operation fails; if an
         attribute value already exists and DiscloseOnError or Add is
         granted to that attribute value, the resultCode
         attributeOrValueExists SHALL be returned, otherwise, the
         resultCode insufficientAccessRights SHALL be returned.

      b) Remove permission is required for the attribute type specified
         in a delete modification with no listed attribute values.  If
         this permission is not granted, the operation fails; if
         DiscloseOnError permission is granted to the attribute being



Legg                    Expires 16 December 2004               [Page 24]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


         removed and the attribute exists, the resultCode
         insufficientAccessRights SHALL be returned, otherwise, the
         resultCode noSuchAttribute SHALL be returned.

         No specific permissions are required for any of the attribute
         values present within the attribute being removed.

      c) Remove permission is required for each of the values in a
         delete modification with listed attribute values.  If all
         current values of the attribute are specified to be removed
         (which causes the attribute itself to be removed), then Remove
         permission for the attribute type is also required.  If these
         permissions are not granted, the operation fails; if
         DiscloseOnError permission is granted to any of the attribute
         values being removed, the resultCode insufficientAccessRights
         SHALL be returned, otherwise, the resultCode noSuchAttribute
         SHALL be returned.

      d) Remove and Add permission is required for the attribute type,
         and Add permission is required for each of the specified
         attribute values, in a replace modification.  If these
         permissions are not granted the operation fails and the
         resultCode insufficientAccessRights SHALL be returned.

         No specific permissions are required to remove any existing
         attribute values of the attribute being replaced.

3.4.7.  Modify DN Operation Decision Points

   The following sequence of access controls apply for an entry having
   its DN modified.

   1) If the effect of the operation is to change the RDN of the entry
      then Rename permission (determined with respect to its original
      name) is required for the entry.  If this permission is not
      granted, the operation fails; the procedure described in 5.4.1.3
      is followed with respect to the entry being renamed (considered
      with its original name).

      No additional permissions are required even if, as a result of
      modifying the RDN of the entry, a new distinguished value needs to
      be added, or an old one removed.  No specific permissions are
      required for the subordinates of the renamed entry.

   2) If the effect of the operation is to move an entry to a new
      superior in the DIT then Export permission (determined with
      respect to its original name) and Import permission (determined
      with respect to its new name) are required for the entry.  If



Legg                    Expires 16 December 2004               [Page 25]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      either of these permissions is not granted, the operation fails;
      the procedure described in 5.4.1.3 is followed with respect to the
      entry being moved (considered with its original name).

      The Import permission is provided as prescriptive ACI when
      attempting to move an entry and as prescriptive ACI or subentry
      ACI when attempting to move a subentry.  Any values of the
      entryACI attribute in the entry or subentry being moved SHALL be
      ignored.

      No specific permissions are required for the subordinates of the
      moved entry.

   Note that a single Modify DN Operation may simultaneously rename and
   move an entry.

3.5.  Access Control Decision Function

   This section describes how ACI items are processed in order to decide
   whether to grant or deny a particular requestor a specified
   permission to a given protected item.

   Section 3.5.1 describes the inputs to the ACDF.  Sections 3.5.2
   through 3.5.4 describe the steps in the ACDF.  The output is a
   decision to grant or deny access to the protected item.

3.5.1.  Inputs

   For each invocation of the ACDF, the inputs are:

   a) the requestor's Distinguished Name, unique identifier, and
      authentication level, or as many of these as are available;

   b) the protected item (an entry, an attribute, or an attribute value)
      being considered at the current decision point for which the ACDF
      was invoked;

   c) the requested permission specified for the current decision point;

   d) the ACI items applicable to the entry containing (or which is) the
      protected item.

   In addition, if the ACI items include any of the protected item
   constraints described in 5.2.1.4, the whole entry and the number of
   immediate subordinates of its superior entry may also be required as
   inputs.

3.5.2.  Tuples



Legg                    Expires 16 December 2004               [Page 26]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   For each ACI item, expand the item into a set of tuples, one tuple
   for each element of the itemPermissions and userPermissions sets,
   containing the following elements:

      ( userClasses, authenticationLevel, protectedItems,
         grantsAndDenials, precedence )

   Collect all tuples from all ACI items into a single set.

   For any tuple whose grantsAndDenials specify both grants and denials,
   replace the tuple with two tuples - one specifying only grants and
   the other specifying only denials.

3.5.3.  Discarding Irrelevant Tuples

   Perform the following steps to discard all irrelevant tuples:

   1) Discard all tuples that do not include the requestor in the
      tuple's userClasses as follows:

      a) For tuples that grant access, discard all tuples that do not
         include the requestor's identity in the tuples's userClasses
         element, taking into account UniqueIdentifier elements if
         relevant.  Where a tuple's userClasses specifies a
         UniqueIdentifier, a matching value shall be present in the
         requestor's identity if the tuple is not to be discarded.
         Discard tuples that specify an authentication level higher than
         that associated with the requestor.

      b) For tuples that deny access, retain all tuples that include the
         requestor in the tuple's userClasses element, taking into
         account uniqueIdentifier elements if relevant.  Also retain all
         tuples that deny access and which specify an authentication
         level higher than that associated with the requestor.  This
         reflects the fact that the requestor has not adequately proved
         non-membership in the user class for which the denial is
         specified.  All other tuples that deny access are discarded.

   2) Discard all tuples that do not include the protected item in
      protectedItems.

   3) Examine all tuples that include maxValueCount, maxImmSub or
      restrictedBy.  Discard all such tuples which grant access and
      which do not satisfy any of these constraints.

   4) Discard all tuples that do not include the requested permission as
      one of the set bits in grantsAndDenials.




Legg                    Expires 16 December 2004               [Page 27]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   The order in which tuples are discarded does not change the output of
   the ACDF.

3.5.4.  Highest Precedence and Specificity

   Perform the following steps to select those tuples of highest
   precedence and specificity:

   1) Discard all tuples having a precedence less than the highest
      precedence among the remaining tuples.

   2) If more than one tuple remains, choose the tuples with the most
      specific user class.  If there are any tuples matching the
      requestor with UserClasses element name or thisEntry, discard all
      other tuples.  Otherwise if there are any tuples matching
      UserGroup, discard all other tuples.  Otherwise if there are any
      tuples matching subtree, discard all other tuples.

   3) If more than one tuple remains, choose the tuples with the most
      specific protected item.  If the protected item is an attribute
      and there are tuples that specify the attribute type explicitly,
      discard all other tuples.  If the protected item is an attribute
      value, and there are tuples that specify the attribute value
      explicitly, discard all other tuples.  A protected item which is a
      rangeOfValues is to be treated as specifying an attribute value
      explicitly.

   Grant access if and only if one or more tuples remain and all grant
   access.  Otherwise deny access.

4.  Simplified Access Control

   This section describes the functionality of the Simplified Access
   Control scheme.  It provides a subset of the functionality found in
   Basic Access Control.

   When Simplified Access Control is used, the accessControlScheme
   operational attribute [ACA] SHALL have the value
   simplified-access-control (2.5.28.2).

   The functionality of Simplified Access Control is the same as Basic
   Access Control except that:

   1) Access control decisions shall be made only on the basis of values
      of prescriptiveACI and subentryACI operational attributes.  Values
      of the entryACI attribute, if present, SHALL NOT be used to make
      access control decisions.




Legg                    Expires 16 December 2004               [Page 28]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   2) Access Control Inner Areas are not used.  Values of
      prescriptiveACI attributes appearing in subentries of ACIPs SHALL
      NOT be used to make access control decisions.

   All other provisions SHALL be as defined for Basic Access Control.

5.  Security Considerations

   Access control administrators should beware of basing access controls
   on membership of non-locally available groups or groups which are
   available only through replication (and which may, therefore, be out
   of date).

   A particular DSA might not have the ACI governing any data that it
   caches.  Administrators should be aware that a directory server with
   the capability of caching may pose a significant security risk to
   other directory servers, in that it may reveal information to
   unauthorized users.

6.  Acknowledgements

   This document is derived from, and duplicates substantial portions
   of, Section 8 of X.501 [X501], and selected extracts from X.511
   [X511].

7.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) is requested to update
   the LDAP descriptors registry [BCP64] as indicated by the following
   templates:

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): basic-access-control
      Object Identifier: 2.5.28.1
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: other (access control scheme)
      Specification: RFC XXXX
      Author/Change Controller: IESG

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): simplified-access-control
      Object Identifier: 2.5.28.2
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: other (access control scheme)
      Specification: RFC XXXX
      Author/Change Controller: IESG



Legg                    Expires 16 December 2004               [Page 29]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): prescriptiveACI
      Object Identifier: 2.5.24.4
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: attribute type
      Specification: RFC XXXX
      Author/Change Controller: IESG

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): entryACI
      Object Identifier: 2.5.24.5
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: attribute type
      Specification: RFC XXXX
      Author/Change Controller: IESG

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): subentryACI
      Object Identifier: 2.5.24.6
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: attribute type
      Specification: RFC XXXX
      Author/Change Controller: IESG

Appendix A. LDAP Specific Encoding for the ACI Item Syntax

   This appendix is non-normative.

   The LDAP-specific encoding for the ACI Item syntax is specified by
   the Generic String Encoding Rules [GSER].  The ABNF [RFC2234] in this
   appendix for this syntax is provided only as a convenience and is
   equivalent to the encoding specified by the application of GSER.
   Since the ACI Item ASN.1 type may be extended in future editions of
   X.501 [X501], the provided ABNF should be regarded as a snapshot in
   time.  The LDAP-specific encoding for any extension to the ACI Item
   ASN.1 type can be determined from the rules of GSER.

   In the event that there is a discrepancy between this ABNF and the
   encoding determined by GSER, then GSER is to be taken as definitive.

   ACIItem = "{" sp aci-identificationTag ","
                 sp aci-precedence ","
                 sp aci-authenticationLevel ","
                 sp aci-itemOrUserFirst
                 sp "}"



Legg                    Expires 16 December 2004               [Page 30]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   aci-identificationTag   = id-identificationTag   msp
                                DirectoryString
   aci-precedence          = id-precedence          msp Precedence
   aci-authenticationLevel = id-authenticationLevel msp
                                AuthenticationLevel
   aci-itemOrUserFirst     = id-itemOrUserFirst     msp
                                ItemOrUserFirst
   id-identificationTag    = %x69.64.65.6E.74.69.66.69.63.61.74.69.6F
                                %x6E.54.61.67 ; "identificationTag"
   id-precedence           = %x70.72.65.63.65.64.65.6E.63.65
                                ; "precedence"
   id-authenticationLevel  = %x61.75.74.68.65.6E.74.69.63.61.74.69.6F
                                %x6E.4C.65.76.65.6C
                                ; "authenticationLevel"
   id-itemOrUserFirst      = %x69.74.65.6D.4F.72.55.73.65.72.46.69.72
                                %x73.74 ; "itemOrUserFirst"

   Precedence = INTEGER-0-MAX ; MUST be less than 256

   AuthenticationLevel = al-basicLevels / al-other
   al-basicLevels      = id-basicLevels ":" BasicLevels
   al-other            = id-other       ":" EXTERNAL
   id-basicLevels      = %x62.61.73.69.63.4C.65.76.65.6C.73
                            ; "basicLevels"
   id-other            = %x6F.74.68.65.72 ; "other"

   BasicLevels = "{"      sp bl-level
                    [ "," sp bl-localQualifier ]
                    [ "," sp bl-signed         ]
                          sp "}"

   bl-level          = id-level          msp Level
   bl-localQualifier = id-localQualifier msp INTEGER
   bl-signed         = id-signed         msp BOOLEAN
   Level             = id-none / id-simple / id-strong
   id-level          = %x6C.65.76.65.6C ; "level"
   id-localQualifier = %x6C.6F.63.61.6C.51.75.61.6C.69.66.69.65.72
                          ; "localQualifier"
   id-signed         = %x73.69.67.6E.65.64 ; "signed"
   id-none           = %x6E.6F.6E.65       ; "none"
   id-simple         = %x73.69.6D.70.6C.65 ; "simple"
   id-strong         = %x73.74.72.6F.6E.67 ; "strong"

   ItemOrUserFirst    = ( id-itemFirst ":" ItemFirst ) /
                        ( id-userFirst ":" UserFirst )
   id-itemFirst       = %x69.74.65.6D.46.69.72.73.74 ; "itemFirst"
   id-userFirst       = %x75.73.65.72.46.69.72.73.74 ; "userFirst"




Legg                    Expires 16 December 2004               [Page 31]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   ItemFirst          = "{" sp if-protectedItems ","
                            sp if-itemPermissions
                            sp "}"
   if-protectedItems  = id-protectedItems  msp ProtectedItems
   if-itemPermissions = id-itemPermissions msp ItemPermissions
   id-protectedItems  = %x70.72.6F.74.65.63.74.65.64.49.74.65.6D.73
                           ; "protectedItems"
   id-itemPermissions = %x69.74.65.6D.50.65.72.6D.69.73.73.69.6F.6E
                           %x73 ; "itemPermissions"

   UserFirst          = "{" sp uf-userClasses ","
                            sp uf-userPermissions
                            sp "}"
   uf-userClasses     = id-userClasses     msp UserClasses
   uf-userPermissions = id-userPermissions msp UserPermissions
   id-userClasses     = %x75.73.65.72.43.6C.61.73.73.65.73
                           ; "userClasses"
   id-userPermissions = %x75.73.65.72.50.65.72.6D.69.73.73.69.6F.6E
                           %x73 ; "userPermissions"

   ItemPermissions     = "{" [ sp ItemPermission
                            *( "," sp ItemPermission ) ] sp "}"
   ItemPermission      = "{" [ sp ip-precedence "," ]
                               sp ip-userClasses ","
                               sp ip-grantsAndDenials
                               sp "}"
   ip-precedence       = id-precedence       msp Precedence
   ip-userClasses      = id-userClasses      msp UserClasses
   ip-grantsAndDenials = id-grantsAndDenials msp GrantsAndDenials
   id-grantsAndDenials = %x67.72.61.6E.74.73.41.6E.64.44.65.6E.69.61
                            %x6C.73 ; "grantsAndDenials"

   UserClasses  = "{"     [ sp uc-allUsers ]
                      [ sep sp uc-thisEntry ]
                      [ sep sp uc-name ]
                      [ sep sp uc-userGroup ]
                      [ sep sp uc-subtree ]
                            sp "}"
   uc-allUsers  = id-allUsers  msp NULL
   uc-thisEntry = id-thisEntry msp NULL
   uc-name      = id-name      msp NameAndOptionalUIDs
   uc-userGroup = id-userGroup msp NameAndOptionalUIDs
   uc-subtree   = id-subtree   msp SubtreeSpecifications
   id-allUsers  = %x61.6C.6C.55.73.65.72.73    ; "allUsers"
   id-thisEntry = %x74.68.69.73.45.6E.74.72.79 ; "thisEntry"
   id-name      = %x6E.61.6D.65                ; "name"
   id-userGroup = %x75.73.65.72.47.72.6F.75.70 ; "userGroup"
   id-subtree   = %x73.75.62.74.72.65.65       ; "subtree"



Legg                    Expires 16 December 2004               [Page 32]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   NameAndOptionalUIDs = "{" sp NameAndOptionalUID
                            *( "," sp NameAndOptionalUID ) sp "}"
   NameAndOptionalUID  = "{"      sp nu-dn
                            [ "," sp nu-uid ]
                                  sp "}"
   nu-dn               = id-dn  msp DistinguishedName
   nu-uid              = id-uid msp UniqueIdentifier
   UniqueIdentifier    = BIT-STRING
   id-dn               = %x64.6E    ; "dn"
   id-uid              = %x75.69.64 ; "uid"

   SubtreeSpecifications = "{" sp SubtreeSpecification
                              *( "," sp SubtreeSpecification ) sp "}"

   UserPermissions     = "{" [ sp UserPermission
                            *( "," sp UserPermission ) ] sp "}"
   UserPermission      = "{" [ sp up-precedence "," ]
                               sp up-protectedItems ","
                               sp up-grantsAndDenials
                               sp "}"
   up-precedence       = id-precedence       msp Precedence
   up-protectedItems   = id-protectedItems   msp ProtectedItems
   up-grantsAndDenials = id-grantsAndDenials msp GrantsAndDenials

   ProtectedItems = "{"     [ sp pi-entry ]
                        [ sep sp pi-allUserAttributeTypes ]
                        [ sep sp pi-attributeType ]
                        [ sep sp pi-allAttributeValues ]
                        [ sep sp pi-allUserTypesAndValues ]
                        [ sep sp pi-attributeValue ]
                        [ sep sp pi-selfValue ]
                        [ sep sp pi-rangeOfValues ]
                        [ sep sp pi-maxValueCount ]
                        [ sep sp pi-maxImmSub ]
                        [ sep sp pi-restrictedBy ]
                        ; contexts omitted
                        [ sep sp pi-classes ]
                              sp "}"

   pi-entry                 = id-entry msp NULL
   pi-allUserAttributeTypes = id-allUserAttributeTypes msp NULL
   pi-attributeType         = id-attributeType msp AttributeTypes
   pi-allAttributeValues    = id-allAttributeValues msp
                                 AttributeTypes
   pi-allUserTypesAndValues = id-allUserAttributeTypesAndValues msp
                                 NULL
   pi-attributeValue        = id-attributeValue msp
                                 AttributeTypeAndValues



Legg                    Expires 16 December 2004               [Page 33]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   pi-selfValue             = id-selfValue msp AttributeTypes
   pi-rangeOfValues         = id-rangeOfValues msp Filter
   pi-maxValueCount         = id-maxValueCount msp MaxValueCounts
   pi-maxImmSub             = id-maxImmSub msp INTEGER
   pi-restrictedBy          = id-restrictedBy msp RestrictedValues
   pi-classes               = id-classes msp Refinement
   id-entry                 = %x65.6E.74.72.79 ; "entry"
   id-allUserAttributeTypes = %x61.6C.6C.55.73.65.72.41.74.74.72.69
                                 %x62.75.74.65.54.79.70.65.73
                                 ; "allUserAttributeTypes"
   id-attributeType         = %x61.74.74.72.69.62.75.74.65.54.79.70
                                 %x65 ; "attributeType"
   id-allAttributeValues    = %x61.6C.6C.41.74.74.72.69.62.75.74.65
                                 %x56.61.6C.75.65.73
                                 ; "allAttributeValues"
   id-attributeValue        = %x61.74.74.72.69.62.75.74.65.56.61.6C
                                 %x75.65 ; "attributeValue"
   id-selfValue             = %x73.65.6C.66.56.61.6C.75.65
                                 ; "selfValue"
   id-rangeOfValues         = %x72.61.6E.67.65.4F.66.56.61.6C.75.65
                                 %x73 ; "rangeOfValues"
   id-maxValueCount         = %x6D.61.78.56.61.6C.75.65.43.6F.75.6E
                                 %x74 ; "maxValueCount"
   id-maxImmSub             = %x6D.61.78.49.6D.6D.53.75.62
                                 ; "maxImmSub"
   id-restrictedBy          = %x72.65.73.74.72.69.63.74.65.64.42.79
                                 ; "restrictedBy"
   id-classes               = %x63.6C.61.73.73.65.73 ; "classes"

   id-allUserAttributeTypesAndValues = %x61.6C.6C.55.73.65.72.41.74
                              %x74.72.69.62.75.74.65.54.79.70.65.73
                              %x41.6E.64.56.61.6C.75.65.73
                              ; "allUserAttributeTypesAndValues"

   AttributeTypes = "{" sp AttributeType
                       *( "," sp AttributeType ) sp "}"

   AttributeTypeAndValues = "{" sp AttributeTypeAndValue
                               *( "," sp AttributeTypeAndValue )
                               sp "}"

   AttributeTypeAndValue = "{" sp atav-type ","
                               sp atav-value
                               sp "}"
   atav-type  = id-type  msp AttributeType
   atav-value = id-value msp Value
   id-type    = %x74.79.70.65    ; "type"
   id-value   = %x76.61.6C.75.65 ; "value"



Legg                    Expires 16 December 2004               [Page 34]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   MaxValueCounts = "{" sp MaxValueCount
                       *( "," sp MaxValueCount ) sp "}"
   MaxValueCount  = "{" sp mvc-type ","
                        sp mvc-maxCount
                        sp "}"
   mvc-type       = id-type msp AttributeType
   mvc-maxCount   = id-maxCount msp INTEGER
   id-maxCount    = %x6D.61.78.43.6F.75.6E.74 ; "maxCount"

   RestrictedValues = "{" sp RestrictedValue
                         *( "," sp RestrictedValue ) sp "}"
   RestrictedValue  = "{" sp rv-type ","
                          sp rv-valuesin
                          sp "}"
   rv-type          = id-type     msp AttributeType
   rv-valuesin      = id-valuesin msp AttributeType
   id-valuesin      = %x76.61.6C.75.65.73.69.6E ; "valuesin"

   GrantsAndDenials = "{" [ sp grantOrDeny
                         *( "," sp grantOrDeny ) ] sp "}"
   grantOrDeny = id-grantAdd
                 / id-denyAdd
                 / id-grantDiscloseOnError
                 / id-denyDiscloseOnError
                 / id-grantRead
                 / id-denyRead
                 / id-grantRemove
                 / id-denyRemove
                 / id-grantBrowse
                 / id-denyBrowse
                 / id-grantExport
                 / id-denyExport
                 / id-grantImport
                 / id-denyImport
                 / id-grantModify
                 / id-denyModify
                 / id-grantRename
                 / id-denyRename
                 / id-grantReturnDN
                 / id-denyReturnDN
                 / id-grantCompare
                 / id-denyCompare
                 / id-grantFilterMatch
                 / id-denyFilterMatch
                 ; grantInvoke omitted
                 ; denyInvoke omitted

   id-grantAdd     = %x67.72.61.6E.74.41.64.64 ; "grantAdd"



Legg                    Expires 16 December 2004               [Page 35]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   id-denyAdd      = %x64.65.6E.79.41.64.64 ; "denyAdd"
   id-grantBrowse  = %x67.72.61.6E.74.42.72.6F.77.73.65
                        ; "grantBrowse"
   id-denyBrowse   = %x64.65.6E.79.42.72.6F.77.73.65 ; "denyBrowse"
   id-grantCompare = %x67.72.61.6E.74.43.6F.6D.70.61.72.65
                        ; "grantCompare"
   id-denyCompare  = %x64.65.6E.79.43.6F.6D.70.61.72.65
                        ; "denyCompare"

   id-grantDiscloseOnError = %x67.72.61.6E.74.44.69.73.63.6C.6F.73.65
                                %x4F.6E.45.72.72.6F.72
                                ; "grantDiscloseOnError"
   id-denyDiscloseOnError  = %x64.65.6E.79.44.69.73.63.6C.6F.73.65.4F
                                %x6E.45.72.72.6F.72
                                ; "denyDiscloseOnError"

   id-grantExport      = %x67.72.61.6E.74.45.78.70.6F.72.74
                            ; "grantExport"
   id-denyExport       = %x64.65.6E.79.45.78.70.6F.72.74
                            ; "denyExport"
   id-grantFilterMatch = %x67.72.61.6E.74.46.69.6C.74.65.72.4D.61.74
                            %x63.68 ; "grantFilterMatch"
   id-denyFilterMatch  = %x64.65.6E.79.46.69.6C.74.65.72.4D.61.74.63
                            %x68 ; "denyFilterMatch"
   id-grantImport      = %x67.72.61.6E.74.49.6D.70.6F.72.74
                            ; "grantImport"
   id-denyImport       = %x64.65.6E.79.49.6D.70.6F.72.74
                            ; "denyImport"
   id-grantModify      = %x67.72.61.6E.74.4D.6F.64.69.66.79
                            ; "grantModify"
   id-denyModify       = %x64.65.6E.79.4D.6F.64.69.66.79
                            ; "denyModify"
   id-grantRead        = %x67.72.61.6E.74.52.65.61.64 ; "grantRead"
   id-denyRead         = %x64.65.6E.79.52.65.61.64 ; "denyRead"
   id-grantRemove      = %x67.72.61.6E.74.52.65.6D.6F.76.65
                            ; "grantRemove"
   id-denyRemove       = %x64.65.6E.79.52.65.6D.6F.76.65
                            ; "denyRemove"
   id-grantRename      = %x67.72.61.6E.74.52.65.6E.61.6D.65
                            ; "grantRename"
   id-denyRename       = %x64.65.6E.79.52.65.6E.61.6D.65
                            ; "denyRename"
   id-grantReturnDN    = %x67.72.61.6E.74.52.65.74.75.72.6E.44.4E
                            ; "grantReturnDN"
   id-denyReturnDN     = %x64.65.6E.79.52.65.74.75.72.6E.44.4E
                            ; "denyReturnDN"

   The <sp>, <msp>, <sep>, <AttributeType>, <BIT-STRING>, <BOOLEAN>,



Legg                    Expires 16 December 2004               [Page 36]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   <DirectoryString>, <DistinguishedName>, <EXTERNAL>, <INTEGER>,
   <INTEGER-0-MAX> and <NULL> rules are described in [GCE].

   The <SubtreeSpecification> and <Refinement> rules are described in
   [SUBENTRY].

   The <Value> rule is described in [GSER].

   Filter      = filter-item / filter-and / filter-or / filter-not
   filter-item = id-item ":" FilterItem
   filter-and  = id-and  ":" SetOfFilter
   filter-or   = id-or   ":" SetOfFilter
   filter-not  = id-not  ":" Filter
   id-and      = %x61.6E.64    ; "and"
   id-item     = %x69.74.65.6D ; "item"
   id-not      = %x6E.6F.74    ; "not"
   id-or       = %x6F.72       ; "or"

   SetOfFilter = "{" [ sp Filter *( "," sp Filter ) ] sp "}"

   FilterItem = fi-equality
                / fi-substrings
                / fi-greaterOrEqual
                / fi-lessOrEqual
                / fi-present
                / fi-approximateMatch
                / fi-extensibleMatch
                ; contextPresent omitted

   fi-equality         = id-equality ":" AttributeValueAssertion
   fi-substrings       = id-substrings ":" SubstringsAssertion
   fi-greaterOrEqual   = id-greaterOrEqual ":"
                            AttributeValueAssertion
   fi-lessOrEqual      = id-lessOrEqual ":" AttributeValueAssertion
   fi-present          = id-present ":" AttributeType
   fi-approximateMatch = id-approximateMatch ":"
                            AttributeValueAssertion
   fi-extensibleMatch  = id-extensibleMatch ":" MatchingRuleAssertion
   id-equality         = %x65.71.75.61.6C.69.74.79 ; "equality"
   id-substrings       = %x73.75.62.73.74.72.69.6E.67.73
                            ; "substrings"
   id-greaterOrEqual   = %x67.72.65.61.74.65.72.4F.72.45.71.75.61.6C
                            ; "greaterOrEqual"
   id-lessOrEqual      = %x6C.65.73.73.4F.72.45.71.75.61.6C
                            ; "lessOrEqual"
   id-present          = %x70.72.65.73.65.6E.74 ; "present"
   id-approximateMatch = %x61.70.70.72.6F.78.69.6D.61.74.65.4D.61.74
                            %x63.68 ; "approximateMatch"



Legg                    Expires 16 December 2004               [Page 37]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   id-extensibleMatch  = %x65.78.74.65.6E.73.69.62.6C.65.4D.61.74.63
                            %x68 ; "extensibleMatch"

   AttributeValueAssertion = "{" sp ava-type ","
                                 sp ava-assertion
                                 ; assertedContexts omitted
                                 sp "}"

   ava-type      = id-type      msp AttributeType
   ava-assertion = id-assertion msp Value
   id-assertion  = %x61.73.73.65.72.74.69.6F.6E ; "assertion"

   SubstringsAssertion = "{" sp sa-type ","
                             sp sa-strings
                             sp "}"

   sa-type    = id-type    msp AttributeType
   sa-strings = id-strings msp Substrings
   id-strings = %x73.74.72.69.6E.67.73 ; "strings"

   Substrings = "{" [ sp Substring *( "," sp Substring ) ] sp "}"
   Substring  = ss-initial
                / ss-any
                / ss-final
                ; control omitted
   ss-initial = id-initial ":" Value
   ss-any     = id-any     ":" Value
   ss-final   = id-final   ":" Value
   id-initial = %x69.6E.69.74.69.61.6C ; "initial"
   id-any     = %x61.6E.79             ; "any"
   id-final   = %x66.69.6E.61.6C       ; "final"

   MatchingRuleAssertion = "{"      sp mra-matchingRule
                              [ "," sp mra-type ]
                                "," sp mra-matchValue
                              [ "," sp mra-dnAttributes ]
                                    sp "}"

   mra-matchingRule = id-matchingRule msp MatchingRuleIds
   mra-type         = id-type         msp AttributeType
   mra-matchValue   = id-matchValue   msp Value
   mra-dnAttributes = id-dnAttributes msp BOOLEAN
   id-matchingRule  = %x6D.61.74.63.68.69.6E.67.52.75.6C.65
                         ; "matchingRule"
   id-matchValue    = %x6D.61.74.63.68.56.61.6C.75.65 ; "matchValue"
   id-dnAttributes  = %x64.6E.41.74.74.72.69.62.75.74.65.73
                         ; "dnAttributes"




Legg                    Expires 16 December 2004               [Page 38]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   MatchingRuleIds = "{" sp MatchingRuleId *( "," sp MatchingRuleId ) sp "}"
   MatchingRuleId  = OBJECT-IDENTIFIER

   The <OBJECT-IDENTIFIER> rule is described in [GCE].

Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2251]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory
              Access Protocol (v3)", RFC 2251, December 1997.

   [RFC2252]  Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
              "Lightweight Directory Access Protocol (v3): Attribute
              Syntax Definitions", RFC 2252, December 1997.

   [RFC2256]  Wahl, M., "A Summary of the X.500(96) User Schema for use
              with LDAPv3", RFC 2256, December 1997.

   [RFC3377]  Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

              [BCP64]    Zeilenga, K., "Internet Assigned Numbers
              Authority (IANA) Considerations for the Lightweight
              Directory Access Protcol (LDAP)", BCP 64, RFC 3383,
              September 2002.

   [GSER]     Legg, S., "Generic String Encoding Rules for ASN.1 Types",
              RFC 3641, October 2003.

   [COLLECT]  Zeilenga, K., "Collective Attributes in the Lightweight
              Directory Access Protocol (LDAP)", RFC 3671, December
              2003.

   [SUBENTRY] Zeilenga, K. and S. Legg, "Subentries in the Lightweight
              Directory Access Protocol (LDAP)", RFC 3672, December
              2003.

   [SCHEMA]   Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Additional Matching Rules", RFC 3698, February
              2004.

   [ADMIN]    Legg, S., "Lightweight Directory Access Protocol (LDAP):
              Directory Administrative Model",
              draft-legg-ldap-admin-xx.txt, a work in progress, June
              2004.



Legg                    Expires 16 December 2004               [Page 39]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   [ACA]      Legg, S., "Lightweight Directory Access Protocol (LDAP):
              Access Control Administration",
              draft-legg-ldap-acm-admin-xx.txt, a work in progress, June
              2004.

   [FILTER]   Zeilenga, K., "LDAP Absolute True and False Filters",
              draft-zeilenga-ldap-t-f-xx.txt, a work in progress,
              February 2004.

   [ASN1]     ITU-T Recommendation X.680 (07/02) | ISO/IEC 8824-1,
              Information technology - Abstract Syntax Notation One
              (ASN.1): Specification of basic notation

Informative References

   [RFC2234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", RFC 2234, November 1997.

   [GCE]      Legg, S., "Common Elements of Generic String Encoding
              Rules (GSER) Encodings", RFC 3642, October 2003.

   [X501]     ITU-T Recommendation X.501 (02/01) | ISO/IEC 9594-2:2001,
              Information technology - Open Systems Interconnection -
              The Directory: Models

   [X511]     ITU-T Recommendation X.511 (02/01) | ISO/IEC 9594-3:2001,
              Information technology - Open Systems Interconnection -
              The Directory: Abstract service definition

Author's Address

   Steven Legg
   Adacel Technologies Ltd.
   250 Bay Street
   Brighton, Victoria 3186
   AUSTRALIA

   Phone: +61 3 8530 7710
     Fax: +61 3 8530 7888
   EMail: steven.legg@adacel.com.au

Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an



Legg                    Expires 16 December 2004               [Page 40]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Changes in Draft 01

   The Internet draft draft-legg-ldap-acm-admin-00.txt has been split
   into two drafts, draft-legg-ldap-admin-00.txt and
   draft-legg-ldap-acm-admin-01.txt.  Section 8 of
   draft-legg-ldapext-component-matching-06.txt has been extracted to
   become a separate Internet draft, draft-legg-ldap-gser-xx.txt.  The
   references in this document have been updated accordingly.

   The term "native LDAP encoding" has been replaced by the term
   "LDAP-specific encoding" to align with terminology anticipated to be
   used in the revision of RFC 2252.

   Changes have been made to the Search Operation Decision Points
   (Section 3.4.3):

   In 4) a), the assumed FilterMatch permission for a present match of



Legg                    Expires 16 December 2004               [Page 41]

INTERNET-DRAFT     Basic and Simplified Access Control     June 16, 2004


   the objectClass attribute has been removed. An LDAP search with a
   True filter [FILTER] is the best analogue of the DAP read operation.
   A True filter does not filter any attribute type and therefore does
   not require FilterMatch permissions to succeed.

   In 5) b) and c), there is an additional requirement for Read
   permission for at least one attribute value before an attribute type
   can be returned in a search result.  Without this change a search
   result could, in some circumstances, disclose the existence of
   particular hidden attribute values.

Changes in Draft 02

   RFC 3377 replaces RFC 2251 as the reference for LDAP.

   An IANA Considerations section has been added.

Changes in Draft 03

   The document has been reformatted in line with current practice.































Legg                    Expires 16 December 2004               [Page 42]


alt-openldap11-devel/drafts/draft-ietf-ldapext-ldap-c-api-xx.txt000064400000545516150410163300020446 0ustar00

Network Working Group                                   M. Smith, Editor
INTERNET-DRAFT                             Netscape Communications Corp.
Intended Category: Standards Track                              T. Howes
Obsoletes: RFC 1823                                      Loudcloud, Inc.
Expires: May 2001                                              A. Herron
                                                         Microsoft Corp.
                                                                 M. Wahl
                                                  Sun Microsystems, Inc.
                                                              A. Anantha
                                                         Microsoft Corp.


                                                        17 November 2000

                The C LDAP Application Program Interface
                 <draft-ietf-ldapext-ldap-c-api-05.txt>


1.  Status of this Memo

This document is an Internet-Draft and is in full conformance with all
provisions of Section 10 of RFC2026.  Internet-Drafts are working docu-
ments of the Internet Engineering Task Force (IETF), its areas, and its
working groups.  Note that other groups may also distribute working
documents as Internet-Drafts.

Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time.  It is inappropriate to use Internet-Drafts as reference material
or to cite them other than as "work in progress."

The list of current Internet-Drafts can be accessed at
http://www.ietf.org/ietf/1id-abstracts.txt.

The list of Internet-Draft Shadow Directories can be accessed at
http://www.ietf.org/shadow.html.

This draft document will be submitted to the RFC Editor as a Standards
Track document. Distribution of this memo is unlimited.  Technical dis-
cussion of this document will take place on the IETF LDAP Extension
Working Group mailing list <ietf-ldapext@netscape.com>.  Please send
editorial comments directly to the authors.

Copyright (C) The Internet Society (1997-1999). All Rights Reserved.

Please see the Copyright section near the end of this document for more
information.




Expires: May 2001                                               [Page 1]

C LDAP API        C LDAP Application Program Interface  17 November 2000


2.  Introduction

This document defines a C language application program interface (API)
to the Lightweight Directory Access Protocol (LDAP). This document
replaces the previous definition of this API, defined in RFC 1823,
updating it to include support for features found in version 3 of the
LDAP protocol.  New extended operation functions were added to support
LDAPv3 features such as controls.  In addition, other LDAP API changes
were made to support information hiding and thread safety.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
document are to be interpreted as described in RFC 2119[1].

The C LDAP API is designed to be powerful, yet simple to use. It defines
compatible synchronous and asynchronous interfaces to LDAP to suit a
wide variety of applications. This document gives a brief overview of
the LDAP model, then an overview of how the API is used by an applica-
tion program to obtain LDAP information.  The API calls are described in
detail, followed by appendices that provide example code demonstrating
use of the API, the namespace consumed by the API, a summary of require-
ments for API extensions, known incompatibilities with RFC 1823, and a
list of changes made since the last revision of this document.


3.  Table of Contents

1.     Status of this Memo............................................1
2.     Introduction...................................................2
3.     Table of Contents..............................................2
4.     Overview of the LDAP Model.....................................4
5.     Overview of LDAP API Use and General Requirements..............4
6.     Header Requirements............................................6
7.     Common Data Structures and Types...............................7
8.     Memory Handling Overview.......................................9
9.     Retrieving Information About the API Implementation............9
9.1.      Retrieving Information at Compile Time......................10
9.2.      Retrieving Information During Execution.....................11
10.    Result Codes...................................................14
11.    Performing LDAP Operations.....................................16
11.1.     Initializing an LDAP Session................................16
11.2.     LDAP Session Handle Options.................................17
11.3.     Working With Controls.......................................23
11.3.1.      A Client Control That Governs Referral Processing........24
11.4.     Authenticating to the directory.............................25
11.5.     Closing the session.........................................27
11.6.     Searching...................................................28
11.7.     Reading an Entry............................................32



Expires: May 2001                                               [Page 2]

C LDAP API        C LDAP Application Program Interface  17 November 2000



11.8.     Listing the Children of an Entry............................32
11.9.     Comparing a Value Against an Entry..........................33
11.10.    Modifying an entry..........................................35
11.11.    Modifying the Name of an Entry..............................37
11.12.    Adding an entry.............................................39
11.13.    Deleting an entry...........................................41
11.14.    Extended Operations.........................................43
12.    Abandoning An Operation........................................44
13.    Obtaining Results and Peeking Inside LDAP Messages.............45
14.    Handling Errors and Parsing Results............................47
15.    Stepping Through a List of Results.............................51
16.    Parsing Search Results.........................................51
16.1.     Stepping Through a List of Entries or References............52
16.2.     Stepping Through the Attributes of an Entry.................53
16.3.     Retrieving the Values of an Attribute.......................54
16.4.     Retrieving the name of an entry.............................55
16.5.     Retrieving controls from an entry...........................56
16.6.     Parsing References..........................................57
17.    Encoded ASN.1 Value Manipulation...............................58
17.1.     BER Data Structures and Types...............................58
17.2.     Memory Disposal and Utility Functions.......................60
17.3.     Encoding....................................................60
17.4.     Encoding Example............................................63
17.5.     Decoding....................................................64
17.6.     Decoding Example............................................67
18.    Security Considerations........................................70
19.    Acknowledgements...............................................70
20.    Copyright......................................................70
21.    Bibliography...................................................71
22.    Authors' Addresses.............................................72
23.    Appendix A - Sample C LDAP API Code............................73
24.    Appendix B - Namespace Consumed By This Specification..........74
25.    Appendix C - Summary of Requirements for API Extensions........75
25.1.     Compatibility...............................................75
25.2.     Style.......................................................75
25.3.     Dependence on Externally Defined Types......................75
25.4.     Compile Time Information....................................76
25.5.     Runtime Information.........................................76
25.6.     Values Used for Session Handle Options......................76
26.    Appendix D - Known Incompatibilities with RFC 1823.............76
26.1.     Opaque LDAP Structure.......................................76
26.2.     Additional Result Codes.....................................77
26.3.     Freeing of String Data with ldap_memfree()..................77
26.4.     Changes to ldap_result()....................................77
26.5.     Changes to ldap_first_attribute() and ldap_next_attribute...77
26.6.     Changes to ldap_modrdn() and ldap_modrdn_s() Functions......78
26.7.     Changes to the berval structure.............................78
26.8.     API Specification Clarified.................................78


Expires: May 2001                                               [Page 3]

C LDAP API        C LDAP Application Program Interface  17 November 2000


26.9.     Deprecated Functions........................................78
27.    Appendix E - Data Types and Legacy Implementations.............79
28.    Appendix F - Changes Made Since Last Document Revision.........80
28.1.     API Changes.................................................80
28.2.     Editorial Changes and Clarifications........................81


4.  Overview of the LDAP Model

LDAP is the lightweight directory access protocol, described in [2] and
[3]. It can provide a lightweight frontend to the X.500 directory [4],
or a stand-alone service. In either mode, LDAP is based on a client-
server model in which a client makes a TCP connection to an LDAP server,
over which it sends requests and receives responses.

The LDAP information model is based on the entry, which contains infor-
mation about some object (e.g., a person).  Entries are composed of
attributes, which have a type and one or more values. Each attribute has
a syntax that determines what kinds of values are allowed in the attri-
bute (e.g., ASCII characters, a jpeg photograph, etc.) and how those
values behave during directory operations (e.g., is case significant
during comparisons).

Entries may be organized in a tree structure, usually based on politi-
cal, geographical, and organizational boundaries. Each entry is uniquely
named relative to its sibling entries by its relative distinguished name
(RDN) consisting of one or more distinguished attribute values from the
entry.  At most one value from each attribute may be used in the RDN.
For example, the entry for the person Babs Jensen might be named with
the "Barbara Jensen" value from the commonName attribute.

A globally unique name for an entry, called a distinguished name or DN,
is constructed by concatenating the sequence of RDNs from the entry up
to the root of the tree. For example, if Babs worked for the University
of Michigan, the DN of her U-M entry might be "cn=Barbara Jensen,
o=University of Michigan, c=US". The DN format used by LDAP is defined
in [5].

Operations are provided to authenticate, search for and retrieve infor-
mation, modify information, and add and delete entries from the tree.
The next sections give an overview of how the API is used and detailed
descriptions of the LDAP API calls that implement all of these func-
tions.


5.  Overview of LDAP API Use and General Requirements

An application generally uses the C LDAP API in four simple steps.



Expires: May 2001                                               [Page 4]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   1.   Initialize an LDAP session with a primary LDAP server. The
        ldap_init() function returns a handle to the session, allowing
        multiple connections to be open at once.

   2.   Authenticate to the LDAP server. The ldap_sasl_bind() function
        and friends support a variety of authentication methods.

   3.   Perform some LDAP operations and obtain some results.
        ldap_search() and friends return results which can be parsed by
        ldap_parse_result(), ldap_first_entry(), ldap_next_entry(), etc.

   4.   Close the session. The ldap_unbind() function closes the connec-
        tion.

Operations can be performed either synchronously or asynchronously.  The
names of the synchronous functions end in _s. For example, a synchronous
search can be completed by calling ldap_search_s(). An asynchronous
search can be initiated by calling ldap_search(). All synchronous rou-
tines return an indication of the outcome of the operation (e.g, the
constant LDAP_SUCCESS or some other result code).  The asynchronous rou-
tines make available to the caller the message id of the operation ini-
tiated. This id can be used in subsequent calls to ldap_result() to
obtain the result(s) of the operation. An asynchronous operation can be
abandoned by calling ldap_abandon() or ldap_abandon_ext().  Note that
there is no requirement that an LDAP API implementation not block when
handling asynchronous API functions; the term "asynchronous" as used in
this document refers to the fact that the sending of LDAP requests can
be separated from the receiving of LDAP responses.

Results and errors are returned in an opaque structure called LDAPMes-
sage.  Routines are provided to parse this structure, step through
entries and attributes returned, etc. Routines are also provided to
interpret errors. Later sections of this document describe these rou-
tines in more detail.

LDAP version 3 servers can return referrals and references to other
servers.  By default, implementations of this API will attempt to follow
referrals automatically for the application.  This behavior can be dis-
abled globally (using the ldap_set_option() call) or on a per-request
basis through the use of a client control.

All DN and string attribute values passed into or produced by this C
LDAP API are represented using the character set of the underlying LDAP
protocol version in use.  When this API is used with LDAPv3, DN and
string values are represented as UTF-8[6] characters.  When this API is
used with LDAPv2, the US-ASCII[7] or T.61[7] character set are used.
Future documents MAY specify additional APIs supporting other character
sets.



Expires: May 2001                                               [Page 5]

C LDAP API        C LDAP Application Program Interface  17 November 2000


For compatibility with existing applications, implementations of this
API will by default use version 2 of the LDAP protocol.  Applications
that intend to take advantage of LDAP version 3 features will need to
use the ldap_set_option() call with a LDAP_OPT_PROTOCOL_VERSION to
switch to version 3.

Unless otherwise indicated, conformant implementations of this specifi-
cation MUST implement all of the C LDAP API functions as described in
this document, and they MUST use the function prototypes, macro defini-
tions, and types defined in this document.

Note that this API is designed for use in environments where the 'int'
type is at least 32 bits in size.


6.  Header Requirements

To promote portability of applications, the following requirements are
imposed on the headers used by applications to access the services of
this API:

Name and Inclusion
        Applications only need to include a single header named ldap.h
        to access all of the API services described in this document.
        Therefore, the following C source program MUST compile and exe-
        cute without errors:

           #include <ldap.h>

           int
           main()
           {
               return 0;
           }

        The ldap.h header MAY include other implementation-specific
        headers.

Implementations SHOULD also provide a header named lber.h to facilitate
development of applications desiring compatibility with older LDAP
implementations.  The lber.h header MAY be empty.  Old applications that
include lber.h in order to use BER facilities will need to include
ldap.h.


Idempotence
        All headers SHOULD be idempotent; that is, if they are included
        more than once the effect is as if they had only been included



Expires: May 2001                                               [Page 6]

C LDAP API        C LDAP Application Program Interface  17 November 2000


        once.

Must Be Included Before API Is Used
        An application MUST include the ldap.h header before referencing
        any of the function or type definitions described in this API
        specification.

Mutual Independence
        Headers SHOULD be mutually independent with minimal dependence
        on system or any other headers.

Use of the 'const' Keyword
        This API specification is defined in terms of ISO C[8].  It
        makes use of function prototypes and the 'const' keyword.  The
        use of 'const' in this specification is limited to simple, non-
        array function parameters to avoid forcing applications to
        declare parameters and variables that accept return values from
        LDAP API functions as 'const.'  Implementations specifically
        designed to be used with non-ISO C translators SHOULD provide
        function declarations without prototypes or function prototypes
        without specification of 'const' arguments.

Definition of 'struct timeval'
        This API specification uses the 'struct timeval' type.  Imple-
        mentations of this API MUST ensure that the struct timeval type
        is by default defined as a consequence of including the ldap.h
        header.  Because struct timeval is usually defined in one or
        more system headers, it is possible for header conflicts to
        occur if ldap.h also defines it or arranges for it to be defined
        by including another header.  Therefore, applications MAY want
        to arrange for struct timeval to be defined before they include
        ldap.h.  To support this, the ldap.h header MUST NOT itself
        define struct timeval if the preprocessor symbol
        LDAP_TYPE_TIMEVAL_DEFINED is defined before ldap.h is included.


7.  Common Data Structures and Types

Data structures and types that are common to several LDAP API functions
are defined here:

       typedef struct ldap LDAP;

       typedef struct ldapmsg LDAPMessage;

       typedef struct berelement BerElement;

       typedef <impl_len_t> ber_len_t;



Expires: May 2001                                               [Page 7]

C LDAP API        C LDAP Application Program Interface  17 November 2000


       typedef struct berval {
           ber_len_t       bv_len;
           char            *bv_val;
       } BerValue;

       struct timeval {
           <impl_sec_t>    tv_sec;
           <impl_usec_t>   tv_usec;
       };

The LDAP structure is an opaque data type that represents an LDAP ses-
sion Typically this corresponds to a connection to a single server, but
it MAY encompass several server connections in the face of LDAPv3 refer-
rals.

The LDAPMessage structure is an opaque data type that is used to return
entry, reference, result, and error information.  An LDAPMessage struc-
ture can represent the beginning of a list, or chain of messages that
consists of a series of entries, references, and result messages as
returned by LDAP operations such as search.  LDAP API functions such as
ldap_parse_result() that operate on message chains that can contain more
than one result message always operate on the first result message in
the chain.  See the "Obtaining Results and Peeking Inside LDAP Messages"
section of this document for more information.

The BerElement structure is an opaque data type that is used to hold
data and state information about encoded data.  It is described in more
detail in the section "Encoded ASN.1 Value Manipulation" later in this
document.

The `ber_len_t' type is an unsigned integral data type that is large
enough to contain the length of the largest piece of data supported by
the API implementation.  The `<impl_len_t>' in the `ber_len_t' typedef
MUST be replaced with an appropriate type.  The width (number of signi-
ficant bits) of `ber_len_t' MUST be at least 32 and no larger than that
of `unsigned long'.  See the appendix "Data Types and Legacy Implementa-
tions" for additional considerations.

The BerValue structure is used to represent arbitrary binary data and
its fields have the following meanings:

bv_len   Length of data in bytes.

bv_val   A pointer to the data itself.


The timeval structure is used to represent an interval of time and its
fields have the following meanings:



Expires: May 2001                                               [Page 8]

C LDAP API        C LDAP Application Program Interface  17 November 2000


tv_sec   Seconds component of time interval.

tv_usec  Microseconds component of time interval.

Note that because the struct timeval definition typically is derived
from a system header, the types used for the tv_sec and tv_usec com-
ponents are implementation-specific integral types.  Therefore,
`<impl_sec_t>' and `<impl_usec_t>' in the struct timeval definition MUST
be replaced with appropriate types.  See the earlier section "Header
Requirements" for more information on struct timeval.


8.  Memory Handling Overview

All memory that is allocated by a function in this C LDAP API and
returned to the caller SHOULD be disposed of by calling the appropriate
"free" function provided by this API.  The correct "free" function to
call is documented in each section of this document where a function
that allocates memory is described.

Memory that is allocated through means outside of the C LDAP API MUST
NOT be disposed of using a function provided by this API.

If a pointer value passed to one of the C LDAP API "free" functions is
NULL, graceful failure (i.e, ignoring of the NULL pointer) MUST occur.

The complete list of "free" functions that are used to dispose of allo-
cated memory is:

   ber_bvecfree()
   ber_bvfree()
   ber_free()
   ldap_control_free()
   ldap_controls_free()
   ldap_memfree()
   ldap_msgfree()
   ldap_value_free()
   ldap_value_free_len()


9.  Retrieving Information About the API Implementation

Applications developed to this specification need to be able to deter-
mine information about the particular API implementation they are using
both at compile time and during execution.






Expires: May 2001                                               [Page 9]

C LDAP API        C LDAP Application Program Interface  17 November 2000


9.1.  Retrieving Information at Compile Time

All conformant implementations MUST include the following five defini-
tions in a header so compile time tests can be done by LDAP software
developers:

   #define LDAP_API_VERSION     level
   #define LDAP_VERSION_MIN     min-version
   #define LDAP_VERSION_MAX     max-version
   #define LDAP_VENDOR_NAME     "vend-name"
   #define LDAP_VENDOR_VERSION  vend-version

where:

     "level" is replaced with the RFC number given to this C LDAP API
     specification when it is published as a standards track RFC.

     min-version is replaced with the lowest LDAP protocol version sup-
     ported by the implementation.

     max-version is replaced with the highest LDAP protocol version sup-
     ported by the implementation.  This SHOULD be 3.

     "vend-name" is replaced with a text string that identifies the
     party that supplies the API implementation.

     "vend-version" is a supplier-specific version number multiplied
     times 100.

Note that the LDAP_VENDOR_NAME macro SHOULD be defined as "" if no ven-
dor name is available and the LDAP_VENDOR_VERSION macro SHOULD be
defined as 0 if no vendor-specific version information is available.

For example, if this specification is published as RFC 88888, Netscape
Communication's version 4.0 implementation that supports LDAPv2 and v3
might include macro definitions like these:

   #define LDAP_API_VERSION     88888      /* RFC 88888 compliant */
   #define LDAP_VERSION_MIN     2
   #define LDAP_VERSION_MAX     3
   #define LDAP_VENDOR_NAME     "Netscape Communications Corp."
   #define LDAP_VENDOR_VERSION  400        /* version 4.0 */

and application code can test the C LDAP API version level using a
construct such as this one:

   #if (LDAP_API_VERSION >= 88888)
           /* use features supported in RFC 88888 or later */



Expires: May 2001                                              [Page 10]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   #endif

Until such time as this document is published as an RFC, implementations
SHOULD use the value 2000 plus the revision number of this draft for
LDAP_API_VERSION.  For example, the correct value for LDAP_API_VERSION
for revision 05 of this draft is 2005.

Documents that extend this specification SHOULD define a macro of the
form:

   #define LDAP_API_FEATURE_x level

where "x" is replaced with a name (textual identifier) for the feature
and "level" is replaced with the number of the RFC that specifies the
API extension.  The name SHOULD NOT begin with the string "X_".

For example, if C LDAP API extensions for Transport Layer Security [9]
were published in RFC 99999, that RFC might require conformant implemen-
tations to define a macro like this:

   #define LDAP_API_FEATURE_TLS 99999


Private or experimental API extensions SHOULD be indicated by defining a
macro of this same form where "x" (the extension's name) begins with the
string "X_" and "level" is replaced with a integer number that is
specific to the extension.

It is RECOMMENDED that private or experimental API extensions use only
the following prefixes for macros, types, and function names:
       LDAP_X_
       LBER_X_
       ldap_x_
       ber_x_
and that these prefixes not be used by standard extensions.


9.2.  Retrieving Information During Execution

The ldap_get_option() call (described in greater detail later in this
document) can be used during execution in conjunction with an option
parameter value of LDAP_OPT_API_INFO (0x00) to retrieve some basic
information about the API and about the specific implementation being
used.  The ld parameter to ldap_get_option() can be either NULL or a
valid LDAP session handle which was obtained by calling ldap_init().
The optdata parameter to ldap_get_option() SHOULD be the address of an
LDAPAPIInfo structure which is defined as follows:




Expires: May 2001                                              [Page 11]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   typedef struct ldapapiinfo {
       int  ldapai_info_version;     /* version of this struct (1) */
       int  ldapai_api_version;      /* revision of API supported */
       int  ldapai_protocol_version; /* highest LDAP version supported */
       char **ldapai_extensions;     /* names of API extensions */
       char *ldapai_vendor_name;     /* name of supplier */
       int  ldapai_vendor_version;   /* supplier-specific version times 100 */
   } LDAPAPIInfo;

In addition, API implementations MUST include the following macro defin-
ition:

   #define LDAP_API_INFO_VERSION    1

Note that the ldapai_info_version field of the LDAPAPIInfo structure
SHOULD be set to the value LDAP_API_INFO_VERSION (1) before calling
ldap_get_option() so that it can be checked for consistency.  All other
fields are set by the ldap_get_option() function.

The members of the LDAPAPIInfo structure are:

ldapai_info_version
          A number that identifies the version of the LDAPAPIInfo struc-
          ture.  This SHOULD be set to the value LDAP_API_INFO_VERSION
          (1) before calling ldap_get_option().  If the value received
          is not recognized by the API implementation, the
          ldap_get_option() function sets ldapai_info_version to a valid
          value that would be recognized, sets the ldapai_api_version to
          the correct value, and returns an error without filling in any
          of the other fields in the LDAPAPIInfo structure.

ldapai_api_version
          A number that matches that assigned to the C LDAP API RFC sup-
          ported by the API implementation.  This SHOULD match the value
          of the LDAP_API_VERSION macro defined earlier.

ldapai_protocol_version
          The highest LDAP protocol version supported by the implementa-
          tion.  For example, if LDAPv3 is the highest version supported
          then this field will be set to 3.

ldapai_vendor_name
          A zero-terminated string that contains the name of the party
          that produced the LDAP API implementation.  This field may be
          set to NULL if no name is available.  If non-NULL, the caller
          is responsible for disposing of the memory occupied by passing
          this pointer to ldap_memfree() which is described later in
          this document.  This value SHOULD match the value of the



Expires: May 2001                                              [Page 12]

C LDAP API        C LDAP Application Program Interface  17 November 2000


          LDAP_VENDOR_NAME macro described earlier in this document.

ldapai_vendor_version
          An implementation-specific version number multiplied by 100.
          For example, if the implementation version is 4.0 then this
          field will be set to 400.  If no version information is avail-
          able, this field will be set to 0.  This value SHOULD match
          the value of the LDAP_VENDOR_VERSION macro described earlier
          in this document.

ldapai_extensions
          A NULL-terminated array of character strings that lists the
          names of the API extensions supported by the LDAP API imple-
          mentation.  These names will typically match the textual iden-
          tifiers that appear in the "x" portion of the
          LDAP_API_FEATURE_x macros described above, although the pre-
          cise value MUST be defined by documents that specify C LDAP
          API extensions.  If no API extensions are supported, this
          field will be set to NULL.  The caller is responsible for
          disposing of the memory occupied by this array by passing it
          to ldap_value_free() which is described later in this docu-
          ment.  To retrieve more information about a particular exten-
          sion, the ldap_get_option() call can be used with an option
          parameter value of LDAP_OPT_API_FEATURE_INFO (0x15).  The opt-
          data parameter to the ldap_get_option() SHOULD be the address
          of an LDAPAPIFeatureInfo structure which is defined as fol-
          lows:

             typedef struct ldap_apifeature_info {
                 int   ldapaif_info_version; /* version of this struct (1) */
                 char  *ldapaif_name;        /* name of supported feature */
                 int   ldapaif_version;      /* revision of supported feature */
             } LDAPAPIFeatureInfo;

          In addition, API implementations MUST include the following
          macro definition:

             #define LDAP_FEATURE_INFO_VERSION    1

          Note that the ldapaif_info_version field of the LDAPAPI-
          FeatureInfo structure SHOULD be set to the value
          LDAP_FEATURE_INFO_VERSION (1) and the ldapaif_name field
          SHOULD be set to the extension name string as described below
          before ldap_get_option() is called.  The call will fill in the
          ldapaif_version field of the LDAPAPIFeatureInfo structure.

   The members of the LDAPAPIFeatureInfo structure are:




Expires: May 2001                                              [Page 13]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   ldapaif_info_version
             A number that identifies the version of the LDAPAPI-
             FeatureInfo structure.  This SHOULD be set to the value
             LDAP_FEATURE_INFO_VERSION (1) before calling
             ldap_get_option().  If the value received is not recognized
             by the API implementation, the ldap_get_option() function
             sets ldapaif_info_version to a valid value that would be
             recognized and returns an error without filling in the
             ldapaif_version field in the LDAPAPIFeatureInfo structure.

   ldapaif_name
             The name of an extension, as returned in the
             ldapai_extensions array of the LDAPAPIInfo structure and as
             specified in the document that describes the extension.

   ldapaif_version
             This field will be set as a result of calling
             ldap_get_option().  It is a number that matches that
             assigned to the C LDAP API extension RFC supported for this
             extension.  For private or experimental API extensions, the
             value is extension-specific.  In either case, the value of
             ldapaxi_ext_version SHOULD be identical to the value of the
             LDAP_API_FEATURE_x macro defined for the extension
             (described above).


10.  Result Codes

Many of the LDAP API routines return result codes, some of which indi-
cate local API errors and some of which are LDAP resultCodes that are
returned by servers.  All of the result codes are non-negative integers.
Supported result codes are as follows (hexadecimal values are given in
parentheses after the constant):

           LDAP_SUCCESS (0x00)
           LDAP_OPERATIONS_ERROR (0x01)
           LDAP_PROTOCOL_ERROR (0x02)
           LDAP_TIMELIMIT_EXCEEDED (0x03)
           LDAP_SIZELIMIT_EXCEEDED (0x04)
           LDAP_COMPARE_FALSE (0x05)
           LDAP_COMPARE_TRUE (0x06)
           LDAP_STRONG_AUTH_NOT_SUPPORTED (0x07)
           LDAP_STRONG_AUTH_REQUIRED (0x08)
           LDAP_REFERRAL (0x0a)                            -- new in LDAPv3
           LDAP_ADMINLIMIT_EXCEEDED (0x0b)                 -- new in LDAPv3
           LDAP_UNAVAILABLE_CRITICAL_EXTENSION (0x0c)      -- new in LDAPv3
           LDAP_CONFIDENTIALITY_REQUIRED (0x0d)            -- new in LDAPv3
           LDAP_SASL_BIND_IN_PROGRESS (0x0e)               -- new in LDAPv3



Expires: May 2001                                              [Page 14]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           LDAP_NO_SUCH_ATTRIBUTE (0x10)
           LDAP_UNDEFINED_TYPE (0x11)
           LDAP_INAPPROPRIATE_MATCHING (0x12)
           LDAP_CONSTRAINT_VIOLATION (0x13)
           LDAP_TYPE_OR_VALUE_EXISTS (0x14)
           LDAP_INVALID_SYNTAX (0x15)
           LDAP_NO_SUCH_OBJECT (0x20)
           LDAP_ALIAS_PROBLEM (0x21)
           LDAP_INVALID_DN_SYNTAX (0x22)
           LDAP_IS_LEAF (0x23)                             -- not used in LDAPv3
           LDAP_ALIAS_DEREF_PROBLEM (0x24)
           LDAP_INAPPROPRIATE_AUTH (0x30)
           LDAP_INVALID_CREDENTIALS (0x31)
           LDAP_INSUFFICIENT_ACCESS (0x32)
           LDAP_BUSY (0x33)
           LDAP_UNAVAILABLE (0x34)
           LDAP_UNWILLING_TO_PERFORM (0x35)
           LDAP_LOOP_DETECT (0x36)
           LDAP_NAMING_VIOLATION (0x40)
           LDAP_OBJECT_CLASS_VIOLATION (0x41)
           LDAP_NOT_ALLOWED_ON_NONLEAF (0x42)
           LDAP_NOT_ALLOWED_ON_RDN (0x43)
           LDAP_ALREADY_EXISTS (0x44)
           LDAP_NO_OBJECT_CLASS_MODS (0x45)
           LDAP_RESULTS_TOO_LARGE (0x46)                   -- reserved for CLDAP
           LDAP_AFFECTS_MULTIPLE_DSAS (0x47)               -- new in LDAPv3
           LDAP_OTHER (0x50)
           LDAP_SERVER_DOWN (0x51)
           LDAP_LOCAL_ERROR (0x52)
           LDAP_ENCODING_ERROR (0x53)
           LDAP_DECODING_ERROR (0x54)
           LDAP_TIMEOUT (0x55)
           LDAP_AUTH_UNKNOWN (0x56)
           LDAP_FILTER_ERROR (0x57)
           LDAP_USER_CANCELLED (0x58)
           LDAP_PARAM_ERROR (0x59)
           LDAP_NO_MEMORY (0x5a)
           LDAP_CONNECT_ERROR (0x5b)
           LDAP_NOT_SUPPORTED (0x5c)
           LDAP_CONTROL_NOT_FOUND (0x5d)
           LDAP_NO_RESULTS_RETURNED (0x5e)
           LDAP_MORE_RESULTS_TO_RETURN (0x5f)
           LDAP_CLIENT_LOOP (0x60)
           LDAP_REFERRAL_LIMIT_EXCEEDED (0x61)







Expires: May 2001                                              [Page 15]

C LDAP API        C LDAP Application Program Interface  17 November 2000


11.  Performing LDAP Operations

This section describes each LDAP operation API call in detail. Most
functions take a "session handle," a pointer to an LDAP structure con-
taining per-connection information.  Many routines return results in an
LDAPMessage structure. These structures and others are described as
needed below.


11.1.  Initializing an LDAP Session

ldap_init() initializes a session with an LDAP server. The server is not
actually contacted until an operation is performed that requires it,
allowing various options to be set after initialization.

           LDAP *ldap_init(
                   const char      *hostname,
                   int             portno
           );

Use of the following routine is deprecated:

           LDAP *ldap_open(
                   const char      *hostname,
                   int             portno
           );

Unlike ldap_init(), ldap_open() attempts to make a server connection
before returning to the caller.  A more complete description can be
found in RFC 1823.

Parameters are:

hostname Contains a space-separated list of hostnames or dotted strings
         representing the IP address of hosts running an LDAP server to
         connect to. Each hostname in the list MAY include a port number
         which is separated from the host itself with a colon (:) char-
         acter.  The hosts will be tried in the order listed, stopping
         with the first one to which a successful connection is made.

   Note: A suitable representation for including a literal IPv6[10]
   address in the hostname parameter is desired, but has not yet been
   determined or implemented in practice.

portno   Contains the TCP port number to connect to. The default LDAP
         port of 389 can be obtained by supplying the value zero (0) or
         the macro LDAP_PORT (389).  If a host includes a port number
         then this parameter is ignored.



Expires: May 2001                                              [Page 16]

C LDAP API        C LDAP Application Program Interface  17 November 2000


ldap_init() and ldap_open() both return a "session handle," a pointer to
an opaque structure that MUST be passed to subsequent calls pertaining
to the session. These routines return NULL if the session cannot be ini-
tialized in which case the operating system error reporting mechanism
can be checked to see why the call failed.

Note that if you connect to an LDAPv2 server, one of the LDAP bind calls
described below SHOULD be completed before other operations can be per-
formed on the session.  LDAPv3 does not require that a bind operation be
completed before other operations can be performed.

The calling program can set various attributes of the session by calling
the routines described in the next section.


11.2.  LDAP Session Handle Options

The LDAP session handle returned by ldap_init() is a pointer to an
opaque data type representing an LDAP session. In RFC 1823 this data
type was a structure exposed to the caller, and various fields in the
structure could be set to control aspects of the session, such as size
and time limits on searches.

In the interest of insulating callers from inevitable changes to this
structure, these aspects of the session are now accessed through a pair
of accessor functions, described below.

ldap_get_option() is used to access the current value of various
session-wide parameters. ldap_set_option() is used to set the value of
these parameters.  Note that some options are READ-ONLY and cannot be
set; it is an error to call ldap_set_option() and attempt to set a
READ-ONLY option.

Note that if automatic referral following is enabled (the default), any
connections created during the course of following referrals will
inherit the options associated with the session that sent the original
request that caused the referrals to be returned.

           int ldap_get_option(
                   LDAP            *ld,
                   int             option,
                   void            *outvalue
           );

           int ldap_set_option(
                   LDAP            *ld,
                   int             option,
                   const void      *invalue



Expires: May 2001                                              [Page 17]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           );

           #define LDAP_OPT_ON     (<impl_void_star_value>)
           #define LDAP_OPT_OFF    ((void *)0)

   LDAP_OPT_ON MUST be defined as a non-null pointer to void;  that is,
   <impl_void_star_value> MUST be replaced with a non-null pointer to
   void, e.g., one could use:
           #define LDAP_OPT_ON     ((void *)1)
   if that value is safe to use on the architecture where the API is
   implemented.

Parameters are:

ld     The session handle.  If this is NULL, a set of global defaults is
       accessed.  New LDAP session handles created with ldap_init() or
       ldap_open() inherit their characteristics from these global
       defaults.

option The name of the option being accessed or set. This parameter
       SHOULD be one of the following constants, which have the indi-
       cated meanings.  After the constant the actual hexadecimal value
       of the constant is listed in parentheses.


   LDAP_OPT_API_INFO (0x00)
      Type for invalue parameter: not applicable (option is READ-ONLY)

      Type for outvalue parameter: LDAPAPIInfo *

      Description:
           Used to retrieve some basic information about the LDAP API
           implementation at execution time.  See the section "Retriev-
           ing Information About the API Implementation" above for more
           information.  This option is READ-ONLY and cannot be set.

   LDAP_OPT_DEREF (0x02)
      Type for invalue parameter: int *

      Type for outvalue parameter: int *

      Description:
           Determines how aliases are handled during search. It SHOULD
           have one of the following values: LDAP_DEREF_NEVER (0x00),
           LDAP_DEREF_SEARCHING (0x01), LDAP_DEREF_FINDING (0x02), or
           LDAP_DEREF_ALWAYS (0x03).  The LDAP_DEREF_SEARCHING value
           means aliases are dereferenced during the search but not when
           locating the base object of the search. The



Expires: May 2001                                              [Page 18]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           LDAP_DEREF_FINDING value means aliases are dereferenced when
           locating the base object but not during the search.  The
           default value for this option is LDAP_DEREF_NEVER.

   LDAP_OPT_SIZELIMIT (0x03)
      Type for invalue parameter: int *

      Type for outvalue parameter: int *

      Description:
           A limit on the number of entries to return from a search. A
           value of LDAP_NO_LIMIT (0) means no limit.  The default value
           for this option is LDAP_NO_LIMIT.

   LDAP_OPT_TIMELIMIT (0x04)
      Type for invalue parameter: int *

      Type for outvalue parameter: int *

      Description:
           A limit on the number of seconds to spend on a search. A
           value of LDAP_NO_LIMIT (0) means no limit.  The default value
           for this option is LDAP_NO_LIMIT.  This value is passed to
           the server in the search request only; it does not affect how
           long the C LDAP API implementation itself will wait locally
           for search results.  Note that the timeout parameter passed
           to the ldap_search_ext_s() or ldap_result() functions can be
           used to specify a limit on how long the API implementation
           will wait for results.

   LDAP_OPT_REFERRALS (0x08)
      Type for invalue parameter: void * (LDAP_OPT_ON or LDAP_OPT_OFF)

      Type for outvalue parameter: int *

      Description:
           Determines whether the LDAP library automatically follows
           referrals returned by LDAP servers or not. It MAY be set to
           one of the constants LDAP_OPT_ON or LDAP_OPT_OFF; any non-
           NULL pointer value passed to ldap_set_option() enables this
           option.  When reading the current setting using
           ldap_get_option(), a zero value means OFF and any non-zero
           value means ON.  By default, this option is ON.

   LDAP_OPT_RESTART (0x09)
      Type for invalue parameter: void * (LDAP_OPT_ON or LDAP_OPT_OFF)

      Type for outvalue parameter: int *



Expires: May 2001                                              [Page 19]

C LDAP API        C LDAP Application Program Interface  17 November 2000


      Description:
           Determines whether LDAP I/O operations are automatically res-
           tarted if they abort prematurely. It MAY be set to one of the
           constants LDAP_OPT_ON or LDAP_OPT_OFF; any non-NULL pointer
           value passed to ldap_set_option() enables this option.  When
           reading the current setting using ldap_get_option(), a zero
           value means OFF and any non-zero value means ON. This option
           is useful if an LDAP I/O operation can be interrupted prema-
           turely, for example by a timer going off, or other interrupt.
           By default, this option is OFF.

   LDAP_OPT_PROTOCOL_VERSION (0x11)
      Type for invalue parameter: int *

      Type for outvalue parameter: int *

      Description:
           This option indicates the version of the LDAP protocol used
           when communicating with the primary LDAP server. It SHOULD be
           one of the constants LDAP_VERSION2 (2) or LDAP_VERSION3 (3).
           If no version is set the default is LDAP_VERSION2 (2).

   LDAP_OPT_SERVER_CONTROLS (0x12)
      Type for invalue parameter: LDAPControl **

      Type for outvalue parameter: LDAPControl ***

      Description:
           A default list of LDAP server controls to be sent with each
           request.  See the Working With Controls section below.

   LDAP_OPT_CLIENT_CONTROLS (0x13)
      Type for invalue parameter: LDAPControl **

      Type for outvalue parameter: LDAPControl ***

      Description:
           A default list of client controls that affect the LDAP ses-
           sion.  See the Working With Controls section below.

   LDAP_OPT_API_FEATURE_INFO (0x15)
      Type for invalue parameter: not applicable (option is READ-ONLY)

      Type for outvalue parameter: LDAPAPIFeatureInfo *

      Description:
           Used to retrieve version information about LDAP API extended
           features at execution time.  See the section "Retrieving



Expires: May 2001                                              [Page 20]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           Information About the API Implementation" above for more
           information.  This option is READ-ONLY and cannot be set.

   LDAP_OPT_HOST_NAME (0x30)
      Type for invalue parameter: char *

      Type for outvalue parameter: char **

      Description:
           The host name (or list of hosts) for the primary LDAP server.
           See the definition of the hostname parameter to ldap_init()
           for the allowed syntax.  Note that if the portno parameter
           passed to ldap_init() is a value other than 0 or 389
           (LDAP_PORT), this value SHOULD include a string like
           ":portno" after each hostname or IP address that did not have
           one in the original hostname parameter that was passed to
           ldap_init().  For example, if this hostname value was passed
           to ldap_init():

               "ldap.example.com:389 ldap2.example.com"

           and the portno parameter passed to ldap_init() was 6389, then
           the value returned for the LDAP_OPT_HOST_NAME option SHOULD
           be:

               "ldap.example.com:389 ldap2.example.com:6389"


   LDAP_OPT_RESULT_CODE (0x31)
      Type for invalue parameter: int *

      Type for outvalue parameter: int *

      Description:
           The most recent local (API generated) or server returned LDAP
           result code that occurred for this session.

   LDAP_OPT_ERROR_STRING (0x32)
      Type for invalue parameter: char *

      Type for outvalue parameter: char **

      Description:
           The message returned with the most recent LDAP error that
           occurred for this session.

   LDAP_OPT_MATCHED_DN (0x33)
      Type for invalue parameter: char *



Expires: May 2001                                              [Page 21]

C LDAP API        C LDAP Application Program Interface  17 November 2000


      Type for outvalue parameter: char **

      Description:
           The matched DN value returned with the most recent LDAP error
           that occurred for this session.


outvalue The address of a place to put the value of the option. The
         actual type of this parameter depends on the setting of the
         option parameter.  For outvalues of type char ** and LDAPCon-
         trol **, a copy of the data that is associated with the LDAP
         session ld is returned; callers should dispose of the memory by
         calling ldap_memfree() or ldap_controls_free(), depending on
         the type of data returned.

invalue  A pointer to the value the option is to be given. The actual
         type of this parameter depends on the setting of the option
         parameter. The data associated with invalue is copied by the
         API implementation to allow callers of the API to dispose of or
         otherwise change their copy of the data after a successful call
         to ldap_set_option().  If a value passed for invalue is invalid
         or cannot be accepted by the implementation, ldap_set_option()
         should return -1 to indicate an error.

Both ldap_get_option() and ldap_set_option() return 0 if successful and
-1 if an error occurs.  If -1 is returned by either function, a specific
result code MAY be retrieved by calling ldap_get_option() with an option
value of LDAP_OPT_RESULT_CODE.  Note that there is no way to retrieve a
more specific result code if a call to ldap_get_option() with an option
value of LDAP_OPT_RESULT_CODE fails.

When a call to ldap_get_option() succeeds, the API implementation MUST
NOT change the state of the LDAP session handle or the state of the
underlying implementation in a way that affects the behavior of future
LDAP API calls.  When a call to ldap_get_option() fails, the only ses-
sion handle change permitted is setting the LDAP result code (as
returned by the LDAP_OPT_RESULT_CODE option).

When a call to ldap_set_option() fails, it MUST NOT change the state of
the LDAP session handle or the state of the underlying implementation in
a way that affects the behavior of future LDAP API calls.

Standards track documents that extend this specification and specify new
options SHOULD use values for option macros that are between 0x1000 and
0x3FFF inclusive.  Private and experimental extensions SHOULD use values
for the option macros that are between 0x4000 and 0x7FFF inclusive.  All
values below 0x1000 and above 0x7FFF that are not defined in this docu-
ment are reserved and SHOULD NOT be used.  The following macro MUST be



Expires: May 2001                                              [Page 22]

C LDAP API        C LDAP Application Program Interface  17 November 2000


defined by C LDAP API implementations to aid extension implementors:
   #define LDAP_OPT_PRIVATE_EXTENSION_BASE 0x4000  /* to 0x7FFF inclusive */



11.3.  Working With Controls

LDAPv3 operations can be extended through the use of controls.  Controls
can be sent to a server or returned to the client with any LDAP message.
These controls are referred to as server controls.

The LDAP API also supports a client-side extension mechanism through the
use of client controls. These controls affect the behavior of the LDAP
API only and are never sent to a server.  A common data structure is
used to represent both types of controls:

           typedef struct ldapcontrol {
                   char            *ldctl_oid;
                   struct berval   ldctl_value;
                   char            ldctl_iscritical;
           } LDAPControl;

The fields in the ldapcontrol structure have the following meanings:

ldctl_oid        The control type, represented as a string.

ldctl_value      The data associated with the control (if any).  To
                 specify a zero-length value, set ldctl_value.bv_len to
                 zero and ldctl_value.bv_val to a zero-length string.
                 To indicate that no data is associated with the con-
                 trol, set ldctl_value.bv_val to NULL.

ldctl_iscritical Indicates whether the control is critical of not. If
                 this field is non-zero, the operation will only be car-
                 ried out if the control is recognized by the server
                 and/or client.  Note that the LDAP unbind and abandon
                 operations have no server response, so clients SHOULD
                 NOT mark server controls critical when used with these
                 two operations.

Some LDAP API calls allocate an ldapcontrol structure or a NULL-
terminated array of ldapcontrol structures.  The following routines can
be used to dispose of a single control or an array of controls:

           void ldap_control_free( LDAPControl *ctrl );
           void ldap_controls_free( LDAPControl **ctrls );
If the ctrl or ctrls parameter is NULL, these calls do nothing.




Expires: May 2001                                              [Page 23]

C LDAP API        C LDAP Application Program Interface  17 November 2000


A set of controls that affect the entire session can be set using the
ldap_set_option() function (see above).  A list of controls can also be
passed directly to some LDAP API calls such as ldap_search_ext(), in
which case any controls set for the session through the use of
ldap_set_option() are ignored. Control lists are represented as a NULL-
terminated array of pointers to ldapcontrol structures.

Server controls are defined by LDAPv3 protocol extension documents; for
example, a control has been proposed to support server-side sorting of
search results [11].

One client control is defined in this document (described in the follow-
ing section).  Other client controls MAY be defined in future revisions
of this document or in documents that extend this API.


11.3.1.  A Client Control That Governs Referral Processing

As described previously in the section "LDAP Session Handle Options,"
applications can enable and disable automatic chasing of referrals on a
session-wide basic by using the ldap_set_option() function with the
LDAP_OPT_REFERRALS option.  It is also useful to govern automatic refer-
ral chasing on per-request basis.  A client control with an OID of
1.2.840.113556.1.4.616 exists to provide this functionality.

   /* OID for referrals client control */
   #define LDAP_CONTROL_REFERRALS              "1.2.840.113556.1.4.616"

   /* Flags for referrals client control value */
   #define LDAP_CHASE_SUBORDINATE_REFERRALS    0x00000020U
   #define LDAP_CHASE_EXTERNAL_REFERRALS       0x00000040U

To create a referrals client control, the ldctl_oid field of an LDAPCon-
trol structure MUST be set to LDAP_CONTROL_REFERRALS
("1.2.840.113556.1.4.616") and the ldctl_value field MUST be set to a
value that contains a set of flags.  The ldctl_value.bv_len field MUST
be set to sizeof(ber_uint_t), and the ldctl_value.bv_val field MUST
point to a ber_uint_t which contains the flags value." The ber_uint_t
type is define in the section "BER Data Structures and Types" below.

The flags value can be set to zero to disable automatic chasing of
referrals and LDAPv3 references altogether.  Alternatively, the flags
value can be set to the value LDAP_CHASE_SUBORDINATE_REFERRALS
(0x00000020U) to indicate that only LDAPv3 search continuation refer-
ences are to be automatically chased by the API implementation, to the
value LDAP_CHASE_EXTERNAL_REFERRALS (0x00000040U) to indicate that only
LDAPv3 referrals are to be automatically chased, or the logical OR of
the two flag values (0x00000060U) to indicate that both referrals and



Expires: May 2001                                              [Page 24]

C LDAP API        C LDAP Application Program Interface  17 November 2000


references are to be automatically chased.


11.4.  Authenticating to the directory

The following functions are used to authenticate an LDAP client to an
LDAP directory server.

The ldap_sasl_bind() and ldap_sasl_bind_s() functions can be used to do
general and extensible authentication over LDAP through the use of the
Simple Authentication Security Layer [12].  The routines both take the
dn to bind as, the method to use, as a dotted-string representation of
an OID identifying the method, and a struct berval holding the creden-
tials. The special constant value LDAP_SASL_SIMPLE (NULL) can be passed
to request simple authentication, or the simplified routines
ldap_simple_bind() or ldap_simple_bind_s() can be used.

           int ldap_sasl_bind(
                   LDAP                    *ld,
                   const char              *dn,
                   const char              *mechanism,
                   const struct berval     *cred,
                   LDAPControl             **serverctrls,
                   LDAPControl             **clientctrls,
                   int                     *msgidp
           );

           int ldap_sasl_bind_s(
                   LDAP                    *ld,
                   const char              *dn,
                   const char              *mechanism,
                   const struct berval     *cred,
                   LDAPControl             **serverctrls,
                   LDAPControl             **clientctrls,
                   struct berval           **servercredp
           );

           int ldap_simple_bind(
                   LDAP                    *ld,
                   const char              *dn,
                   const char              *passwd
           );

           int ldap_simple_bind_s(
                   LDAP                    *ld,
                   const char              *dn,
                   const char              *passwd
           );



Expires: May 2001                                              [Page 25]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   The use of the following routines is deprecated and more complete
   descriptions can be found in RFC 1823:

           int ldap_bind( LDAP *ld, const char *dn, const char *cred,
                   int method );

           int ldap_bind_s( LDAP *ld, const char *dn, const char *cred,
                   int method );

           int ldap_kerberos_bind( LDAP *ld, const char *dn );

           int ldap_kerberos_bind_s( LDAP *ld, const char *dn );

Parameters are:

ld           The session handle.

dn           The name of the entry to bind as.  If NULL, a zero length
             DN is sent to the server.

mechanism    Either LDAP_SASL_SIMPLE (NULL) to get simple authentica-
             tion, or a text string identifying the SASL method.

cred         The credentials with which to authenticate. Arbitrary
             credentials can be passed using this parameter. The format
             and content of the credentials depends on the setting of
             the mechanism parameter.  If the cred parameter is NULL and
             the mechanism is LDAP_SASL_SIMPLE, a zero-length octet
             string is sent to the server in the simple credentials
             field of the bind request.  If the cred parameter is NULL
             and the mechanism is anything else, no credentials are sent
             to the server in the bind request.

passwd       For ldap_simple_bind(), the password that is sent to the
             server in the simple credentials field of the bind request.
             If NULL, a zero length password is sent to the server.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are used.

clientctrls  List of client controls, or NULL if no client controls are
             used.

msgidp       This result parameter will be set to the message id of the
             request if the ldap_sasl_bind() call succeeds.  The value
             is undefined if a value other than LDAP_SUCCESS is
             returned.




Expires: May 2001                                              [Page 26]

C LDAP API        C LDAP Application Program Interface  17 November 2000


servercredp  This result parameter will be filled in with the creden-
             tials passed back by the server for mutual authentication,
             if given. An allocated berval structure is returned that
             SHOULD be disposed of by calling ber_bvfree().  NULL SHOULD
             be passed to ignore this field.  If an API error occurs or
             the server did not return any credentials, *servercredp is
             set to NULL.

Additional parameters for the deprecated routines are not described.
Interested readers are referred to RFC 1823.

The ldap_sasl_bind() function initiates an asynchronous bind operation
and returns the constant LDAP_SUCCESS if the request was successfully
sent, or another LDAP result code if not.  See the section below on
error handling for more information about possible errors and how to
interpret them.  If successful, ldap_sasl_bind() places the message id
of the request in *msgidp. A subsequent call to ldap_result(), described
below, can be used to obtain the result of the bind.

The ldap_simple_bind() function initiates a simple asynchronous bind
operation and returns the message id of the operation initiated.  A sub-
sequent call to ldap_result(), described below, can be used to obtain
the result of the bind. In case of error, ldap_simple_bind() will return
-1, setting the session error parameters in the LDAP structure appropri-
ately.

The synchronous ldap_sasl_bind_s() and ldap_simple_bind_s() functions
both return the result of the operation, either the constant
LDAP_SUCCESS if the operation was successful, or another LDAP result
code if it was not. See the section below on error handling for more
information about possible errors and how to interpret them.

Note that if an LDAPv2 server is contacted, no other operations over the
connection can be attempted before a bind call has successfully com-
pleted.

Subsequent bind calls can be used to re-authenticate over the same con-
nection, and multistep SASL sequences can be accomplished through a
sequence of calls to ldap_sasl_bind() or ldap_sasl_bind_s().


11.5.  Closing the session

The following functions are used to unbind from the directory, close
open connections, and dispose of the session handle.

           int ldap_unbind_ext( LDAP *ld, LDAPControl **serverctrls,
                   LDAPControl **clientctrls );



Expires: May 2001                                              [Page 27]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           int ldap_unbind( LDAP *ld );

           int ldap_unbind_s( LDAP *ld );

Parameters are:

ld           The session handle.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are
             to be used.

The ldap_unbind_ext(), ldap_unbind() and ldap_unbind_s() all work syn-
chronously in the sense that they send an unbind request to the server,
close all open connections associated with the LDAP session handle, and
dispose of all resources associated with the session handle before
returning.  Note, however, that there is no server response to an LDAP
unbind operation.  All three of the unbind functions return LDAP_SUCCESS
(or another LDAP result code if the request cannot be sent to the LDAP
server).  After a call to one of the unbind functions, the session han-
dle ld is invalid and it is illegal to make any further LDAP API calls
using ld.

The ldap_unbind() and ldap_unbind_s() functions behave identically.  The
ldap_unbind_ext() function allows server and client controls to be
included explicitly, but note that since there is no server response to
an unbind request there is no way to receive a response to a server con-
trol sent with an unbind request.



11.6.  Searching

The following functions are used to search the LDAP directory, returning
a requested set of attributes for each entry matched.  There are five
variations.

           int ldap_search_ext(
                   LDAP            *ld,
                   const char      *base,
                   int             scope,
                   const char      *filter,
                   char            **attrs,
                   int             attrsonly,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls,



Expires: May 2001                                              [Page 28]

C LDAP API        C LDAP Application Program Interface  17 November 2000


                   struct timeval  *timeout,
                   int             sizelimit,
                   int             *msgidp
           );

           int ldap_search_ext_s(
                   LDAP            *ld,
                   const char      *base,
                   int             scope,
                   const char      *filter,
                   char            **attrs,
                   int             attrsonly,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls,
                   struct timeval  *timeout,
                   int             sizelimit,
                   LDAPMessage     **res
           );

           int ldap_search(
                   LDAP            *ld,
                   const char      *base,
                   int             scope,
                   const char      *filter,
                   char            **attrs,
                   int             attrsonly
           );

           int ldap_search_s(
                   LDAP            *ld,
                   const char      *base,
                   int             scope,
                   const char      *filter,
                   char            **attrs,
                   int             attrsonly,
                   LDAPMessage     **res
           );

           int ldap_search_st(
                   LDAP            *ld,
                   const char      *base,
                   int             scope,
                   const char      *filter,
                   char            **attrs,
                   int             attrsonly,
                   struct timeval  *timeout,
                   LDAPMessage     **res
           );



Expires: May 2001                                              [Page 29]

C LDAP API        C LDAP Application Program Interface  17 November 2000


Parameters are:

ld           The session handle.

base         The dn of the entry at which to start the search.  If NULL,
             a zero length DN is sent to the server.

scope        One of LDAP_SCOPE_BASE (0x00), LDAP_SCOPE_ONELEVEL (0x01),
             or LDAP_SCOPE_SUBTREE (0x02), indicating the scope of the
             search.

filter       A character string as described in [13], representing the
             search filter.  The value NULL can be passed to indicate
             that the filter "(objectclass=*)" which matches all entries
             is to be used.  Note that if the caller of the API is using
             LDAPv2, only a subset of the filter functionality described
             in [13] can be successfully used.

attrs        A NULL-terminated array of strings indicating which attri-
             butes to return for each matching entry. Passing NULL for
             this parameter causes all available user attributes to be
             retrieved.  The special constant string LDAP_NO_ATTRS
             ("1.1") MAY be used as the only string in the array to
             indicate that no attribute types are to be returned by the
             server.  The special constant string LDAP_ALL_USER_ATTRS
             ("*") can be used in the attrs array along with the names
             of some operational attributes to indicate that all user
             attributes plus the listed operational attributes are to be
             returned.

attrsonly    A boolean value that MUST be zero if both attribute types
             and values are to be returned, and non-zero if only types
             are wanted.

timeout      For the ldap_search_st() function, this specifies the local
             search timeout value (if it is NULL, the timeout is infin-
             ite).  If a zero timeout (where tv_sec and tv_usec are both
             zero) is passed, API implementations SHOULD return
             LDAP_PARAM_ERROR.

             For the ldap_search_ext() and ldap_search_ext_s() func-
             tions, the timeout parameter specifies both the local
             search timeout value and the operation time limit that is
             sent to the server within the search request.  Passing a
             NULL value for timeout causes the default timeout stored in
             the LDAP session handle (set by using ldap_set_option()
             with the LDAP_OPT_TIMELIMIT parameter) to be sent to the
             server with the request but an infinite local search



Expires: May 2001                                              [Page 30]

C LDAP API        C LDAP Application Program Interface  17 November 2000


             timeout to be used.  If a zero timeout (where tv_sec and
             tv_usec are both zero) is passed in, API implementations
             SHOULD return LDAP_PARAM_ERROR.  If a zero value for tv_sec
             is used but tv_usec is non-zero, an operation time limit of
             1 SHOULD be passed to the LDAP server as the operation time
             limit.  For other values of tv_sec, the tv_sec value itself
             SHOULD be passed to the LDAP server.

sizelimit    For the ldap_search_ext() and ldap_search_ext_s() calls,
             this is a limit on the number of entries to return from the
             search.  A value of LDAP_NO_LIMIT (0) means no limit.  A
             value of LDAP_DEFAULT_SIZELIMIT (-1) means use the default
             timeout from the LDAP session handle (which is set by cal-
             ling ldap_set_option() with the LDAP_OPT_SIZELIMIT parame-
             ter).

res          For the synchronous calls, this is a result parameter which
             will contain the results of the search upon completion of
             the call.  If an API error occurs or no results are
             returned, *res is set to NULL.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are
             to be used.

msgidp       This result parameter will be set to the message id of the
             request if the ldap_search_ext() call succeeds. The value
             is undefined if a value other than LDAP_SUCCESS is
             returned.

There are three options in the session handle ld which potentially
affect how the search is performed. They are:

        LDAP_OPT_SIZELIMIT
        LDAP_OPT_TIMELIMIT
        LDAP_OPT_DEREF

These options are fully described in the earlier section "LDAP Session
Handle Options."

The ldap_search_ext() function initiates an asynchronous search opera-
tion and returns the constant LDAP_SUCCESS if the request was success-
fully sent, or another LDAP result code if not.  See the section below
on error handling for more information about possible errors and how to
interpret them.  If successful, ldap_search_ext() places the message id
of the request in *msgidp. A subsequent call to ldap_result(), described



Expires: May 2001                                              [Page 31]

C LDAP API        C LDAP Application Program Interface  17 November 2000


below, can be used to obtain the results from the search.  These results
can be parsed using the result parsing routines described in detail
later.

Similar to ldap_search_ext(), the ldap_search() function initiates an
asynchronous search operation and returns the message id of the opera-
tion initiated.  As for ldap_search_ext(), a subsequent call to
ldap_result(), described below, can be used to obtain the result of the
bind. In case of error, ldap_search() will return -1, setting the ses-
sion error parameters in the LDAP structure appropriately.

The synchronous ldap_search_ext_s(), ldap_search_s(), and
ldap_search_st() functions all return the result of the operation,
either the constant LDAP_SUCCESS if the operation was successful, or
another LDAP result code if it was not. See the section below on error
handling for more information about possible errors and how to interpret
them.  Entries returned from the search (if any) are contained in the
res parameter. This parameter is opaque to the caller.  Entries, attri-
butes, values, etc., can be extracted by calling the parsing routines
described below. The results contained in res SHOULD be freed when no
longer in use by calling ldap_msgfree(), described later.

The ldap_search_ext() and ldap_search_ext_s() functions support LDAPv3
server controls, client controls, and allow varying size and time limits
to be easily specified for each search operation.  The ldap_search_st()
function is identical to ldap_search_s() except that it takes an addi-
tional parameter specifying a local timeout for the search.  The local
search timeout is used to limit the amount of time the API implementa-
tion will wait for a search to complete.  After the local search timeout
expires, the API implementation will send an abandon operation to abort
the search operation.

11.7.  Reading an Entry

LDAP does not support a read operation directly. Instead, this operation
is emulated by a search with base set to the DN of the entry to read,
scope set to LDAP_SCOPE_BASE, and filter set to "(objectclass=*)" or
NULL. attrs contains the list of attributes to return.


11.8.  Listing the Children of an Entry

LDAP does not support a list operation directly. Instead, this operation
is emulated by a search with base set to the DN of the entry to list,
scope set to LDAP_SCOPE_ONELEVEL, and filter set to "(objectclass=*)" or
NULL. attrs contains the list of attributes to return for each child
entry.




Expires: May 2001                                              [Page 32]

C LDAP API        C LDAP Application Program Interface  17 November 2000


11.9.  Comparing a Value Against an Entry

The following routines are used to compare a given attribute value
assertion against an LDAP entry.  There are four variations:

           int ldap_compare_ext(
                   LDAP                    *ld,
                   const char              *dn,
                   const char              *attr,
                   const struct berval     *bvalue,
                   LDAPControl             **serverctrls,
                   LDAPControl             **clientctrls,
                   int                     *msgidp
           );

           int ldap_compare_ext_s(
                   LDAP                    *ld,
                   const char              *dn,
                   const char              *attr,
                   const struct berval     *bvalue,
                   LDAPControl             **serverctrls,
                   LDAPControl             **clientctrls
           );

           int ldap_compare(
                   LDAP                    *ld,
                   const char              *dn,
                   const char              *attr,
                   const char              *value
           );

           int ldap_compare_s(
                   LDAP                    *ld,
                   const char              *dn,
                   const char              *attr,
                   const char              *value
           );

Parameters are:

ld           The session handle.

dn           The name of the entry to compare against.  If NULL, a zero
             length DN is sent to the server.

attr         The attribute to compare against.

bvalue       The attribute value to compare against those found in the



Expires: May 2001                                              [Page 33]

C LDAP API        C LDAP Application Program Interface  17 November 2000


             given entry. This parameter is used in the extended rou-
             tines and is a pointer to a struct berval so it is possible
             to compare binary values.

value        A string attribute value to compare against, used by the
             ldap_compare() and ldap_compare_s() functions.  Use
             ldap_compare_ext() or ldap_compare_ext_s() if you need to
             compare binary values.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are
             to be used.

msgidp       This result parameter will be set to the message id of the
             request if the ldap_compare_ext() call succeeds. The value
             is undefined if a value other than LDAP_SUCCESS is
             returned.

The ldap_compare_ext() function initiates an asynchronous compare opera-
tion and returns the constant LDAP_SUCCESS if the request was success-
fully sent, or another LDAP result code if not.  See the section below
on error handling for more information about possible errors and how to
interpret them.  If successful, ldap_compare_ext() places the message id
of the request in *msgidp. A subsequent call to ldap_result(), described
below, can be used to obtain the result of the compare.

Similar to ldap_compare_ext(), the ldap_compare() function initiates an
asynchronous compare operation and returns the message id of the opera-
tion initiated.  As for ldap_compare_ext(), a subsequent call to
ldap_result(), described below, can be used to obtain the result of the
bind. In case of error, ldap_compare() will return -1, setting the ses-
sion error parameters in the LDAP structure appropriately.

The synchronous ldap_compare_ext_s() and ldap_compare_s() functions both
return the result of the operation: one of the constants
LDAP_COMPARE_TRUE or LDAP_COMPARE_FALSE if the operation was successful,
or another LDAP result code if it was not.  See the section below on
error handling for more information about possible errors and how to
interpret them.

The ldap_compare_ext() and ldap_compare_ext_s() functions support LDAPv3
server controls and client controls.







Expires: May 2001                                              [Page 34]

C LDAP API        C LDAP Application Program Interface  17 November 2000


11.10.  Modifying an entry

The following routines are used to modify an existing LDAP entry.  There
are four variations:

           typedef union mod_vals_u {
                   char            **modv_strvals;
                   struct berval   **modv_bvals;
           } mod_vals_u_t;

           typedef struct ldapmod {
                   int             mod_op;
                   char            *mod_type;
                   mod_vals_u_t    mod_vals;
           } LDAPMod;
           #define mod_values      mod_vals.modv_strvals
           #define mod_bvalues     mod_vals.modv_bvals

           int ldap_modify_ext(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPMod         **mods,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls,
                   int             *msgidp
           );

           int ldap_modify_ext_s(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPMod         **mods,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls
           );

           int ldap_modify(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPMod         **mods
           );

           int ldap_modify_s(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPMod         **mods
           );

Parameters are:



Expires: May 2001                                              [Page 35]

C LDAP API        C LDAP Application Program Interface  17 November 2000


ld           The session handle.

dn           The name of the entry to modify.  If NULL, a zero length DN
             is sent to the server.

mods         A NULL-terminated array of modifications to make to the
             entry.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are
             to be used.

msgidp       This result parameter will be set to the message id of the
             request if the ldap_modify_ext() call succeeds. The value
             is undefined if a value other than LDAP_SUCCESS is
             returned.

The fields in the LDAPMod structure have the following meanings:

mod_op       The modification operation to perform. It MUST be one of
             LDAP_MOD_ADD (0x00), LDAP_MOD_DELETE (0x01), or
             LDAP_MOD_REPLACE (0x02).  This field also indicates the
             type of values included in the mod_vals union. It is logi-
             cally ORed with LDAP_MOD_BVALUES (0x80) to select the
             mod_bvalues form. Otherwise, the mod_values form is used.

mod_type     The type of the attribute to modify.

mod_vals     The values (if any) to add, delete, or replace. Only one of
             the mod_values or mod_bvalues variants can be used,
             selected by ORing the mod_op field with the constant
             LDAP_MOD_BVALUES. mod_values is a NULL-terminated array of
             zero-terminated strings and mod_bvalues is a NULL-
             terminated array of berval structures that can be used to
             pass binary values such as images.

For LDAP_MOD_ADD modifications, the given values are added to  the
entry, creating the attribute if necessary.

For LDAP_MOD_DELETE modifications, the given values are deleted from the
entry, removing the attribute if no values remain. If the entire attri-
bute is to be deleted, the mod_vals field can be set to NULL.

For LDAP_MOD_REPLACE modifications, the attribute will have the listed
values after the modification, having been created if necessary, or
removed if the mod_vals field is NULL. All modifications are performed



Expires: May 2001                                              [Page 36]

C LDAP API        C LDAP Application Program Interface  17 November 2000


in the order in which they are listed.

The ldap_modify_ext() function initiates an asynchronous modify opera-
tion and returns the constant LDAP_SUCCESS if the request was success-
fully sent, or another LDAP result code if not.  See the section below
on error handling for more information about possible errors and how to
interpret them.  If successful, ldap_modify_ext() places the message id
of the request in *msgidp. A subsequent call to ldap_result(), described
below, can be used to obtain the result of the modify.

Similar to ldap_modify_ext(), the ldap_modify() function initiates an
asynchronous modify operation and returns the message id of the opera-
tion initiated.  As for ldap_modify_ext(), a subsequent call to
ldap_result(), described below, can be used to obtain the result of the
modify. In case of error, ldap_modify() will return -1, setting the ses-
sion error parameters in the LDAP structure appropriately.

The synchronous ldap_modify_ext_s() and ldap_modify_s() functions both
return the result of the operation, either the constant LDAP_SUCCESS if
the operation was successful, or another LDAP result code if it was not.
See the section below on error handling for more information about pos-
sible errors and how to interpret them.

The ldap_modify_ext() and ldap_modify_ext_s() functions support LDAPv3
server controls and client controls.


11.11.  Modifying the Name of an Entry

In LDAPv2, the ldap_modrdn(), ldap_modrdn_s(), ldap_modrdn2(), and
ldap_modrdn2_s() routines were used to change the name of an LDAP entry.
They could only be used to change the least significant component of a
name (the RDN or relative distinguished name). LDAPv3 provides the
Modify DN protocol operation that allows more general name change
access. The ldap_rename() and ldap_rename_s() routines are used to
change the name of an entry, and the use of the ldap_modrdn(),
ldap_modrdn_s(), ldap_modrdn2(), and ldap_modrdn2_s() routines is depre-
cated.

           int ldap_rename(
                   LDAP            *ld,
                   const char      *dn,
                   const char      *newrdn,
                   const char      *newparent,
                   int             deleteoldrdn,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls,
                   int             *msgidp



Expires: May 2001                                              [Page 37]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           );
           int ldap_rename_s(
                   LDAP            *ld,
                   const char      *dn,
                   const char      *newrdn,
                   const char      *newparent,
                   int             deleteoldrdn,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls
           );

   The use of the following routines is deprecated and more complete
   descriptions can be found in RFC 1823:

           int ldap_modrdn(
                   LDAP            *ld,
                   const char      *dn,
                   const char      *newrdn
           );
           int ldap_modrdn_s(
                   LDAP            *ld,
                   const char      *dn,
                   const char      *newrdn
           );
           int ldap_modrdn2(
                   LDAP            *ld,
                   const char      *dn,
                   const char      *newrdn,
                   int             deleteoldrdn
           );
           int ldap_modrdn2_s(
                   LDAP            *ld,
                   const char      *dn,
                   const char      *newrdn,
                   int             deleteoldrdn
           );

Parameters are:

ld           The session handle.

dn           The name of the entry whose DN is to be changed.  If NULL,
             a zero length DN is sent to the server.

newrdn       The new RDN to give the entry.

newparent    The new parent, or superior entry.  If this parameter is
             NULL, only the RDN of the entry is changed.  The root DN



Expires: May 2001                                              [Page 38]

C LDAP API        C LDAP Application Program Interface  17 November 2000


             SHOULD be specified by passing a zero length string, "".
             The newparent parameter SHOULD always be NULL when using
             version 2 of the LDAP protocol; otherwise the server's
             behavior is undefined.

deleteoldrdn This parameter only has meaning on the rename routines if
             newrdn is different than the old RDN. It is a boolean
             value, if non-zero indicating that the old RDN value(s) is
             to be removed, if zero indicating that the old RDN value(s)
             is to be retained as non-distinguished values of the entry.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are
             to be used.

msgidp       This result parameter will be set to the message id of the
             request if the ldap_rename() call succeeds. The value is
             undefined if a value other than LDAP_SUCCESS is returned.

The ldap_rename() function initiates an asynchronous modify DN operation
and returns the constant LDAP_SUCCESS if the request was successfully
sent, or another LDAP result code if not.  See the section below on
error handling for more information about possible errors and how to
interpret them.  If successful, ldap_rename() places the DN message id
of the request in *msgidp. A subsequent call to ldap_result(), described
below, can be used to obtain the result of the rename.

The synchronous ldap_rename_s() returns the result of the operation,
either the constant LDAP_SUCCESS if the operation was successful, or
another LDAP result code if it was not.  See the section below on error
handling for more information about possible errors and how to interpret
them.

The ldap_rename() and ldap_rename_s() functions both support LDAPv3
server controls and client controls.


11.12.  Adding an entry

The following functions are used to add entries to the LDAP directory.
There are four variations:

           int ldap_add_ext(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPMod         **attrs,



Expires: May 2001                                              [Page 39]

C LDAP API        C LDAP Application Program Interface  17 November 2000


                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls,
                   int             *msgidp
           );

           int ldap_add_ext_s(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPMod         **attrs,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls
           );

           int ldap_add(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPMod         **attrs
           );

           int ldap_add_s(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPMod         **attrs
           );

Parameters are:

ld           The session handle.

dn           The name of the entry to add.  If NULL, a zero length DN is
             sent to the server.

attrs        The entry's attributes, specified using the LDAPMod struc-
             ture defined for ldap_modify(). The mod_type and mod_vals
             fields MUST be filled in.  The mod_op field is ignored
             unless ORed with the constant LDAP_MOD_BVALUES, used to
             select the mod_bvalues case of the mod_vals union.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are
             to be used.

msgidp       This result parameter will be set to the message id of the
             request if the ldap_add_ext() call succeeds. The value is
             undefined if a value other than LDAP_SUCCESS is returned.




Expires: May 2001                                              [Page 40]

C LDAP API        C LDAP Application Program Interface  17 November 2000


Note that the parent of the entry being added must already exist or the
parent must be empty (i.e., equal to the root DN) for an add to succeed.

The ldap_add_ext() function initiates an asynchronous add operation and
returns the constant LDAP_SUCCESS if the request was successfully sent,
or another LDAP result code if not.  See the section below on error han-
dling for more information about possible errors and how to interpret
them.  If successful, ldap_add_ext() places the message id of the
request in *msgidp. A subsequent call to ldap_result(), described below,
can be used to obtain the result of the add.

Similar to ldap_add_ext(), the ldap_add() function initiates an asyn-
chronous add operation and returns the message id of the operation ini-
tiated.  As for ldap_add_ext(), a subsequent call to ldap_result(),
described below, can be used to obtain the result of the add. In case of
error, ldap_add() will return -1, setting the session error parameters
in the LDAP structure appropriately.

The synchronous ldap_add_ext_s() and ldap_add_s() functions both return
the result of the operation, either the constant LDAP_SUCCESS if the
operation was successful, or another LDAP result code if it was not.
See the section below on error handling for more information about pos-
sible errors and how to interpret them.

The ldap_add_ext() and ldap_add_ext_s() functions support LDAPv3 server
controls and client controls.



11.13.  Deleting an entry

The following functions are used to delete a leaf entry from the LDAP
directory.  There are four variations:

           int ldap_delete_ext(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls,
                   int             *msgidp
           );

           int ldap_delete_ext_s(
                   LDAP            *ld,
                   const char      *dn,
                   LDAPControl     **serverctrls,
                   LDAPControl     **clientctrls
           );



Expires: May 2001                                              [Page 41]

C LDAP API        C LDAP Application Program Interface  17 November 2000



           int ldap_delete(
                   LDAP            *ld,
                   const char      *dn
           );

           int ldap_delete_s(
                   LDAP            *ld,
                   const char      *dn
           );

Parameters are:

ld           The session handle.

dn           The name of the entry to delete.  If NULL, a zero length DN
             is sent to the server.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are
             to be used.

msgidp       This result parameter will be set to the message id of the
             request if the ldap_delete_ext() call succeeds. The value
             is undefined if a value other than LDAP_SUCCESS is
             returned.

Note that the entry to delete must be a leaf entry (i.e., it must have
no children). Deletion of entire subtrees in a single operation is not
supported by LDAP.

The ldap_delete_ext() function initiates an asynchronous delete opera-
tion and returns the constant LDAP_SUCCESS if the request was success-
fully sent, or another LDAP result code if not.  See the section below
on error handling for more information about possible errors and how to
interpret them.  If successful, ldap_delete_ext() places the message id
of the request in *msgidp. A subsequent call to ldap_result(), described
below, can be used to obtain the result of the delete.

Similar to ldap_delete_ext(), the ldap_delete() function initiates an
asynchronous delete operation and returns the message id of the opera-
tion initiated.  As for ldap_delete_ext(), a subsequent call to
ldap_result(), described below, can be used to obtain the result of the
delete. In case of error, ldap_delete() will return -1, setting the ses-
sion error parameters in the LDAP structure appropriately.




Expires: May 2001                                              [Page 42]

C LDAP API        C LDAP Application Program Interface  17 November 2000


The synchronous ldap_delete_ext_s() and ldap_delete_s() functions both
return the result of the operation, either the constant LDAP_SUCCESS if
the operation was successful, or another LDAP result code if it was not.
See the section below on error handling for more information about pos-
sible errors and how to interpret them.

The ldap_delete_ext() and ldap_delete_ext_s() functions support LDAPv3
server controls and client controls.


11.14.  Extended Operations

The ldap_extended_operation() and ldap_extended_operation_s() routines
allow extended LDAP operations to be passed to the server, providing a
general protocol extensibility mechanism.

           int ldap_extended_operation(
                   LDAP                    *ld,
                   const char              *requestoid,
                   const struct berval     *requestdata,
                   LDAPControl             **serverctrls,
                   LDAPControl             **clientctrls,
                   int                     *msgidp
           );

           int ldap_extended_operation_s(
                   LDAP                    *ld,
                   const char              *requestoid,
                   const struct berval     *requestdata,
                   LDAPControl             **serverctrls,
                   LDAPControl             **clientctrls,
                   char                    **retoidp,
                   struct berval           **retdatap
           );

Parameters are:

ld           The session handle.

requestoid   The dotted-OID text string naming the request.

requestdata  The arbitrary data needed by the operation (if NULL, no
             data is sent to the server).

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are



Expires: May 2001                                              [Page 43]

C LDAP API        C LDAP Application Program Interface  17 November 2000


             to be used.

msgidp       This result parameter will be set to the message id of the
             request if the ldap_extended_operation() call succeeds. The
             value is undefined if a value other than LDAP_SUCCESS is
             returned.

retoidp      Pointer to a character string that will be set to an allo-
             cated, dotted-OID text string returned by the server.  This
             string SHOULD be disposed of using the ldap_memfree() func-
             tion.  If an API error occurs or no OID is returned by the
             server, *retoidp is set to NULL.

retdatap     Pointer to a berval structure pointer that will be set an
             allocated copy of the data returned by the server.  This
             struct berval SHOULD be disposed of using ber_bvfree().  If
             an API error occurs or no data is returned by the server,
             *retdatap is set to NULL.

The ldap_extended_operation() function initiates an asynchronous
extended operation and returns the constant LDAP_SUCCESS if the request
was successfully sent, or another LDAP result code if not.  See the sec-
tion below on error handling for more information about possible errors
and how to interpret them.  If successful, ldap_extended_operation()
places the message id of the request in *msgidp. A subsequent call to
ldap_result(), described below, can be used to obtain the result of the
extended operation which can be passed to ldap_parse_extended_result()
to obtain the OID and data contained in the response.

The synchronous ldap_extended_operation_s() function returns the result
of the operation, either the constant LDAP_SUCCESS if the operation was
successful, or another LDAP result code if it was not.  See the section
below on error handling for more information about possible errors and
how to interpret them.  The retoid and retdata parameters are filled in
with the OID and data from the response.

The ldap_extended_operation() and ldap_extended_operation_s() functions
both support LDAPv3 server controls and client controls.


12.  Abandoning An Operation

The following calls are used to abandon an operation in progress:

           int ldap_abandon_ext(
                   LDAP            *ld,
                   int             msgid,
                   LDAPControl     **serverctrls,



Expires: May 2001                                              [Page 44]

C LDAP API        C LDAP Application Program Interface  17 November 2000


                   LDAPControl     **clientctrls
           );

           int ldap_abandon(
                   LDAP            *ld,
                   int             msgid
           );


ld           The session handle.

msgid        The message id of the request to be abandoned.

serverctrls  List of LDAP server controls, or NULL if no server controls
             are to be used.

clientctrls  List of client controls, or NULL if no client controls are
             to be used.

ldap_abandon_ext() abandons the operation with message id msgid and
returns the constant LDAP_SUCCESS if the abandon was successful or
another LDAP result code if not.  See the section below on error han-
dling for more information about possible errors and how to interpret
them.

ldap_abandon() is identical to ldap_abandon_ext() except that it does
not accept client or server controls and it returns zero if the abandon
was successful, -1 otherwise.

After a successful call to ldap_abandon() or ldap_abandon_ext(), results
with the given message id are never returned from a subsequent call to
ldap_result().  There is no server response to LDAP abandon operations.


13.  Obtaining Results and Peeking Inside LDAP Messages

ldap_result() is used to obtain the result of a previous asynchronously
initiated operation. Note that depending on how it is called,
ldap_result() can actually return a list or "chain" of result messages.
The ldap_result() function only returns messages for a single request,
so for all LDAP operations other than search only one result message is
expected; that is, the only time the "result chain" can contain more
than one message is if results from a search operation are returned.
Once a chain of messages has been returned to the caller, it is no
longer tied in any caller-visible way to the LDAP request that produced
it.  However, it MAY be tied to the session handle.  Therefore, a chain
of messages returned by calling ldap_result() or by calling a synchro-
nous search routine will never be affected by subsequent LDAP API calls



Expires: May 2001                                              [Page 45]

C LDAP API        C LDAP Application Program Interface  17 November 2000


except for ldap_msgfree() (which is used to dispose of a chain of mes-
sages) and the unbind calls (which dispose of a session handle):
ldap_unbind(), ldap_unbind_s(), or ldap_unbind_ext(), or functions
defined by extensions of this API.

ldap_msgfree() frees the result messages (possibly an entire chain of
messages) obtained from a previous call to ldap_result() or from a call
to a synchronous search routine.

ldap_msgtype() returns the type of an LDAP message.

ldap_msgid() returns the message ID of an LDAP message.

           int ldap_result(
                   LDAP            *ld,
                   int             msgid,
                   int             all,
                   struct timeval  *timeout,
                   LDAPMessage     **res
           );

           int ldap_msgfree( LDAPMessage *res );

           int ldap_msgtype( LDAPMessage *res );

           int ldap_msgid( LDAPMessage *res );

Parameters are:

ld       The session handle.

msgid    The message id of the operation whose results are to be
         returned, the constant LDAP_RES_UNSOLICITED (0) if an unsoli-
         cited result is desired, or or the constant LDAP_RES_ANY (-1)
         if any result is desired.

all      Specifies how many messages will be retrieved in a single call
         to ldap_result().  This parameter only has meaning for search
         results.  Pass the constant LDAP_MSG_ONE (0x00) to retrieve one
         message at a time.  Pass LDAP_MSG_ALL (0x01) to request that
         all results of a search be received before returning all
         results in a single chain.  Pass LDAP_MSG_RECEIVED (0x02) to
         indicate that all messages retrieved so far are to be returned
         in the result chain.

timeout  A timeout specifying how long to wait for results to be
         returned.  A NULL value causes ldap_result() to block until
         results are available.  A timeout value of zero seconds



Expires: May 2001                                              [Page 46]

C LDAP API        C LDAP Application Program Interface  17 November 2000


         specifies a polling behavior.

res      For ldap_result(), a result parameter that will contain the
         result(s) of the operation. If an API error occurs or no
         results are returned, *res is set to NULL.  For ldap_msgfree(),
         the result chain to be freed, obtained from a previous call to
         ldap_result(), ldap_search_s(), or ldap_search_st().  If res is
         NULL, nothing is done and ldap_msgfree() returns zero.

Upon successful completion, ldap_result() returns the type of the first
result returned in the res parameter. This will be one of the following
constants.

             LDAP_RES_BIND (0x61)
             LDAP_RES_SEARCH_ENTRY (0x64)
             LDAP_RES_SEARCH_REFERENCE (0x73)      -- new in LDAPv3
             LDAP_RES_SEARCH_RESULT (0x65)
             LDAP_RES_MODIFY (0x67)
             LDAP_RES_ADD (0x69)
             LDAP_RES_DELETE (0x6B)
             LDAP_RES_MODDN (0x6D)
             LDAP_RES_COMPARE (0x6F)
             LDAP_RES_EXTENDED (0x78)              -- new in LDAPv3

ldap_result() returns 0 if the timeout expired and -1 if an error
occurs, in which case the error parameters of the LDAP session handle
will be set accordingly.

ldap_msgfree() frees each message in the result chain pointed to by res
and returns the type of the last message in the chain.  If res is NULL,
nothing is done and the value zero is returned.

ldap_msgtype() returns the type of the LDAP message it is passed as a
parameter. The type will be one of the types listed above, or -1 on
error.

ldap_msgid() returns the message ID associated with the LDAP message
passed as a parameter, or -1 on error.


14.  Handling Errors and Parsing Results

The following calls are used to extract information from results and
handle errors returned by other LDAP API routines.  Note that
ldap_parse_sasl_bind_result() and ldap_parse_extended_result() must typ-
ically be used in addition to ldap_parse_result() to retrieve all the
result information from SASL Bind and Extended Operations respectively.




Expires: May 2001                                              [Page 47]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           int ldap_parse_result(
                   LDAP            *ld,
                   LDAPMessage     *res,
                   int             *errcodep,
                   char            **matcheddnp,
                   char            **errmsgp,
                   char            ***referralsp,
                   LDAPControl     ***serverctrlsp,
                   int             freeit
           );

           int ldap_parse_sasl_bind_result(
                   LDAP            *ld,
                   LDAPMessage     *res,
                   struct berval   **servercredp,
                   int             freeit
           );

           int ldap_parse_extended_result(
                   LDAP            *ld,
                   LDAPMessage     *res,
                   char            **retoidp,
                   struct berval   **retdatap,
                   int             freeit
           );

           #define LDAP_NOTICE_OF_DISCONNECTION    "1.3.6.1.4.1.1466.20036"

           char *ldap_err2string( int err );

   The use of the following routines is deprecated and more complete
   descriptions can be found in RFC 1823:

           int ldap_result2error(
                   LDAP            *ld,
                   LDAPMessage     *res,
                   int             freeit
           );

           void ldap_perror( LDAP *ld, const char *msg );

Parameters are:

ld           The session handle.

res          The result of an LDAP operation as returned by
             ldap_result() or one of the synchronous API operation
             calls.



Expires: May 2001                                              [Page 48]

C LDAP API        C LDAP Application Program Interface  17 November 2000


errcodep     This result parameter will be filled in with the LDAP
             resultCode field from the LDAPMessage message.  This is the
             indication from the server of the outcome of the operation.
             NULL SHOULD be passed to ignore this field.

matcheddnp   If the server returned a matchedDN string to indicate how
             much of a name passed in a request was recognized, this
             result parameter will be filled in with that matchedDN
             string.  Otherwise, this field will be set to NULL.  NULL
             SHOULD be passed to ignore this field.  The matched DN
             string SHOULD be freed by calling ldap_memfree() which is
             described later in this document.  Note that the server may
             return a zero length matchedDN (in which case *matchednp is
             set to an allocated copy of "") which is different than not
             returning a value at all (in which case *matcheddnp is set
             to NULL).

errmsgp      This result parameter will be filled in with the contents
             of the error message field from the LDAPMessage message.
             The error message string SHOULD be freed by calling
             ldap_memfree() which is described later in this document.
             NULL SHOULD be passed to ignore this field.

referralsp   This result parameter will be filled in with the contents
             of the referrals field from the LDAPMessage message, indi-
             cating zero or more alternate LDAP servers where the
             request is to be retried.  The referrals array SHOULD be
             freed by calling ldap_value_free() which is described later
             in this document.  NULL SHOULD be passed to ignore this
             field.  If no referrals were returned, *referralsp is set
             to NULL.

serverctrlsp This result parameter will be filled in with an allocated
             array of controls copied out of the LDAPMessage message.
             If serverctrlsp is NULL, no controls are returned.  The
             control array SHOULD be freed by calling
             ldap_controls_free() which was described earlier.  If no
             controls were returned, *serverctrlsp is set to NULL.

freeit       A boolean that determines whether the res parameter is
             disposed of or not.  Pass any non-zero value to have these
             routines free res after extracting the requested informa-
             tion.  This is provided as a convenience; you can also use
             ldap_msgfree() to free the result later.  If freeit is
             non-zero, the entire chain of messages represented by res
             is disposed of.

servercredp  For SASL bind results, this result parameter will be filled



Expires: May 2001                                              [Page 49]

C LDAP API        C LDAP Application Program Interface  17 November 2000


             in with the credentials passed back by the server for
             mutual authentication, if given. An allocated berval struc-
             ture is returned that SHOULD be disposed of by calling
             ber_bvfree().  NULL SHOULD be passed to ignore this field.

retoidp      For extended results, this result parameter will be filled
             in with the dotted-OID text representation of the name of
             the extended operation response.  This string SHOULD be
             disposed of by calling ldap_memfree().  NULL SHOULD be
             passed to ignore this field.  If no OID was returned,
             *retoidp is set to NULL.  The LDAP_NOTICE_OF_DISCONNECTION
             macro is defined as a convenience for clients that wish to
             check an OID to see if it matches the one used for the
             unsolicited Notice of Disconnection (defined in RFC 2251[2]
             section 4.4.1).

retdatap     For extended results, this result parameter will be filled
             in with a pointer to a struct berval containing the data in
             the extended operation response.  It SHOULD be disposed of
             by calling ber_bvfree(). NULL SHOULD be passed to ignore
             this field.  If no data is returned, *retdatap is set to
             NULL.

err          For ldap_err2string(), an LDAP result code, as returned by
             ldap_parse_result() or another LDAP API call.

Additional parameters for the deprecated routines are not described.
Interested readers are referred to RFC 1823.

The ldap_parse_result(), ldap_parse_sasl_bind_result(), and
ldap_parse_extended_result() functions all skip over messages of type
LDAP_RES_SEARCH_ENTRY and LDAP_RES_SEARCH_REFERENCE when looking for a
result message to parse.  They return the constant LDAP_SUCCESS if the
result was successfully parsed and another LDAP API result code if not.
If a value other than LDAP_SUCCESS is returned, the values of all the
result parameters are undefined.  Note that the LDAP result code that
indicates the outcome of the operation performed by the server is placed
in the errcodep ldap_parse_result() parameter.  If a chain of messages
that contains more than one result message is passed to these routines
they always operate on the first result in the chain.

ldap_err2string() is used to convert a numeric LDAP result code, as
returned by ldap_parse_result(), ldap_parse_sasl_bind_result(),
ldap_parse_extended_result() or one of the synchronous API operation
calls, into an informative zero-terminated character string message
describing the error.  It returns a pointer to static data and it MUST
NOT return NULL; the value returned is always a valid null-terminated
"C" string.



Expires: May 2001                                              [Page 50]

C LDAP API        C LDAP Application Program Interface  17 November 2000


15.  Stepping Through a List of Results

The ldap_first_message() and ldap_next_message() routines are used to
step through the list of messages in a result chain returned by
ldap_result().  For search operations, the result chain can actually
include referral messages, entry messages, and result messages.
ldap_count_messages() is used to count the number of messages returned.
The ldap_msgtype() function, described above, can be used to distinguish
between the different message types.

           LDAPMessage *ldap_first_message( LDAP *ld, LDAPMessage *res );

           LDAPMessage *ldap_next_message( LDAP *ld, LDAPMessage *msg );

           int ldap_count_messages( LDAP *ld, LDAPMessage *res );

Parameters are:

ld     The session handle.

res    The result chain, as obtained by a call to one of the synchronous
       search routines or ldap_result().

msg    The message returned by a previous call to ldap_first_message()
       or ldap_next_message().

ldap_first_message() and ldap_next_message() will return NULL when no
more messages exist in the result set to be returned.  NULL is also
returned if an error occurs while stepping through the entries, in which
case the error parameters in the session handle ld will be set to indi-
cate the error.

If successful, ldap_count_messages() returns the number of messages con-
tained in a chain of results; if an error occurs such as the res parame-
ter being invalid, -1 is returned.  The ldap_count_messages() call can
also be used to count the number of messages that remain in a chain if
called with a message, entry, or reference returned by
ldap_first_message(), ldap_next_message(), ldap_first_entry(),
ldap_next_entry(), ldap_first_reference(), ldap_next_reference().


16.  Parsing Search Results

The following calls are used to parse the entries and references
returned by ldap_search() and friends. These results are returned in an
opaque structure that MAY be accessed by calling the routines described
below. Routines are provided to step through the entries and references
returned, step through the attributes of an entry, retrieve the name of



Expires: May 2001                                              [Page 51]

C LDAP API        C LDAP Application Program Interface  17 November 2000


an entry, and retrieve the values associated with a given attribute in
an entry.


16.1.  Stepping Through a List of Entries or References

The ldap_first_entry() and ldap_next_entry() routines are used to step
through and retrieve the list of entries from a search result chain.
The ldap_first_reference() and ldap_next_reference() routines are used
to step through and retrieve the list of continuation references from a
search result chain.  ldap_count_entries() is used to count the number
of entries returned. ldap_count_references() is used to count the number
of references returned.

           LDAPMessage *ldap_first_entry( LDAP *ld, LDAPMessage *res );

           LDAPMessage *ldap_next_entry( LDAP *ld, LDAPMessage *entry );

           LDAPMessage *ldap_first_reference( LDAP *ld, LDAPMessage *res );

           LDAPMessage *ldap_next_reference( LDAP *ld, LDAPMessage *ref );

           int ldap_count_entries( LDAP *ld, LDAPMessage *res );

           int ldap_count_references( LDAP *ld, LDAPMessage *res );

Parameters are:

ld     The session handle.

res    The search result, as obtained by a call to one of the synchro-
       nous search routines or ldap_result().

entry  The entry returned by a previous call to ldap_first_entry() or
       ldap_next_entry().

ref    The reference returned by a previous call to
       ldap_first_reference() or ldap_next_reference().

ldap_first_entry(), ldap_next_entry(), ldap_first_reference() and
ldap_next_reference() all return NULL when no more entries or references
exist in the result set to be returned.  NULL is also returned if an
error occurs while stepping through the entries or references, in which
case the error parameters in the session handle ld will be set to indi-
cate the error.

ldap_count_entries() returns the number of entries contained in a chain
of entries; if an error occurs such as the res parameter being invalid,



Expires: May 2001                                              [Page 52]

C LDAP API        C LDAP Application Program Interface  17 November 2000


-1 is returned.  The ldap_count_entries() call can also be used to count
the number of entries that remain in a chain if called with a message,
entry or reference returned by ldap_first_message(),
ldap_next_message(), ldap_first_entry(), ldap_next_entry(),
ldap_first_reference(), ldap_next_reference().

ldap_count_references() returns the number of references contained in a
chain of search results; if an error occurs such as the res parameter
being invalid, -1 is returned.  The ldap_count_references() call can
also be used to count the number of references that remain in a chain.


16.2.  Stepping Through the Attributes of an Entry

The ldap_first_attribute() and ldap_next_attribute() calls are used to
step through the list of attribute types returned with an entry.

           char *ldap_first_attribute(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   BerElement      **ptr
           );

           char *ldap_next_attribute(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   BerElement      *ptr
           );

           void ldap_memfree( char *mem );

Parameters are:

ld     The session handle.

entry  The entry whose attributes are to be stepped through, as returned
       by ldap_first_entry() or ldap_next_entry().

ptr    In ldap_first_attribute(), the address of a pointer used inter-
       nally to keep track of the current position in the entry. In
       ldap_next_attribute(), the pointer returned by a previous call to
       ldap_first_attribute().  The BerElement type itself is an opaque
       structure that is described in more detail later in this document
       in the section "Encoded ASN.1 Value Manipulation".

mem    A pointer to memory allocated by the LDAP library, such as the
       attribute type names returned by ldap_first_attribute() and
       ldap_next_attribute, or the DN returned by ldap_get_dn().  If mem



Expires: May 2001                                              [Page 53]

C LDAP API        C LDAP Application Program Interface  17 November 2000


       is NULL, the ldap_memfree() call does nothing.

ldap_first_attribute() and ldap_next_attribute() will return NULL when
the end of the attributes is reached, or if there is an error, in which
case the error parameters in the session handle ld will be set to indi-
cate the error.

Both routines return a pointer to an allocated buffer containing the
current attribute name. This SHOULD be freed when no longer in use by
calling ldap_memfree().

ldap_first_attribute() will allocate and return in ptr a pointer to a
BerElement used to keep track of the current position. This pointer MAY
be passed in subsequent calls to ldap_next_attribute() to step through
the entry's attributes. After a set of calls to ldap_first_attribute()
and ldap_next_attribute(), if ptr is non-NULL, it SHOULD be freed by
calling ber_free( ptr, 0 ). Note that it is very important to pass the
second parameter as 0 (zero) in this call, since the buffer associated
with the BerElement does not point to separately allocated memory.

The attribute type names returned are suitable for passing in a call to
ldap_get_values() and friends to retrieve the associated values.


16.3.  Retrieving the Values of an Attribute

ldap_get_values() and ldap_get_values_len() are used to retrieve the
values of a given attribute from an entry. ldap_count_values() and
ldap_count_values_len() are used to count the returned values.
ldap_value_free() and ldap_value_free_len() are used to free the values.

           char **ldap_get_values(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   const char      *attr
           );

           struct berval **ldap_get_values_len(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   const char      *attr
           );

           int ldap_count_values( char **vals );

           int ldap_count_values_len( struct berval **vals );

           void ldap_value_free( char **vals );



Expires: May 2001                                              [Page 54]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           void ldap_value_free_len( struct berval **vals );

Parameters are:

ld     The session handle.

entry  The entry from which to retrieve values, as returned by
       ldap_first_entry() or ldap_next_entry().

attr   The attribute whose values are to be retrieved, as returned by
       ldap_first_attribute() or ldap_next_attribute(), or a caller-
       supplied string (e.g., "mail").

vals   The values returned by a previous call to ldap_get_values() or
       ldap_get_values_len().

Two forms of the various calls are provided. The first form is only
suitable for use with non-binary character string data. The second _len
form is used with any kind of data.

ldap_get_values() and ldap_get_values_len() return NULL if no values are
found for attr or if an error occurs.

ldap_count_values() and ldap_count_values_len() return -1 if an error
occurs such as the vals parameter being invalid.

If a NULL vals parameter is passed to ldap_value_free() or
ldap_value_free_len(), nothing is done.

Note that the values returned are dynamically allocated and SHOULD be
freed by calling either ldap_value_free() or ldap_value_free_len() when
no longer in use.


16.4.  Retrieving the name of an entry

ldap_get_dn() is used to retrieve the name of an entry.
ldap_explode_dn() and ldap_explode_rdn() are used to break up a name
into its component parts. ldap_dn2ufn() is used to convert the name into
a more "user friendly" format.

           char *ldap_get_dn( LDAP *ld, LDAPMessage *entry );

           char **ldap_explode_dn( const char *dn, int notypes );

           char **ldap_explode_rdn( const char *rdn, int notypes );

           char *ldap_dn2ufn( const char *dn );



Expires: May 2001                                              [Page 55]

C LDAP API        C LDAP Application Program Interface  17 November 2000


Parameters are:

ld      The session handle.

entry   The entry whose name is to be retrieved, as returned by
        ldap_first_entry() or ldap_next_entry().

dn      The dn to explode, such as returned by ldap_get_dn().  If NULL,
        a zero length DN is used.

rdn     The rdn to explode, such as returned in the components of the
        array returned by ldap_explode_dn().  If NULL, a zero length DN
        is used.

notypes A boolean parameter, if non-zero indicating that the dn or rdn
        components are to have their type information stripped off
        (i.e., "cn=Babs" would become "Babs").

ldap_get_dn() will return NULL if there is some error parsing the dn,
setting error parameters in the session handle ld to indicate the error.
It returns a pointer to newly allocated space that the caller SHOULD
free by calling ldap_memfree() when it is no longer in use.  Note the
format of the DNs returned is given by [5].  The root DN is returned as
a zero length string ("").

ldap_explode_dn() returns a NULL-terminated char * array containing the
RDN components of the DN supplied, with or without types as indicated by
the notypes parameter. The components are returned in the order they
appear in the dn.  The array returned SHOULD be freed when it is no
longer in use by calling ldap_value_free().

ldap_explode_rdn() returns a NULL-terminated char * array containing the
components of the RDN supplied, with or without types as indicated by
the notypes parameter. The components are returned in the order they
appear in the rdn.  The array returned SHOULD be freed when it is no
longer in use by calling ldap_value_free().

ldap_dn2ufn() converts the DN into the user friendly format described in
[14]. The UFN returned is newly allocated space that SHOULD be freed by
a call to ldap_memfree() when no longer in use.


16.5.  Retrieving controls from an entry

ldap_get_entry_controls() is used to extract LDAP controls from an
entry.





Expires: May 2001                                              [Page 56]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           int ldap_get_entry_controls(
                   LDAP            *ld,
                   LDAPMessage     *entry,
                   LDAPControl     ***serverctrlsp
           );

Parameters are:

ld           The session handle.

entry        The entry to extract controls from, as returned by
             ldap_first_entry() or ldap_next_entry().

serverctrlsp This result parameter will be filled in with an allocated
             array of controls copied out of entry. The control array
             SHOULD be freed by calling ldap_controls_free().  If ser-
             verctrlsp is NULL, no controls are returned.  If no con-
             trols were returned, *serverctrlsp is set to NULL.

ldap_get_entry_controls() returns an LDAP result code that indicates
whether the reference could be successfully parsed (LDAP_SUCCESS if all
goes well). If ldap_get_entry_controls() returns a value other than
LDAP_SUCCESS, the value of the serverctrlsp output parameter is unde-
fined.



16.6.  Parsing References

ldap_parse_reference() is used to extract referrals and controls from a
SearchResultReference message.


           int ldap_parse_reference(
                   LDAP            *ld,
                   LDAPMessage     *ref,
                   char            ***referralsp,
                   LDAPControl     ***serverctrlsp,
                   int             freeit
           );

Parameters are:

ld           The session handle.

ref          The reference to parse, as returned by ldap_result(),
             ldap_first_reference(), or ldap_next_reference().




Expires: May 2001                                              [Page 57]

C LDAP API        C LDAP Application Program Interface  17 November 2000


referralsp   This result parameter will be filled in with an allocated
             array of character strings.  The elements of the array are
             the referrals (typically LDAP URLs) contained in ref.  The
             array SHOULD be freed when no longer in used by calling
             ldap_value_free().  If referralsp is NULL, the referral
             URLs are not returned.  If no referrals were returned,
             *referralsp is set to NULL.

serverctrlsp This result parameter will be filled in with an allocated
             array of controls copied out of ref. The control array
             SHOULD be freed by calling ldap_controls_free().  If ser-
             verctrlsp is NULL, no controls are returned.  If no con-
             trols were returned, *serverctrlsp is set to NULL.

freeit       A boolean that determines whether the ref parameter is
             disposed of or not.  Pass any non-zero value to have this
             routine free ref after extracting the requested informa-
             tion.  This is provided as a convenience; you can also use
             ldap_msgfree() to free the result later.

ldap_parse_reference() returns an LDAP result code that indicates
whether the reference could be successfully parsed (LDAP_SUCCESS if all
goes well).  If a value other than LDAP_SUCCESS is returned, the value
of the referralsp and serverctrlsp result parameters are undefined.



17.  Encoded ASN.1 Value Manipulation

This section describes routines which MAY be used to encode and decode
BER-encoded ASN.1 values, which are often used inside of control and
extension values.

With the exceptions of two new functions ber_flatten() and ber_init(),
these functions are compatible with the University of Michigan LDAP 3.3
implementation of BER.

Note that the functions defined in this section all provide a method for
determining success or failure but generally do not provide access to
specific error codes.  Therefore, applications that require precise
error information when encoding or decoding ASN.1 values SHOULD NOT use
these functions.


17.1.  BER Data Structures and Types

The following additional integral types are defined for use in manipula-
tion of BER encoded ASN.1 values:



Expires: May 2001                                              [Page 58]

C LDAP API        C LDAP Application Program Interface  17 November 2000


       typedef <impl_tag_t> ber_tag_t;     /* for BER tags */

       typedef <impl_int_t> ber_int_t;     /* for BER ints, enums, and Booleans */

       typedef <impl_unit_t> ber_uint_t;   /* unsigned equivalent of ber_uint_t */

       typedef <impl_slen_t> ber_slen_t;   /* signed equivalent of ber_len_t */

Note that the actual definition for these four integral types is imple-
mentation specific; that is, `<impl_tag_t>', `<impl_int_t>',
`<impl_uint_t>', and `<impl_slen_t>' MUST each be replaced with an
appropriate implementation-specific type.

The `ber_tag_t' type is an unsigned integral data type that is large
enough to hold the largest BER tag supported by the API implementation.
The width (number of significant bits) of `ber_tag_t' MUST be at least
32, greater than or equal to that of `unsigned int' (so that integer
promotions won't promote it to `int'), and no wider than that of
`unsigned long'.

The `ber_int_t' and `ber_uint_t' types are the signed and unsigned vari-
ants of an integral type that is large enough to hold integers for pur-
poses of BER encoding and decoding.  The width of `ber_int_t' MUST be at
least 32 and no larger than that of `long'.

The `ber_slen_t' type is the signed variant of the `ber_len_t' integral
type, i.e. if `ber_len_t' is unsigned long, then `ber_slen_t' is signed
long.  The `<impl_slen_t>' in the `ber_len_t' typedef MUST be replaced
with an appropriate type.  Note that `ber_slen_t' is not used directly
in the C LDAP API but is provided for the convenience of application
developers and for use by extensions to the API.

           typedef struct berval {
                   ber_len_t       bv_len;
                   char            *bv_val;
           } BerValue;

As defined earlier in the section "Common Data Structures", a berval
structure contains an arbitrary sequence of bytes and an indication of
its length.  The bv_len element is an unsigned integer.  The bv_val is
not necessarily zero-terminated.  Applications MAY allocate their own
berval structures.

As defined earlier in the section "Common Data Structures", the BerEle-
ment structure is an opaque structure:

           typedef struct berelement BerElement;




Expires: May 2001                                              [Page 59]

C LDAP API        C LDAP Application Program Interface  17 November 2000


It contains not only a copy of the encoded value, but also state infor-
mation used in encoding or decoding.  Applications cannot allocate their
own BerElement structures.  The internal state is neither thread-
specific nor locked, so two threads SHOULD NOT manipulate the same
BerElement value simultaneously.

A single BerElement value cannot be used for both encoding and decoding.

17.2.  Memory Disposal and Utility Functions

           void ber_bvfree( struct berval *bv );

ber_bvfree() frees a berval structure returned from this API.  Both the
bv->bv_val string and the berval structure itself are freed.  If bv is
NULL, this call does nothing.

           void ber_bvecfree( struct berval **bv );

ber_bvecfree() frees an array of berval structures returned from this
API.  Each of the berval structures in the array are freed using
ber_bvfree(), then the array itself is freed.  If bv is NULL, this call
does nothing.

           struct berval *ber_bvdup( const struct berval *bv );

ber_bvdup() returns a copy of a berval structure.  The bv_val field in
the returned berval structure points to a different area of memory than
the bv_val field in the bv argument.  The NULL pointer is returned on
error (e.g. out of memory).

           void ber_free( BerElement *ber, int fbuf );

ber_free() frees a BerElement which is returned from the API calls
ber_alloc_t() or ber_init().  Each BerElement SHOULD be freed by the
caller.  The second argument fbuf SHOULD always be set to 1 to ensure
that the internal buffer used by the BER functions is freed as well as
the BerElement container itself.  If ber is NULL, this call does noth-
ing.


17.3.  Encoding

           BerElement *ber_alloc_t( int options );

ber_alloc_t() constructs and returns BerElement.  The NULL pointer is
returned on error.  The options field contains a bitwise-or of options
which are to be used when generating the encoding of this BerElement.
One option is defined and SHOULD always be supplied:



Expires: May 2001                                              [Page 60]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           #define LBER_USE_DER 0x01

When this option is present, lengths will always be encoded in the
minimum number of octets.  Note that this option does not cause values
of sets to be rearranged in tag and byte order or default values to be
removed, so these functions are not sufficient for generating DER output
as defined in X.509 and X.680.  If the caller takes responsibility for
ordering values of sets correctly and removing default values, DER out-
put as defined in X.509 and X.680 can be produced.

Unrecognized option bits are ignored.

The BerElement returned by ber_alloc_t() is initially empty.  Calls to
ber_printf() will append bytes to the end of the ber_alloc_t().

           int ber_printf( BerElement *ber, const char *fmt, ... );

The ber_printf() routine is used to encode a BER element in much the
same way that sprintf() works.  One important difference, though, is
that state information is kept in the ber argument so that multiple
calls can be made to ber_printf() to append to the end of the BER ele-
ment. ber MUST be a pointer to a BerElement returned by ber_alloc_t().
ber_printf() interprets and formats its arguments according to the for-
mat string fmt.  ber_printf() returns -1 if there is an error during
encoding and a non-negative number if successful.  As with sprintf(),
each character in fmt refers to an argument to ber_printf().

The format string can contain the following format characters:

't'     Tag.  The next argument is a ber_tag_t specifying the tag to
        override the next element to be written to the ber.  This works
        across calls.  The integer tag value SHOULD contain the tag
        class, constructed bit, and tag value.  For example, a tag of
        "[3]" for a constructed type is 0xA3U.  All implementations MUST
        support tags that fit in a single octet (i.e., where the tag
        value is less than 32) and they MAY support larger tags.

'b'     Boolean.  The next argument is an ber_int_t, containing either 0
        for FALSE or 0xff for TRUE.  A boolean element is output.  If
        this format character is not preceded by the 't' format modif-
        ier, the tag 0x01U is used for the element.

'e'     Enumerated.  The next argument is a ber_int_t, containing the
        enumerated value in the host's byte order.  An enumerated ele-
        ment is output.  If this format character is not preceded by the
        't' format modifier, the tag 0x0AU is used for the element.

'i'     Integer.  The next argument is a ber_int_t, containing the



Expires: May 2001                                              [Page 61]

C LDAP API        C LDAP Application Program Interface  17 November 2000


        integer in the host's byte order.  An integer element is output.
        If this format character is not preceded by the 't' format
        modifier, the tag 0x02U is used for the element.

'B'     Bitstring.  The next two arguments are a char * pointer to the
        start of the bitstring, followed by a ber_len_t containing the
        number of bits in the bitstring.  A bitstring element is output,
        in primitive form.  If this format character is not preceded by
        the 't' format modifier, the tag 0x03U is used for the element.

'X'     Reserved and not to be used.  In older revisions of this specif-
        ication,

'n'     Null.  No argument is needed.  An ASN.1 NULL element is output.
        If this format character is not preceded by the 't' format
        modifier, the tag 0x05U is used for the element.

'o'     Octet string.  The next two arguments are a char *, followed by
        a ber_len_t with the length of the string.  The string MAY con-
        tain null bytes and are do not have to be zero-terminated.   An
        octet string element is output, in primitive form.  If this for-
        mat character is not preceded by the 't' format modifier, the
        tag 0x04U is used for the element.

's'     Octet string.  The next argument is a char * pointing to a
        zero-terminated string.  An octet string element in primitive
        form is output, which does not include the trailing '\0' (null)
        byte. If this format character is not preceded by the 't' format
        modifier, the tag 0x04U is used for the element.

'v'     Several octet strings.  The next argument is a char **, an array
        of char * pointers to zero-terminated strings.  The last element
        in the array MUST be a NULL pointer. The octet strings do not
        include the trailing '\0' (null) byte.  Note that a construct
        like '{v}' is used to get an actual SEQUENCE OF octet strings.
        The 't' format modifier cannot be used with this format charac-
        ter.

'V'     Several octet strings.  A NULL-terminated array of struct berval
        *'s is supplied.  Note that a construct like '{V}' is used to
        get an actual SEQUENCE OF octet strings. The 't' format modifier
        cannot be used with this format character.

'{'     Begin sequence.  No argument is needed.  If this format charac-
        ter is not preceded by the 't' format modifier, the tag 0x30U is
        used.

'}'     End sequence.  No argument is needed.  The 't' format modifier



Expires: May 2001                                              [Page 62]

C LDAP API        C LDAP Application Program Interface  17 November 2000


        cannot be used with this format character.

'['     Begin set.  No argument is needed.  If this format character is
        not preceded by the 't' format modifier, the tag 0x31U is used.

']'     End set.  No argument is needed.  The 't' format modifier cannot
        be used with this format character.

Each use of a '{' format character SHOULD be matched by a '}' character,
either later in the format string, or in the format string of a subse-
quent call to ber_printf() for that BerElement.  The same applies to the
'[' and ']' format characters.

Sequences and sets nest, and implementations of this API MUST maintain
internal state to be able to properly calculate the lengths.

           int ber_flatten( BerElement *ber, struct berval **bvPtr );

The ber_flatten routine allocates a struct berval whose contents are a
BER encoding taken from the ber argument. The bvPtr pointer points to
the returned berval structure, which SHOULD be freed using ber_bvfree().
This routine returns 0 on success and -1 on error.

The ber_flatten API call is not present in U-M LDAP 3.3.

The use of ber_flatten on a BerElement in which all '{' and '}' format
modifiers have not been properly matched is an error (i.e., -1 will be
returned by ber_flatten() if this situation is exists).


17.4.  Encoding Example

The following is an example of encoding the following ASN.1 data type:

      Example1Request ::= SEQUENCE {
           s     OCTET STRING, -- must be printable
           val1  INTEGER,
           val2  [0] INTEGER DEFAULT 0
      }


      int encode_example1(const char *s, ber_int_t val1, ber_int_t val2,
               struct berval **bvPtr)
      {
           BerElement *ber;
           int rc = -1;

           *bvPtr = NULL;  /* in case of error */



Expires: May 2001                                              [Page 63]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           ber = ber_alloc_t(LBER_USE_DER);

           if (ber == NULL) return -1;

           if (ber_printf(ber,"{si",s,val1) == -1) {
                   goto done;
           }

           if (val2 != 0) {
                   if (ber_printf(ber,"ti",(ber_tag_t)0x80,val2) == -1) {
                           goto done;
                   }
           }

           if (ber_printf(ber,"}") == -1) {
                   goto done;
           }

           rc = ber_flatten(ber,bvPtr);

   done:
           ber_free(ber,1);
           return rc;
      }


17.5.  Decoding

The following two macros are available to applications: LBER_ERROR and
LBER_DEFAULT.  Both of these macros MUST be #define'd as ber_tag_t
integral values that are treated as invalid tags by the API implementa-
tion.  It is RECOMMENDED that the values of LBER_ERROR and LBER_DEFAULT
be the same and that they be defined as values where all octets have the
value 0xFF.  ISO C guarantees that these definitions will work:

           #define LBER_ERROR   ((ber_tag_t)-1)
           #define LBER_DEFAULT ((ber_tag_t)-1)

The intent is that LBER_ERROR and LBER_DEFAULT are both defined as the
integer value that has all octets set to 0xFF, as such a value is not a
valid BER tag.

           BerElement *ber_init( const struct berval *bv );

The ber_init function constructs a BerElement and returns a new BerEle-
ment containing a copy of the data in the bv argument.  ber_init returns
the NULL pointer on error.




Expires: May 2001                                              [Page 64]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           ber_tag_t ber_scanf( BerElement *ber, const char *fmt, ... );

The ber_scanf() routine is used to decode a BER element in much the same
way that sscanf() works.  One important difference, though, is that some
state information is kept with the ber argument so that multiple calls
can be made to ber_scanf() to sequentially read from the BER element.
The ber argument SHOULD be a pointer to a BerElement returned by
ber_init().  ber_scanf interprets the bytes according to the format
string fmt, and stores the results in its additional arguments.
ber_scanf() returns LBER_ERROR on error, and a different value on suc-
cess.  If an error occurred, the values of all the result parameters are
undefined.

The format string contains conversion specifications which are used to
direct the interpretation of the BER element.  The format string can
contain the following characters:

'a'     Octet string.  A char ** argument MUST be supplied.  Memory is
        allocated, filled with the contents of the octet string, zero-
        terminated, and the pointer to the string is stored in the argu-
        ment.  The returned value SHOULD be freed using ldap_memfree.
        The tag of the element MUST indicate the primitive form (con-
        structed strings are not supported) but is otherwise ignored and
        discarded during the decoding.  This format cannot be used with
        octet strings which could contain null bytes.

'O'     Octet string.  A struct berval ** argument MUST be supplied,
        which upon return points to an allocated struct berval contain-
        ing the octet string and its length.  ber_bvfree() SHOULD be
        called to free the allocated memory.  The tag of the element
        MUST indicate the primitive form (constructed strings are not
        supported) but is otherwise ignored during the decoding.

'b'     Boolean.  A pointer to a ber_int_t MUST be supplied. The
        ber_int_t value stored will be 0 for FALSE or nonzero for TRUE.
        The tag of the element MUST indicate the primitive form but is
        otherwise ignored during the decoding.

'e'     Enumerated.  A pointer to a ber_int_t MUST be supplied. The
        enumerated value stored will be in host byte order.  The tag of
        the element MUST indicate the primitive form but is otherwise
        ignored during the decoding.  ber_scanf() will return an error
        if the value of the enumerated value cannot be stored in a
        ber_int_t.

'i'     Integer.  A pointer to a ber_int_t MUST be supplied. The
        ber_int_t value stored will be in host byte order.  The tag of
        the element MUST indicate the primitive form but is otherwise



Expires: May 2001                                              [Page 65]

C LDAP API        C LDAP Application Program Interface  17 November 2000


        ignored during the decoding.  ber_scanf() will return an error
        if the integer cannot be stored in a ber_int_t.

'B'     Bitstring.  A char ** argument MUST be supplied which will point
        to the allocated bits, followed by a ber_len_t * argument, which
        will point to the length (in bits) of the bitstring returned.
        ldap_memfree SHOULD be called to free the bitstring.  The tag of
        the element MUST indicate the primitive form (constructed bit-
        strings are not supported) but is otherwise ignored during the
        decoding.

'n'     Null.  No argument is needed.  The element is verified to have a
        zero-length value and is skipped.  The tag is ignored.

't'     Tag.  A pointer to a ber_tag_t MUST be supplied.  The ber_tag_t
        value stored will be the tag of the next element in the BerEle-
        ment ber, represented so it can be written using the 't' format
        of ber_printf().  The decoding position within the ber argument
        is unchanged by this; that is, the fact that the tag has been
        retrieved does not affect future use of ber.

'v'     Several octet strings.  A char *** argument MUST be supplied,
        which upon return points to an allocated NULL-terminated array
        of char *'s containing the octet strings.  NULL is stored if the
        sequence is empty.  ldap_memfree SHOULD be called to free each
        element of the array and the array itself.  The tag of the
        sequence and of the octet strings are ignored.

'V'     Several octet strings (which could contain null bytes).  A
        struct berval *** MUST be supplied, which upon return points to
        a allocated NULL-terminated array of struct berval *'s contain-
        ing the octet strings and their lengths.  NULL is stored if the
        sequence is empty. ber_bvecfree() can be called to free the
        allocated memory.  The tag of the sequence and of the octet
        strings are ignored.

'x'     Skip element.  The next element is skipped.  No argument is
        needed.

'{'     Begin sequence.  No argument is needed.  The initial sequence
        tag and length are skipped.

'}'     End sequence.  No argument is needed.

'['     Begin set.  No argument is needed.  The initial set tag and
        length are skipped.

']'     End set.  No argument is needed.



Expires: May 2001                                              [Page 66]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           ber_tag_t ber_peek_tag( BerElement *ber,
                   ber_len_t *lenPtr );

ber_peek_tag() returns the tag of the next element to be parsed in the
BerElement argument.  The length of this element is stored in the
*lenPtr argument.  LBER_DEFAULT is returned if there is no further data
to be read.  The decoding position within the ber argument is unchanged
by this call; that is, the fact that ber_peek_tag() has been called does
not affect future use of ber.

           ber_tag_t ber_skip_tag( BerElement *ber, ber_len_t *lenPtr );

ber_skip_tag() is similar to ber_peek_tag(), except that the state
pointer in the BerElement argument is advanced past the first tag and
length, and is pointed to the value part of the next element.  This rou-
tine SHOULD only be used with constructed types and situations when a
BER encoding is used as the value of an OCTET STRING.  The length of the
value is stored in *lenPtr.

           ber_tag_t ber_first_element( BerElement *ber,
                   ber_len_t *lenPtr, char **opaquePtr );

           ber_tag_t ber_next_element( BerElement *ber,
                   ber_len_t *lenPtr, char *opaque );

ber_first_element() and ber_next_element() are used to traverse a SET,
SET OF, SEQUENCE or SEQUENCE OF data value. ber_first_element() calls
ber_skip_tag(), stores internal information in *lenPtr and *opaquePtr,
and calls ber_peek_tag() for the first element inside the constructed
value. LBER_DEFAULT is returned if the constructed value is empty.
ber_next_element() positions the state at the start of the next element
in the constructed type.  LBER_DEFAULT is returned if there are no
further values.

The len and opaque values SHOULD NOT be used by applications other than
as arguments to ber_next_element(), as shown in the example below.


17.6.  Decoding Example

The following is an example of decoding an ASN.1 data type:

      Example2Request ::= SEQUENCE {
           dn    OCTET STRING, -- must be printable
           scope ENUMERATED { b (0), s (1), w (2) },
           ali   ENUMERATED { n (0), s (1), f (2), a (3) },
           size  INTEGER,
           time  INTEGER,



Expires: May 2001                                              [Page 67]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           tonly BOOLEAN,
           attrs SEQUENCE OF OCTET STRING, -- must be printable
           [0] SEQUENCE OF SEQUENCE {
              type  OCTET STRING -- must be printable,
              crit  BOOLEAN DEFAULT FALSE,
              value OCTET STRING
           } OPTIONAL }

      #define TAG_CONTROL_LIST 0xA0U /* context specific cons 0 */

      int decode_example2(struct berval *bv)
      {
           BerElement *ber;
           ber_len_t len;
           ber_tag_t res;
           ber_int_t scope, ali, size, time, tonly;
           char *dn = NULL, **attrs = NULL;
           int i,rc = 0;

           ber = ber_init(bv);
           if (ber == NULL) {
                   fputs("ERROR ber_init failed\n", stderr);
                   return -1;
           }

           res = ber_scanf(ber,"{aiiiib{v}",&dn,&scope,&ali,
                           &size,&time,&tonly,&attrs);

           if (res == LBER_ERROR) {
                   fputs("ERROR ber_scanf failed\n", stderr);
                   ber_free(ber,1);
                   return -1;
           }

           /* *** use dn */
           ldap_memfree(dn);

           for (i = 0; attrs != NULL && attrs[i] != NULL; i++) {
                   /* *** use attrs[i] */
                   ldap_memfree(attrs[i]);
           }
           ldap_memfree((char *)attrs);

           if (ber_peek_tag(ber,&len) == TAG_CONTROL_LIST) {
                   char *opaque;
                   ber_tag_t tag;

                   for (tag = ber_first_element(ber,&len,&opaque);



Expires: May 2001                                              [Page 68]

C LDAP API        C LDAP Application Program Interface  17 November 2000


                        tag != LBER_DEFAULT;
                        tag = ber_next_element (ber,&len,opaque)) {

                           ber_len_t tlen;
                           ber_tag_t ttag;
                           char *type;
                           ber_int_t crit;
                           struct berval *value;

                           if (ber_scanf(ber,"{a",&type) == LBER_ERROR) {
                                   fputs("ERROR cannot parse type\n", stderr);
                                   break;
                           }
                           /* *** use type */
                           ldap_memfree(type);

                           ttag = ber_peek_tag(ber,&tlen);
                           if (ttag == 0x01U) {  /* boolean */
                                   if (ber_scanf(ber,"b",
                                                 &crit) == LBER_ERROR) {
                                           fputs("ERROR cannot parse crit\n",
                                               stderr);
                                           rc = -1;
                                           break;
                                   }
                           } else if (ttag == 0x04U) { /* octet string */
                                   crit = 0;
                           } else {
                                   fputs("ERROR extra field in controls\n",
                                       stderr );
                                   break;
                           }

                           if (ber_scanf(ber,"O}",&value) == LBER_ERROR) {
                                   fputs("ERROR cannot parse value\n", stderr);
                                   rc = -1;
                                   break;
                           }
                           /* *** use value */
                           ber_bvfree(value);
                   }
           }

           if ( rc == 0 ) {        /* no errors so far */
                   if (ber_scanf(ber,"}") == LBER_ERROR) {
                           rc = -1;
                   }
           }



Expires: May 2001                                              [Page 69]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           ber_free(ber,1);

           return rc;
       }



18.  Security Considerations

LDAPv2 supports security through protocol-level authentication using
clear-text passwords.  LDAPv3 adds support for SASL [12] (Simple Authen-
tication Security Layer) methods.  LDAPv3 also supports operation over a
secure transport layer using Transport Layer Security TLS [9].  Readers
are referred to the protocol documents for discussion of related secu-
rity considerations.

Implementations of this API SHOULD be cautious when handling authentica-
tion credentials.  In particular, keeping long-lived copies of creden-
tials without the application's knowledge is discouraged.


19.  Acknowledgements

Many members of the IETF ASID and LDAPEXT working groups as well as
members of the Internet at large have provided useful comments and
suggestions that have been incorporated into this document.  Chris
Weider deserves special mention for his contributions as co-author of
earlier revisions of this document.

The original material upon which this specification is based was sup-
ported by the National Science Foundation under Grant No.  NCR-9416667.


20.  Copyright

Copyright (C) The Internet Society (1997-2000). All Rights Reserved.

This document and translations of it may be copied and furnished to oth-
ers, and derivative works that comment on or otherwise explain it or
assist in its implementation may be prepared, copied, published and dis-
tributed, in whole or in part, without restriction of any kind, provided
that the above copyright notice and this paragraph are included on all
such copies and derivative works.  However, this document itself may not
be modified in any way, such as by removing the copyright notice or
references to the Internet Society or other Internet organizations,
except as needed for the  purpose of developing Internet standards in
which case the procedures for copyrights defined in the Internet Stan-
dards process must be followed, or as required to translate it into



Expires: May 2001                                              [Page 70]

C LDAP API        C LDAP Application Program Interface  17 November 2000


languages other than English.

The limited permissions granted above are perpetual and will not be
revoked by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS
IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT
INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FIT-
NESS FOR A PARTICULAR PURPOSE.


21.  Bibliography

[1]  Bradner, S., "Key words for use in RFCs to Indicate Requirement
     Levels", RFC 2119, March 1997.

[2]  M. Wahl, T. Howes, S. Kille, "Lightweight Directory Access Protocol
     (v3)", RFC 2251, December 1997.

[3]  M. Wahl, A. Coulbeck, T. Howes, S. Kille, W. Yeong, C. Robbins,
     "Lightweight Directory Access Protocol (v3): Attribute Syntax
     Definitions", RFC 2252, December 1997.

[4]  The Directory: Selected Attribute Syntaxes.  CCITT, Recommendation
     X.520.

[5]  M. Wahl, S. Kille, T. Howes, "Lightweight Directory Access Protocol
     (v3): A UTF-8 String Representation of Distinguished Names", RFC
     2253, December 1997.

[6]  F. Yergeau, "UTF-8, a transformation format of Unicode and ISO
     10646", RFC 2044, October 1996.

[7]  K. Simonsen, "Character Mnemonics and Character Sets," RFC 1345,
     June 1992.

[8]  "Programming Languages - C", ANSI/ISO Standard 9899, revised 1997.

[9]  J. Hodges, R. Morgan, M. Wahl, "Lightweight Directory Access Proto-
     col (v3):  Extension for Transport Layer Security", INTERNET-DRAFT
     (work in progress) <draft-ietf-ldapext-ldapv3-tls-05.txt>, June
     1999.

[10] R. Hinden, S. Deering, "IP Version 6 Addressing Architecture," RFC
     1884, December 1995.




Expires: May 2001                                              [Page 71]

C LDAP API        C LDAP Application Program Interface  17 November 2000


[11] A. Herron, T. Howes, M. Wahl, A. Anantha, "LDAP Control Extension
     for Server Side Sorting of Search Results", INTERNET-DRAFT (work in
     progress) <draft-ietf-ldapext-sorting-02.txt>, 5 April 1999.

[12] J. Meyers, "Simple Authentication and Security Layer (SASL)", RFC
     2222, October 1997.

[13] T. Howes, "The String Representation of LDAP Search Filters," RFC
     2254, December 1997.

[14] S. Kille, "Using the OSI Directory to Achieve User Friendly Nam-
     ing," RFC 1781, March 1995.


22.  Authors' Addresses

   Mark Smith (document editor)
   Netscape Communications Corp.
   901 San Antonio Rd.
   Palo Alto, CA  94303-4900
   Mail Stop SCA17 - 201
   USA
   +1 650 937-3477
   mcs@netscape.com

   Tim Howes
   Loudcloud, Inc.
   599 N. Mathilda Avenue
   Sunnyvale, CA 94085
   USA
   +1 408 744-7300
   howes@loudcloud.com

   Andy Herron
   Microsoft Corp.
   1 Microsoft Way
   Redmond, WA 98052
   USA
   +1 425 882-8080
   andyhe@microsoft.com

   Mark Wahl
   Sun Microsystems, Inc.
   8911 Capital of Texas Hwy, Suite 4140
   Austin, TX 78759
   USA
   +1 626 919 3600
   Mark.Wahl@sun.com



Expires: May 2001                                              [Page 72]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   Anoop Anantha
   Microsoft Corp.
   1 Microsoft Way
   Redmond, WA 98052
   USA
   +1 425 882-8080
   anoopa@microsoft.com


23.  Appendix A - Sample C LDAP API Code

   #include <stdio.h>
   #include <ldap.h>

   main()
   {
           LDAP            *ld;
           LDAPMessage     *res, *e;
           int             i, rc;
           char            *a, *dn;
           BerElement      *ptr;
           char            **vals;

           /* open an LDAP session */
           if ( (ld = ldap_init( "dotted.host.name", LDAP_PORT )) == NULL )
                   return 1;

           /* authenticate as nobody */
           if (( rc = ldap_simple_bind_s( ld, NULL, NULL )) != LDAP_SUCCESS ) {
                   fprintf( stderr, "ldap_simple_bind_s: %s\n",
                       ldap_err2string( rc ));
                   ldap_unbind( ld );
                   return 1;
           }

           /* search for entries with cn of "Babs Jensen", return all attrs  */
           if (( rc = ldap_search_s( ld, "o=University of Michigan, c=US",
               LDAP_SCOPE_SUBTREE, "(cn=Babs Jensen)", NULL, 0, &res ))
               != LDAP_SUCCESS ) {
                   fprintf( stderr, "ldap_search_s: %s\n",
                       ldap_err2string( rc ));
                   if ( res == NULL ) {
                           ldap_unbind( ld );
                           return 1;
                   }
           }

           /* step through each entry returned */



Expires: May 2001                                              [Page 73]

C LDAP API        C LDAP Application Program Interface  17 November 2000


           for ( e = ldap_first_entry( ld, res ); e != NULL;
               e = ldap_next_entry( ld, e ) ) {
                   /* print its name */
                   dn = ldap_get_dn( ld, e );
                   printf( "dn: %s\n", dn );
                   ldap_memfree( dn );

                   /* print each attribute */
                   for ( a = ldap_first_attribute( ld, e, &ptr ); a != NULL;
                       a = ldap_next_attribute( ld, e, ptr ) ) {
                           printf( "\tattribute: %s\n", a );

                           /* print each value */
                           vals = ldap_get_values( ld, e, a );
                           for ( i = 0; vals[i] != NULL; i++ ) {
                                   printf( "\t\tvalue: %s\n", vals[i] );
                           }
                           ldap_value_free( vals );
                           ldap_memfree( a );
                   }
                   if ( ptr != NULL ) {
                           ber_free( ptr, 0 );
                   }
           }
           /* free the search results */
           ldap_msgfree( res );

           /* close and free connection resources */
           ldap_unbind( ld );

           return 0;
   }


24.  Appendix B - Namespace Consumed By This Specification

The following 2 prefixes are used in this specification to name func-
tions:
   ldap_
   ber_

The following 6 prefixes are used in this specification to name struc-
tures, unions, and typedefs:
   ldap
   LDAP
   mod_vals_u
   ber
   Ber



Expires: May 2001                                              [Page 74]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   timeval

The following 3 prefixes are used in this specification to name #defined
macros:
   LDAP
   LBER_
   mod_


25.  Appendix C - Summary of Requirements for API Extensions

As the LDAP protocol is extended, this C LDAP API will need to be
extended as well.  For example, an LDAPv3 control extension has already
been defined for server-side sorting of search results [7].  This appen-
dix summarizes the requirements for extending this API.

25.1.  Compatibility

Extensions to this document SHOULD NOT, by default, alter the behavior
of any of the APIs specified in this document.  If an extension option-
ally changes the behavior of any existing C LDAP API function calls, the
behavior change MUST be well documented.  If an extension that operates
on an LDAP session affects a chain of messages that was previously
obtained by a call to ldap_result() or by calling a synchronous search
routine, this MUST be well documented.

25.2.  Style

Extensions to this API SHOULD follow the general style and naming con-
ventions used in this document.  For example, function names SHOULD
start with "ldap_" or "ber_" and consist entirely of lowercase letters,
digits, and underscore ('_') characters.  It is RECOMMENDED that private
and experimental extensions use only the following prefixes for macros,
types, and function names:
       LDAP_X_
       LBER_X_
       ldap_x_
       ber_x_
and that these prefixes not be used by standard extensions.

25.3.  Dependence on Externally Defined Types

Extensions to this API SHOULD minimize dependencies on types and macros
that are defined in system headers and generally use only intrinsic
types that are part of the C language, types defined in this specifica-
tion, or types defined in the extension document itself.





Expires: May 2001                                              [Page 75]

C LDAP API        C LDAP Application Program Interface  17 November 2000


25.4.  Compile Time Information

Extensions to this API SHOULD conform to the requirements contained in
the "Retrieving Information at Compile Time" section of this document.
That is, extensions SHOULD define a macro of the form:

   #define LDAP_API_FEATURE_x level

so that applications can detect the presence or absence of the extension
at compile time and also test the version or level of the extension pro-
vided by an API implementation.

25.5.  Runtime Information

Extensions to this API SHOULD conform to the requirements contained in
the "Retrieving Information During Execution" section of this document.
That is, each extension SHOULD be given a character string name and that
name SHOULD appear in the ldapai_extensions array field of the LDAPAPI-
Info structure following a successful call to ldap_get_option() with an
option parameter value of LDAP_OPT_API_INFO.  In addition, information
about the extension SHOULD be available via a call to ldap_get_option()
with an option parameter value of LDAP_OPT_API_FEATURE_INFO.

25.6.  Values Used for Session Handle Options

Extensions to this API that add new session options (for use with the
ldap_get_option() and ldap_set_option() functions) SHOULD meet the
requirements contained in the last paragraph of the "LDAP Session Handle
Options" section of this document.  Specifically, standards track docu-
ments MUST use values for option macros that are between 0x1000 and
0x3FFF inclusive and private and experimental extensions MUST use values
for the option macros that are between 0x4000 and 0x7FFF inclusive.


26.  Appendix D - Known Incompatibilities with RFC 1823

This appendix lists known incompatibilities between this API specifica-
tion and the one contained in RFC 1823, beyond the additional API func-
tions added in support of LDAPv3.


26.1.  Opaque LDAP Structure

In RFC 1823, some fields in the LDAP structure were exposed to applica-
tion programmers.  To provide a cleaner interface and to make it easier
for implementations to evolve over time without sacrificing binary com-
patibility with older applications, the LDAP structure is now entirely
opaque.  The new ldap_set_option() and ldap_get_option() calls can be



Expires: May 2001                                              [Page 76]

C LDAP API        C LDAP Application Program Interface  17 November 2000


used to manipulate per-session and global options.


26.2.  Additional Result Codes

The following new result code macros were introduced to support LDAPv3:
   LDAP_REFERRAL
   LDAP_ADMINLIMIT_EXCEEDED
   LDAP_UNAVAILABLE_CRITICAL_EXTENSION
   LDAP_CONFIDENTIALITY_REQUIRED
   LDAP_SASL_BIND_IN_PROGRESS
   LDAP_AFFECTS_MULTIPLE_DSAS
   LDAP_CONNECT_ERROR
   LDAP_NOT_SUPPORTED
   LDAP_CONTROL_NOT_FOUND
   LDAP_NO_RESULTS_RETURNED
   LDAP_MORE_RESULTS_TO_RETURN
   LDAP_CLIENT_LOOP
   LDAP_REFERRAL_LIMIT_EXCEEDED


26.3.  Freeing of String Data with ldap_memfree()

All strings received from the API (e.g., those returned by the
ldap_get_dn() or ldap_dn2ufn() functions) SHOULD be freed by calling
ldap_memfree() not free().  RFC 1823 did not define an ldap_memfree()
function.


26.4.  Changes to ldap_result()

The meaning of the all parameter to ldap_result has changed slightly.
Nonzero values from RFC 1823 correspond to LDAP_MSG_ALL (0x01).  There
is also a new possible value, LDAP_MSG_RECEIVED (0x02).

The result type LDAP_RES_MODDN is now returned where RFC 1823 returned
LDAP_RES_MODRDN.  The actual value for these two macros is the same
(0x6D).


26.5.  Changes to ldap_first_attribute() and ldap_next_attribute

Each non-NULL return value SHOULD be freed by calling ldap_memfree()
after use.  In RFC 1823, these two functions returned a pointer to a
per-session buffer, which was not very thread-friendly.

After the last call to ldap_first_attribute() or ldap_next_attribute(),
the value set in the ptr parameter SHOULD be freed by calling ber_free(



Expires: May 2001                                              [Page 77]

C LDAP API        C LDAP Application Program Interface  17 November 2000


ptr, 0 ).  RFC 1823 did not mention that the ptr value SHOULD be freed.

The type of the ptr parameter was changed from void * to BerElement *.


26.6.  Changes to ldap_modrdn() and ldap_modrdn_s() Functions

In RFC 1823, the ldap_modrdn() and ldap_modrdn_s() functions include a
parameter called deleteoldrdn.  This does not match the great majority
of implementations, so in this specification the deleteoldrdn parameter
was removed from ldap_modrdn() and ldap_modrdn_s().  Two additional
functions that support deleteoldrdn and are widely implemented as well
were added to this specification: ldap_modrdn2() and ldap_modrdn2_s().


26.7.  Changes to the berval structure

In RFC 1823, the bv_len element of the berval structure was defined as
an `unsigned long'.  In this specification, the type is implementation-
specific, although it MUST be an unsigned integral type that is at least
32 bits in size.  See the appendix "Data Types and Legacy Implementa-
tions" for additional considerations.


26.8.  API Specification Clarified

RFC 1823 left many things unspecified, including behavior of various
memory disposal functions when a NULL pointer is presented, requirements
for headers, values of many macros, and so on.  This specification is
more complete and generally tighter than the one in RFC 1823.


26.9.  Deprecated Functions

A number of functions that are in RFC 1823 are labeled as "deprecated"
in this specification.  In most cases, a replacement that provides
equivalent functionality has been defined.  The deprecated functions
are:

   ldap_bind()
           Use ldap_simple_bind() or ldap_sasl_bind() instead.

   ldap_bind_s()
           Use ldap_simple_bind_s() or ldap_sasl_bind_s() instead.

   ldap_kerberos_bind() and ldap_kerberos_bind_s()
           No equivalent functions are provided.




Expires: May 2001                                              [Page 78]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   ldap_modrdn() and ldap_modrdn2()
           Use ldap_rename() instead.

   ldap_modrdn_s() and ldap_modrdn2_s()
           Use ldap_rename_s() instead.

   ldap_open()
           Use ldap_init() instead.

   ldap_perror()
           Use ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc ) followed
           by fprintf( stderr, "%s: %s", msg, ldap_err2string( rc ))
           instead.

   ldap_result2error()
           Use ldap_parse_result() instead.


27.  Appendix E - Data Types and Legacy Implementations

The data types associated with the length of a ber value (ber_len_t),
and the tag (ber_tag_t) have been defined in this specification as
unsigned integral types of implementation-specific size.  The data type
used for encoding and decoding ber integer, enumerated, and boolean
values has been defined in this specification as a signed integral type
of implementation-specific size.  This was done so that source and
binary compatibility of the C LDAP API can be maintained across ILP32
environments (where int, long, and pointers are all 32 bits in size) and
LP64 environments (where ints remain 32 bits but longs and pointers grow
to 64 bits).

In older implementations of the C LDAP API, such as those based on RFC
1823, implementors may have chosen to use an `unsigned long' for length
and tag values.  If a long data type was used for either of these items,
a port of an application to a 64-bit operating system using the LP64
data model would find the size of the types used by the C LDAP API to
increase.  Also, if the legacy implementation had chosen to implement
the tag and types as an unsigned int, adoption of a specification that
mandated use of unsigned longs would cause a source incompatibility in
an LP64 application.  By using implementation-specific data types, the C
LDAP API implementation is free to choose the correct data type and the
ability to maintain source compatibility.

For example, suppose a legacy implementation chose to define the return
value of ber_skip_tag() as an unsigned long but wishes to have the
library return a 32-bit quantity in both ILP32 and LP64 data models.
The following typedefs for ber_tag_t will provide a fixed sized data
structure while preserving existing ILP32 source -- all without



Expires: May 2001                                              [Page 79]

C LDAP API        C LDAP Application Program Interface  17 November 2000


generating compiler warnings:
           #include <limits.h>     /* provides UINT_MAX in ISO C */
           #if UINT_MAX >= 0xffffffffU
               typedef unsigned int ber_tag_t;
           #else
               typedef unsigned long ber_tag_t;
           #endif

Similar code can be used to define appropriate ber_len_t, ber_int_t,
ber_slen_t and ber_uint_t types.


28.  Appendix F - Changes Made Since Last Document Revision

The previous version of this document was draft-ietf-ldapext-ldap-c-
api-04.txt, dated 8 October 1999.  This appendix lists all of the
changes made to that document to produce this one.

28.1.  API Changes

   "Header Requirements" section: added requirement that the simple pro-
   gram provided must execute as well as compile without errors.

   "LDAP Session Handle Options" section: changed the name of the
   LDAP_OPT_ERROR_NUMBER option to LDAP_OPT_RESULT_CODE.  Allow
   LDAP_OPT_ON to be defined as an implementation specific value (to
   avoid problems on architectures where the value ((void *)1) is not
   usable).

   "Initializing an LDAP Session" section: allow use of the value zero
   for the `portno' parameter to mean "use port 389."

   "Searching" section: added LDAP_DEFAULT_SIZELIMIT (-1) to allow
   application programmers to use the sizelimit from the LDAP session
   handle with ldap_search_ext() and ldap_search_ext_s().

   "Modifying an entry" section: moved mod_vals union out of LDAPMod and
   added mod_vals_u_t typedef so users of the API can declare variables
   using the union type.  "Handling Errors and Parsing Results" section:
   added text to require that ldap_err2string() MUST NOT return NULL.

   "A Client Control That Governs Referral Processing" section: modified
   the text to specify that a ber_uint_t value should be used to hold
   the flags.







Expires: May 2001                                              [Page 80]

C LDAP API        C LDAP Application Program Interface  17 November 2000


28.2.  Editorial Changes and Clarifications

   "Overview of LDAP API Use and General Requirements" section: added
   text to clarify our use of the term "asynchronous."

   "Retrieving Information During Execution" section: added text
   describing the `ldapai_vendor_name' and `ldapai_vendor_version'
   fields (text was accidently deleted during a previous round of
   edits).

   "LDAP Session Handle Options" section: improved the text that
   describes the LDAP_OPT_TIMELIMIT, LDAP_OPT_SIZELIMIT, and
   LDAP_OPT_RESULT_CODE options.  Provided details and an example of the
   correct LDAP_OPT_HOST_NAME string to return when the `portno' passed
   to ldap_init() is not zero or 389.

   "Result Codes" section: renamed section (was "LDAP Error Codes").

   "Authenticating to the directory" section: clarified that the `dn',
   `cred', and `passwd' parameters can be NULL.  Added text indicate
   that the `servercredp' is set to NULL if an API error occurs.

   "Performing LDAP Operations" section: replaced "All functions take a
   session handle" with "Most functions...."

   "Search" section: removed the detailed discussion of the session han-
   dle options (already covered in the "Retrieving Information During
   Execution" section).  Also removed the word "global" when discussing
   the session default value for the `timeout' parameter.  Also clari-
   fied that a NULL `base' parameter means use a zero-length string for
   the base DN.

   "Comparing a Value Against an Entry" section: corrected the "success-
   ful" return codes for ldap_compare_ext_s() and ldap_compare_s() (was
   LDAP_SUCCESS; changed to LDAP_COMPARE_TRUE or LDAP_COMPARE_FALSE).

   "Extended Operations" section: added text to indicate that the
   `retoidp' and `retdatap' result parameters are set to NULL if an API
   error occurs in ldap_extended_operation_s().

   "Handling Errors and Parsing Results" section: added text to say that
   the `matcheddnp' result parameter will be set to NULL if the server
   does not return a matched DN string.  Added text to indicate that
   serverctrlsp can be NULL.  Added text to indicate that *retoidpp,
   *retdatap, *referralsp, and *serverctrlsp will be set to NULL if no
   items of that type are returned.  Removed specific reference to
   LDAP_NO_SUCH_OBJECT result code when discussing the `matcheddnp'
   result parameter and added clarifying note about "" vs. NULL.



Expires: May 2001                                              [Page 81]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   "Parsing References" section: added text to indicate that *refer-
   ralsp, and *serverctrlsp will be set to NULL if no items of that type
   are returned.

   "Obtaining Results and Peeking Inside LDAP Messages" section: added
   text to say that LDAPMessage chains MAY be tied to a session handle.

   "BER Data Structures and Types" section: removed note about
   ber_uint_t not being used in this document (it is now).  Changed text
   to simplify the description of ber_slen_t.  Removed misleading sen-
   tence about the width of ber_uint_t.

   "Encoded ASN.1 Value Manipulation / Encoding" section: added note
   that 'X' is reserved.  Also fixed a few small bugs in the example
   code.

   "Encoded ASN.1 Value Manipulation / Decoding" section: clarified the
   requirements for LBER_ERROR and LBER_DEFAULT (expressed using octets
   instead of bits).  Also fixed a few small bugs in the example code.

   Added the following text to all descriptions of the `serverctrls' and
   `clientctrls' parameters: ", or NULL if no <server/client> controls
   are to be used."

   Added the following text to the description of all `dn' and `rdn'
   parameters: "If NULL, a zero length DN is sent to the server."

   Replaced many occurrences of the phrase "error code" with "result
   code" throughout the document.

   Added text to indicate that the value of the `msgidp' result parame-
   ter is undefined if an error occurs in the following functions:
   ldap_sasl_bind(), ldap_search_ext(), ldap_compare_ext(),
   ldap_modify_ext(), ldap_add_ext(), ldap_delete_ext(),
   ldap_extended_operation().

   Added text to indicate that the `res' result parameter is set to NULL
   if an API error occurs in the following functions: ldap_result(),
   ldap_search_s(), ldap_search_st().

   Added text to indicate that all result parameters have undefined
   values if an API error is returned by the following functions:
   ldap_parse_result(), ldap_parse_sasl_bind_result(),
   ldap_parse_extended_result(), ldap_parse_reference(), ber_scanf().

   Added angle brackets around ficticious impl_XXX_t types to make it
   more obvious that these are not real "C" types, e.g., typedef
   <impl_len_t> ber_len_t'.



Expires: May 2001                                              [Page 82]

C LDAP API        C LDAP Application Program Interface  17 November 2000


   Appendix B: Added mod_vals_u and removed PLDAP from the struct,
   unions, and typedefs prefix list.

   Appendix C: Added note in "Compatibility" section about extensions
   possible affecting chains of messages and the fact that that must be
   well documented.  Appendix D: Improved text for ldap_perror() (what
   to use instead).

   "Authors" section: updated contact information for Mark Smith, Tim
   Howes, and Mark Wahl.

   Fixed a few obvious typos, improved indentation, added missing blank
   lines, and so on.






































Expires: May 2001                                              [Page 83]

alt-openldap11-devel/drafts/draft-zeilenga-ldap-noop-xx.txt000064400000026707150410163300017634 0ustar00





INTERNET-DRAFT                                      Kurt D. Zeilenga
Intended Category: Standard Track                      Isode Limited
Expires in six months                               14 February 2007



                          The LDAP No-Op Control
                    <draft-zeilenga-ldap-noop-10.txt>


Status of this Memo

  This document is intended to be, after appropriate review and
  revision, submitted to the IESG for consideration as a Standard Track
  document.  Distribution of this memo is unlimited.  Technical
  discussion of this document will take place on the IETF LDAP
  Extensions mailing list <ldapext@ietf.org>.  Please send editorial
  comments directly to the author <Kurt.Zeilenga@Isode.COM>.

  By submitting this Internet-Draft, each author represents that any
  applicable patent or other IPR claims of which he or she is aware have
  been or will be disclosed, and any of which he or she becomes aware
  will be disclosed, in accordance with Section 6 of BCP 79.

  Internet-Drafts are working documents of the Internet Engineering Task
  Force (IETF), its areas, and its working groups. Note that other
  groups may also distribute working documents as Internet-Drafts.

  Internet-Drafts are draft documents valid for a maximum of six months
  and may be updated, replaced, or obsoleted by other documents at any
  time. It is inappropriate to use Internet-Drafts as reference material
  or to cite them other than as "work in progress."

  The list of current Internet-Drafts can be accessed at
  http://www.ietf.org/1id-abstracts.html.

  The list of Internet-Draft Shadow Directories can be accessed at
  http://www.ietf.org/shadow.html.


  Copyright (C) The IETF Trust (2007).  All Rights Reserved.

  Please see the Full Copyright section near the end of this document
  for more information.







Zeilenga                   LDAP No-Op Control                   [Page 1]

INTERNET-DRAFT         draft-zeilenga-ldap-noop-10      14 February 2007


Abstract

  This document defines the Lightweight Directory Access Protocol (LDAP)
  No-Op control which can be used to disable the normal effect of an
  operation.  The control can be used to discover how a server might
  react to a particular update request without updating the directory.


1.  Overview

  It is often desirable to be able to determine if a directory operation
  [RFC4511] would successful complete or not without having the normal
  effect of the operation take place.  For example, an administrative
  client might want to verify that new user could update their entry
  (and not other entries) without the directory actually being updated.
  The mechanism could be used to build more sophisticated security
  auditing tools.

  This document defines the Lightweight Directory Access Protocol (LDAP)
  [RFC4510] No-Op control extension.  The presence of the No-Op control
  in an operation request message disables its normal effect upon the
  directory which operation would otherwise have.  Instead of updating
  the directory and returning the normal indication of success, the
  server does not update the directory and indicates so by returning the
  noOperation resultCode (introduced below).

  For example, when the No-Op control is present in a LDAP modify
  operation [RFC4511], the server is do all processing necessary to
  perform the operation without actually updating the directory.  If it
  detects an error during this processing, it returns a non-success
  (other than noOperation) resultCode as it normally would.  Otherwise,
  it returns the noOperation.  In either case, the directory is left
  unchanged.

  This No-Op control is not intended to be to an "effective access"
  mechanism [RFC2820, U12].


1.1.  Terminology

  The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  document are to be interpreted as described in BCP 14 [RFC2119].

  DN stands for Distinguished Name.
  DSA stands for Directory System Agent.
  DSE stands for DSA-specific entry.




Zeilenga                   LDAP No-Op Control                   [Page 2]

INTERNET-DRAFT         draft-zeilenga-ldap-noop-10      14 February 2007


2.  No-Op Control

  The No-Op control is an LDAP Control [RFC4511] whose controlType is
  IANA-ASSIGNED-OID and controlValue is absent.  Clients MUST provide a
  criticality value of TRUE to prevent unintended modification of the
  directory.

  The control is appropriate for request messages of LDAP Add, Delete,
  Modify and ModifyDN operations [RFC4511].  The control is also
  appropriate for requests of extended operations which update the
  directory (or other data stores), such as Password Modify Extended
  Operation [RFC3062].  There is no corresponding response control.

  When the control is attached to an LDAP request, the server does all
  normal processing possible for the operation without modification of
  the directory.  That is, when the control is attached to an LDAP
  request, the directory SHALL NOT be updated and the response SHALL NOT
  have a resultCode of success (0).

  A result code other than noOperation (IANA-ASSIGNED-CODE) means that
  the server is unable or unwilling to complete the processing for the
  reason indicated by the result code.  A result code of noOperation
  (IANA-ASSIGNED-CODE) indicates that the server discovered no reason
  why the operation would fail if submitted without the No-Op control.
  It is noted that there may be reasons why the operation may fail which
  are only discoverable when submitting without the No-Op control.

  Servers SHOULD indicate their support for this control by providing
  IANA-ASSIGNED-OID as a value of the 'supportedControl' attribute type
  [RFC4512] in their root DSE entry.  A server MAY choose to advertise
  this extension only when the client is authorized to use this
  operation.


3.  Security Considerations

  The No-Op control mechanism allows directory administrators and users
  to verify that access control and other administrative policy controls
  are properly configured.  The mechanism may also lead to the
  development (and deployment) of more effective security auditing
  tools.

  Implementors of this LDAP extension should be familiar with security
  considerations applicable to the LDAP operations [RFC4511] extended by
  this control, as well as general LDAP security considerations
  [Roadmap].





Zeilenga                   LDAP No-Op Control                   [Page 3]

INTERNET-DRAFT         draft-zeilenga-ldap-noop-10      14 February 2007


4.  IANA Considerations

4.1.  Object Identifier

  It is requested that IANA assign an LDAP Object Identifier [RFC4520]
  to identify the LDAP No-Op Control defined in this document.

      Subject: Request for LDAP Object Identifier Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Specification: RFC XXXX
      Author/Change Controller: IESG
      Comments:
          Identifies the LDAP No-Op Control


4.2  LDAP Protocol Mechanism

  Registration of this protocol mechanism is requested [RFC4520].

  Subject: Request for LDAP Protocol Mechanism Registration
  Object Identifier: IANA-ASSIGNED-OID
  Description: No-Op Control
  Person & email address to contact for further information:
      Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
  Usage: Control
  Specification: RFC XXXX
  Author/Change Controller: IESG
  Comments: none


4.3  LDAP Result Code

  Assignment of an LDAP Result Code called 'noOperation' is requested.

      Subject: LDAP Result Code Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Result Code Name: noOperation
      Specification: RFC XXXX
      Author/Change Controller: IESG
      Comments:  none


5.  Author's Address

  Kurt D. Zeilenga
  Isode Limited



Zeilenga                   LDAP No-Op Control                   [Page 4]

INTERNET-DRAFT         draft-zeilenga-ldap-noop-10      14 February 2007


  Email: Kurt.Zeilenga@Isode.COM


6. References

  [[Note to the RFC Editor: please replace the citation tags used in
  referencing Internet-Drafts with tags of the form RFCnnnn where
  possible.]]


6.1. Normative References

  [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                Requirement Levels", BCP 14 (also RFC 2119), March 1997.

  [RFC4510]     Zeilenga, K. (editor), "LDAP: Technical Specification
                Road Map", RFC 4510, June 2006.

  [RFC4511]     Sermersheim, J. (editor), "LDAP: The Protocol", RFC
                4511, June 2006.

  [RFC4512]     Zeilenga, K. (editor), "LDAP: Directory Information
                Models", RFC 4512, June 2006.


6.2. Informative References

  [X.500]       International Telecommunication Union -
                Telecommunication Standardization Sector, "The Directory
                -- Overview of concepts, models and services,"
                X.500(1993) (also ISO/IEC 9594-1:1994).

  [RFC2820]     Stokes, E., et. al., "Access Control Requirements for
                LDAP", RFC 2820, May 2000.

  [RFC3062]     Zeilenga, K., "LDAP Password Modify Extended Operation",
                RFC 3062, February 2000.

  [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                (IANA) Considerations for the Lightweight Directory
                Access Protocol (LDAP)", RFC 4520, BCP 64, June 2006.



Intellectual Property

  The IETF takes no position regarding the validity or scope of any
  Intellectual Property Rights or other rights that might be claimed to



Zeilenga                   LDAP No-Op Control                   [Page 5]

INTERNET-DRAFT         draft-zeilenga-ldap-noop-10      14 February 2007


  pertain to the implementation or use of the technology described in
  this document or the extent to which any license under such rights
  might or might not be available; nor does it represent that it has
  made any independent effort to identify any such rights.  Information
  on the procedures with respect to rights in RFC documents can be found
  in BCP 78 and BCP 79.

  Copies of IPR disclosures made to the IETF Secretariat and any
  assurances of licenses to be made available, or the result of an
  attempt made to obtain a general license or permission for the use of
  such proprietary rights by implementers or users of this specification
  can be obtained from the IETF on-line IPR repository at
  http://www.ietf.org/ipr.

  The IETF invites any interested party to bring to its attention any
  copyrights, patents or patent applications, or other proprietary
  rights that may cover technology that may be required to implement
  this standard.  Please address the information to the IETF at
  ietf-ipr@ietf.org.



Full Copyright

  Copyright (C) The IETF Trust (2007).

  This document is subject to the rights, licenses and restrictions
  contained in BCP 78, and except as set forth therein, the authors
  retain all their rights.

  This document and the information contained herein are provided on an
  "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.














Zeilenga                   LDAP No-Op Control                   [Page 6]

alt-openldap11-devel/drafts/draft-zeilenga-ldap-relax.txt000064400000054677150410163310017347 0ustar00





INTERNET-DRAFT                                   Kurt D. Zeilenga
Intended Category: Experimental                  Isode Limited
Expires in six months                            14 February 2007



                       The LDAP Relax Rules Control
                    <draft-zeilenga-ldap-relax-01.txt>


Status of this Memo

  This document is intended to be, after appropriate review and
  revision, submitted to the RFC Editor for publication as an
  Experimental document.   Distribution of this memo is unlimited.
  Technical discussion of this document will take place on the IETF LDAP
  Extensions mailing list <ldapext@ietf.org>.  Please send editorial
  comments directly to the author <Kurt.Zeilenga@Isode.COM>.

  This document replaces draft-zeilenga-ldap-managedit-xx.txt.

  By submitting this Internet-Draft, each author represents that any
  applicable patent or other IPR claims of which he or she is aware have
  been or will be disclosed, and any of which he or she becomes aware
  will be disclosed, in accordance with Section 6 of BCP 79.

  Internet-Drafts are working documents of the Internet Engineering Task
  Force (IETF), its areas, and its working groups. Note that other
  groups may also distribute working documents as Internet-Drafts.

  Internet-Drafts are draft documents valid for a maximum of six months
  and may be updated, replaced, or obsoleted by other documents at any
  time. It is inappropriate to use Internet-Drafts as reference material
  or to cite them other than as "work in progress."

  The list of current Internet-Drafts can be accessed at
  http://www.ietf.org/1id-abstracts.html.

  The list of Internet-Draft Shadow Directories can be accessed at
  http://www.ietf.org/shadow.html.


  Copyright (C) The IETF Trust (2007).  All Rights Reserved.

  Please see the Full Copyright section near the end of this document
  for more information.





Zeilenga                LDAP Relax Rules Control                [Page 1]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


Abstract

  This document defines the Lightweight Directory Access Protocol (LDAP)
  Relax Rules Control which allows a directory user agent (a client) to
  request the directory service temporarily relax enforcement of various
  data and service model rules.


1.  Background and Intended Use

  Directory servers accessible via Lightweight Directory Access Protocol
  (LDAP) [RFC4510] are expected to act in accordance with the X.500
  [X.500] series of ITU-T Recommendations.  In particular, servers are
  expected to ensure the X.500 data and service models are not violated.

  An LDAP server is expected to prevent modification of the structural
  object class of an object [RFC4512].  That is, the X.500 models do not
  allow a 'person' object to be transformed into an
  'organizationalPerson' object through modification of the object.
  Instead, the 'person' object must be deleted and then a new
  'organizationalPerson' object created in its place.  This approach,
  aside from being inconvient, is problematic for a number reasons.
  First, as LDAP does not have a standardized method for performing the
  two operations in a single transaction, the intermediate directory
  state (after the delete, before the add) is visible to other clients,
  which may lead to undesirable client behavior.  Second, attributes
  such as 'entryUUID' [RFC4530] will reflect the object was replaced,
  not transformed.

  An LDAP server is expected to prevent clients from modifying values of
  NO-USER-MODIFICATION attributes [RFC4512].  For instance, an entry is
  not allowed to assign or modify the value of the 'entryUUID'
  attribute.  However, where an administrator is restoring a previously
  existing object, for instance when repartitioning data between
  directory servers or when migrating from one vendor server product to
  another, it may be desirable to allow the client to assign or modify
  the value of the 'entryUUID' attribute.

  This document defines the LDAP Relax Rules control.  This control may
  be attached to LDAP requests to update the Directory Information Tree
  (DIT) to request various data and service rules be temporarily relaxed
  during the performance of the requested DIT update.  The server is
  however to ensure the resulting directory state is valid.

  Use of this control is expected that use of this extension will be
  restricted by administrative and/or access controls.  It is intended
  to be used primarily by directory administrators.




Zeilenga                LDAP Relax Rules Control                [Page 2]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


  This extension is considered experimental as it is not yet clear
  whether it adequately addresses directory administrators' needs for
  flexible mechanisms for managing directory objects.  It is hoped that
  after suitable amount of time, either this extension or a suitable
  replacement will be standardization.


1.1. Terminology

  Protocol elements are described using ASN.1 [X.680] with implicit
  tags.  The term "BER-encoded" means the element is to be encoded using
  the Basic Encoding Rules [X.690] under the restrictions detailed in
  Section 5.1 of [RFC4511].

  The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  document are to be interpreted as described in BCP 14 [RFC2119].

  DSA stands for Directory System Agent, a server.  DSE stands for
  DSA-specific Entry.


2.  The Relax Rules Control

  The Relax Rules control is an LDAP Control [RFC4511] whose controlType
  is IANA-ASSIGNED-OID, controlValue is empty, and the criticality of
  TRUE.

  There is no corresponding response control.

  The control is appropriate for all LDAP update requests, including
  add, delete, modify, and modifyDN (rename) [RFC4511].

  The presence of the Rules Rules control in an LDAP update request
  indicates the server temporarily relax X.500 model contraints during
  performance of the directory update.

  The server may restrict use of this control and/or limit the extent of
  the relaxation provided based upon local policy or factors.

  The server is obligated to ensure the resulting directory state is
  consistent with the X.500 models.  For instance, the server ensure
  that values of attributes conform to the value syntax.

  It is noted that while this extension may be used to add or modify
  objects in a manner which violate the controlling subschema, the
  presence of objects in the DIT is not inconsistent with the X.500
  models.  For instance, an object created prior to establshment of a



Zeilenga                LDAP Relax Rules Control                [Page 3]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


  DIT content rule may contain an attribute now precluded by the current
  controlling DIT Content Rule.

  Servers implementing this technical specification SHOULD publish the
  object identifier IANA-ASSIGNED-OID as a value of the
  'supportedControl' attribute [RFC4512] in their root DSE.  A server
  MAY choose to advertise this extension only when the client is
  authorized to use it.


3.  Use Cases

3.1. Object metamorphism

  In absence of this control, an attempt to modify an object's
  'objectClass' in a manner which cause a change in the structural
  object class of the object would normally lead to an
  objectClassModsProhibited error [RFC4511].  The presence of the Relax
  Rules control in the modify request requests the change be allowed.
  If the server is willing and able to allow the change in the
  structural object class of the object.

  For instance, to change an 'organization' object into an
  'organizationalUnit' object, a client could issue the following LDAP
  request:

      dn: o=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: modify
      delete: objectClass
      objectClass: organization
      -
      add: objectClass
      objectClass: organizationalUnit
      -

  In this case, the server is expected to either effect the requested
  change in the structural object class, including updating of the value
  of the structural object class, or fail the operation.


3.2. Inactive Attribute Types

  In absence of the Relax Rules control, an attempt to add or modify
  values to an attribute whose type has been marked inactive in the
  controlling subschema (its attribute type description contains the
  OBSOLETE field) [RFC4512] normally results in a failure.




Zeilenga                LDAP Relax Rules Control                [Page 4]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


  In the presence of the Relax Rules control, the server performs the
  update operation as if the attribute's type is marked active in the
  controlling subschema (its attribute type description does not contain
  the OBSOLETE field).


3.3. DIT Content Rules

  In absence of the Relax Rules control, an attempt to include the name
  (or OID) of an auxiliary class to an object's 'objectClass' which is
  not allowed by the controlling DIT Content Rule would be disallowed
  [RFC4512].   Additionally, an attempt to add values of an attribute
  not allowed (or explicitly precluded) by the DIT Content Rule would
  fail.

  In presence of the Relax Rules control, the server performs the update
  operation as if the controlling DIT Content Rule allowed any and all
  known auxiliary classses to be present and allowed any and all known
  attributes to be present (and precluded no attributes).


3.4. DIT Structure Rules and Name Forms

  In absence of the Relax Rules control, the service enforces DIT
  structure rules and name form requirements of the controlling
  subschema [RFC4512].

  In the presence of the Relax Rules control, the server performs the
  update operation ignoring all DIT structure rules and name forms in
  the controlling subschema.


3.5. Modification of Nonconformant Objects

  It is also noted that in absense of this control, modification of an
  object which presently violates the controlling subschema will fail
  unless the modification would result in the object conforming to the
  controlling subschema.  That is, modifications of an non-conformant
  object should result in a conformant object.

  In the presence of this control, modifications of a non-conformant
  object need not result in a conformant object.


3.6. NO-USER-MODIFICATION attribute modification

  In absence of this control, an attempt to modify values of a
  NO-USER-MODIFICATION attribute [RFC4512] would normally lead to a



Zeilenga                LDAP Relax Rules Control                [Page 5]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


  constraintViolation or other appropriate error [RFC4511].  In the
  presence of the Relax Rules control in the update request requests the
  modification be allowed.

  Relaxation of the NO-USER-MODIFICATION constraint is not appropriate
  for some operational attribute types. For instance, as the value of
  the 'structuralObjectClass' is derived by the values of the
  'objectClass' attribute, the 'structuralObjectClass' attribute type's
  NO-USER-MODIFICATION contraint MUST NOT be relaxed.  To effect a
  change in the structuralObjectClass class, values of objectClass
  should be changed as discussed in Section 3.1.  Other attributes for
  which the NO-USER-MODIFICATION constraint should not be relaxed
  include 'subschemaSubentry' [RFC4512] and
  'collectiveAttributeSubentries' [RFC3671].

  The subsections of this section discuss modification of various
  operational attributes where their NO-USER-MODIFICATION constraint may
  be relaxed.  Future documents may specify where NO-USER-MODIFICATION
  constraints on other operational attribute may be relaxed.  In absence
  of a document detailing that the NO-USER-MODIFICATION constraint on a
  particular operational attribute may be relaxed, implementors SHOULD
  assume relaxation of the constraint is not appropriate for that
  attribute.


3.1.1. 'entryUUID' attribute

  To provide a value for the 'entryUUID' [RFC4530] attribute on entry
  creation, the client should issue an LDAP Add request with a Relax
  Rules control providing the desired value.  For instance:

      dn: ou=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: add
      objectClass: organizationalUnit
      ou: Unit
      entryUUID: 597ae2f6-16a6-1027-98f4-d28b5365dc14

  In this case, the server is either to add the entry using the
  provided 'entryUUID' value or fail the request.

  To provide a replacement value for the 'entryUUID' after entry
  creation, the client should issue an LDAP Modify request with a
  Relax Rules control including an approrpiate change.  For instance:

      dn: ou=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: modify



Zeilenga                LDAP Relax Rules Control                [Page 6]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


      replace: entryUUID
      entryUUID: 597ae2f6-16a6-1027-98f4-d28b5365dc14
      -

  In this case, the server is either to replace the 'entryUUID' value
  as requested or fail the request.


3.2.2. createTimestamp

  To provide a value for the 'createTimestamp' [RFC4512] attribute
  on entry creation, the client should issue an LDAP Add request with
  a Relax Rules control providing the desired 'createTimestamp'
  value.  For instance:

      dn: ou=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: add
      objectClass: organizationalUnit
      ou: Unit
      createTimestamp: 20060101000000Z

  In this case, the server is either to add the entry using the
  provided 'createTimestamp' value or fail the request.

  To provide a replacement value for the 'createTimestamp' after
  entry creation, the client should issue an LDAP Modify request with
  a Relax Rules control including an approrpiate change.  For instance:

      dn: ou=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: modify
      replace: createTimestamp
      createTimestamp: 20060101000000Z
      -

  In this case, the server is either to replace the 'createTimestamp'
  value as requested or fail the request.

  The server should ensure the requested 'createTimestamp' value is
  appropriate.  In particular, it should fail the request if the
  requested 'createTimestamp' value is in the future or is greater
  than the value of the 'modifyTimestamp' attribute.


3.2.3. modifyTimestamp

  To provide a value for the 'modifyTimestamp' [RFC4512] attribute



Zeilenga                LDAP Relax Rules Control                [Page 7]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


  on entry creation, the client should issue an LDAP Add request with
  a Relax Rules control providing the desired 'modifyTimestamp'
  value.  For instance:

      dn: ou=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: add
      objectClass: organizationalUnit
      ou: Unit
      modifyTimestamp: 20060101000000Z

  In this case, the server is either to add the entry using
  the provided 'modifyTimestamp' value or fail the request.

  To provide a replacement value for the 'modifyTimestamp' after
  entry creation, the client should issue an LDAP Modify
  request with a Relax Rules control including an approrpiate
  change.  For instance:

      dn: ou=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: modify
      replace: modifyTimestamp
      modifyTimestamp: 20060101000000Z
      -

  In this case, the server is either to replace the 'modifyTimestamp'
  value as requested or fail the request.

  The server should ensure the requested 'modifyTimestamp' value is
  appropriate.  In particular, it should fail the request if the
  requested 'modifyTimestamp' value is in the future or is less than
  the value of the 'createTimestamp' attribute.


  3.2.3. creatorsName and modifiersName

  To provide a value for the 'creatorsName' and/or 'modifiersName'
  [RFC4512] attribute on entry creation, the client should issue an
  LDAP Add request with a Relax Rules control providing the desired
  values.  For instance:

      dn: ou=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: add
      objectClass: organizationalUnit
      ou: Unit
      creatorsName: cn=Jane Doe,dc=example,net



Zeilenga                LDAP Relax Rules Control                [Page 8]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


      modifiersName: cn=Jane Doe,dc=example,net

  In this case, the server is either to add the entry using
  the provided values or fail the request.

  To provide a replacement values after entry creation for either of
  the 'creatorsName' or 'modifiersName' attributes or both, the
  client should issue an LDAP Modify request with a Relax Rules control
  including the approrpiate changes.  For instance:

      dn: ou=Unit,dc=example,dc=net
      control: IANA-ASSIGNED-OID
      changetype: modify
      replace: creatorsName
      creatorsName: cn=Jane Doe,dc=example,net
      -
      replace: modifiersName
      modifiersName: cn=Jane Doe,dc=example,net
      -

  In this case, the server is either to replace the provided
  values as requested or fail the request.


4.  Security Considerations

  Use of this extension should be subject to appropriate administrative
  and access controls.  Use of this mechanism is intended to be
  restricted to directory administrators.

  Security considerations for the base operations [RFC4511] extended
  by this control, as well as general LDAP security considerations
  [RFC4510], generally apply to implementation and use of this
  extension.


5.  IANA Considerations

5.1.  Object Identifier

  It is requested that the IANA assign a LDAP Object Identifier
  [RFC4520] to identify the LDAP Relax Rules Control defined in this
  document.

      Subject: Request for LDAP Object Identifier Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Specification: RFC XXXX



Zeilenga                LDAP Relax Rules Control                [Page 9]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


      Author/Change Controller: Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Comments: Identifies the LDAP Relax Rules Control

5.2  LDAP Protocol Mechanism

  Registration of this protocol mechanism [RFC4520] is requested.

      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: IANA-ASSIGNED-OID
      Description: Relax Rules Control
      Person & email address to contact for further information:
          Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Usage: Control
      Specification: RFC XXXX
      Author/Change Controller: Kurt Zeilenga <Kurt.Zeilenga@Isode.COM>
      Comments: none


6.  Author's Address

  Kurt D. Zeilenga
  Isode Limited

  Email: Kurt.Zeilenga@Isode.COM


7. References

  [[Note to the RFC Editor: please replace the citation tags used in
  referencing Internet-Drafts with tags of the form RFCnnnn where
  possible.]]


7.1. Normative References

  [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                Requirement Levels", BCP 14 (also RFC 2119), March 1997.

  [RFC3671]     Zeilenga, K., "Collective Attributes in LDAP", RFC 3671,
                December 2003.

  [RFC4510]     Zeilenga, K. (editor), "LDAP: Technical Specification
                Road Map", RFC 4510, June 2006.

  [RFC4511]     Sermersheim, J. (editor), "LDAP: The Protocol", RFC
                4511, June 2006.

  [RFC4512]     Zeilenga, K. (editor), "LDAP: Directory Information



Zeilenga                LDAP Relax Rules Control               [Page 10]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


                Models", RFC 4512, June 2006.

  [RFC4530]     Zeilenga, K., "Lightweight Directory Access Protocol
                (LDAP) entryUUID Operational Attribute", RFC 4530, June
                2006.

  [X.500]       International Telecommunication Union -
                Telecommunication Standardization Sector, "The Directory
                -- Overview of concepts, models and services,"
                X.500(1993) (also ISO/IEC 9594-1:1994).


7.2. Informative References

  [RFC4520]     Zeilenga, K., "Internet Assigned Numbers Authority
                (IANA) Considerations for the Lightweight Directory
                Access Protocol (LDAP)", RFC 4520, BCP 64, June 2006.



Intellectual Property

  The IETF takes no position regarding the validity or scope of any
  Intellectual Property Rights or other rights that might be claimed to
  pertain to the implementation or use of the technology described in
  this document or the extent to which any license under such rights
  might or might not be available; nor does it represent that it has
  made any independent effort to identify any such rights.  Information
  on the procedures with respect to rights in RFC documents can be found
  in BCP 78 and BCP 79.

  Copies of IPR disclosures made to the IETF Secretariat and any
  assurances of licenses to be made available, or the result of an
  attempt made to obtain a general license or permission for the use of
  such proprietary rights by implementers or users of this specification
  can be obtained from the IETF on-line IPR repository at
  http://www.ietf.org/ipr.

  The IETF invites any interested party to bring to its attention any
  copyrights, patents or patent applications, or other proprietary
  rights that may cover technology that may be required to implement
  this standard.  Please address the information to the IETF at
  ietf-ipr@ietf.org.



Full Copyright




Zeilenga                LDAP Relax Rules Control               [Page 11]

INTERNET-DRAFT        draft-zeilenga-ldap-relax-01      14 February 2007


  Copyright (C) The IETF Trust (2007).

  This document is subject to the rights, licenses and restrictions
  contained in BCP 78, and except as set forth therein, the authors
  retain all their rights.

  This document and the information contained herein are provided on an
  "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
  OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
  THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
  THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
  WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.






































Zeilenga                LDAP Relax Rules Control               [Page 12]

alt-openldap11-devel/drafts/draft-masarati-ldap-whatfailed-xx.txt000064400000031134150410163310020763 0ustar00


Network Working Group                                        P. Masarati
Internet-Draft                                     Politecnico di Milano
Intended status: Standards Track                       November 19, 2008
Expires: May 23, 2009


                      LDAP "What Failed?" Control
                 draft-masarati-ldap-whatfailed-00.txt

Status of this Memo

   By submitting this Internet-Draft, each author represents that any
   applicable patent or other IPR claims of which he or she is aware
   have been or will be disclosed, and any of which he or she becomes
   aware will be disclosed, in accordance with Section 6 of BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on May 23, 2009.


















Masarati                  Expires May 23, 2009                  [Page 1]

Internet-Draft               LDAP WHATFAILED               November 2008


Abstract

   This document describes the LDAP "What Failed?" control.  This
   control allows DUAs to request, in response to a failed operation
   request, the object identifier of those extensions that caused the
   operation to fail.


Table of Contents

   1.  Background and Intended Use  . . . . . . . . . . . . . . . . .  3
   2.  LDAP "What Failed?" Control  . . . . . . . . . . . . . . . . .  4
     2.1.  Control Semantics  . . . . . . . . . . . . . . . . . . . .  4
     2.2.  Control Request  . . . . . . . . . . . . . . . . . . . . .  4
     2.3.  Control Response . . . . . . . . . . . . . . . . . . . . .  5
   3.  Implementation Notes . . . . . . . . . . . . . . . . . . . . .  6
   4.  Security Considerations  . . . . . . . . . . . . . . . . . . .  7
   5.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . .  8
     5.1.  Object Identifier Registration . . . . . . . . . . . . . .  8
   6.  Acknowledgments  . . . . . . . . . . . . . . . . . . . . . . .  9
   7.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 10
     7.1.  Normative References . . . . . . . . . . . . . . . . . . . 10
     7.2.  Informative References . . . . . . . . . . . . . . . . . . 10
   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 11
   Intellectual Property and Copyright Statements . . . . . . . . . . 12


























Masarati                  Expires May 23, 2009                  [Page 2]

Internet-Draft               LDAP WHATFAILED               November 2008


1.  Background and Intended Use

   The LDAP Protocol [RFC4510] is extensible.  Extensions include
   controls, extended requests and extensions related to other aspects
   of the protocol, for example those described in [RFC4526], [RFC4529]
   and more.

   Operations may fail for different reasons.  The resultCode may help
   in determining the reason of a failure.  The (optional)
   diagnosticsMessage fields of a LDAPResponse could also be of help.
   However, according to [RFC4511], implementations MUST NOT rely on the
   returned values, which are simply intended to be presented as are to
   human users.

   In case of failure related to the inability to process a control
   marked as critical in a request, the specific resultCode
   unavailableCriticalExtension is returned.  In case of failure related
   to an unrecognized extendedReq, the generic resultCode protocolError
   is returned.  Failures related to handling other extensions may
   result in other generic resultCode values.

   As a consequence, DUAs may be unable to exactly determine what
   extension, if any, caused a failure.  The "What Failed?" control
   represents a means for the DSA to inform DUAs about what specific
   extensions, if any, caused an error notified by the DSA.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in [RFC2119].






















Masarati                  Expires May 23, 2009                  [Page 3]

Internet-Draft               LDAP WHATFAILED               November 2008


2.  LDAP "What Failed?" Control

2.1.  Control Semantics

   The presence of the "What Failed?"  LDAP control in a LDAP request
   indicates that the DUA, in case of error, wishes to receive detailed
   information about what extension, if any, caused the error.

   The criticality of the control in the request SHOULD be FALSE.
   According to the semantics of the criticality field as indicated in
   [RFC4511], this ensures that in case the control is not recognized by
   the DSA, it does not cause itself an error.

   The presence of this control in a request does not guarantee that the
   DSA will return detailed information about what extensions caused an
   error.  Considering the requirement on the criticality of the
   control, the DSA MAY simply choose to ignore the control.  The DSA
   MAY hide information about failure in handling an extension to
   prevent disclosure of other information.  The DSA MAY choose to
   notify an error as soon as it is detected, instead of proceed
   checking its ability to handle any other extension present in a
   request.

   Implementations may choose to check the validity of extensions,
   including controls, as soon as they are parsed.  As a consequence, a
   critical control might result in an error before thw "What Failed?"
   control request is parsed.  Implementations SHOULD check anyway the
   presence of this control, unless they detect that the remaining part
   of the request is malformed.  Clients SHOULD NOT rely on any specific
   ordering of controls handling when requesting the "What Failed?"
   control.

   Servers implementing this technical specification SHOULD publish the
   object identifier whatFailed-oid (IANA assigned; see Section 5) as a
   value of the 'supportedControl' attribute [RFC4512] in their root
   DSE.

2.2.  Control Request

   The controlType is whatFailed-oid (IANA assigned; see Section 5); the
   controlValue MUST be absent; the criticality SHOULD be FALSE.










Masarati                  Expires May 23, 2009                  [Page 4]

Internet-Draft               LDAP WHATFAILED               November 2008


2.3.  Control Response

   The controlType is whatFailed-oid (IANA assigned; see Section 5); the
   controlValue is:

       controlValue ::= SET OF oid LDAPOID

   If the set of extension OID is empty, the control is omitted from the
   response.  The criticality MUST be FALSE.










































Masarati                  Expires May 23, 2009                  [Page 5]

Internet-Draft               LDAP WHATFAILED               November 2008


3.  Implementation Notes

   The "What Failed?"  LDAP Control is implemented in OpenLDAP software
   using the temporary OID 1.3.6.1.4.1.4203.666.5.17 under OpenLDAP's
   experimental OID arc.














































Masarati                  Expires May 23, 2009                  [Page 6]

Internet-Draft               LDAP WHATFAILED               November 2008


4.  Security Considerations

   Implementations MUST take measures to prevent the disclosure of
   sensible information whenever this may result from disclosing what
   extension caused an error.  This can consist in excluding the OID of
   specific extensions from the controlValue in the response, or in
   entirely omitting the control in the response.












































Masarati                  Expires May 23, 2009                  [Page 7]

Internet-Draft               LDAP WHATFAILED               November 2008


5.  IANA Considerations

5.1.  Object Identifier Registration

   It is requested that IANA register upon Standards Action an LDAP
   Object Identifier for use in this technical specification.

         Subject: Request for LDAP OID Registration
         Person & email address to contact for further information:
             Pierangelo Masarati <ando@OpenLDAP.org>
         Specification: (I-D)
         Author/Change Controller: IESG
         Comments:
             Identifies the LDAP "What Failed?" Control request
             and response




































Masarati                  Expires May 23, 2009                  [Page 8]

Internet-Draft               LDAP WHATFAILED               November 2008


6.  Acknowledgments


















































Masarati                  Expires May 23, 2009                  [Page 9]

Internet-Draft               LDAP WHATFAILED               November 2008


7.  References

7.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4510]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC 4510,
              June 2006.

   [RFC4511]  Sermersheim, J., "Lightweight Directory Access Protocol
              (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512,
              June 2006.

7.2.  Informative References

   [RFC4526]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP) Absolute True and False Filters", RFC 4526,
              June 2006.

   [RFC4529]  Zeilenga, K., "Requesting Attributes by Object Class in
              the Lightweight Directory Access Protocol", RFC 4529,
              June 2006.
























Masarati                  Expires May 23, 2009                 [Page 10]

Internet-Draft               LDAP WHATFAILED               November 2008


Author's Address

   Pierangelo Masarati
   Politecnico di Milano
   Dipartimento di Ingegneria Aerospaziale
   via La Masa 34
   Milano  20156
   IT

   Phone: +39 02 2399 8309
   Fax:   +39 02 2399 8334
   Email: ando@OpenLDAP.org
   URI:   http://www.aero.polimi.it/masarati/






































Masarati                  Expires May 23, 2009                 [Page 11]

Internet-Draft               LDAP WHATFAILED               November 2008


Full Copyright Statement

   Copyright (C) The IETF Trust (2008).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.











Masarati                  Expires May 23, 2009                 [Page 12]

alt-openldap11-devel/drafts/draft-chu-ldap-csn-xx.txt000064400000033077150410163310016424 0ustar00





INTERNET-DRAFT                                      Howard Y. Chu
Intended Category: Standard Track                   Symas Corporation
Expires in six months                               1 December 2004


                     Change Sequence Numbers for LDAP
                       <draft-chu-ldap-csn-00.txt>


Status of this Memo

  This document is an Internet-Draft and is in full conformance with all
  provisions of Section 10 of RFC2026.

  This document is intended to be, after appropriate review and
  revision, submitted to the RFC Editor as an Standard Track document.
  Distribution of this memo is unlimited.  Technical discussion of this
  document will take place on the IETF LDAP Extensions mailing list
  <ldapext@ietf.org>.  Please send editorial comments directly to the
  author <Kurt@OpenLDAP.org>.

  Internet-Drafts are working documents of the Internet Engineering Task
  Force (IETF), its areas, and its working groups.  Note that other
  groups may also distribute working documents as Internet-Drafts.
  Internet-Drafts are draft documents valid for a maximum of six months
  and may be updated, replaced, or obsoleted by other documents at any
  time.  It is inappropriate to use Internet-Drafts as reference
  material or to cite them other than as ``work in progress.''

  The list of current Internet-Drafts can be accessed at
  <http://www.ietf.org/ietf/1id-abstracts.txt>. The list of
  Internet-Draft Shadow Directories can be accessed at
  <http://www.ietf.org/shadow.html>.

  Copyright (C) The Internet Society (2004).  All Rights Reserved.

  Please see the Full Copyright section near the end of this document
  for more information.


Abstract

  This document describes the LDAP/X.500 Change Sequence Number 'CSN'
  syntax and matching rules and associated attributes. CSNs are used
  to impose a total ordering upon the sequence of updates applied
  to a directory.




Chu               draft-chu-ldap-csn-00              [Page 1]

INTERNET-DRAFT               LDAP CSN                    1 December 2004


1. Background and Intended Use

  In X.500 Directory Services [X.501], updates to a directory may need
  to be distributed to multiple servers. The 'modifyTimeStamp' is already
  defined for recording the time of an update, but it may be inadequate in
  an environment where multiple servers with loosely synchronized clocks
  are interoperating.

  This document describes the 'CSN' syntax which augments a timestamp with
  additional information to assist in coordinating updates among multiple
  directory servers. This document describes the 'entryCSN' operational
  attribute which carries the CSN of the last update applied to an entry
  and also the 'contextCSN' operational attribute which carries the
  greatest CSN of all updates applied to a directory context. Directory
  clients and servers may use these attributes to assist in synchronizing
  shadowed copies of directory information.

  This document describes the 'csnMatch' and 'csnOrderingMatch' matching
  rules corresponding to the 'CSN' syntax. 

  The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
  "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
  document are to be interpreted as described in BCP 14 [RFC2119].

  Schema definitions are provided using LDAP description formats
  [RFC2252].  Definitions provided here are formatted (line wrapped) for
  readability.


2. CSN Schema Elements

2.1 CSN Syntax

  Values in this syntax are encoded according to the following BNF:

  CSN = timestamp '#' operation-counter '#' replica-id 

  timestamp = <generalizedTimeString as specified in 6.14 of [RFC2252]>

  operation-counter = 6hex-digit

  replica-id = 2hex-digit

  The timestamp SHALL use GMT and SHALL NOT include fractional seconds.

  The operation-counter is set to zero at the start of each second, and
  incremented by one for each update operation that occurs within that
  second.

  The replica-id is an identifier that represents a specific Replica in
  a collection of cooperating servers.

  The following is a LDAP syntax description [RFC2252] suitable for
  publication in the subschema.

      ( IANA-ASSIGNED-OID.1 DESC 'CSN' )





Chu               draft-chu-ldap-csn-00              [Page 2]

INTERNET-DRAFT               LDAP CSN                    1 December 2004


2.2 'csnMatch' Matching Rule

  The 'csnMatch' matching rule compares an asserted CSN with a stored
  CSN for equality.  Its semantics are same as the octetStringMatch
  [X.520][RFC2252] matching rule.

  The following is a LDAP matching rule description [RFC2252] suitable
  for publication in the subschema.

      ( IANA-ASSIGNED-OID.2 NAME 'csnMatch'
          SYNTAX IANA-ASSIGNED-OID.1 )


2.3 'csnOrderingMatch' Matching Rule

  The 'csnOrderingMatch' matching rule compares an asserted CSN
  with a stored CSN for ordering.  Its semantics are the same as the
  octetStringOrderingMatch [X.520][RFC2252] matching rule.

  The following is a LDAP matching rule description [RFC2252] suitable
  for publication in the subschema.

      ( IANA-ASSIGNED-OID.3 NAME 'csnOrderingMatch'
          SYNTAX IANA-ASSIGNED-OID.1 )


2.4. 'entryCSN' attribute

  The 'entryCSN' operational attribute provides the CSN of the last
  update applied to the entry.

  The following is a LDAP attribute type description [RFC2252] suitable
  for publication in the subschema.

      ( IANA-ASSIGNED-OID.4 NAME 'entryCSN'
          DESC 'CSN of the entry content'
          EQUALITY csnMatch
          ORDERING csnOrderingMatch



Chu               draft-chu-ldap-csn-00              [Page 3]

INTERNET-DRAFT               LDAP CSN                    1 December 2004


          SYNTAX IANA-ASSIGNED-OID.1
          SINGLE-VALUE
          NO-USER-MODIFICATION
          USAGE directoryOperation )

  Servers SHALL assign a CSN to each entry upon its addition to the
  directory  and provide the entry's CSN as the value of the
  'entryCSN' operational attribute.  The entryCSN attribute SHOULD be
  updated upon every update of the entry.

2.5. 'contextCSN' attribute

  The 'contextCSN' operational attribute provides the greatest CSN of
  all the updates applied to a context.

  The following is a LDAP attribute type description [RFC2252] suitable
  for publication in the subschema.

     ( IANA-ASSIGNED-OID.5 NAME 'contextCSN'
         DESC 'the largest committed CSN of a context'
         EQUALITY csnMatch
         ORDERING csnOrderingMatch
         SYNTAX IANA-ASSIGNED-OID.1
         SINGLE-VALUE
         NO-USER-MODIFICATION
         USAGE directoryOperation )

  Servers SHALL record the greatest CSN of all updates applied to a
  context in the root entry of the context.


3. Security Considerations


  General LDAP security considerations [RFC3377] apply.


4. IANA Considerations

4.1. Object Identifier Registration

  It is requested that IANA register upon Standards Action an LDAP
  Object Identifier for use in this technical specification.

      Subject: Request for LDAP OID Registration
      Person & email address to contact for further information:
          Howard Chu <hyc@symas.com>
      Specification: RFC XXXX
      Author/Change Controller: IESG
      Comments:
          Identifies the CSN schema elements


4.2. Registration of the csnMatch descriptor

  It is requested that IANA register upon Standards Action the LDAP
  'csnMatch' descriptor.

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): csnMatch
      Object Identifier: IANA-ASSIGNED-OID.2
      Person & email address to contact for further information:
          Howard Chu <hyc@symas.com>
      Usage: Matching Rule
      Specification: RFC XXXX
      Author/Change Controller: IESG




Chu               draft-chu-ldap-csn-00              [Page 4]

INTERNET-DRAFT               LDAP CSN                    1 December 2004


4.3. Registration of the csnOrderingMatch descriptor

  It is requested that IANA register upon Standards Action the LDAP
  'csnOrderingMatch' descriptor.

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): csnOrderingMatch
      Object Identifier: IANA-ASSIGNED-OID.3
      Person & email address to contact for further information:
          Howard Chu <hyc@symas.com>
      Usage: Matching Rule
      Specification: RFC XXXX
      Author/Change Controller: IESG


4.4. Registration of the entryCSN descriptor

  It is requested that IANA register upon Standards Action the LDAP
  'entryCSN' descriptor.

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): entryCSN
      Object Identifier: IANA-ASSIGNED-OID.4
      Person & email address to contact for further information:
          Howard Chu <hyc@symas.com>
      Usage: Attribute Type
      Specification: RFC XXXX
      Author/Change Controller: IESG


4.5. Registration of the contextCSN descriptor

  It is requested that IANA register upon Standards Action the LDAP
  'contextCSN' descriptor.

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): contextCSN
      Object Identifier: IANA-ASSIGNED-OID.5
      Person & email address to contact for further information:
          Howard Chu <hyc@symas.com>
      Usage: Attribute Type
      Specification: RFC XXXX
      Author/Change Controller: IESG


5. Acknowledgments

  This document is based on prior work from the IETF LDUP working
  group including the LDAP Replication Architecture [LDUPMODEL]
  and the LDAP Content Synchronization Operation [LDUPSYNC].


6. Author's Addresses

  Howard Y. Chu
  Symas Corporation
  <hyc@symas.com>

  Kurt D. Zeilenga
  OpenLDAP Foundation
  <Kurt@OpenLDAP.org>


7. Normative References

  [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
                Requirement Levels", BCP 14 (also RFC 2119), March 1997.



Chu               draft-chu-ldap-csn-00              [Page 5]

INTERNET-DRAFT               LDAP CSN                    1 December 2004


  [RFC2252]     Wahl, M., A. Coulbeck, T. Howes, and S. Kille,
                "Lightweight Directory Access Protocol (v3):  Attribute
                Syntax Definitions", RFC 2252, December 1997.

  [RFC3377]     Hodges, J. and R. Morgan, "Lightweight Directory Access
                Protocol (v3): Technical Specification", RFC 3377,
                September 2002.

  [X.501]       International Telecommunication Union -
                Telecommunication Standardization Sector, "The Directory
                -- Models," X.501(1993) (also ISO/IEC 9594-2:1994).

  [X.520]       International Telecommunication Union -
                Telecommunication Standardization Sector, "The
                Directory: Selected Attribute Types", X.520(1993) (also
                ISO/IEC 9594-6:1994).

  [X.680]       International Telecommunication Union -
                Telecommunication Standardization Sector, "Abstract
                Syntax Notation One (ASN.1) - Specification of Basic
                Notation", X.680(1997) (also ISO/IEC 8824-1:1998).

  [LDUPSYNC]    Zeilenga, K. and Choi, J-H "LDAP Content Synchronization
                Operation", draft-zeilenga-ldup-sync-05.txt, a work in
                progress.


8. Informative References

  [RFC3383]     Zeilenga, K., "IANA Considerations for LDAP", BCP 64
                (also RFC 3383), September 2002.

  [LDUPMODEL]   Merrellls, J., Srinivasan, U., and Reed, E., "LDAP
                Replication Architecture", draft-ietf-ldup-model-09.txt.



Intellectual Property Rights

  The IETF takes no position regarding the validity or scope of any



Chu               draft-chu-ldap-csn-00              [Page 6]

INTERNET-DRAFT               LDAP CSN                    1 December 2004


  intellectual property or other rights that might be claimed to pertain
  to the implementation or use of the technology described in this
  document or the extent to which any license under such rights might or
  might not be available; neither does it represent that it has made any
  effort to identify any such rights.  Information on the IETF's
  procedures with respect to rights in standards-track and
  standards-related documentation can be found in BCP-11.  Copies of
  claims of rights made available for publication and any assurances of
  licenses to be made available, or the result of an attempt made to
  obtain a general license or permission for the use of such proprietary
  rights by implementors or users of this specification can be obtained
  from the IETF Secretariat.

  The IETF invites any interested party to bring to its attention any
  copyrights, patents or patent applications, or other proprietary
  rights which may cover technology that may be required to practice
  this standard.  Please address the information to the IETF Executive
  Director.



Full Copyright

  Copyright (C) The Internet Society (2004). All Rights Reserved.

  This document and translations of it may be copied and furnished to
  others, and derivative works that comment on or otherwise explain it
  or assist in its implmentation may be prepared, copied, published and
  distributed, in whole or in part, without restriction of any kind,
  provided that the above copyright notice and this paragraph are
  included on all such copies and derivative works.  However, this
  document itself may not be modified in any way, such as by removing
  the copyright notice or references to the Internet Society or other
  Internet organizations, except as needed for the  purpose of
  developing Internet standards in which case the procedures for
  copyrights defined in the Internet Standards process must be followed,
  or as required to translate it into languages other than English.














Chu               draft-chu-ldap-csn-00              [Page 7]

alt-openldap11-devel/drafts/draft-ietf-ldapext-ldapv3-vlv-xx.txt000064400000104713150410163310020524 0ustar00
Internet-Draft                                 D. Boreham, Bozeman Pass 
LDAPext Working Group                            J. Sermersheim, Novell 
Intended Category: Standards Track                  A. Kashi, Microsoft 
<draft-ietf-ldapext-ldapv3-vlv-09.txt>                                  
Expires: Jun 2003                                              Nov 2002 
    
    
       LDAP Extensions for Scrolling View Browsing of Search Results 
    
    
1. Status of this Memo 
    
   This document is an Internet-Draft and is in full conformance with 
   all provisions of Section 10 of RFC2026. 
    
   Internet-Drafts are working documents of the Internet Engineering 
   Task Force (IETF), its areas, and its working groups. Note that other 
   groups may also distribute working documents as Internet-Drafts. 
    
   Internet-Drafts are draft documents valid for a maximum of six months 
   and may be updated, replaced, or obsoleted by other documents at any 
   time. It is inappropriate to use Internet-Drafts as reference 
   material or to cite them other than as "work in progress." 
    
   The list of current Internet-Drafts can be accessed at 
   http://www.ietf.org/ietf/1id-abstracts.txt 
    
   The list of Internet-Draft Shadow Directories can be accessed at 
   http://www.ietf.org/shadow.html. 
    
   This document is intended to be submitted, after review and revision, 
   as a Standards Track document. Distribution of this memo is 
   unlimited. 
   Please send comments to the authors. 
    
    
2. Abstract 
    
   This document describes a Virtual List View extension for the 
   Lightweight Directory Access Protocol (LDAP) Search operation. This 
   extension is designed to allow the "virtual list box" feature, common 
   in existing commercial e-mail address book applications, to be 
   supported efficiently by LDAP servers. LDAP servers' inability to 
   support this client feature is a significant impediment to LDAP 
   replacing proprietary protocols in commercial e-mail systems. 
    
   The extension allows a client to specify that the server return, for 
   a given LDAP search with associated sort keys, a contiguous subset of 
   the search result set. This subset is specified in terms of offsets 
   into the ordered list, or in terms of a greater than or equal 
   comparison value. 
    
    
   Boreham et al           Internet-Draft                             1 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
3. Conventions used in this document 
   The key words "MUST", "SHALL", "SHOULD", "SHOULD NOT", and "MAY" in 
   this document are to be interpreted as described in RFC 2119 
   [Bradner97]. 
    
   Protocol elements are described using ASN.1 [X.680].  The term "BER-
   encoded" means the element is to be encoded using the Basic Encoding 
   Rules [X.690] under the restrictions detailed in Section 5.1 of 
   [LDAPPROT]. 
    
   The phrase "subsequent virtual list request" is used in this document 
   to describe a search request accompanied by a VirtualListViewRequest 
   control, where the search base, scope, and filter are the same as a 
   previous search request also accompanied by a VirtualListViewRequest 
   control, and where the contextID of the subsequent 
   VirtualListViewRequest control, is set to that of the contextID in 
   the VirtualListViewResponse control that accompanied the previous 
   search response. 
    
   The phrase "contiguous virtual list request" is used to describe a 
   subsequent virtual list request which is requesting search results 
   adjoining or overlapping the result returned from the prior virtual 
   list request.  
    
    
4. Background 
    
   A Virtual List is a graphical user interface technique employed where 
   ordered lists containing a large number of entries need to be 
   displayed. A window containing a small number of visible list entries 
   is drawn. The visible portion of the list may be relocated to 
   different points within the list by means of user input. This input 
   can be to a scroll bar slider; from cursor keys; from page up/down 
   keys; from alphanumeric keys for "typedown". The user is given the 
   impression that they may browse the complete list at will, even 
   though it may contain millions of entries. It is the fact that the 
   complete list contents are never required at any one time that 
   characterizes Virtual List View. Rather than fetch the complete list 
   from wherever it is stored (typically from disk or a remote server), 
   only that information which is required to display the part of the 
   list currently in view is fetched. The subject of this document is 
   the interaction between client and server required to implement this 
   functionality in the context of the results from an ordered [SSS] 
   Lightweight Directory Access Protocol (LDAP) search operation 
   [LDAPPROT]. 
    
   For example, suppose an e-mail address book application displays a 
   list view onto the list containing the names of all the holders of e-
   mail accounts at a large university. The list is ordered 
   alphabetically. While there may be tens of thousands of entries in 
   this list, the address book list view displays only 20 such accounts 
    
   Boreham et al           Internet-Draft                             2 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
   at any one time. The list has an accompanying scroll bar and text 
   input window for type-down. When first displayed, the list view shows 
   the first 20 entries in the list, and the scroll bar slider is 
   positioned at the top of its range. Should the user drag the slider 
   to the bottom of its range, the displayed contents of the list view 
   should be updated to show the last 20 entries in the list. Similarly, 
   if the slider is positioned somewhere in the middle of its travel, 
   the displayed contents of the list view should be updated to contain 
   the 20 entries located at that relative position within the complete 
   list. Starting from any display point, if the user uses the cursor 
   keys or clicks on the scroll bar to request that the list be scrolled 
   up or down by one entry, the displayed contents should be updated to 
   reflect this. Similarly the list should be displayed correctly when 
   the user requests a page scroll up or down. Finally, when the user 
   types characters in the type-down window, the displayed contents of 
   the list should "jump" or "seek" to the appropriate point within the 
   list. For example, if the user types "B", the displayed list could 
   center around the first user with a name beginning with the letter 
   "B". When this happens, the scroll bar slider should also be updated 
   to reflect the new relative location within the list. 
    
   This document defines a request control which extends the LDAP search 
   operation. Always used in conjunction with the server side sorting 
   control [SSS], this allows a client to retrieve selected portions of 
   large search result set in a fashion suitable for the implementation 
   of a virtual list view. 
    
    
5. Client-Server Interaction 
    
   The Virtual List View control extends a regular LDAP Search operation 
   which MUST also include a server-side sorting control [SSS]. Rather 
   than returning the complete set of appropriate SearchResultEntry 
   messages, the server is instructed to return a contiguous subset of 
   those entries, taken from the ordered result set, centered around a 
   particular target entry. Henceforth, in the interests of brevity, the 
   ordered search result set will be referred to as "the list". 
    
   The sort control may contain any sort specification valid for the 
   server. The attributeType field in the first SortKeyList sequence 
   element has special significance for "typedown". The Virtual List 
   View control acts upon a set of ordered entries and this order must 
   be repeatable for all subsequent virtual list requests. The server-
   side sorting control is intended to aid in this ordering, but other 
   mechanisms may need to be employed to produce a repeatable order--
   especially for entries that don't have a value of the sort key. 
    
   The desired target entry and the number of entries to be returned, 
   both before and after that target entry in the list, are determined 
   by the client's VirtualListViewRequest control. 
    
    
   Boreham et al           Internet-Draft                             3 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
   When the server returns the set of entries to the client, it attaches 
   a VirtualListViewResponse control to the SearchResultDone message. 
   The server returns in this control: its current estimate for the list 
   content count, the location within the list corresponding to the 
   target entry, any error codes, and optionally a context identifier. 
    
   The target entry is specified in the VirtualListViewRequest control 
   by one of two methods. The first method is for the client to indicate 
   the target entry's offset within the list. The second way is for the 
   client to supply an attribute assertion value. The value is compared 
   against the values of the attribute specified as the primary sort key 
   in the sort control attached to the search operation. The first sort 
   key in the SortKeyList is the primary sort key. The target entry is 
   the first entry in the list with value greater than or equal to (in 
   the primary sort order), the presented value. The order is determined 
   by rules defined in [SSS]. Selection of the target entry by this 
   means is designed to implement "typedown". Note that it is possible 
   that no entry satisfies these conditions, in which case there is no 
   target entry. This condition is indicated by the server returning the 
   special value contentCount + 1 in the target position field.  
    
   Because the server may not have an accurate estimate of the number of 
   entries in the list, and to take account of cases where the list size 
   is changing during the time the user browses the list, and because 
   the client needs a way to indicate specific list targets "beginning" 
   and "end", offsets within the list are transmitted between client and 
   server as ratios---offset to content count. The server sends its 
   latest estimate as to the number of entries in the list (content 
   count) to the client in every response control. The client sends its 
   assumed value for the content count in every request control. The 
   server examines the content count and offsets presented by the client 
   and computes the corresponding offsets within the list, based on its 
   own idea of the content count. 
    
        Si = Sc * (Ci / Cc) 
    
        Where: 
        Si is the actual list offset used by the server 
        Sc is the server's estimate for content count 
        Ci is the client's submitted offset 
        Cc is the client's submitted content count 
        The result is rounded to the nearest integer. 
    
   If the content count is stable, and the client returns to the server 
   the content count most recently received, Cc = Sc and the offsets 
   transmitted become the actual server list offsets. 
    
   The following special cases exist when the client is specifying the 
   offset and content count:  
   - an offset of one and a content count of non-one (Ci = 1, Cc != 1) 
     indicates that the target is the first entry in the list. 
    
   Boreham et al           Internet-Draft                             4 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
   - equivalent values (Ci = Cc) indicate that the target is the last 
     entry in the list. 
   - a content count of zero (Cc = 0, Ci != 0) means the client has no 
     idea what the content count is, the server MUST use its own 
     content count estimate in place of the client's. 
    
   Because the server always returns contentCount and targetPosition, 
   the client can always determine which of the returned entries is the 
   target entry. Where the number of entries returned is the same as the 
   number requested, the client is able to identify the target by simple 
   arithmetic. Where the number of entries returned is not the same as 
   the number requested (because the requested range crosses the 
   beginning or end of the list, or both), the client MUST use the 
   target position and content count values returned by the server to 
   identify the target entry. For example, suppose that 10 entries 
   before and 10 after the target were requested, but the server returns 
   13 entries, a content count of 100 and a target position of 3. The 
   client can determine that the first entry must be entry number 1 in 
   the list, therefore the 13 entries returned are the first 13 entries 
   in the list, and the target is the third one. 
    
   A server-generated contextID MAY be returned to clients. A client 
   receiving a contextID MUST return it unchanged or not return it at 
   all, in a subsequent request which relates to the same list. The 
   purpose of this interaction is to maintain state information between 
   the client and server. 
    
    
6. The Controls 
    
   Support for the virtual list view control extension is indicated by 
   the presence of the OID "2.16.840.1.113730.3.4.9" in the 
   supportedControl attribute of a server's root DSE. 
    
6.1. Request Control 
    
   This control is included in the SearchRequest message as part of the 
   controls field of the LDAPMessage, as defined in Section 4.1.12 of 
   [LDAPPROT]. The controlType is set to "2.16.840.1.113730.3.4.9". If 
   this control is included in a SearchRequest message, a Server Side 
   Sorting request control [SSS] MUST also be present in the message. 
   The controlValue, an OCTET STRING, is the BER-encoding of the 
   following SEQUENCE: 
    
   VirtualListViewRequest ::= SEQUENCE { 
          beforeCount    INTEGER (0..maxInt), 
          afterCount     INTEGER (0..maxInt), 
          target       CHOICE { 
                         byOffset        [0] SEQUENCE {                           
                              offset          INTEGER (1 .. maxInt), 
                              contentCount    INTEGER (0 .. maxInt) }, 
    
   Boreham et al           Internet-Draft                             5 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
                         greaterThanOrEqual [1] AssertionValue }, 
          contextID     OCTET STRING OPTIONAL } 
    
   beforeCount indicates how many entries before the target entry the 
   client wants the server to send.  
    
   afterCount indicates the number of entries after the target entry the 
   client wants the server to send.  
    
   offset and contentCount identify the target entry as detailed in 
   section 5.  
    
   greaterThanOrEqual is a matching rule assertion value defined in 
   [LDAPPROT]. The assertion value is encoded according to the ORDERING 
   matching rule for the attributeDescription in the sort control [SSS]. 
   If present, the value supplied in greaterThanOrEqual is used to 
   determine the target entry by comparison with the values of the 
   attribute specified as the primary sort key. The first list entry 
   who's value is no less than (less than or equal to when the sort 
   order is reversed) the supplied value is the target entry.  
    
   If present, the contextID field contains the value of the most 
   recently received contextID field from a VirtualListViewResponse 
   control for the same list view. If the contextID is not known because 
   no contextID has been sent by the server in a VirtualListViewResponse 
   control, it SHALL be omitted. If the server receives a contextID that 
   is invalid, it SHALL fail the search operation and indicate the 
   failure with a protocolError (3) value in the virtualListViewResult 
   field of the VirtualListViewResponse. The contextID provides state 
   information between the client and server. This state information is 
   used by the server to ensure continuity contiguous virtual list 
   requests. When a server receives a VirtualListViewRequest control 
   that includes a contextID, it SHALL determine whether the client has 
   sent a contiguous virtual list request and SHALL provide contiguous 
   entries if possible. If a valid contextID is sent, and the server is 
   unable to determine whether contiguous data is requested, or is 
   unable to provide requested contiguous data, it SHALL fail the search 
   operation and indicate the failure with an unwillingToPerform (53) 
   value in the virtualListViewResult field of the 
   VirtualListViewResponse. contextID values have no validity outside 
   the connection and query with which they were received. A client MUST 
   NOT submit a contextID which it received from a different connection, 
   a different query, or a different server. 
    
   The type AssertionValue and value maxInt are defined in [LDAPPROT]. 
    
    
6.2. Response Control 
    


    
   Boreham et al           Internet-Draft                             6 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
   If the request control is serviced, this response control is included 
   in the SearchResultDone message as part of the controls field of the 
   LDAPMessage, as defined in Section 4.1.12 of [LDAPPROT]. 
    
   The controlType is set to "2.16.840.1.113730.3.4.10". The 
   controlValue, an OCTET STRING, is the BER-encoding of the following 
   SEQUENCE: 
    
   VirtualListViewResponse ::= SEQUENCE { 
          targetPosition    INTEGER (0 .. maxInt), 
          contentCount     INTEGER (0 .. maxInt), 
          virtualListViewResult ENUMERATED { 
               success (0), 
               operationsError (1), 
               protocolError (3), 
               unwillingToPerform (53), 
               insufficientAccessRights (50), 
               timeLimitExceeded (3), 
               adminLimitExceeded (11), 
               innapropriateMatching (18), 
               sortControlMissing (60), 
               offsetRangeError (61), 
               other(80), 
               ... }, 
          contextID     OCTET STRING OPTIONAL } 
    
   targetPosition gives the list offset for the target entry.  
    
   contentCount gives the server's estimate of the current number of 
   entries in the list. Together these give sufficient information for 
   the client to update a list box slider position to match the newly 
   retrieved entries and identify the target entry. The contentCount 
   value returned SHOULD be used in a subsequent VirtualListViewRequest 
   control.  
    
   contextID is a server-defined octet string. If present, the contents 
   of the contextID field SHOULD be returned to the server by a client 
   in a subsequent virtual list request. The presence of a contextID 
   here indicates that the server is willing to return contiguous data 
   from a subsequent search request which uses the same search criteria, 
   accompanied by a VirtualListViewRequest which indicates that the 
   client wishes to receive an adjoining page of data. 
    
   The virtualListViewResult codes which are common to the LDAP 
   searchResultDone (adminLimitExceeded, timeLimitExceeded, 
   operationsError, unwillingToPerform, insufficientAccessRights, 
   success, other) have the same meanings as defined in [LDAPPROT], but 
   they pertain specifically to the VLV operation. For example, the 
   server could exceed a VLV-specific administrative limit while 
   processing a SearchRequest with a VirtualListViewRequest control. 
   Obviously, the same administrative limit would not be exceeded should 
    
   Boreham et al           Internet-Draft                             7 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
   the same SearchRequest be submitted by the client without the 
   VirtualListViewRequest control. In this case, the client can 
   determine that the administrative limit has been exceeded in 
   servicing the VLV request, and can if it chooses resubmit the 
   SearchRequest without the VirtualListViewRequest control, or with 
   different parameters. 
    
   insufficientAccessRights means that the server denied the client 
   permission to perform the VLV operation. 
    
   If the server determines that the results of the search presented 
   exceed the range specified in INTEGER values, or if the client 
   specifies an invalid offset or contentCount, the server MUST set the 
   virtualListViewResult value to offsetRangeError. 
    
6.2.1 virtualListViewError 
 
   A new LDAP error is introduced called virtualListViewError. Its value 
   is 76. This error indicates that the search operation failed due to 
   the inclusion of the VirtualListViewRequest control. 
    
   If the resultCode in the SearchResultDone message is set to 
   virtualListViewError (76), then the virtualListViewResult value MUST 
   NOT be success (as virtualListViewResult indicates the specific error 
   condition). If resultCode in the SearchResultDone message is not set 
   to virtualListViewError (76), then the virtualListViewResult value 
   SHOULD be success (0) and its value MUST be ignored. 
    
7. Protocol Example 
    
   Here we walk through the client-server interaction for a specific 
   virtual list view example: The task is to display a list of all 78564 
   persons in the US company "Ace Industry". This will be done by 
   creating a graphical user interface object to display the list 
   contents, and by repeatedly sending different versions of the same 
   virtual list view search request to the server. The list view 
   displays 20 entries on the screen at a time. 
    
   We form a search with baseObject of "o=Ace Industry,c=us"; scope of 
   wholeSubtree; and filter of "(objectClass=person)". We attach a 
   server-side sort control [SSS] to the search request, specifying 
   ascending sort on attribute "cn". To this search request, we attach a 
   virtual list view request control with contents determined by the 
   user activity and send the search request to the server. We display 
   the results from each search result entry in the list window and 
   update the slider position. 
    
   When the list view is first displayed, we want to initialize the 
   contents showing the beginning of the list. Therefore, we set 
   beforeCount to 0, afterCount to 19, contentCount to 0, offset to 1 
   and send the request to the server. The server duly returns the first 
    
   Boreham et al           Internet-Draft                             8 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
   20 entries in the list, plus a content count of 78564 and 
   targetPosition of 1. We therefore leave the scroll bar slider at its 
   current location (the top of its range). 
    
   Say that next the user drags the scroll bar slider down to the bottom 
   of its range. We now wish to display the last 20 entries in the list, 
   so we set beforeCount to 19, afterCount to 0, contentCount to 78564, 
   offset to 78564 and send the request to the server. The server 
   returns the last 20 entries in the list, plus a content count of 
   78564 and a targetPosition of 78564. 
    
   Next the user presses a page up key. Our page size is 20, so we set 
   beforeCount to 0, afterCount to 19, contentCount to 78564, offset to 
   78564-19-20 and send the request to the server. The server returns 
   the preceding 20 entries in the list, plus a content count of 78564 
   and a targetPosition of 78525. 
    
   Now the user grabs the scroll bar slider and drags it to 68% of the 
   way down its travel. 68% of 78564 is 53424 so we set beforeCount to 
   9, afterCount to 10, contentCount to 78564, offset to 53424 and send 
   the request to the server. The server returns the preceding 20 
   entries in the list, plus a content count of 78564 and a 
   targetPosition of 53424. 
    
   Lastly, the user types the letter "B". We set beforeCount to 9, 
   afterCount to 10 and greaterThanOrEqual to "B". The server finds the 
   first entry in the list not less than "B", let's say "Babs Jensen", 
   and returns the nine preceding entries, the target entry, and the 
   proceeding 10 entries. The server returns a content count of 78564 
   and a targetPosition of 5234 and so the client updates its scroll bar 
   slider to 6.7% of full scale. 
    
    
8. Notes for Implementers 
    
   While the feature is expected to be generally useful for arbitrary 
   search and sort specifications, it is specifically designed for those 
   cases where the result set is very large. The intention is that this 
   feature be implemented efficiently by means of pre-computed indices 
   pertaining to a set of specific cases. For example, an offset 
   relating to "all the employees in the local organization, sorted by 
   surname" would be a common case. 
    
   The intention for client software is that the feature should fit 
   easily with the host platform's graphical user interface facilities 
   for the display of scrolling lists. Thus the task of the client 
   implementers should be one of reformatting up the requests for 
   information received from the list view code to match the format of 
   the virtual list view request and response controls. 
    

    
   Boreham et al           Internet-Draft                             9 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
   Client implementers MUST be aware that any offset value returned by 
   the server might be approximate. Do not design clients that only 
   operate correctly when offsets are exact. However, if contextIDs are 
   used, and adjoining pages of information are requested, the server 
   will return contiguous data. 
    
   Server implementers using indexing technology which features 
   approximate positioning should consider returning contextIDs to 
   clients. The use of a contextID will allow the server to distinguish 
   between client requests which relate to different displayed lists on 
   the client. Consequently the server can decide more intelligently 
   whether to reposition an existing database cursor accurately to 
   within a short distance of its current position, or to reposition to 
   an approximate position. Thus the client will see precise offsets for 
   "short" repositioning (e.g. paging up or down), but approximate 
   offsets for a "long" reposition (e.g. a slider movement). 
    
   Server implementers are free to return an LDAP result code of 
   virtualListViewError and a virtualListViewResult of 
   unwillingToPerform should their server be unable to service any 
   particular VLV search. This might be because the resolution of the 
   search is computationally infeasible, or because excessive server 
   resources would be required to service the search. 
    
   Client implementers should note that this control is only defined on 
   a client interaction with a single server. If a search scope spans 
   multiple naming contexts that are not held locally, search result 
   references will be returned, and may occur at any point in the search 
   operation. The client is responsible for deciding when and how to 
   apply this control to the referred-to servers, and how to collate the 
   results from multiple servers. 
    
    
9. Relationship to "Simple Paged Results" 
    
   These controls are designed to support the virtual list view, which 
   has proved hard to implement with the Simple Paged Results mechanism 
   [SPaged]. However, the controls described here support any operation 
   possible with the Simple Paged Results mechanism. The two mechanisms 
   are not complementary; rather one has a superset of the other's 
   features. One area where the mechanism presented here is not a strict 
   superset of the Simple Paged Results scheme is that here we require a 
   sort order to be specified. No such requirement is made for paged 
   results. 
    
    
10. Security Considerations 
    
   Server implementers may wish to consider whether clients are able to 
   consume excessive server resources in requesting virtual list 
   operations. Access control to the feature itself; configuration 
    
   Boreham et al           Internet-Draft                            10 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
   options limiting the feature's use to certain predetermined search 
   base DNs and filters; throttling mechanisms designed to limit the 
   ability for one client to soak up server resources, may be 
   appropriate. 
    
   Consideration should be given as to whether a client will be able to 
   retrieve the complete contents, or a significant subset of the 
   complete contents of the directory using this feature. This may be 
   undesirable in some circumstances and consequently it may be 
   necessary to enforce some access control or administrative limit. 
    
   Clients can, using this control, determine how many entries match a 
   particular filter, before the entries are returned to the client. 
   This may require special processing in servers which perform access 
   control checks on entries to determine whether the existence of the 
   entry can be disclosed to the client. 
    
   Server implementers should exercise caution concerning the content of 
   the contextID. Should the contextID contain internal server state, it 
   may be possible for a malicious client to use that information to 
   gain unauthorized access to information. 
    
11. IANA Considerations 
    
11.1 Request for LDAP Result Code 
    
   In accordance with section 3.6 of [LDAPIANA], it is requested that 
   IANA register the LDAP result code virtualListViewError (76) upon 
   Standards Action by the IESG. The value 76 has been suggested by 
   experts, had expert review, and is currently being used by some 
   implementations. If 76 is unavailable on not chosen, the value in the 
   paragraphs in Section 6.2.1 will need to be updated. The following 
   registration template is suggested: 
    
   Subject: LDAP Result Code Registration 
   Person & email address to contact for further information: Jim 
   Sermersheim  
   Result Code Name: virtualListViewError 
   Specification: RFCXXXX 
   Author/Change Controller: IESG 
   Comments:  request LDAP result codes be assigned 
    
    
    
12. Acknowledgements 
    
   Chris Weider, Anoop Anantha, and Michael Armijo of Microsoft co-
   authored previous versions of this document. 
    
    

    
   Boreham et al           Internet-Draft                            11 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
13. Normative References 
    
    
   [X.680]    ITU-T Rec. X.680, "Abstract Syntax Notation One (ASN.1) - 
              Specification of Basic Notation", 1994. 
    
   [X.690]    ITU-T Rec. X.690, "Specification of ASN.1 encoding rules: 
              Basic, Canonical, and Distinguished Encoding Rules", 
              1994. 
    
   [LDAPPROT]  Wahl, M., Kille, S. and T. Howes, "Lightweight Directory 
               Access Protocol (v3)", Internet Standard, RFC 2251, 
               December, 1997. 
    
   [SSS]       Wahl, M., Herron, A. and T. Howes, "LDAP Control 
               Extension for Server Side Sorting of Search Results", 
               RFC 2891, August, 2000. 
                
   [Bradner97] Bradner, S., "Key Words for use in RFCs to Indicate 
               Requirement Levels", BCP 14, RFC 2119, March 1997. 
                
   [LDAPIANA] Zeilenga, K., "Internet Assigned Numbers Authority (IANA) 
              Considerations for the Lightweight Directory Access 
              Protocol (LDAP)", RFC 3383, September 2002. 
                
14. Informative References 
    
   [SPaged]    Weider, C., Herron, A., Anantha, A. and T. Howes, "LDAP 
               Control Extension for Simple Paged Results Manipulation", 
               RFC2696, September 1999. 
    
    
15. Authors' Addresses 
    
        David Boreham 
        Bozeman Pass, Inc 
        +1 406 222 7093 
        david@bozemanpass.com 
         
        Jim Sermersheim 
        Novell 
        1800 South Novell Place 
        Provo, Utah 84606, USA 
        jimse@novell.com 
         
        Asaf Kashi 
        Microsoft Corporation 
        1 Microsoft Way 
        Redmond, WA 98052, USA 
        +1 425 882-8080 
        asafk@microsoft.com 
    
   Boreham et al           Internet-Draft                            12 
    
                 LDAP Extensions for Scrolling View            Nov 2002 
                     Browsing of Search Results 
    
         
    
16. Full Copyright Statement 
    
   Copyright (C) The Internet Society (2002). All Rights Reserved. 
   This document and translations of it may be copied and furnished to 
   others, and derivative works that comment on or otherwise explain it 
   or assist in its implementation may be prepared, copied, published 
   and distributed, in whole or in part, without restriction of any 
   kind, provided that the above copyright notice and this paragraph are 
   included on all such copies and derivative works. However, this 
   document itself may not be modified in any way, such as by removing 
   the copyright notice or references to the Internet Society or other 
   Internet organizations, except as needed for the purpose of 
   developing Internet standards in which case the procedures for 
   copyrights defined in the Internet Standards process must be 
   followed, or as required to translate it into languages other than 
   English. The limited permissions granted above are perpetual and will 
   not be revoked by the Internet Society or its successors or assigns. 
   This document and the information contained herein is provided on an 
   "AS IS" basis and THE INTERNET SOCIETY AND THE 
   INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR 
   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF 
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED 
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE." 


























    
   Boreham et al           Internet-Draft                            13 
alt-openldap11-devel/drafts/draft-ietf-ldapext-locate-xx.txt000064400000034230150410163310017771 0ustar00

INTERNET-DRAFT                                         Michael P. Armijo
<draft-ietf-ldapext-locate-08.txt>                          Levon Esibov
June 5, 2002                                                  Paul Leach
Expires: December 5, 2002                          Microsoft Corporation
							     R.L. Morgan
						University of Washington

                Discovering LDAP Services with DNS

Status of this Memo

   This document is an Internet-Draft and is in full conformance with
   all provisions of Section 10 of RFC2026.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet- Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   Distribution of this memo is unlimited.  It is filed as <draft-
   ietf-ldapext-locate-08.txt>, and expires on December 5, 2002.
   Please send comments to the authors.

   Copyright Notice

   Copyright (C) The Internet Society (2001).  All Rights Reserved.


Abstract

   A Lightweight Directory Access Protocol (LDAP) request must be
   directed to an appropriate server for processing.  This document
   specifies a method for discovering such servers using information in
   the Domain Name System. 









Armijo, Esibov, Leach and Morgan                                [Page 1]

INTERNET-DRAFT   Discovering LDAP Services with DNS         June 5, 2002



1. Introduction

   The LDAPv3 protocol [1] is designed to be a lightweight access
   protocol for directory services supporting X.500 models.  As a
   distributed directory service, the complete set of directory
   information (known as the Directory Information Base) is spread
   across many different servers.  Hence there is the need to
   determine, when initiating or processing a request, which servers
   hold the relevant information.  In LDAP, the Search, Modify, Add,
   Delete, ModifyDN, and Compare operations all specify a Distinguished
   Name (DN) [2] on which the operation is performed.  A client, or a
   server acting on behalf of a client, must be able to determine the
   server(s) that hold the naming context containing that DN, since
   that server (or one of that set of servers) must receive and process
   the request.  This determination process is called "server
   location".  To support dynamic distributed operation, the
   information needed to support server location must be available via
   lookups done at request processing time, rather than, for example,
   as static data configured into each client or server.

   It is possible to maintain the information needed to support server
   location in the directory itself, and X.500 directory deployments
   typically do so.  In practice, however, this only permits location
   of servers within a limited X.500-connected set.  LDAP-specific
   methods of maintaining server location information in the directory
   have not yet been standardized.  This document defines an
   alternative method of managing server location information using the
   Domain Name System. This method takes advantage of the global
   deployment of the DNS, by allowing LDAP server location information
   for any existing DNS domain to be published by creating the records
   described below.  A full discussion of the benefits and drawbacks of
   the various directory location and naming methods is beyond the
   scope of this document.

   RFC 2247[3] defines an algorithm for mapping DNS domain names into
   DNs.  This document defines the inverse mapping, from DNs to DNS
   domain names, based on the conventions in [3], for use in this
   server location method.  The server location method described in
   this document is only defined for DNs that can be so mapped, i.e.,
   those DNs that are based on domain names.  In practice this is
   reasonable because many objects of interest are named with domain
   names, and use of domain-name-based DNs is becoming common.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in RFC 2119 [9].






Armijo, Esibov, Leach and Morgan                                [Page 2]

INTERNET-DRAFT   Discovering LDAP Services with DNS         June 5, 2002


2. Mapping Distinguished Names into Domain Names

   This section defines a method of converting a DN into a DNS domain
   name for use in the server location method described below.  Some
   DNs cannot be converted into a domain name.  Converted DNs result 
   in a fully qualified domain name.


   The output domain name is initially empty.  The DN is processed in
   right-to-left order (i.e., beginning with the first RDN in the
   sequence of RDNs).  An RDN is able to be converted if it (1)
   consists of a single AttributeTypeAndValue; (2) the attribute type
   is "DC"; and (3) the attribute value is non-null.  If it can be
   converted, the attribute value is used as a domain name component
   (label).  The first such value becomes the rightmost (i.e., most
   significant) domain name component, and successive converted RDN
   values extend to the left.  If an RDN cannot be converted,
   processing stops.  If the output domain name is empty when
   processing stops, the DN cannot be converted into a domain name.

   For DN:

   cn=John Doe,ou=accounting,dc=example,dc=net

   The client would convert the DC components as defined above into 
   DNS name:

   example.net

   The determined DNS name will be submitted as a DNS query using the 
   algorithm defined in section 3.



3. Locating LDAPv3 servers through DNS

   LDAPv3 server location information is to be stored using DNS Service
   Location Record (SRV)[5].  The data in a SRV record contains the DNS
   name of the server that provides the LDAP service, corresponding
   Port number, and parameters that enable the client to choose an
   appropriate server from multiple servers according to the algorithm
   described in [5].  The name of this record has the following format:

      _<Service>._<Proto>.<Domain>.

   where <Service> is "ldap", and <Proto> is "tcp". <Domain> is the
   domain name formed by converting the DN of a naming context mastered
   by the LDAP Server into a domain name using the algorithm in
   Section 2.  Note that "ldap" is the symbolic name for the LDAP
   service in Assigned Numbers[6], as required by [5].



Armijo, Esibov, Leach and Morgan                                [Page 3]

INTERNET-DRAFT   Discovering LDAP Services with DNS         June 5, 2002


   Presence of such records enables clients to find the LDAP servers
   using standard DNS query [4].  A client (or server) seeking an LDAP
   server for a particular DN converts that DN to a domain name using
   the algorithm of Section 2, does a SRV record query using the DNS
   name formed as described in the preceding paragraph, and interprets
   the response as described in [5] to determine a host (or hosts) to
   contact. As an example, a client that searches for an LDAP server
   for the DN "ou=foo,dc=example,dc=net" that supports the TCP protocol
   will submit a DNS query for a set of SRV records with owner name:

      _ldap._tcp.example.net.

   The client will receive the list of SRV records published in DNS
   that satisfy the requested criteria.  The following is an example of
   such a record:

      _ldap._tcp.example.net.   IN   SRV  0 0 389 phoenix.example.net.

   The set of returned records may contain multiple records in the case
   where multiple LDAP servers serve the same domain.  If there are no 
   matching SRV records available for the converted DN the client SHOULD 
   NOT attempt to 'walk the tree' by removing the least significant 
   portion of the constructed fully qualified domain name.


4.  IANA Considerations

   This document does not require any IANA actions.


5. Security Considerations

   DNS responses can typically be easily spoofed.  Clients using this
   location method SHOULD ensure, via use of strong security
   mechanisms, that the LDAP server they contact is the one they
   intended to contact.  See [7] for more information on security
   threats and security mechanisms.

   When using LDAP with TLS the client MUST check the server's name,
   as described in section 3.6 of [RFC 2830].  As specified there, the
   name the client checks for is the server's name before any
   potentially insecure transformations, including the SRV record
   lookup specified in this memo.  Thus the name the client MUST check
   for is the name obtained by doing the mapping step defined in
   section 2 above.  For example, if the DN "cn=John
   Doe,ou=accounting,dc=example,dc=net" is converted to the DNS name
   "example.net", the server's name MUST match "example.net".

   This document describes a method that uses DNS SRV records to 
   discover LDAP servers.  All security considerations related to DNS
   SRV records are inherited by this document.  See the security 
   considerations section in [5] for more details.

Armijo, Esibov, Leach and Morgan                                [Page 4]

INTERNET-DRAFT   Discovering LDAP Services with DNS         June 5, 2002


6. References

   [1]  Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access
        Protocol(v3)", RFC 2251, December 1997.

   [2]  Wahl, M., Kille, S. and T. Howes, "Lightweight Directory Access
        Protocol (v3):  UTF-8 String Representation of Distinguished
        Names", RFC 2253, December 1997.

   [3]  Kille, S. and M. Wahl, "Using Domains in LDAP/X.500
        Distinguished Names", RFC 2247, January 1998.

   [4]  Mockapetris, P., "DOMAIN NAMES - CONCEPTS AND FACILITIES", RFC
        1034, STD 13, November 1987.

   [5]  Gulbrandsen, A., Vixie, P. and L. Esibov, "A DNS RR for
        specifying the location of services (DNS SRV)", RFC 2782,
        February 2000.

   [6]  Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC
        1700, October 1994.

   [7]  Wahl, M., Alvestrand, H., Hodges, J. and Morgan, R.,
        "Authentication Methods for LDAP", RFC 2829, May 2000.

   [8]  Hodges, J., Morgan, R., Wahl, M., "Lightweight Directory Access
        Protocol (v3): Extension for Transport Layer Security",
        RFC 2830, May 2000.

   [9] Bradner, S., "Key words for use in RFCs to Indicate Requirement
       Levels", BCP 14, RFC 2119, March 1997.




7. Authors' Addresses

   Michael P. Armijo
   One Microsoft Way
   Redmond, WA 98052
   micharm@microsoft.com

   Paul Leach
   One Microsoft Way
   Redmond, WA 98052
   paulle@microsoft.com

   Levon Esibov
   One Microsoft Way
   Redmond, WA 98052
   levone@microsoft.com


Armijo, Esibov, Leach and Morgan                                [Page 5]

INTERNET-DRAFT   Discovering LDAP Services with DNS         June 5, 2002

   RL "Bob" Morgan
   University of Washington
   4545 15th Ave NE
   Seattle, WA  98105
   US

   Phone: +1 206 221 3307
   EMail: rlmorgan@washington.edu
   URI:   http://staff.washington.edu/rlmorgan/


8.  Intellectual Property Statement

The IETF takes no position regarding the validity or scope of any
intellectual property or other rights that might be claimed to  pertain
to the implementation or use of the technology described in this
document or the extent to which any license under such rights might or
might not be available; neither does it represent that it has made any
effort to identify any such rights.  Information on the IETF's
procedures with respect to rights in standards-track and standards-
related documentation can be found in BCP-11.  Copies of claims of
rights made available for publication and any assurances of licenses to
be made available, or the result of an attempt made to obtain a general
license or permission for the use of such proprietary rights by
implementors or users of this specification can be obtained from the
IETF Secretariat.

The IETF invites any interested party to bring to its attention any
copyrights, patents or patent applications, or other proprietary rights
which may cover technology that may be required to practice this
standard.  Please address the information to the IETF Executive
Director.


9.  Full Copyright Statement

Copyright (C) The Internet Society (2001).  All Rights Reserved.
This document and translations of it may be copied and furnished to
others, and derivative works that comment on or otherwise explain it or
assist in its implementation may be prepared, copied, published and
distributed, in whole or in part, without restriction of any kind,
provided that the above copyright notice and this paragraph are included
on all such copies and derivative works.  However, this document itself
may not be modified in any way, such as by removing the copyright notice
or references to the Internet Society or other Internet organizations,
except as needed for the purpose of developing Internet standards in
which case the procedures for copyrights defined in the Internet
Standards process must be followed, or as required to translate it into
languages other than English.  The limited permissions granted above are
perpetual and will not be revoked by the Internet Society or its
successors or assigns.  This document and the information contained
herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE


Armijo, Esibov, Leach and Morgan                                [Page 6]

INTERNET-DRAFT   Discovering LDAP Services with DNS         June 5, 2002

INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."


10.  Expiration Date

   This document is filed as <draft-ietf-ldapext-locate-08.txt>, and 
   expires December 5, 2002.

Armijo, Esibov, Leach and Morgan                                [Page 7]alt-openldap11-devel/drafts/draft-chu-ldap-ldapi-xx.txt000064400000036237150410163310016733 0ustar00


Network Working Group                                             H. Chu
Internet-Draft                                               Symas Corp.
Intended status: Informational                         February 28, 2007
Expires: September 1, 2007


                     Using LDAP Over IPC Mechanisms
                      draft-chu-ldap-ldapi-00.txt

Status of this Memo

   By submitting this Internet-Draft, each author represents that any
   applicable patent or other IPR claims of which he or she is aware
   have been or will be disclosed, and any of which he or she becomes
   aware will be disclosed, in accordance with Section 6 of BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on September 1, 2007.

Copyright Notice

   Copyright (C) The IETF Trust (2007).














Chu                     Expires September 1, 2007               [Page 1]

Internet-Draft                LDAP Over IPC                February 2007


Abstract

   When both the LDAP client and server reside on the same machine,
   communication efficiency can be greatly improved using host- specific
   IPC mechanisms instead of a TCP session.  Such mechanisms can also
   implicitly provide the client's identity to the server for extremely
   lightweight authentication.  This document describes the
   implementation of LDAP over Unix IPC that has been in use in OpenLDAP
   since January 2000, including the URL format used to specify an IPC
   session.


Table of Contents

   1.          Introduction . . . . . . . . . . . . . . . . . . . . .  3
   2.          Conventions  . . . . . . . . . . . . . . . . . . . . .  4
   3.          Motivation . . . . . . . . . . . . . . . . . . . . . .  5
   4.          User-Visible Specification . . . . . . . . . . . . . .  6
   4.1.        URL Scheme . . . . . . . . . . . . . . . . . . . . . .  6
   5.          Implementation Details . . . . . . . . . . . . . . . .  7
   5.1.        Client Authentication  . . . . . . . . . . . . . . . .  7
   5.2.        Other Platforms  . . . . . . . . . . . . . . . . . . .  8
   6.          Security Considerations  . . . . . . . . . . . . . . .  9
   7.          References . . . . . . . . . . . . . . . . . . . . . . 10
   7.1.        Normative References . . . . . . . . . . . . . . . . . 10
   7.2.        Informative References . . . . . . . . . . . . . . . . 10
   Appendix A. IANA Considerations  . . . . . . . . . . . . . . . . . 11
               Author's Address . . . . . . . . . . . . . . . . . . . 12
               Intellectual Property and Copyright Statements . . . . 13






















Chu                     Expires September 1, 2007               [Page 2]

Internet-Draft                LDAP Over IPC                February 2007


1.  Introduction

   While LDAP is a distributed access protocol, it is common for clients
   to be deployed on the same machine that hosts the server.  Many
   applications are built on a tight integration of the client code and
   a co-resident server.  In these tightly integrated deployments, where
   no actual network traffic is involved in the communication, the use
   of TCP/IP is overkill.  Systems like Unix offer native IPC mechanisms
   that still provide the stream-oriented semantics of a TCP session,
   but with much greater efficiency.

   Since January 2000, OpenLDAP releases have provided the option to
   establish LDAP sessions over Unix Domain sockets as well as over
   TCP/IP.  Such sessions are inherently as secure as TCP loopback
   sessions, but they consume fewer system resources, are much faster to
   establish and tear down, and they also provide secure identification
   of the client without requiring any additional passwords or other
   credentials.

































Chu                     Expires September 1, 2007               [Page 3]

Internet-Draft                LDAP Over IPC                February 2007


2.  Conventions

   Imperative keywords defined in [RFC2119] are used in this document,
   and carry the meanings described there.















































Chu                     Expires September 1, 2007               [Page 4]

Internet-Draft                LDAP Over IPC                February 2007


3.  Motivation

   Many LDAP sessions consist of just one or two requests.  Connection
   setup and teardown can become a significant portion of the time
   needed to process these sessions.  Also under heavy load, the
   constraints of the 2MSL limit in TCP become a bottleneck.  For
   example, a modest single processor dual-core AMD64 server running
   OpenLDAP can handle over 32,000 authentication requests per second on
   100Mbps ethernet, with one connection per request.  Connected over a
   host's loopback interface, the rate is much higher, but connections
   get completely throttled in under one second, because all of the
   host's port numbers have been used up and are in TIME_WAIT state.  So
   even when the TCP processing overhead is insignificant, the
   constraints imposed in [RFC0793] create an artificial limit on the
   server's performance.  No such constraints exist when using IPC
   mechanisms instead of TCP.



































Chu                     Expires September 1, 2007               [Page 5]

Internet-Draft                LDAP Over IPC                February 2007


4.  User-Visible Specification

   The only change clients need to implement to use this feature is to
   use a special URL scheme instead of an ldap:// URL when specifying
   the target server.  Likewise, the server needs to include this URL in
   the list of addresses on which it will listen.

4.1.  URL Scheme

   The "ldapi:" URL scheme is used to denote an LDAP over IPC session.
   The address portion of the URL is the name of a Unix Domain socket,
   which is usually a fully qualified Unix filesystem pathname.  Slashes
   in the pathname must be percent-encoded as described in section 2.1
   of [RFC3986] since they do not represent URL path delimiters in this
   usage.  E.g., for a socket named "/var/run/ldapi" the server URL
   would be "ldapi://%26var%26run%26ldapi/".  In all other respects, an
   ldapi URL conforms to [RFC4516].

   If no specific address is supplied, a default address MAY be used
   implicitly.  In OpenLDAP the default address is a compile-time
   constant and its value is chosen by whoever built the software.






























Chu                     Expires September 1, 2007               [Page 6]

Internet-Draft                LDAP Over IPC                February 2007


5.  Implementation Details

   The basic transport uses a stream-oriented Unix Domain socket.  The
   semantics of communication over such a socket are essentially
   identical to using a TCP session.  Aside from the actual connection
   establishment, no special considerations are needed in the client,
   libraries, or server.

5.1.  Client Authentication

   Since their introduction in 4.2 BSD Unix, Unix Domain sockets have
   also allowed passing credentials from one process to another.  Modern
   systems may provide a server with easier means of obtaining the
   client's identity.  The OpenLDAP implementation exploits multiple
   methods to acquire the client's identity.  The discussion that
   follows is necessarily platform-specific.

   The OpenLDAP library provides a getpeereid() function to encapsulate
   all of the mechanisms used to acquire the identity.

   On FreeBSD and MacOSX the native getpeereid() is used.

   On modern Solaris systems the getpeerucred() system call is used.

   On systems like Linux that support the SO_PEERCRED option to
   getsockopt(), that option is used.

   On Unix systems lacking these explicit methods, descriptor passing is
   used.  In this case, the client must send a message containing the
   descriptor as its very first action immediately after the socket is
   connected.  The descriptor is attached to an LDAP Abandon Request
   [RFC4511] with message ID zero, whose parameter is also message ID
   zero.  This request is a pure no-op, and will be harmlessly ignored
   by any server that doesn't implement the protocol.

   For security reasons, the passed descriptor must be tightly
   controlled.  The client creates a pipe and sends the pipe descriptor
   in the message.  The server receives the descriptor and does an
   fstat() on it to determine the client's identity.  The received
   descriptor MUST be a pipe, and its permission bits MUST only allow
   access to its owner.  The owner uid and gid are then used as the
   client's identity.

   Note that these mechanisms are merely used to make the client's
   identity available to the server.  The server will not actually use
   the identity information unless the client performs a SASL Bind
   [RFC4513] using the EXTERNAL mechanism.  I.e., as with any normal
   LDAP session, the session remains in the anonymous state until the



Chu                     Expires September 1, 2007               [Page 7]

Internet-Draft                LDAP Over IPC                February 2007


   client issues a Bind request.

5.2.  Other Platforms

   It is possible to implement the corresponding functionality on
   Microsoft Windows-based systems using Named Pipes, but thus far there
   has been no demand for it, so the implementation has not been
   written.  These are brief notes on the steps required for an
   implementation.

   The Pipe should be created in byte-read mode, and the client must
   specify SECURITY_IMPERSONATION access when it opens the pipe.  The
   server can then retrieve the client's identity using the
   GetNamedPipeHandleState() function.

   Since Windows socket handles are not interchangeable with IPC
   handles, an alternate event handler would have to be provided instead
   of using Winsock's select() function.

































Chu                     Expires September 1, 2007               [Page 8]

Internet-Draft                LDAP Over IPC                February 2007


6.  Security Considerations

   This document describes a mechanism for accessing an LDAP server that
   is co-resident with the client machine.  As such, it is inherently
   immune to security issues associated with using LDAP across a
   network.  The mechanism also provides a means for a client to
   authenticate itself to the server without exposing any sensitive
   passwords.  The security of this authentication is equal to the
   security of the host machine.










































Chu                     Expires September 1, 2007               [Page 9]

Internet-Draft                LDAP Over IPC                February 2007


7.  References

7.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2717]  Petke, R. and I. King, "Registration Procedures for URL
              Scheme Names", BCP 35, RFC 2717, November 1999.

   [RFC3986]  Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
              Resource Identifier (URI): Generic Syntax", STD 66,
              RFC 3986, January 2005.

   [RFC4511]  Sermersheim, J., "Lightweight Directory Access Protocol
              (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4513]  Harrison, R., "Lightweight Directory Access Protocol
              (LDAP): Authentication Methods and Security Mechanisms",
              RFC 4513, June 2006.

   [RFC4516]  Smith, M. and T. Howes, "Lightweight Directory Access
              Protocol (LDAP): Uniform Resource Locator", RFC 4516,
              June 2006.

7.2.  Informative References

   [RFC0793]  Postel, J., "Transmission Control Protocol", STD 7,
              RFC 793, September 1981.






















Chu                     Expires September 1, 2007              [Page 10]

Internet-Draft                LDAP Over IPC                February 2007


Appendix A.  IANA Considerations

   This document satisfies the requirements of [RFC2717] for
   registration of a new URL scheme.















































Chu                     Expires September 1, 2007              [Page 11]

Internet-Draft                LDAP Over IPC                February 2007


Author's Address

   Howard Chu
   Symas Corp.
   18740 Oxnard Street, Suite 313A
   Tarzana, California  91356
   USA

   Phone: +1 818 757-7087
   Email: hyc@symas.com









































Chu                     Expires September 1, 2007              [Page 12]

Internet-Draft                LDAP Over IPC                February 2007


Full Copyright Statement

   Copyright (C) The IETF Trust (2007).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.


Acknowledgment

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).





Chu                     Expires September 1, 2007              [Page 13]

alt-openldap11-devel/drafts/draft-legg-ldap-admin-xx.txt000064400000035652150410163310017071 0ustar00INTERNET-DRAFT                                                   S. Legg
draft-legg-ldap-admin-02.txt                         Adacel Technologies
Intended Category: Standards Track                         June 16, 2004


             Lightweight Directory Access Protocol (LDAP):
                     Directory Administrative Model

    Copyright (C) The Internet Society (2004). All Rights Reserved.

   Status of this Memo


   This document is an Internet-Draft and is in full conformance with
   all provisions of Section 10 of RFC2026.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as
   Internet-Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress".

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   Distribution of this document is unlimited.  Comments should be sent
   to the author.

   This Internet-Draft expires on 16 December 2004.


Abstract

   This document adapts the X.500 directory administrative model for use
   by the Lightweight Directory Access Protocol.  The administrative
   model partitions the Directory Information Tree for various aspects
   of directory data administration, e.g., subschema, access control and
   collective attributes.  The generic framework that applies to every
   aspect of administration is described in this document.  The
   definitions that apply for a specific aspect of administration, e.g.,
   access control administration, are described in other documents.



Legg                    Expires 16 December 2004                [Page 1]

INTERNET-DRAFT       Directory Administrative Model        June 16, 2004


Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  2
   2.  Conventions. . . . . . . . . . . . . . . . . . . . . . . . . .  2
   3.  Administrative Areas . . . . . . . . . . . . . . . . . . . . .  2
   4.  Autonomous Administrative Areas. . . . . . . . . . . . . . . .  3
   5.  Specific Administrative Areas. . . . . . . . . . . . . . . . .  3
   6.  Inner Administrative Areas . . . . . . . . . . . . . . . . . .  4
   7.  Administrative Entries . . . . . . . . . . . . . . . . . . . .  4
   8.  Security Considerations. . . . . . . . . . . . . . . . . . . .  5
   9.  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . .  5
   10. References . . . . . . . . . . . . . . . . . . . . . . . . . .  5
       10.1.  Normative References. . . . . . . . . . . . . . . . . .  5
       10.2.  Informative References. . . . . . . . . . . . . . . . .  5
   11. Author's Address . . . . . . . . . . . . . . . . . . . . . . .  6
   Full Copyright Statement . . . . . . . . . . . . . . . . . . . . .  6

1.  Introduction

   This document adapts the X.500 directory administrative model [X501]
   for use by the Lightweight Directory Access Protocol (LDAP) [LDAP].
   The administrative model partitions the Directory Information Tree
   (DIT) for various aspects of directory data administration, e.g.,
   subschema, access control and collective attributes.  This document
   provides the definitions for the generic parts of the administrative
   model that apply to every aspect of directory data administration.

   Sections 3 to 7, in conjunction with [SUBENTRY], describe the means
   by which administrative authority is aportioned and exercised in the
   DIT.

   Aspects of administration that conform to the administrative model
   described in this document are detailed elsewhere, e.g., access
   control administration is described in [ACA] and collective attribute
   administration is described in [COLLECT].

   This document is derived from, and duplicates substantial portions
   of, Sections 4 and 8 of X.501 [X501].

2.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and  "OPTIONAL" in this
   document are to be interpreted as described in BCP 14, RFC 2119
   [RFC2119].

3.  Administrative Areas




Legg                    Expires 16 December 2004                [Page 2]

INTERNET-DRAFT       Directory Administrative Model        June 16, 2004


   An administrative area is a subtree of the DIT considered from the
   perspective of administration.  The root entry of the subtree is an
   administrative point.  An administrative point is represented by an
   entry holding an administrativeRole attribute [SUBENTRY].  The values
   of this attribute identify the kind of administrative point.

4.  Autonomous Administrative Areas

   The DIT may be partitioned into one or more non-overlapping subtrees
   termed autonomous administrative areas.  It is expected that the
   entries in an autonomous administrative area are all administered by
   the same administrative authority.

   An administrative authority may be responsible for several autonomous
   administrative areas in separated parts of the DIT but it SHOULD NOT
   arbitrarily partition the collection of entries under its control
   into autonomous administrative areas (thus creating adjacent
   autonomous areas administered by the same authority).

   The root entry of an autonomous administrative area's subtree is
   called an autonomous administrative point.  An autonomous
   administrative area extends from its autonomous administrative point
   downwards until another autonomous administrative point is
   encountered, at which point another autonomous administrative area
   begins.

5.  Specific Administrative Areas

   Entries in an administrative area may be considered in terms of a
   specific administrative function.  When viewed in this context, an
   administrative area is termed a specific administrative area.

   Examples of specific administrative areas are subschema specific
   administrative areas, access control specific areas and collective
   attribute specific areas.

   An autonomous administrative area may be considered as implicitly
   defining a single specific administrative area for each specific
   aspect of administration.  In this case, there is a precise
   correspondence between each such specific administrative area and the
   autonomous administrative area.

   Alternatively, for each specific aspect of administration, the
   autonomous administrative area may be partitioned into
   non-overlapping specific administrative areas.

   If so partitioned for a particular aspect of administration, each
   entry of the autonomous administrative area is contained in one and



Legg                    Expires 16 December 2004                [Page 3]

INTERNET-DRAFT       Directory Administrative Model        June 16, 2004


   only one specific administrative area for that aspect, i.e., specific
   administrative areas do not overlap.

   The root entry of a specific administrative area's subtree is called
   a specific administrative point.  A specific administrative area
   extends from its specific administrative point downwards until
   another specific administrative point of the same administrative
   aspect is encountered, at which point another specific administrative
   area begins.  Specific administrative areas are always bounded by the
   autonomous administrative area they partition.

   Where an autonomous administrative area is not partitioned for a
   specific aspect of administration, the specific administrative area
   for that aspect coincides with the autonomous administrative area.
   In this case, the autonomous administrative point is also the
   specific administrative point for this aspect of administration.  A
   particular administrative point may be the root of an autonomous
   administrative area and may be the root of one or more specific
   administrative areas for different aspects of administration.

   It is not necessary for an administrative point to represent each
   specific aspect of administrative authority.  For example, there
   might be an administrative point, subordinate to the root of the
   autonomous administrative area, which is used for access control
   purposes only.

6.  Inner Administrative Areas

   For some aspects of administration, e.g., access control or
   collective attributes, inner administrative areas may be defined
   within the specific administrative areas, to allow a limited form of
   delegation, or for administrative or operational convenience.

   An inner administrative area may be nested within another inner
   administrative area.  The rules for nested inner areas are defined as
   part of the definition of the specific administrative aspect for
   which they are allowed.

   The root entry of an inner administrative area's subtree is called an
   inner administrative point.  An inner administrative area (within a
   specific administrative area) extends from its inner administrative
   point downwards until a specific administrative point of the same
   administrative aspect is encountered.  An inner administrative area
   is bounded by the specific administrative area within which it is
   defined.

7.  Administrative Entries




Legg                    Expires 16 December 2004                [Page 4]

INTERNET-DRAFT       Directory Administrative Model        June 16, 2004


   An entry located at an administrative point is an administrative
   entry.  Administrative entries MAY have subentries [SUBENTRY] as
   immediate subordinates.  The administrative entry and its associated
   subentries are used to control the entries encompassed by the
   associated administrative area.  Where inner administrative areas are
   used, the scopes of these areas may overlap.  Therefore, for each
   specific aspect of administrative authority, a definition is required
   of the method of combination of administrative information when it is
   possible for entries to be included in more than one subtree or
   subtree refinement associated with an inner area defined for that
   aspect.

8.  Security Considerations

   This document defines a generic framework for employing policy of
   various kinds, e.g., access controls, to entries in the DIT.  Such
   policy can only be correctly enforced at a directory server holding a
   replica of a portion of the DIT if the administrative entries for
   administrative areas that overlap the portion of the DIT being
   replicated, and the subentries of those administrative entries
   relevant to any aspect of policy that is required to be enforced at
   the replica, are included in the replicated information.

   Administrative entries and subentries SHOULD be protected from
   unauthorized examination or changes by appropriate access controls.

9.  Acknowledgements

   This document is derived from, and duplicates substantial portions
   of, Sections 4 and 8 of X.501 [X501].

10.  References

10.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [LDAP]     Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

   [SUBENTRY] Zeilenga, K. and S. Legg, "Subentries in the Lightweight
              Directory Access Protocol (LDAP)", RFC 3672, December
              2003.

10.2.  Informative References




Legg                    Expires 16 December 2004                [Page 5]

INTERNET-DRAFT       Directory Administrative Model        June 16, 2004


   [COLLECT]  Zeilenga, K., "Collective Attributes in the Lightweight
              Directory Access Protocol (LDAP)", RFC 3671, December
              2003.

   [ACA]      Legg, S., "Lightweight Directory Access Protocol (LDAP):
              Access Control Administration",
              draft-legg-ldap-acm-admin-xx.txt, a work in progress, June
              2004.

   [X501]     ITU-T Recommendation X.501 (02/01) | ISO/IEC 9594-2:2001,
              Information technology - Open Systems Interconnection -
              The Directory: Models

11.  Author's Address

   Steven Legg
   Adacel Technologies Ltd.
   250 Bay Street
   Brighton, Victoria 3186
   AUSTRALIA

   Phone: +61 3 8530 7710
     Fax: +61 3 8530 7888
   EMail: steven.legg@adacel.com.au

Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and
   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be



Legg                    Expires 16 December 2004                [Page 6]

INTERNET-DRAFT       Directory Administrative Model        June 16, 2004


   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Changes in Draft 00

   This document reproduces Section 4 from
   draft-legg-ldap-acm-admin-00.txt as a standalone document.  All
   changes made are purely editorial.  No technical changes have been
   introduced.

Changes in Draft 01

   RFC 3377 replaces RFC 2251 as the reference for LDAP.

Changes in Draft 02

   The document has been reformatted in line with current practice.






















Legg                    Expires 16 December 2004                [Page 7]


alt-openldap11-devel/drafts/draft-joslin-config-schema-xx.txt000064400000177300150410163310020143 0ustar00
INTERNET-DRAFT                                                 M. Ansari
draft-joslin-config-schema-10.txt                               Infoblox
Category: Informational                                        L. Howard
Expires: September 2005                          PADL Software Pty. Ltd.
                                                  B. Neal-Joslin, Editor
                                                 Hewlett-Packard Company
                                                           4 March, 2005


                 A Configuration Schema for LDAP Based
                         Directory User Agents


Status of this Memo

     Copyright (C) The Internet Society (2005). This document is subject
     to the rights, licenses and restrictions contained in BCP 78, and
     except as set forth therein, the authors retain all their rights.

     This document and the information contained herein are provided on
     an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
     REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND
     THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES,
     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT
     THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR
     ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
     PARTICULAR PURPOSE.

     Internet-Drafts are working documents of the Internet Engineering
     Task Force (IETF), its areas, and its working groups.  Note that
     other groups may also distribute working documents as Internet-
     Drafts.

     Internet-Drafts are draft documents valid for a maximum of six
     months and may be updated, replaced, or obsoleted by other
     documents at any time.  It is inappropriate to use Internet-Drafts
     as reference material or to cite them other than as "work in
     progress."

     The list of current Internet-Drafts can be accessed at
     http://www.ietf.org/1id-abstracts.html

     The list of Internet-Draft Shadow Directories can be accessed at
     http://www.ietf.org/shadow.html

IPR Statement

     By submitting this Internet-Draft, I certify that any applicable



Neal-Joslin                                                    [Page 1]

Internet-Draft          DUA Configuration Schema              March 2005


     patent or other IPR claims of which I am aware have been disclosed,
     or will be disclosed, and any of which I become aware will be
     disclosed, in accordance with RFC 3668.

     The IETF takes no position regarding the validity or scope of any
     Intellectual Property Rights or other rights that might be claimed
     to pertain to the implementation or use of the technology described
     in this document or the extent to which any license under such
     rights might or might not be available; nor does it represent that
     it has made any independent effort to identify any such rights.
     Information on the procedures with respect to rights in RFC
     documents can be found in BCP 78 and BCP 79.

     The IETF invites any interested party to bring to its attention any
     copyrights, patents or patent applications, or other proprietary
     rights that may cover technology that may be required to implement
     this standard.  Please address the information to the IETF at
     ietf-ipr@ietf.org.

     Copies of IPR disclosures made to the IETF Secretariat and any
     assurances of licenses to be made available, or the result of an
     attempt made to obtain a general license or permission for the use
     of such proprietary rights by implementers or users of this
     specification can be obtained from the IETF on-line IPR repository
     at http://www.ietf.org/ipr.





Abstract

     This document describes a mechanism for distributed configuration
     of similar directory user agents.  This document defines a schema
     for configuration of these DUAs that may be discovered using the
     Lightweight Directory Access Protocol in RFC 2251[1].  A set of
     attribute types and an objectclass are proposed, along with
     specific guidelines for interpreting them.  A proposal of using
     attribute and objectclass mapping allows DUAs to re-configure their
     schema to that of the end user's environment. This document is
     intended to be a skeleton for future documents that describe
     configuration of specific DUA services.









Neal-Joslin                                                    [Page 2]

Internet-Draft          DUA Configuration Schema              March 2005


                           Table of Contents

 1.  Background & Motivation ......................................  4
 2.  General Issues ...............................................  5
 2.1 Terminology ..................................................  5
 2.2 Attributes ...................................................  5
 2.3 Object Classes ...............................................  6
 2.4 Syntax Definitions ...........................................  6
 3.  Attribute Definitions ........................................  6
 4.  Class Definition .............................................  8
 5.  Implementation Details .......................................  9
 5.1.1 Interpreting the preferredServerList attribute .............  9
 5.1.2 Interpreting the defaultServerList attribute ............... 10
 5.1.3 Interpreting the defaultSearchBase attribute ............... 11
 5.1.4 Interpreting the authenticationMethod attribute ............ 12
 5.1.5 Interpreting the credentialLevel attribute ................. 13
 5.1.6 Interpreting the serviceSearchDescriptor attribute ......... 14
 5.1.7 Interpreting the attributeMap attribute .................... 17
 5.1.8 Interpreting the searchTimeLimit attribute ................. 20
 5.1.9 Interpreting the bindTimeLimit attribute ................... 20
 5.1.10 Interpreting the followReferrals attribute ................ 21
 5.1.11 Interpreting the dereferenceAliases attribute ............. 21
 5.1.12 Interpreting the profileTTL attribute ..................... 21
 5.1.13 Interpreting the objectclassMap attribute ................. 22
 5.1.14 Interpreting the defaultSearchScope attribute ............. 24
 5.1.15 Interpreting the serviceAuthenticationMethod attribute .... 24
 5.1.16 Interpreting the serviceCredentialLevel attribute ......... 25
 5.2 Binding to the Directory Server .............................. 26
 6.  Security Considerations ...................................... 26
 7.  Acknowledgments .............................................. 27
 8.  References ................................................... 27
 8.1 Normative References ......................................... 27
 8.2 Informative References ....................................... 28
 9.  Examples ..................................................... 29

















Neal-Joslin                                                    [Page 3]

Internet-Draft          DUA Configuration Schema              March 2005


1.  Background & Motivation

     The LDAP protocol has brought about a new and nearly ubiquitous
     acceptance of the directory server.  Many new client applications
     (DUAs) are being created that use LDAP directories for many
     different services.  And although the LDAP protocol has eased the
     development of these applications, some challenges still exist for
     both developers and directory administrators.

     The authors of this document are implementers of DUAs described by
     RFC 2307 [2].  In developing these agents, we felt there are
     several issues that still need to be addressed to ease the
     deployment and configuration of a large network of these DUAs.

     One of these challenges stems from the lack of a utopian schema.  A
     utopian schema would be one that every application developer could
     agree upon and that would support every application.  Unfortunately
     today, many DUAs define their own schema (like RFC 2307 vs.
     Microsoft's Services for Unix [3]) containing similar attributes,
     but with different attribute names.  This can lead to data
     redundancy within directory entries and give directory
     administrators unwanted challenges, updating schemas and
     synchronizing data.

     So, one goal of this document is to eliminate data redundancy by
     having DUAs configure themselves to the schema of the deployed
     directory, instead of forcing its own schema on the directory.

     Another goal of this document is to provide the DUA with enough
     configuration information so that it can discover how to retrieve
     its data in the directory, such as what locations to search in the
     directory tree.

     Finally, this document intends to describe a configuration method
     for DUAs that can be shared among many DUAs, on various platforms,
     providing as such, a configuration profile, the purpose is to
     centralize and simplify management of DUAs.

     This document is intended to provide the skeleton framework for
     future drafts, which will describe the individual implementation
     details for the particular services provided by that DUA.  The
     authors of this document plan to develop such a document for the
     Network Information Service DUA, described by RFC 2307 or its
     successor.

     We expect that as DUAs take advantage of this configuration scheme,
     each DUA will require additional configuration parameters, not
     specified by this document.  Thus, we would expect that new



Neal-Joslin                                                    [Page 4]

Internet-Draft          DUA Configuration Schema              March 2005


     auxiliary object classes, containing new configuration attributes
     will be created, and then joined with the structural class defined
     by this document to create a configuration profile for a particular
     DUA service.  And that by joining various auxiliary objectclasses
     for different DUA services, that configuration of various DUA
     services can be controlled by a single configuration profile entry.


2.  General Issues

     The schema defined by this document is defined under the "DUA
     Configuration Schema."  This schema is derived from the OID: iso
     (1) org (3) dod (6) internet (1) private (4) enterprises (1)
     Hewlett-Packard Company (11) directory (1) LDAP-UX Integration
     Project (3) DUA Configuration Schema (1).  This OID is represented
     in this document by the keystring "DUAConfSchemaOID"
     (1.3.6.1.4.1.11.1.3.1).

2.1 Terminology

     The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
     "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in
     this document are to be interpreted as described in BCP 14 (RFC
     2119) [4].

2.2 Attributes

     The attributes and classes defined in this document are summarized
     below.

     The following attributes are defined in this document:

          preferredServerList
          defaultServerList
          defaultSearchBase
          defaultSearchScope
          authenticationMethod
          credentialLevel
          serviceSearchDescriptor
          serviceCredentialLevel
          serviceAuthenticationMethod
          attributeMap
          objectclassMap
          searchTimeLimit
          bindTimeLimit
          followReferrals
          dereferenceAliases
          profileTTL



Neal-Joslin                                                    [Page 5]

Internet-Draft          DUA Configuration Schema              March 2005


2.3 Object Classes

     The following object class is defined in this document:

          DUAConfigProfile

2.4 Syntax Definitions

     The following syntax definitions are used throughout this document.
     This document does not define new syntaxes that must be supported
     by the directory server.  The string encoding used by the
     attributes defined in this document can be found section 5.

          keystring                 as defined by RFC 2252 [5]
          descr                     as defined by RFC 2252 section 4.1
          a                         as defined by RFC 2252 section 4.1
          d                         as defined by RFC 2252 section 4.1
          space                     as defined by RFC 2252 section 4.1
          whsp                      as defined by RFC 2252 section 4.1
          base                      as defined by RFC 2253 [6]
          DistinguishedName         as defined by RFC 2253 section 2
          RelativeDistinguishedName as defined by RFC 2253 section 2
          scope                     as defined by RFC 2255 [7]
          host                      as defined by RFC 3986
                                    section 3.2.2 [8]
          hostport                  host [":" port ]
          port                      as defined by RFC 3986
                                    section 3.2.3 [8]
          serviceID                 = keystring


3.  Attribute Definitions

     This section contains attribute definitions to be used by DUAs when
     discovering their configuration.

          ( DUAConfSchemaOID.1.0 NAME 'defaultServerList'
            DESC 'Default LDAP server host addresses used by a DUA'
            EQUALITY caseIgnoreMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.1 NAME 'defaultSearchBase'
            DESC 'Default LDAP base DN used by a DUA'
            EQUALITY distinguishedNameMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
            SINGLE-VALUE )




Neal-Joslin                                                    [Page 6]

Internet-Draft          DUA Configuration Schema              March 2005


          ( DUAConfSchemaOID.1.2 NAME 'preferredServerList'
            DESC 'Preferred LDAP server host addresses to be used by a
            DUA'
            EQUALITY caseIgnoreMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.3 NAME 'searchTimeLimit'
            DESC 'Maximum time in seconds a DUA should allow for a
            search to complete'
            EQUALITY integerMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.4 NAME 'bindTimeLimit'
            DESC 'Maximum time in seconds a DUA should allow for the
            bind operation to complete'
            EQUALITY integerMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.5 NAME 'followReferrals'
            DESC 'Tells DUA if it should follow referrals
            returned by a DSA result'
            EQUALITY booleanMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.6 NAME 'authenticationMethod'
            DESC 'A keystring which identifies the type of
            authentication methods used to contact the DSA'
            EQUALITY caseIgnoreMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.7 NAME 'profileTTL'
            DESC 'Time to live, in seconds, before a client DUA
            should re-read this configuration profile'
            EQUALITY integerMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.9 NAME 'attributeMap'
            DESC 'Attribute mappings used by a DUA'
            EQUALITY caseIgnoreIA5Match
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

          ( DUAConfSchemaOID.1.10 NAME 'credentialLevel'



Neal-Joslin                                                    [Page 7]

Internet-Draft          DUA Configuration Schema              March 2005


            DESC 'Identifies type of credentials a DUA should
            use when binding to the LDAP server'
            EQUALITY caseIgnoreIA5Match
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.11 NAME 'objectclassMap'
            DESC 'Objectclass mappings used by a DUA'
            EQUALITY caseIgnoreIA5Match
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

          ( DUAConfSchemaOID.1.12 NAME 'defaultSearchScope'
            DESC 'Default search scope used by a DUA'
            EQUALITY caseIgnoreIA5Match
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
            SINGLE-VALUE )

          ( DUAConfSchemaOID.1.13 NAME 'serviceCredentialLevel'
            DESC 'Identifies type of credentials a DUA
            should use when binding to the LDAP server for a
            specific service'
            EQUALITY caseIgnoreIA5Match
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

          ( DUAConfSchemaOID.1.14 NAME 'serviceSearchDescriptor'
            DESC 'LDAP search descriptor list used by a DUA'
            EQUALITY caseExactMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

          ( DUAConfSchemaOID.1.15 NAME 'serviceAuthenticationMethod'
            DESC 'Identifies type of authentication method a DUA
            should use when binding to the LDAP server for a
            specific service'
            EQUALITY caseIgnoreMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

          ( DUAConfSchemaOID.1.16 NAME 'dereferenceAliases'
            DESC 'Tells DUA if it should dereference aliases'
            EQUALITY booleanMatch
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
            SINGLE-VALUE )


4.  Class Definition

     The objectclass below is constructed from the attributes defined in
     3, with the exception of the cn attribute, which is defined in RFC
     2256 [9].  cn is used to represent the name of the DUA



Neal-Joslin                                                    [Page 8]

Internet-Draft          DUA Configuration Schema              March 2005


     configuration profile.

        ( DUAConfSchemaOID.2.5 NAME 'DUAConfigProfile'
          SUP top STRUCTURAL
          DESC 'Abstraction of a base configuration for a DUA'
          MUST ( cn )
          MAY ( defaultServerList $ preferredServerList $
                defaultSearchBase $ defaultSearchScope $
                searchTimeLimit $ bindTimeLimit $
                credentialLevel $ authenticationMethod $
                followReferrals $ dereferenceAliases $
                serviceSearchDescriptor $ serviceCredentialLevel $
                serviceAuthenticationMethod $ objectclassMap $
                attributeMap $ profileTTL ) )


5.  Implementation Details

5.1.1 Interpreting the preferredServerList attribute

     Interpretation:

          As described by the syntax, the preferredServerList parameter
          is a white-space separated list of server addresses and
          associated port numbers.  When the DUA needs to contact a DSA,
          the DUA MUST first attempt to contact one of the servers
          listed in the preferredServerList attribute.  The DUA MUST
          contact the DSA specified by the first server address in the
          list.  If that DSA is unavailable, the remaining DSAs MUST be
          queried in the order provided (left to right) until a
          connection is established with a DSA.  Once a connection with
          a DSA is established, the DUA SHOULD NOT attempt to establish
          a connection with the remaining DSAs.  The purpose of
          enumerating multiple DSAs is not for supplemental data, but
          for high availability of replicated data.  This is also the
          main reason why an LDAP URL[10] syntax was not selected for
          this document.

          If the DUA is unable to contact any of the DSAs specified by
          the preferredServerList, the defaultServerList attribute MUST
          be examined, as described in 5.1.2.  The servers identified by
          the preferredServerList MUST be contacted before attempting to
          contact any of the servers specified by the defaultServerList.

     Syntax:

          serverList       = hostport *(space [hostport])




Neal-Joslin                                                    [Page 9]

Internet-Draft          DUA Configuration Schema              March 2005


     Default Value:

          The preferredServerList attribute does not have a default
          value.  Instead a DUA MUST examine the defaultServerList
          attribute.

     Other attribute notes:

          This attribute is used in conjunction with the
          defaultServerList attribute.  Please see section 5.1.2 for
          additional implementation notes.  Determining how the DUA
          should query the DSAs also depends on the additional
          configuration attributes, credentialLevel,
          serviceCredentialLevel, bindTimeLimit,
          serviceAuthenticationMethod and authenticationMethod.  Please
          review section 5.2 for details on how a DUA should properly
          bind to a DSA.

     Example:

          preferredServerList: 192.168.169.170 ldap1.mycorp.com
            ldap2:1389 [1080::8:800:200C:417A]:389

5.1.2 Interpreting the defaultServerList attribute

     Interpretation:

          The defaultServerList attribute MUST only be examined if the
          preferredServerList attribute is not provided, or the DUA is
          unable to establish a connection with one of the DSAs
          specified by the preferredServerList.

          If more than one address is provided, the DUA may choose to
          either accept the order provided, or choose to create its own
          order, based on what the DUA determines is the "best" order of
          servers to query.  For example, the DUA may choose to examine
          the server list and choose to query the DSAs in order based on
          the "closest" server or the server with the least amount of
          "load." Interpretation of the "best" server order is entirely
          up to the DUA, and not part of this document.

          Once the order of server addresses is determined, the DUA
          contacts the DSA specified by the first server address in the
          list.  If that DSA is unavailable, the remaining DSAs SHOULD
          be queried until an available DSA is found or no more DSAs are
          available.  If a server address or port is invalid, the DUA
          SHOULD proceed to the next server address as described just
          above.



Neal-Joslin                                                   [Page 10]

Internet-Draft          DUA Configuration Schema              March 2005


     Syntax:

          serverList       = hostport *(space [hostport])

     Default Value:

          If a defaultServerList attribute is not provided, the DUA MAY
          attempt to contact the same DSA that provided the
          configuration profile entry itself.  The default DSA is
          contacted only if the preferredServerList attribute is also
          not provided.

     Other attribute notes:

          This attribute is used in conjunction with the
          preferredServerList attribute.  Please see section 5.1.1 for
          additional implementation notes.  Determining how the DUA
          should query the DSAs also depends on the additional
          configuration attributes, credentialLevel,
          serviceCredentialLevel, bindTimeLimit,
          serviceAuthenticationMethod and authenticationMethod.  Please
          review section 5.2 for details on how a DUA should properly
          contact a DSA.

     Example:

          defaultServerList: 192.168.169.170 ldap1.mycorp.com
            ldap2:1389 [1080::8:800:200C:417A]:5912

5.1.3 Interpreting the defaultSearchBase attribute

     Interpretation:

          When a DUA needs to search the DSA for information, this
          attribute provides the base for the search.  This parameter
          can be overridden or appended by the serviceSearchDescriptor
          attribute.  See section 5.1.6.

     Syntax:

          Defined by OID 1.3.6.1.4.1.1466.115.121.1.12 [5]

     Default Value:

          There is no default value for the defaultSearchBase.  A DUA
          MAY define its own method for determining the search base, if
          the defaultSearchBase is not provided.




Neal-Joslin                                                   [Page 11]

Internet-Draft          DUA Configuration Schema              March 2005


     Other attribute notes:

          This attribute is used in conjunction with the
          serviceSearchDescriptor attribute.  See section 5.1.6.

     Example:

          defaultSearchBase: dc=mycompany,dc=com

5.1.4 Interpreting the authenticationMethod attribute

     Interpretation:

          The authenticationMethod attribute defines an ordered list of
          LDAP bind methods to be used when attempting to contact a
          DSA[11].   The serviceAuthenticationMethod overrides this
          value for a particular service (see 5.1.15.)  Each method MUST
          be attempted in the order provided by the attribute, until a
          successful LDAP bind is performed ("none" is assumed to always
          be successful.) However the DUA MAY skip over one or more
          methods.  See section 5.2 for more information.

            none   - The DUA does not perform an LDAP bind.
            simple - The DUA performs an LDAP simple bind.
            sasl   - The DUA performs an LDAP SASL[12] bind using the
                     specified SASL mechanism and options.
            tls    - The DUA performs an LDAP StartTLS operation
                     followed by the specified bind method (for more
                     information refer to section 5.1 of RFC 2830 [13]).

     Syntax:

          authMethod  = method *(";" method)
          method      = none | simple | sasl | tls
          none        = "none"
          simple      = "simple"
          sasl        = "sasl/" saslmech [ ":" sasloption ]
          sasloption  = "auth-conf" | "auth-int"
          tls         = "tls:" (none | simple | sasl)
          saslmech    = SASL mechanism name as defined in [18]

          Note: Although multiple authentication methods may be
          specified in the syntax, at most one of each type is allowed.
          I.E. "simple;simple" is invalid.

     Default Value:

          If the authenticationMethod or serviceAuthenticationMethod



Neal-Joslin                                                   [Page 12]

Internet-Draft          DUA Configuration Schema              March 2005


          (for that particular service) attributes are not provided, the
          DUA MAY choose to bind to the DSA using any method defined by
          the DUA.  However, if either authenticationMethod or
          serviceAuthenticationMethod are provided, the DUA MUST only
          use the methods specified.

     Other attribute notes:

          When using TLS, the string "tls:sasl/EXTERNAL" implies that
          two way (DSA and DUA) authentication is to be performed.  Any
          other TLS authentication method implies one way (DSA side
          credential) authentication.

          Determining how the DUA should bind to the DSAs also depends
          on the additional configuration attributes, credentialLevel,
          serviceCredentialLevel, serviceAuthenticationMethod and
          bindTimeLimit.  Please review section 5.2 for details on how
          to properly bind to a DSA.

     Example:

          authenticationMethod: tls:simple;sasl/DIGEST-MD5
          (see [14])

5.1.5 Interpreting the credentialLevel attribute

     Interpretation:

          The credentialLevel attribute defines what type(s) of
          credential(s) the DUA MUST use when contacting the DSA.  The
          serviceCredentialLevel overrides this value for a particular
          service (5.1.16.)  The credentialLevel can contain more than
          one credential type, separated by white space.

          anonymous - The DUA SHOULD NOT use a credential when binding
          to the DSA.

          proxy - The DUA SHOULD use a known proxy identity when binding
          to the DSA.  A proxy identity is a specific credential that
          was created to represent the DUA.  This document does not
          define how the proxy user should be created, or how the DUA
          should determine what the proxy user's credential is.  This
          functionality is up to each implementation.

          self - When the DUA is acting on behalf of a known identity,
          the DUA MUST attempt to bind to the DSA as that identity.  The
          DUA should contain methods to determine the identity of the
          user such that that identity can be authenticated by the



Neal-Joslin                                                   [Page 13]

Internet-Draft          DUA Configuration Schema              March 2005


          directory server using the defined authentication methods.

          If the credentialLevel contains more than one credential type,
          the DUA MUST use the credential types in the order specified.
          However, the DUA MAY skip over one or more credential types.
          As soon as the DUA is able to successfully bind to the DSA,
          the DUA SHOULD NOT attempt to bind using the remaining
          credential types.

     Syntax:

          credentialLevel   = level *(space level)
          level             = self | proxy | anonymous
          self              = "self"
          proxy             = "proxy"
          anonymous         = "anonymous"

          Note: Although multiple credential levels may be specified in
          the syntax, at most one of each type is allowed.  Refer to
          implementation notes in section 5.2 for additional syntax
          requirements for the credentialLevel attribute.

     Default Value:

          If the credentialLevel attribute is not defined, the DUA
          SHOULD NOT use a credential when binding to the DSA (also
          known as anonymous.)

     Other attribute notes:

          Determining how the DUA should bind to the DSAs also depends
          on the additional configuration attributes,
          authenticationMethod, serviceAuthenticationMethod,
          serviceCredentialLevel and bindTimeLimit.  Please review
          section 5.2 for details on how to properly bind to a DSA.

     Example:

          credentialLevel: proxy anonymous

5.1.6 Interpreting the serviceSearchDescriptor attribute

     Interpretation:

          The serviceSearchDescriptor attribute defines how and where a
          DUA SHOULD search for information for a particular service.
          The serviceSearchDescriptor contains a serviceID, followed by
          one or more base-scope-filter triples.  These base-scope-



Neal-Joslin                                                   [Page 14]

Internet-Draft          DUA Configuration Schema              March 2005


          filter triples are used to define searches only for the
          specific service.  Multiple base-scope-filters allow the DUA
          to search for data in multiple locations of the DIT.  Although
          this syntax is very similar to the LDAP URL[8], this draft
          requires the ability to supply multiple hosts as part of the
          configuration of the DSA.  In addition, an ordered list of
          search descriptors is required, which can not be specified by
          the LDAP URL.

          In addition to the triples, serviceSearchDescriptor might also
          contain the DN of an entry that will contain an alternate
          profile.  The DSA SHOULD re-evaluate the alternate profile and
          perform searches as specified by that profile.

          If the base, as defined in the serviceSearchDescriptor, is
          followed by the "," (ASCII 0x2C) character, this base is known
          as a relative base.  This relative base may be constructed of
          one or more RDN components.  The DUA MUST define the search
          base by appending the relative base with the
          defaultSearchBase.

     Syntax:

          serviceSearchList = serviceID ":" serviceSearchDesc
                              *(";" serviceSearchDesc)
          serviceSearchDesc = confReferral | searchDescriptor
          searchDescriptor  = [base] ["?" [scope] ["?" [filter]]]
          confReferral      = "ref:" DistinguishedName
          base              = DistinguishedName |
                              RelativeBaseName
          RelativeBaseName  = 1*(RelativeDistinguishedName ",")
          filter            = UTF-8 encoded string

          If the base or filter contains the ";" (ASCII 0x3B) "?" (ASCII
          0x3F) """ (ASCII 0x22) or "\" (ASCII 0x5C) characters, those
          characters MUST be escaped (preceded with the "\" character.)
          Alternately the DN may be surrounded by quotes (ASCII 0x22.)
          Refer to RFC 2253, section 4.  If the base or filter are
          surrounded by quotes, only the """ character needs to be
          escaped.  Any character that is preceded by the "\" character,
          which does not need to be escaped results in both "\"
          character and the character itself.

          The usage and syntax of the filter string MUST be defined by
          the DUA service.  A suggested syntax would be that as defined
          by RFC 2254.

          If a DUA is performing a search for a particular service,



Neal-Joslin                                                   [Page 15]

Internet-Draft          DUA Configuration Schema              March 2005


          which has a serviceSearchDescriptor defined, the DUA MUST set
          the base, scope and filter as defined.  Each base-scope-filter
          triple represents a single LDAP search operation.  If multiple
          base-scope-filter triples are provided in the
          serviceSearchDescriptor, the DUA SHOULD perform multiple
          search requests and in that case it MUST be in the order
          specified by the serviceSearchDescriptor.

          FYI: Service search descriptors do not exactly follow the LDAP
          URL syntax [7].  The reasoning for this difference is to
          separate the host name(s) from the filter.  This allows the
          DUA to have a more flexible solution in choosing its DSA.

     Default Values:

          If a serviceSearchDescriptor, or an element their-of, is not
          defined for a particular service, the DUA SHOULD create the
          base, scope and filter as follows:

            base   - Same as the defaultSearchBase or as
                     defined by the DUA service.
            scope  - Same as the defaultSearchScope or as
                     defined by the DUA service.
            filter - Use defaults as defined by DUAs service.

          If the defaultSearchBase or defaultSearchScope are not
          defined, then the DUA service may use its own default.


     Other attribute notes:

          If a serviceSearchDescriptor exists for a given service, the
          service MUST use at least one base-scope-filter triple in
          performing searches.  It SHOULD perform multiple searches per
          service if multiple base-scope-filter triples are defined for
          that service.

          The details of how the "filter" is interpreted by each DUA's
          service is defined by that service.  This means the filter is
          NOT REQUIRED to be a legal LDAP filter [15].  Furthermore,
          determining how attribute and objectclass mapping affects that
          search filter MUST be defined by the service.  I.E. The DUA
          SHOULD specify if the attributes in the filter have assumed to
          already have been mapped, or if it is expected that attribute
          mapping (see 5.1.7) would be applied to the filter.  In
          general practice, implementation and usability suggests that
          attribute and objectclass mapping (sections 5.1.7 and 5.1.13)
          SHOULD NOT be applied to the filter defined in the



Neal-Joslin                                                   [Page 16]

Internet-Draft          DUA Configuration Schema              March 2005


          serviceSearchDescriptor.

          It is assumed the serviceID is unique to a given service
          within the scope of any DUA that might use the given profile.

     Example:

          defaultSearchBase: dc=mycompany,dc=com

          serviceSearchDescriptor: email:ou=people,ou=org1,?
           one;ou=contractor,?one;
           ref:cn=profile,dc=mycompany,dc=com

          In this example, the DUA MUST search in
          "ou=people,ou=org1,dc=mycompany,dc=com" first.  The DUA then
          SHOULD search in "ou=contractor,dc=mycompany,dc=com", and
          finally it SHOULD search other locations as specified in the
          profile described at "cn=profile,dc=mycompany,dc=com".  For
          more examples, see section 9.


5.1.7 Interpreting the attributeMap attribute

     Interpretation:

          A DUA SHOULD perform attribute mapping for all LDAP operations
          performed for a service that has an attributeMap entry.
          Because attribute mapping is specific to each service within
          the DUA, a "serviceID" is required as part of the attributeMap
          syntax.  I.E. not all DUA services should necessarily perform
          the same attribute mapping.

          Attribute mapping in general is expected be used to map
          attributes of similar syntaxes as specified by the service
          supported by the DUA.  However, a DUA is NOT REQUIRED to
          verify syntaxes of mapped attributes.  If the DUA does
          discover that the syntax of the mapped attribute does not
          match that of the original attribute, the DUA MAY perform
          translation between the original syntax and the new syntax.
          When DUAs do support attribute value translation, the list of
          capable translations SHOULD be documented in a description of
          the DUA service.

     Syntax:

          attributeMap      = serviceID ":" origAttribute "="
                              attributes
          origAttribute     = attribute



Neal-Joslin                                                   [Page 17]

Internet-Draft          DUA Configuration Schema              March 2005


          attributes        = wattribute *( space wattribute )
          wattribute        = whsp newAttribute whsp
          newAttribute      = descr | "*NULL*"
          attribute         = descr

          Values of the origAttribute are defined by and SHOULD be
          documented for the DUA service, as a list of known supported
          attributes.

     Default Value:

          By default, attributes that are used by a DUA service are not
          mapped unless mapped by the attributeMap attributes.  The DUA
          MUST NOT map an attribute unless it is explicitly defined by
          an attributeMap attribute.

     Other attribute notes:

          When an attribute is mapped to the special keystring "*NULL*",
          the DUA SHOULD NOT request that attribute from the DSA, when
          performing a search or compare request.  If the DUA is also
          capable of performing modification on the DSA, the DUA SHOULD
          NOT attempt to modify any attribute which has been mapped to
          "*NULL*".

          It is assumed the serviceID is unique to a given service
          within the scope of the DSA.

          A DUA SHOULD support attribute mapping.  If it does, the
          following additional rules apply:

          1) The list of attributes that are allowed to be mapped SHOULD
          defined by and documented for the service.

          2) Any supported translation of mapping from attributes of
          dissimilar syntax SHOULD also be defined and documented.

          3) If an attribute may be mapped to multiple attributes the
          DSA SHOULD define a syntax or usage statement for how the new
          attribute value will be constructed.  Furthermore, the
          resulting translated syntax of the combined attributes MUST be
          the same as the attribute being mapped.

          4) A DUA MUST support mapping of attributes using the
          attribute OID.  It SHOULD support attribute mapping based on
          the attribute name.

          5) It is recommended that attribute mapping not be applied to



Neal-Joslin                                                   [Page 18]

Internet-Draft          DUA Configuration Schema              March 2005


          parents of the target entries.

          6) Attribute mapping is not recursive.  In other words, if an
          attribute has been mapped to a target attribute, that new
          target attribute MUST NOT be mapped to a third attribute.

          7) A given attribute MUST only be mapped once for a given
          service.


     Example:

          Suppose a DUA is acting on behalf of an email service.  By
          default the "email" service uses the "mail", "cn" and "sn"
          attributes to discover mail addresses.  However, the email
          service has been deployed in an environment that uses
          "employeeName" instead of "cn."  And also instead of using the
          "mail" attribute for email addresses, the "email" attribute is
          used for that purpose.  In this case, the attribute "cn" can
          be mapped to "employeeName," allowing the DUA to perform
          searches using the "employeeName" attribute as part of the
          search filter, instead of "cn".  And "mail" can be mapped to
          "email" when attempting to retrieve the email address.  This
          mapping is performed by adding the attributeMap attributes to
          the configuration profile entry as follows (represented in
          LDIF[16]):

          attributeMap: email:cn=employeeName
          attributeMap: email:mail=email

          As described above, the DUA MAY also map a single attribute to
          multiple attributes.  When mapping a single attribute to more
          than one attribute, the new syntax or usage of the mapped
          attribute must be intrinsically defined by the DUAs service.

          attributeMap: email:cn=firstName lastName

          In the above example, the DUA creates the new value by
          generating space separated string using the values of the
          mapped attributes.  In this case, a special mapping must be
          defined so that a proper search filter can be created.  For
          further information on this example, please refer to section
          9.

          Another possibility for multiple attribute mapping might come
          in when constructing returned attributes.  For example,
          perhaps all email addresses are of a guaranteed syntax of
          "uid@domain".  And in this example, the uid and domain are



Neal-Joslin                                                   [Page 19]

Internet-Draft          DUA Configuration Schema              March 2005


          separate attributes in the directory.  The email service may
          define that if the "mail" attribute is mapped to two different
          attributes, it will construct the email address as a
          concatenation of the uid and domain attributes, placing the
          "@" character between them.

          attributeMap: email:mail=uid domain


5.1.8 Interpreting the searchTimeLimit attribute

     Interpretation:

          The searchTimeLimit attribute defines the maximum time, in
          seconds, that a DUA SHOULD allow to perform a search request.

     Syntax:

          Defined by OID 1.3.6.1.4.1.1466.115.121.1.27. [5]

     Default Value:

          If the searchTimeLimit attribute is not defined or is zero,
          the search time limit is not enforced by the DUA.

     Other attribute notes:

          This time limit only includes the amount of time required to
          perform the LDAP search operation.  If other operations are
          required, those operations do not need to be considered part
          of the search time.  See bindTimeLimit for the LDAP bind
          operation.

5.1.9 Interpreting the bindTimeLimit attribute

     Interpretation:

          The bindTimeLimit attribute defines the maximum time, in
          seconds, that a DUA SHOULD allow to perform an LDAP bind
          request against each server on the preferredServerList or
          defaultServerList.

     Syntax:

          Defined by OID 1.3.6.1.4.1.1466.115.121.1.27.

     Default Value:




Neal-Joslin                                                   [Page 20]

Internet-Draft          DUA Configuration Schema              March 2005


          If the bindTimeLimit attribute is not defined or is zero, the
          bind time limit is not enforced by the DUA.

     Other attribute notes:

          This time limit only includes the amount of time required to
          perform the LDAP bind operation.  If other operations are
          required, those operations do not need to be considered part
          of the bind time.  See searchTimeLimit for the LDAP search
          operation.

5.1.10 Interpreting the followReferrals attribute

     Interpretation:

          If set to TRUE, the DUA SHOULD follow any referrals if
          discovered.

          If set to FALSE, the DUA MUST NOT follow referrals.

     Syntax:

          Defined by OID 1.3.6.1.4.1.1466.115.121.1.7. [5]

     Default Value:

          If the followReferrals attribute is not set or set to an
          invalid value the default value is TRUE.

5.1.11 Interpreting the dereferenceAliases attribute

     Interpretation:

          If set to TRUE, the DUA SHOULD enable alias dereferencing.

          If set to FALSE, the DUA MUST NOT enable alias dereferencing.

     Syntax:

          Defined by OID 1.3.6.1.4.1.1466.115.121.1.7.

     Default Value:

          If the dereferenceAliases attribute is not set or set to an
          invalid value the default value is TRUE.

5.1.12 Interpreting the profileTTL attribute




Neal-Joslin                                                   [Page 21]

Internet-Draft          DUA Configuration Schema              March 2005


     Interpretation:

          The profileTTL attribute defines how often the DUA SHOULD re-
          load and reconfigure itself using the corresponding
          configuration profile entry.  The value is represented in
          seconds.  Once a DUA reloads the profile entry, it SHOULD re-
          configure itself with the new values.

     Syntax:

          Defined by OID 1.3.6.1.4.1.1466.115.121.1.27.

     Default Value:

          If not specified the DUA MAY use its own reconfiguration
          policy.

     Other attribute notes:

          If the profileTTL value is zero, the DUA SHOULD NOT
          automatically re-load the configuration profile.

5.1.13 Interpreting the objectclassMap attribute

     Interpretation:

          A DUA MAY perform objectclass mapping for all LDAP operations
          performed for a service that has an objectclassMap entry.
          Because objectclass mapping is specific for each service
          within the DUA, a "serviceID" is required as part of the
          objectclassMap syntax.  I.E. Not all DUA services should
          necessarily perform the same objectclass mapping.

          Objectclass mapping SHOULD be used in conjunction with
          attribute mapping to map the required schema by the service to
          an equivalent schema that is available in the directory.

          Objectclass mapping may or may not be required by a DUA.
          Often, the objectclass attribute is used in search filters.
          If a service search descriptor is provided, it is expected
          that the search filter contains a "correct" search filter
          (though this is not a requirement,) which does not need to be
          re-mapped.  However, when the service search descriptor is not
          provided, and the default search filter for that service
          contains the objectclass attribute, that search filter SHOULD
          be re-defined by objectclass mapping.  If a default search
          filter is not used, it SHOULD be re-defined through the
          serviceSearchDescriptor.  If a serviceSearchDescriptor is



Neal-Joslin                                                   [Page 22]

Internet-Draft          DUA Configuration Schema              March 2005


          defined for a particular service, it SHOULD NOT be re-mapped
          by either the objectclassMap or attributeMap values.

          One condition where the objectclassMap SHOULD be used is when
          the DUA is providing gateway functionality.  In this case, the
          DUA is acting on behalf of another service, which may pass in
          a search filter itself.  In this type of DUA, the DUA may
          alter the search filter according to the appropriate
          attributeMap and objectclassMap values.  And in this case, it
          is also assumed that a serviceSearchDescriptor is not defined.

     Syntax:

          objectclassMap    = serviceID ":" origObjectclass "="
                              objectclass
          origObjectclass   = objectclass
          objectclass       = keystring

          Values of the origObjectclass depend on the type of DUA
          Service using the objectclass mapping feature.

     Default Value:

          The DUA MUST NOT remap an objectclass unless it is explicitly
          defined by an objectclassMap attribute.

     Other attribute notes:

          A DUA SHOULD support objectclass mapping.  If it does, the DUA
          MUST support mapping of objectclasses using the objectclass
          OID.  It SHOULD support objectclass mapping based on the
          objectclass name.

          It is assumed the serviceID is unique to a given service
          within the scope of the DSA.

     Example:

          Suppose a DUA is acting on behalf of an email service.  By
          default the "email" service uses the "mail", "cn" and "sn"
          attributes to discover mail addresses in entries created using
          inetOrgPerson objectclass[17].  However, the email service has
          been deployed in an environment that uses entries created
          using "employee" objectclass.  In this case, the attribute
          "cn" can be mapped to "employeeName", and "inetOrgPerson" can
          be mapped to "employee", allowing the DUA to perform LDAP
          operations using the entries that exist in the directory.
          This mapping is performed by adding attributeMap and



Neal-Joslin                                                   [Page 23]

Internet-Draft          DUA Configuration Schema              March 2005


          objectclassMap attributes to the configuration profile entry
          as follows (represented in LDIF[16]):

          attributeMap: email:cn=employeeName
          objectclassMap: email:inetOrgPerson=employee


5.1.14 Interpreting the defaultSearchScope attribute

     Interpretation:

          When a DUA needs to search the DSA for information, this
          attribute provides the "scope" for the search.  This parameter
          can be overridden by the serviceSearchDescriptor attribute.
          See section 5.1.6.

     Syntax:

          scopeSyntax   = "base" | "one" | "sub"

     Default Value:

          The default value for the defaultSearchScope SHOULD be defined
          by the DUA service.  If the default search scope for a service
          is not defined then the scope SHOULD be for the DUA to perform
          a subtree search.


5.1.15 Interpreting the serviceAuthenticationMethod attribute

     Interpretation:

          The serviceAuthenticationMethod attribute defines an ordered
          list of LDAP bind methods to be used when attempting to
          contact a DSA for a particular service.  Interpretation and
          use of this attribute is the same as 5.1.4, but specific for
          each service.

     Syntax:

          svAuthMethod    = service ":" method *(";" method)

          Note: Although multiple authentication methods may be
          specified in the syntax, at most one of each type is allowed.

     Default Value:

          If the serviceAuthenticationMethod attribute is not provided,



Neal-Joslin                                                   [Page 24]

Internet-Draft          DUA Configuration Schema              March 2005


          the authenticationMethod SHOULD be followed, or its default.

     Other attribute notes:

          Determining how the DUA should bind to the DSAs also depends
          on the additional configuration attributes, credentialLevel,
          serviceCredentialLevel and bindTimeLimit.  Please review
          section 5.2 for details on how to properly bind to a DSA.

     Example:

          serviceAuthenticationMethod: email:tls:simple;sasl/DIGEST-MD5


5.1.16 Interpreting the serviceCredentialLevel attribute

     Interpretation:

          The serviceCredentialLevel attribute defines what type(s) of
          credential(s) the DUA SHOULD use when contacting the DSA for a
          particular service.  Interpretation and used of this attribute
          are the same as 5.1.5.

     Syntax:

          svCredentialLevel = service ":" level *(space level)

          Refer to implementation notes in section 5.2 for additional
          syntax requirements for the credentialLevel attribute.

          Note: Although multiple credential levels may be specified in
          the syntax, at most one of each type is allowed.

     Default Value:

          If the serviceCredentialLevel attribute is not defined, the
          DUA MUST examine the credentialLevel attribute, or follow its
          default if not provided.

     Other attribute notes:

          Determining how the DUA should bind to the DSAs also depends
          on the additional configuration attributes,
          serviceAuthenticationMethod, authenticationMethod and
          bindTimeLimit.  Please review section 5.2 for details on how
          to properly bind to a DSA.

     Example:



Neal-Joslin                                                   [Page 25]

Internet-Draft          DUA Configuration Schema              March 2005


          serviceCredentialLevel: email:proxy anonymous


5.2 Binding to the Directory Server

     The DUA SHOULD use the following algorithm when binding to the
     server:

     for (clevel in credLevel) [see note 1]
       if (clevel is "anonymous")
         for (host in hostnames) [see note 2]
           if (server is responding)
             return success
         return failure
       else
         for (amethod in authMethod) [see note 3]
           if (amethod is none)
             for (host in hostnames)
               if (server is responding)
                 return success
             return failure
           else
             for (host in hostnames)
               authenticate using amethod and clevel
               if (authentication passed)
                 return success
     return failure

     Note 1: The credLevel is a list of credential levels as defined
             in serviceCredentialLevel (section 5.1.16) for a given
             service.  If the serviceCredentialLevel is not defined,
             the DUA MUST examine the credentialLevel attribute.

     Note 2: hostnames is the list of servers to contact as defined
             in 5.1.1 & 5.1.2.

     Note 3: The authMethod a list of authentication methods as defined
             in serviceAuthenticationMethod (section 5.1.15) for a
             given service.  If the serviceAuthenticationMethod is not
             defined, the DUA MUST examine the authenticationMethod
             attribute.



6.  Security Considerations

     The profile entries MUST be protected against unauthorized
     modification.  Each service needs to consider implications of



Neal-Joslin                                                   [Page 26]

Internet-Draft          DUA Configuration Schema              March 2005


     providing its service configuration as part of this profile and
     limit access to the profile entries accordingly.

     The management of the authentication credentials for the DUA is
     outside the scope of this document and needs to be handled by the
     DUA.

     Since the DUA needs to know how to properly bind to the directory
     server, the access control configuration of the DSA MUST assure
     that the DSA can view all the elements of the DUAConfigProfile
     attributes.  For example, if the credentialLevel attribute contains
     "Self" but the DSA is unable to access the credentialLevel
     attribute, the DUA will instead attempt an anonymous connection to
     the directory server.

     The algorithm described by section 5.2 also has security
     considerations.  Altering that design will alter the security
     aspects of the configuration profile.


7.  Acknowledgments

     There were several additional authors of this document.  However we
     chose to represent only one author per company in the heading.
     From Sun we also would like to acknowledge Roberto Tam for his
     design work on Sun's first LDAP name service product and his input
     for this document.  From Hewlett-Packard we'd like to acknowledge
     Dave Binder for his work architecting Hewlett-Packard's LDAP name
     service product as well as his design guidance on this document.
     We'd also like to acknowledge Grace Lu from HP, for her input and
     implementation of HP's configuration profile manager code.


8.  References

8.1 Normative References


[4]  S. Bradner, "Key Words for use in RFCs to Indicate Requirement
     Levels", RFC 2119, March 1997.


[5]  M. Wahl, A. Coulbeck, T. Howes, S. Kille, "Lightweight Directory
     Access Protocol (v3): Attribute Syntax Definitions", RFC 2252,
     December 1997.


[6]  M. Wahl, S. Kille, T. Howes, "Lightweight Directory Access Protocol



Neal-Joslin                                                   [Page 27]

Internet-Draft          DUA Configuration Schema              March 2005


     (v3):  UTF-8 String Representation of Distinguished Names", RFC
     2253, December 1997.


[7]  T. Howes, M. Smith, "The LDAP URL Format", RFC 2255, December 1997.


[8]  R. Hinden, B. Carpenter, L. Masinter, "Uniform Resource Identifier
     (URI): Generic Syntax", RFC 3986, January 2005.


[9]  M. Wahl, "A Summary of the X.500(96) User Schema for use with
     LDAPv3", RFC 2256, December 1997.


[11] M. Wahl, H. Alvestrand, J. Hodges, R. Morgan, "Authentication
     Methods for LDAP", RFC 2828, May 2000


[13] J. Hodges, R. Morgan, M. Wahl, "Lightweight Directory Access
     Protocol [v3]: Extension for Transport Layer Security", RFC 2830,
     May 2000


[18] IANA, "SIMPLE AUTHENTICATION AND SECURITY LAYER (SASL) MECHANISMS",
     http://www.iana.org/assignments/sasl-mechanisms, April 2004


8.2 Informative References


[1]  M. Wahl, T. Howes, S. Kille, "Lightweight Directory Access Protocol
     (v3)", RFC 2251, December 1997.


[2]  L. Howard, "An Approach for Using LDAP as a Network Information
     Service", RFC 2307, March 1998.


[3]  Microsoft Corporation, "Windows Services for Unix 3.5",
     http://www.microsoft.com/windows/sfu/default.asp


[12] J. Meyers, "Simple Authentication and Security Layer [SASL]", RFC
     2222, October 1997


[14] P. Leach, C. Newman, "Using Digest Authentication as a SASL



Neal-Joslin                                                   [Page 28]

Internet-Draft          DUA Configuration Schema              March 2005


     Mechanism", RFC 2831, May 2000


[15] T. Howes, "The String Representation of LDAP Search Filters", RFC
     2254, December 1997.


[16] G. Good, "The LDAP Data Interchange Format (LDIF) - Technical
     Specification", RFC 2849, June 2000.


[17] M. Smith, "Definition of the inetOrgPerson LDAP Object Class", RFC
     2789, April 2000


9.  Examples

     In this section we will describe a fictional DUA which provides one
     service, called the "email" service.  This service would be similar
     to an email client that uses an LDAP directory to discover email
     addresses based on a textual representation of the recipient's
     colloquial name.

     This email service is defined by default to expect that users with
     email addresses will be of the "inetOrgPerson" objectclass type
     [17].  And by default, the "email" service expects the colloquial
     name to be stored in the "cn" attribute, while it expects the email
     address to be stored in the "mail" attribute (as one would expect
     as defined by the inetOrgPerson objectclass.)

     As a special feature, the "email" service will perform a special
     type of attribute mapping, when performing searches.  If the "cn"
     attribute has been mapped to two or more attributes, the "email"
     service will parse the requested search string and map each white-
     space separated token into the mapped attributes, respectively.

     The default search filter for the "email" service is
     "(objectclass=inetOrgPerson)".  The email service also defines that
     when it performs a name to address discovery, it will wrap the
     search filter inside a complex search filter as follows:

     (&(<filter>)(cn~=<name string>)

     or if "cn" has been mapped to multiple attributes, that wrapping
     would appear as follows:

     (&(<filter>)(attr1~=<token1>)(attr2~=<token2>)...)




Neal-Joslin                                                   [Page 29]

Internet-Draft          DUA Configuration Schema              March 2005


     The below examples show how the "email" service builds it search
     requests, based on the defined profile.  In all cases, the
     defaultSearchBase is "o=airius.com" and the defaultSearchScope is
     undefined.

     In addition, for all examples, we assume that the "email" service
     has been requested to discover the email address for "Jane
     Hernandez."


     Example 1:

     serviceSearchDescriptor: email:"ou=marketing,"

     base: ou=marketing,o=airius.com
     scope: sub
     filter: (&(objectclass=inetOrgPerson)(cn~=Jane Hernandez))

     Example 2:

     serviceSearchDescriptor: email:"ou=marketing,"?one?
      (&(objectclass=inetOrgPerson)(c=us))
     attributeMap: email:cn=2.5.4.42 sn

     Note: 2.5.4.42 is the OID that represents the "givenName"
     attribute.

     In this example, the email service performs <name string> parsing
     as described above to generate a complex search filter.  The above
     example results in one search.

     base: ou=marketing,o=airius.com
     scope: one
     filter: (&(&(objectclass=inetOrgPerson)(c=us))
                 (2.5.4.42~=Jane)(sn~=Hernandez))

     Example 3:

     serviceSearchDescriptor: email:ou=marketing,"?base
     attributeMap: email:cn=name

     This example is invalid, because either the quote should have been
     escaped, or there should have been a leading quote.

     Example 4:

     serviceSearchDescriptor: email:ou=\mar\\keting,\"?base
     attributeMap: email:cn=name



Neal-Joslin                                                   [Page 30]

Internet-Draft          DUA Configuration Schema              March 2005


     base: ou=\mar\keting,"
     scope: base
     filter (&(objectclass=inetOrgPerson)(name~=Jane Hernandez))

     Example 5:

     serviceSearchDescriptor: email:ou="marketing",o=supercom

     This example is invalid, since the quote was not a leading quote,
     and thus should have been escaped.

     Example 6:

     serviceSearchDescriptor: email:??(&(objectclass=person)
                                      (ou=Org1 \\(temporary\\)))

     base: o=airius.com
     scope: sub
     filter: (&((&(objectclass=person)(ou=Org1 \(Temporary\)))
               (cn~=Jane Henderson)))

     Example 7:

     serviceSearchDescriptor: email:"ou=funny?org,"

     base: ou=funny?org,o=airius.com
     scope: sub
     filter (&(objectclass=inetOrgPerson)(cn~=Jane Hernandez))


Author's Addresses

     Luke Howard
     PADL Software Pty. Ltd.
     PO Box 59
     Central Park Vic 3145
     Australia

     EMail: lukeh@padl.com


     Bob Neal-Joslin
     Hewlett-Packard Company
     19420 Homestead RD  MS43-LF
     Cupertino, CA 95014
     USA

     Phone: +1 408 447-3044



Neal-Joslin                                                   [Page 31]

Internet-Draft          DUA Configuration Schema              March 2005


     EMail: bob_joslin@hp.com


     Morteza Ansari
     Infoblox
     475 Potrero Avenue
     Sunnyvale, CA 94085
     USA

     Phone: +1 408-716-4300
     EMail: morteza@infoblox.com

     Expires September 2005






































Neal-Joslin                                                   [Page 32]

alt-openldap11-devel/drafts/draft-sermersheim-ldap-csn-xx.txt000064400000053077150410163310020172 0ustar00



Network Working Group                                     J. Sermersheim
Internet-Draft                                               Novell, Inc
Expires: August 5, 2005                                           H. Chu
                                                             Symas Corp.
                                                           February 2005


                    The LDAP Change Sequence Number
                   draft-sermersheim-ldap-csn-02.txt

Status of this Memo

   By submitting this Internet-Draft, each author represents that any
   applicable patent or other IPR claims of which he or she is aware
   have been or will be disclosed, and any of which he or she becomes
   aware will be disclosed, in accordance with Section 6 of BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on August 5, 2005.

Copyright Notice

   Copyright (C) The Internet Society (2005).

Abstract

   This document defines a syntax schema element for the Lightweight
   Directory Access Protocol (LDAP) which is used to hold a Change
   Sequence Number (CSN).  In general, a change sequence number
   represents the place and time that a directory entity was changed.
   It may be used by various attributes for various LDAP replication,
   and synchronization applications.




Sermersheim & Chu        Expires August 5, 2005                 [Page 1]

Internet-Draft                  LDAP CSN                   February 2005


Discussion Forum

   Technical discussion of this document will take place on the IETF
   LDAP Extensions mailing list <ldapext@ietf.org>.  Please send
   editorial comments directly to the author(s).


Table of Contents

   1.          Introduction . . . . . . . . . . . . . . . . . . . . .  3
   2.          Conventions  . . . . . . . . . . . . . . . . . . . . .  4
   3.          Syntaxes . . . . . . . . . . . . . . . . . . . . . . .  5
   3.1.        ChangeSequenceNumber Syntax  . . . . . . . . . . . . .  5
   3.2.        UTF8String . . . . . . . . . . . . . . . . . . . . . .  6
   4.          Matching Rules . . . . . . . . . . . . . . . . . . . .  7
   4.1.        changeSequenceNumberMatch Matching Rule  . . . . . . .  7
   4.2.        utf8CodePointMatch Matching Rule . . . . . . . . . . .  7
   4.3.        changeSequenceNumberOrderingMatch Matching Rule  . . .  7
   4.4.        utf8CodePointOrderingMatch Matching Rule . . . . . . .  8
   5.          Attributes . . . . . . . . . . . . . . . . . . . . . .  9
   5.1.        entryCSN Attribute . . . . . . . . . . . . . . . . . .  9
   6.          Security Considerations  . . . . . . . . . . . . . . . 10
   7.          Normative References . . . . . . . . . . . . . . . . . 10
   Appendix A. IANA Considerations  . . . . . . . . . . . . . . . . . 11
   A.1.        LDAP Object Identifier Registrations . . . . . . . . . 11
   A.2.        LDAP Descriptor Registrations  . . . . . . . . . . . . 11
               Authors' Addresses . . . . . . . . . . . . . . . . . . 15
               Intellectual Property and Copyright Statements . . . . 16























Sermersheim & Chu        Expires August 5, 2005                 [Page 2]

Internet-Draft                  LDAP CSN                   February 2005


1.  Introduction

   A number of technologies have been documented, implemented and
   experimented with which in one way or another seek to replicate, or
   synchronize directory data.  A common need among these technologies
   is to determine which of two copies of an element represents the
   latest or most authoritative data.  Part of meeting this need
   involves associating a change sequence number to an element copy at
   the time of an update to that element.  When replication or
   synchronization occurs, the change sequence numbers associated with
   directory elements can be used to decide which element's data will be
   copied to the other element(s).







































Sermersheim & Chu        Expires August 5, 2005                 [Page 3]

Internet-Draft                  LDAP CSN                   February 2005


2.  Conventions

   Imperative keywords defined in [RFC2119] are used in this document,
   and carry the meanings described there.

   The General Considerations of [I-D.ietf-ldapbis-syntaxes] apply to
   the syntax definition in this document.

   The terms "directory element" and "element" refer to data held in a
   directory and may apply to an attribute value, attribute, entry, or
   any other identifiable directory entity.








































Sermersheim & Chu        Expires August 5, 2005                 [Page 4]

Internet-Draft                  LDAP CSN                   February 2005


3.  Syntaxes

3.1.  ChangeSequenceNumber Syntax

   A value of the ChangeSequenceNumber syntax is the time of a change
   along with a replicaID which represents the Directory System Agent
   (DSA) holding the element when it was changed.  There are also two
   sequence numbers used to disambiguate directory entities that are
   changed at the same time and place.

   The Abstract Syntax Notation One (ASN.1)[X680] type corresponding to
   this syntax is defined as follows:

      ChangeSequenceNumber ::= SEQUENCE {

         time GeneralizedTime,

         timeCount INTEGER (0 ..  MaxInt),

         replicaID UTF8String,

         changeCount INTEGER (0 ..  MaxInt)}

   MaxInt INTEGER ::= 2147483647 -- (2^^31 - 1) --

   GeneralizedTime is defined in [X680].  Local time without a
   differential SHALL NOT be used.

   UTF8String is defined below.

   The LDAP-specific encoding of a value of this syntax is the Generic
   String Encoding Rules (GSER)[RFC3641] encoding of the ASN.1 type.

      Example:

         { time "196701160315-0700",

         timeCount 0,

         replicaID "DSA666",

         changeCount 1 }

   The following is an LDAP syntax description [RFC2252] suitable for
   publication in the subschema.

   ( IANA-ASSIGNED-OID.1 DESC 'ChangeSequenceNumber' )




Sermersheim & Chu        Expires August 5, 2005                 [Page 5]

Internet-Draft                  LDAP CSN                   February 2005


3.2.  UTF8String

   The UTF8String syntax is used to express a string of characters from
   the [ISO.10646-1.1993] character set (a superset of [Unicode]),
   encoded following the [UTF-8] algorithm.  Note that Unicode
   characters U+0000 through U+007F are the same as ASCII 0 through 127,
   respectively, and have the same single octet UTF-8 encoding.  Other
   Unicode characters have a multiple octet UTF-8 encoding.

      UTF8String::= OCTET STRING -- UTF-8 encoded,

      -- [ISO10646] characters

   The LDAP-specific encoding of a value of this syntax are the UTF-8
   encoded characters themselves.

   The following is an LDAP syntax description [RFC2252] suitable for
   publication in the subschema.

   ( IANA-ASSIGNED-OID.2 DESC 'UTF8String' )































Sermersheim & Chu        Expires August 5, 2005                 [Page 6]

Internet-Draft                  LDAP CSN                   February 2005


4.  Matching Rules

4.1.  changeSequenceNumberMatch Matching Rule

   The changeSequenceNumberMatch rule compares an assertion value of the
   ChangeSequenceNumber syntax to a value of a syntax (e.g the
   ChangeSequenceNumber syntax) whose corresponding ASN.1 type is
   ChangeSequenceNumber.

   The rule evaluates to TRUE if and only if each of the components of
   the two values evaluate to TRUE using the following rules:

   o  The time component uses generalizedTimeMatch.

   o  The timeCount and changeCount components use integerMatch.

   o  The replicaID component uses utf8CodePointMatch.

   The following is a LDAP matching rule description [RFC2252] suitable
   for publication in the subschema.

   ( IANA-ASSIGNED-OID.3 NAME changeSequenceNumberMatch SYNTAX IANA-
   ASSIGNED-OID.1 )

4.2.  utf8CodePointMatch Matching Rule

   The utf8CodePointMatch rule compares an assertion value of the
   UTF8String syntax to a value of a syntax (e.g the UTF8String syntax)
   whose corresponding ASN.1 type is UTF8String.  The rule evaluates to
   TRUE if and only if the code points [Unicode] of each of the
   characters is equal.

   The following is a LDAP matching rule description [RFC2252] suitable
   for publication in the subschema.

   ( IANA-ASSIGNED-OID.4 NAME utf8CodePointMatch SYNTAX IANA-ASSIGNED-
   OID.2 )

4.3.  changeSequenceNumberOrderingMatch Matching Rule

   The changeSequenceNumberOrderingMatch rule compares the
   ChangeSequenceNumber ordering of an assertion value of the
   ChangeSequenceNumber syntax to a value of a syntax (e.g the
   ChangeSequenceNumber syntax) whose corresponding ASN.1 type is
   ChangeSequenceNumber.

   When evaluating ChangeSequenceNumber values for ordering, the
   components are evaluated in this order: time, timeCount, replicaID,



Sermersheim & Chu        Expires August 5, 2005                 [Page 7]

Internet-Draft                  LDAP CSN                   February 2005


   changeCount.  If a component evaluates to TRUE using the appropriate
   ordering matching rule specified below, then the rule evaluates to
   TRUE.  Otherwise if the component evaluates to TRUE using the
   equality matching rule specified below, the next component is
   evaluated.  Otherwise the changeSequenceNumberOrderingMatch rule
   evaluates to FALSE or Undefined as appropriate.

   o  The time components of the two values are evaluated for ordering
      using GeneralizedTimeOrderingMatch, and evaluated for equality
      using GeneralizedTimeMatch.

   o  The timeCount and changeCount components of the two values are
      evaluated for ordering using integerOrderingMatch, and evaluated
      for equality using integerMatch.

   o  The replicaID components of the two values are evaluated for
      ordering using utf8CodePointOrderingMatch and evaluated for
      equality using utf8CodePointMatch.

   The following is a LDAP matching rule description [RFC2252] suitable
   for publication in the subschema.

   ( IANA-ASSIGNED-OID.5 NAME changeSequenceNumberOrderingMatch SYNTAX
   SYNTAX IANA-ASSIGNED-OID.1 )

4.4.  utf8CodePointOrderingMatch Matching Rule

   The utf8CodePointOrderingMatch rule compares the ordering of an
   assertion value of the UTF8String syntax to a stored value of a
   syntax (e.g. the UTF8String syntax) whose corresponding ASN.1 type is
   UTF8String.

   The rule evaluates to TRUE if, and only if, in the code point
   collation order, the stored value character string appears earlier
   than the assertion value character string, i.e., the stored value is
   "less than" the assertion value.

   The following is a LDAP matching rule description [RFC2252] suitable
   for publication in the subschema.

   ( IANA-ASSIGNED-OID.6 NAME utf8CodePointOrderingMatch SYNTAX IANA-
   ASSIGNED-OID.2 )









Sermersheim & Chu        Expires August 5, 2005                 [Page 8]

Internet-Draft                  LDAP CSN                   February 2005


5.  Attributes

5.1.  entryCSN Attribute

   The entryCSN operational attribute provides the CSN of the last
   update applied to the entry.

   The following is a LDAP attribute type description [RFC2252] suitable
   for publication in the subschema.

   ( IANA-ASSIGNED-OID.7 NAME entryCSN DESC 'CSN of the entry content'
   EQUALITY changeSequenceNumberMatch ORDERING
   changeSequenceNumberOrderingMatch SYNTAX IANA-ASSIGNED-OID.1 SINGLE-
   VALUE NO-USER-MODIFICATION USAGE directoryOperation )

   Servers MAY assign a CSN to each entry upon its addition to the
   directory and provide the entry's CSN as the value of the entryCSN
   operational attribute.  If the entryCSN attribute is assigned, the
   attribute SHOULD be updated upon every update of the entry.
































Sermersheim & Chu        Expires August 5, 2005                 [Page 9]

Internet-Draft                  LDAP CSN                   February 2005


6.  Security Considerations

7.  Normative References

   [I-D.ietf-ldapbis-syntaxes]
              Legg, S., "Lightweight Directory Access Protocol (LDAP):
              Syntaxes and Matching Rules",
              draft-ietf-ldapbis-syntaxes-11 (work in progress),
              June 2005.

   [ISO.10646-1.1993]
              International Organization for Standardization,
              "Information Technology - Universal Multiple-octet coded
              Character Set (UCS) - Part 1: Architecture and Basic
              Multilingual Plane", ISO Standard 10646-1, May 1993.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2252]  Wahl, M., Coulbeck, A., Howes, T., and S. Kille,
              "Lightweight Directory Access Protocol (v3): Attribute
              Syntax Definitions", RFC 2252, December 1997.

   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [RFC3641]  Legg, S., "Generic String Encoding Rules (GSER) for ASN.1
              Types", RFC 3641, October 2003.

   [UTF-8]    International Organization for Standardization,
              "Information Technology - Universal Multiple-octet coded
              Character Set (UCS) - Amendment 2: UCS Transformation
              Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2,
              October 1996.

   [Unicode]  The Unicode Consortium, "The Unicode Standard", 2004.

   [X680]     International Telecommunications Union, "Abstract Syntax
              Notation One (ASN.1): Specification of basic notation",
              ITU-T Recommendation X.680, July 2002.










Sermersheim & Chu        Expires August 5, 2005                [Page 10]

Internet-Draft                  LDAP CSN                   February 2005


Appendix A.  IANA Considerations

   Registration of the following values is requested [RFC3383].

A.1.  LDAP Object Identifier Registrations

   It is requested that IANA register upon Standards Action an LDAP
   Object Identifier in identifying the protocol elements defined in
   this technical specification.  The following registration template is
   provided:

      Subject: Request for LDAP OID Registration

      Person & email address to contact for further information:

         Jim Sermersheim

         jimse@novell.com

      Specification: RFCXXXX

      Author/Change Controller: IESG

      Comments:

      Seven delegations will be made under the assigned OID:

      IANA-ASSIGNED-OID.1 ChangeSequenceNumber: LDAP Syntax

      IANA-ASSIGNED-OID.2 UTF8String: LDAP Syntax

      IANA-ASSIGNED-OID.3 changeSequenceNumberMatch: LDAP Matching Rule

      IANA-ASSIGNED-OID.4 utf8CodePointMatch: LDAP Matching Rule

      IANA-ASSIGNED-OID.5 changeSequenceNumberOrderingMatch: LDAP
      Matching Rule

      IANA-ASSIGNED-OID.6 utf8CodePointOrderingMatch: LDAP Matching Rule

      IANA-ASSIGNED-OID.7 entryCSN: LDAP Attribute Type

A.2.  LDAP Descriptor Registrations

   It is requested that IANA register upon Standards Action the LDAP
   descriptors described in this document.  The following registration
   templates are given:




Sermersheim & Chu        Expires August 5, 2005                [Page 11]

Internet-Draft                  LDAP CSN                   February 2005


      Subject: Request for LDAP Descriptor Registration

      Descriptor (short name): ChangeSequenceNumber

      Object Identifier: IANA-ASSIGNED-OID.1

      Person & email address to contact for further information:

         Jim Sermersheim

         jimse@novell.com

      Usage: other

      Specification: RFCXXXX

      Author/Change Controller: IESG

      Comments: LDAP Syntax

      Subject: Request for LDAP Descriptor Registration

      Descriptor (short name): UTF8String

      Object Identifier: IANA-ASSIGNED-OID.2

      Person & email address to contact for further information:

         Jim Sermersheim

         jimse@novell.com

      Usage: other

      Specification: RFCXXXX

      Author/Change Controller: IESG

      Comments: LDAP Syntax

      Subject: Request for LDAP Descriptor Registration

      Descriptor (short name): changeSequenceNumberMatch

      Object Identifier: IANA-ASSIGNED-OID.3

      Person & email address to contact for further information:




Sermersheim & Chu        Expires August 5, 2005                [Page 12]

Internet-Draft                  LDAP CSN                   February 2005


         Jim Sermersheim

         jimse@novell.com

      Usage: other

      Specification: RFCXXXX

      Author/Change Controller: IESG

      Comments: LDAP Matching Rule

      Subject: Request for LDAP Descriptor Registration

      Descriptor (short name): utf8CodePointMatch

      Object Identifier: IANA-ASSIGNED-OID.4

      Person & email address to contact for further information:

         Jim Sermersheim

         jimse@novell.com

      Usage: other

      Specification: RFCXXXX

      Author/Change Controller: IESG

      Comments: LDAP Matching Rule

      Subject: Request for LDAP Descriptor Registration

      Descriptor (short name): changeSequenceNumberOrderingMatch

      Object Identifier: IANA-ASSIGNED-OID.5

      Person & email address to contact for further information:

         Jim Sermersheim

         jimse@novell.com

      Usage: other

      Specification: RFCXXXX




Sermersheim & Chu        Expires August 5, 2005                [Page 13]

Internet-Draft                  LDAP CSN                   February 2005


      Author/Change Controller: IESG

      Comments: LDAP Matching Rule

      Subject: Request for LDAP Descriptor Registration

      Descriptor (short name): utf8CodePointOrderingMatch

      Object Identifier: IANA-ASSIGNED-OID.6

      Person & email address to contact for further information:

         Jim Sermersheim

         jimse@novell.com

      Usage: other

      Specification: RFCXXXX

      Author/Change Controller: IESG

      Comments: LDAP Matching Rule

      Subject: Request for LDAP Descriptor Registration

      Descriptor (short name): entryCSN

      Object Identifier: IANA-ASSIGNED-OID.7

      Person & email address to contact for further information:

         Jim Sermersheim

         jimse@novell.com

      Usage: Attribute Type

      Specification: RFCXXXX

      Author/Change Controller: IESG

      Comments: LDAP Attribute Type








Sermersheim & Chu        Expires August 5, 2005                [Page 14]

Internet-Draft                  LDAP CSN                   February 2005


Authors' Addresses

   Jim Sermersheim
   Novell, Inc
   1800 South Novell Place
   Provo, Utah  84606
   USA

   Phone: +1 801 861-3088
   Email: jimse@novell.com


   Howard Chu
   Symas Corp.
   18740 Oxnard Street, Suite 313A
   Tarzana, California  91356
   USA

   Phone: +1 818 757-7087
   Email: hyc@symas.com































Sermersheim & Chu        Expires August 5, 2005                [Page 15]

Internet-Draft                  LDAP CSN                   February 2005


Intellectual Property Statement

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.


Disclaimer of Validity

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Copyright Statement

   Copyright (C) The Internet Society (2005).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and
   except as set forth therein, the authors retain all their rights.


Acknowledgment

   Funding for the RFC Editor function is currently provided by the
   Internet Society.




Sermersheim & Chu        Expires August 5, 2005                [Page 16]


alt-openldap11-devel/drafts/draft-haripriya-dynamicgroup-xx.txt000064400000110050150410163320020621 0ustar00


Network Working Group                                       S. Haripriya
Internet-Draft                                         Jaimon. Jose, Ed.
Updates: 02 (if approved)                               Jim. Sermersheim
Intended status: Standards Track                            Novell, Inc.
Expires: July 9, 2007                                    January 5, 2007


                    LDAP: Dynamic Groups for LDAPv3
                    draft-haripriya-dynamicgroup-02

Status of this Memo

   By submitting this Internet-Draft, each author represents that any
   applicable patent or other IPR claims of which he or she is aware
   have been or will be disclosed, and any of which he or she becomes
   aware will be disclosed, in accordance with Section 6 of BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on July 9, 2007.

Copyright Notice

   Copyright (C) The Internet Society (2007).













Haripriya, et al.         Expires July 9, 2007                  [Page 1]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


Abstract

   This document describes the requirements, semantics, schema elements,
   and operations needed for a dynamic group feature in LDAP.  A dynamic
   group is defined here as a group object with a membership list of
   distinguished names that is dynamically generated using LDAP search
   criteria.  The dynamic membership list may then be interrogated by
   LDAP search and compare operations, and may also be used to find the
   groups that an object is a member of.  This feature eliminates a huge
   amount of the administrative effort required today for maintaining
   group memberships and role-based operations in large enterprises.


Table of Contents

   1.  Conventions used in this document  . . . . . . . . . . . . . .  4
   2.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  5
   3.  Requirements of a dynamic group feature  . . . . . . . . . . .  6
   4.  Schema and Semantic Definitions for Dynamic Groups . . . . . .  7
     4.1.  Object Classes . . . . . . . . . . . . . . . . . . . . . .  7
       4.1.1.  dynamicGroup . . . . . . . . . . . . . . . . . . . . .  7
       4.1.2.  dynamicGroupOfUniqueNames  . . . . . . . . . . . . . .  7
       4.1.3.  dynamicGroupAux  . . . . . . . . . . . . . . . . . . .  7
       4.1.4.  dynamicGroupOfUniqueNamesAux . . . . . . . . . . . . .  7
     4.2.  Attributes . . . . . . . . . . . . . . . . . . . . . . . .  8
       4.2.1.  memberQueryURL . . . . . . . . . . . . . . . . . . . .  8
       4.2.2.  excludedMember . . . . . . . . . . . . . . . . . . . . 11
     4.3.  member . . . . . . . . . . . . . . . . . . . . . . . . . . 11
     4.4.  uniqueMember . . . . . . . . . . . . . . . . . . . . . . . 11
     4.5.  dgIdentity . . . . . . . . . . . . . . . . . . . . . . . . 11
       4.5.1.  dgIdentity - Security implications . . . . . . . . . . 12
   5.  Advertisement of support for dynamic groups  . . . . . . . . . 13
   6.  Dynamic Group Operations . . . . . . . . . . . . . . . . . . . 14
     6.1.  Existing Operations  . . . . . . . . . . . . . . . . . . . 14
       6.1.1.  Access to resources in the directory . . . . . . . . . 14
       6.1.2.  Reading a dynamic group object . . . . . . . . . . . . 14
       6.1.3.  'Is Member Of' functionality . . . . . . . . . . . . . 15
     6.2.  New Extensions . . . . . . . . . . . . . . . . . . . . . . 16
       6.2.1.  Managing the static members of a dynamic group . . . . 16
   7.  Performance Considerations . . . . . . . . . . . . . . . . . . 17
     7.1.  Caching of Dynamic Members . . . . . . . . . . . . . . . . 17
   8.  Security Considerations  . . . . . . . . . . . . . . . . . . . 18
   9.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 19
   10. Conclusions  . . . . . . . . . . . . . . . . . . . . . . . . . 20
   11. Normative References . . . . . . . . . . . . . . . . . . . . . 21
   Appendix A.  Example Values for memberQueryURL . . . . . . . . . . 22
   Appendix B.  Acknowledgments . . . . . . . . . . . . . . . . . . . 23
   Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 24



Haripriya, et al.         Expires July 9, 2007                  [Page 2]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


   Intellectual Property and Copyright Statements . . . . . . . . . . 25


















































Haripriya, et al.         Expires July 9, 2007                  [Page 3]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


1.  Conventions used in this document

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in [1].














































Haripriya, et al.         Expires July 9, 2007                  [Page 4]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


2.  Introduction

   The LDAP schema described in [4] defines two object classes:
   'groupOfNames', and 'groupOfUniqueNames', that hold a static list of
   distinguished names in their 'member' or 'uniqueMember' attributes
   respectively, and are typically used to describe a group of objects
   for various functions.  These grouping functions range from simple
   group membership applications such as email distribution lists to
   describing common authorization for a set of users The administration
   and updating of these membership lists must be done by specifically
   modifying the DN values in the member or uniqueMember attributes.
   Thus, each time a change in membership happens, a process must exist
   which adds or removes the particular entry's DN from the member
   attribute.  For example, consider an organization, where the access
   to its facilities is controlled by membership in a directory group.
   Assume that all employees in a department have been added to the
   group that provides access to the required department facility.  If
   an employee moves from one department to another, the administrator
   must remove the employee from one group and add him to another.
   Similarly consider an organization that wants to provide access to
   its facility, to both interns and employees on weekdays, but only to
   employees on weekends.  It would be effort-consuming to achieve this
   with static groups.

   "Dynamic groups" are like normal groups, but they let one specify
   criteria to be used for evaluating membership to a group; the
   membership of the group is determined dynamically by the directory
   servers involved.  This lets the group administrator define the
   membership in terms of attributes, and let the DSAs worry about who
   are the actual members.  This solution is more scalable and reduces
   administrative costs.  This can also supplement static groups in LDAP
   to provide flexibility to the user.



















Haripriya, et al.         Expires July 9, 2007                  [Page 5]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


3.  Requirements of a dynamic group feature

   The following requirements SHOULD be met by a proposal for the
   dynamic groups feature:

   1.  Creation and administration of dynamic groups should be done
       using normal LDAP operations.

   2.  Applications must be able to use dynamic groups in the same way
       that they are able to use static groups for listing members and
       for membership evaluation.

   3.  Interrogation of a dynamic group's membership should be done
       using normal LDAP operations, and should be consistent.  This
       means that all authorization identities with the same permission
       to the membership attribute of a dynamic group (such as 'read')
       should be presented with the same membership list.


































Haripriya, et al.         Expires July 9, 2007                  [Page 6]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


4.  Schema and Semantic Definitions for Dynamic Groups

   The dynamic group classes are defined by the following schema

4.1.  Object Classes

   The following object classes MUST be supported, and their semantics
   understood by the server, for it to support the dynamic groups
   feature.

4.1.1.  dynamicGroup

   ( <OID.TBD> NAME 'dynamicGroup' SUP groupOfNames STRUCTURAL MAY
   (memberQueryURL $ excludedMember $ dgIdentity ))

   This structural object class is used to create a dynamic group
   object.  It is derived from groupOfNames, which is defined in [4].

4.1.2.  dynamicGroupOfUniqueNames

   ( <OID.TBD> NAME 'dynamicGroupOfUniqueNames' SUP groupOfUniqueNames
   STRUCTURAL MAY (memberQueryURL $ excludedMember $ dgIdentity ))

   This structural object class is used to create a dynamic group object
   whose membership list is held in a uniqueMember attribute.  It is
   derived from groupOfUniqueNames, which is defined in [4].

4.1.3.  dynamicGroupAux

   ( <OID.TBD> NAME 'dynamicGroupAux' SUP groupOfNames AUXILIARY MAY
   (memberQueryURL $ excludedMember $ dgIdentity ))

   This auxiliary object class is used to convert an existing object to
   a dynamic group or to create an object of another object class but
   with dynamic group capabilities.  This is derived from groupOfNames
   which is defined in [4].

4.1.4.  dynamicGroupOfUniqueNamesAux

  ( <OID.TBD> NAME 'dynamicGroupOfUniqueNamesAux' SUP groupOfUniqueNames
  AUXILIARY MAY (memberQueryURL $ excludedMember $ dgIdentity ))

   This auxiliary object class is used to convert an existing object to
   a dynamic group of unique names or to create an object of another
   object class but with dynamic group capabilities.  This is derived
   from groupOfUniqueNames which is defined in [4].





Haripriya, et al.         Expires July 9, 2007                  [Page 7]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


4.2.  Attributes

   The following attribute names MUST be supported by the server.

4.2.1.  memberQueryURL

   This attribute describes the membership of the list using an LDAPURL
   [3].

 (<OID.TBD> NAME 'memberQueryURL' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )

   The value of memberQueryURL is encoded as an LDAPURL [3]







































Haripriya, et al.         Expires July 9, 2007                  [Page 8]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


   The BNF from [3] is listed here for reference.
ldapurl = scheme COLON SLASH SLASH [host [COLON port]] [SLASH dn
                     [QUESTION [attributes] [QUESTION [scope] [QUESTION [filter] [QUESTION
                     extensions]]]]]
                                ; <host> and <port> are defined
                                ;   in Sections 3.2.2 and 3.2.3
                                ;   of [RFC3986].
                                ; <filter> is from Section 3 of
                                ;   [RFC4515], subject to the
                                ;   provisions of the
                                ;   "Percent-Encoding" section
                                ;   below.
scheme      = "ldap"
dn          = distinguishedName ; From Section 3 of [RFC4514],
                                ; subject to the provisions of
                                ; the "Percent-Encoding"
                                ; section below.
attributes  = attrdesc *(COMMA attrdesc)
attrdesc    = selector *(COMMA selector)
selector    = attributeSelector ; From Section 4.5.1 of
                                ; [RFC4511], subject to the
                                ; provisions of the
                                ; "Percent-Encoding" section
                                ; below.
scope       = "base" / "one" / "sub"
extensions  = extension *(COMMA extension)
extension   = [EXCLAMATION] extype [EQUALS exvalue]
extype      = oid               ; From section 1.4 of [RFC4512].
exvalue     = LDAPString        ; From section 4.1.2 of
                                ; [RFC4511], subject to the
                                ; provisions of the
                                ; "Percent-Encoding" section
                                ; below.
EXCLAMATION = %x21              ; exclamation mark ("!")
SLASH       = %x2F              ; forward slash ("/")
COLON       = %x3A              ; colon (":")
QUESTION    = %x3F              ; question mark ("?")


   For the purpose of evaluating dynamic members, the directory server
   uses only the dn, scope, filter and extensions fields.  All remaining
   fields are ignored if specified.  If other fields are specified, the
   server SHALL ignore them and MAY omit them when presenting the value
   to a client.  The dn is used to specify the base dn from which to
   start the search for dynamic members.  The scope specifies the scope
   with respect to the dn in which to search for dynamic members.  The
   filter specifies the criteria with which to select objects for
   dynamic membership.



Haripriya, et al.         Expires July 9, 2007                  [Page 9]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


4.2.1.1.  The x-chain extension

   A new extension is defined for use of the memberQueryURL in dynamic
   groups, named 'x-chain'. x-chain does not take a value.  When x-chain
   is present, the server must follow any search continuation references
   to other servers while searching for dynamic members.  When x-chain
   is absent, the dynamic members computed will be only those that are
   present on the server from which the search is made.  A directory
   server supporting the memberQueryURL MAY support the x-chain
   extension, thus the x-chain extension could be critical or non-
   critical as specified by the '!' prefix to the extension type.

4.2.1.2.  Semantics of multiple values for memberQueryURL

   The memberQueryURL MAY have multiple values, and in that case, the
   members of the dynamic group will be the union of the members
   computed using each individual URL value.  This is useful in
   specifying a group membership that is made up from subtrees rooted at
   different base DNs, and possibly using different filters.

4.2.1.3.  Condition of membership

   An object O is a member of a dynamic group G if and only if

   (( O is a value of the 'member' or 'uniqueMember' attribute of G)

   OR

   (( O is selected by the membership criteria specified in the
   'memberQueryURL' attribute values of G)

   AND

   ( O is not listed in the 'excludedMember' attribute of G) ))

   If a member M of a dynamic group G happens to be a dynamic or a
   static group, the static or dynamic members of M SHALL NOT be
   considered as members of G. M is a member of G though.

   The last condition is imposed because

   o  Recursively evaluating members of members may degrade the
      performance of the server drastically.

   o  Looping may occur particularly in situations where the search
      chains across multiple-servers.





Haripriya, et al.         Expires July 9, 2007                 [Page 10]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


   o  Dynamic membership assertions (compare operation) cannot be
      optimized if recursive memberships are allowed.  Without
      recursion, comparisons can be made light-weight.

4.2.2.  excludedMember

   ( <OID.TBD> NAME 'excludedMember' SUP distinguishedName )

   This attribute is used to exclude entries from being a dynamic member
   of a dynamic group.  Thus an entry is a dynamic member of a dynamic
   group if and only if it is selected by the member criteria specified
   by the 'memberQueryURL' attribute or explicitly added to the member
   or uniqueMember attribute, and it is not listed in the
   'excludedMember' attribute.

4.3.  member

   ( 2.5.4.31 NAME 'member' SUP distinguishedName )

   Defined in [4], this attribute is overloaded when used in the context
   of a dynamic group.  It is used to explicitly specify static members
   of a dynamic group.  If the same entry is listed in both the 'member'
   and 'excludedMember' attributes, the 'member' overrides the
   'excludedMember', and the entry is considered to be a member of the
   group.  This attribute is also used to interrogate both the static
   and dynamic member values of a dynamic group object.  Subclasses of
   this attribute are NOT considered in this manner.

4.4.  uniqueMember

   ( 2.5.4.32 NAME 'uniqueMember' SUP distinguishedName )

   Defined in [4], this attribute is overloaded when used in the context
   of a dynamic group.  It is used to specify the static members of a
   dynamic group.  If the same entry is listed in both the
   'uniqueMember' and 'excludedMember' attributes, the 'uniqueMember'
   overrides the 'excludedMember', and the entry is considered to be a
   member of the group.  This attribute is also used to interrogate both
   the static and dynamic member values of a dynamic group object.
   Subclasses of this attribute are NOT considered in this manner.

4.5.  dgIdentity

   ( <OID.TBD> NAME 'identity' SUP distinguishedName SINGLE-VALUE )

   In order to provide consistent results when processing the search
   criteria, the server must use a single authorization identity.  If
   the authorization of the bound identity is used, the membership list



Haripriya, et al.         Expires July 9, 2007                 [Page 11]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


   will vary, from identity to identity due to differing access
   controls.  This may either be done by the server authenticating as
   the dgIdentity prior to performing a search or compare operation, or
   may be done by simply assuming the authorization of the dgIdentity
   when performing those operations.  As server implementations vary, so
   may the mechanisms to achieve consistent results through the use of
   the dgIdentity.  In the case that the server authenticates as the
   dgIdentity, it may be required by the server that this identity have
   proper authentication credentials, and it may be required that this
   identity reside in the DIB of the local server.

   In the absence of an identity value, or in case the identity value
   cannot be used, the server will process the memberQueryURL as the
   anonymous identity.  This attribute MAY be supported, and represents
   the identity the server will use for processing the memberQueryURL.

4.5.1.  dgIdentity - Security implications

   Because this attribute indirectly but effectively grants anyone with
   read or compare access to the member or uniqueMember attribute
   sufficient permission to gain a DN result set from the
   memberQueryURL, server implementations SHOULD NOT allow this
   attribute to be populated with the DN of any object that is not
   administered by the identity making the change to this attribute.
   For purposes of this document, to "administer an object" indicates
   that the administrative identity has the ability to fully update the
   access control mechanism in place the object in question.  As of this
   writing, there is no way to describe further what it means to be
   fully able to administer the access control mechanism for an object,
   so this definition is left as implementation-specific.

   This requirement will allow an entity that has privileges to
   administer a particular subtree (meaning that entity can add, delete,
   and update objects in that subtree), to place in the dgIdentity DNs
   of only those objects it administers.
















Haripriya, et al.         Expires July 9, 2007                 [Page 12]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


5.  Advertisement of support for dynamic groups

   If the dynamic groups schema is not present on an LDAP server, it
   MUST be assumed that the dynamic groups feature is not supported.















































Haripriya, et al.         Expires July 9, 2007                 [Page 13]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


6.  Dynamic Group Operations

6.1.  Existing Operations

   The following operations SHOULD expose the dynamic groups
   functionality.  These operations do not require any change in the
   LDAP protocol to be exchanged between the client and server.

6.1.1.  Access to resources in the directory

   If access control items are set on a target resource object in the
   directory, with the subject being a dynamic group object, then all
   the members of the group object, including the dynamic members, will
   get the same permissions on the target entry.  This would be the most
   useful application of dynamic groups as seen by an administrator
   because it lets the server control access to resources based on
   dynamic membership to a trustee (subject of ACI) of the resource.
   The way to specify a dynamic ACL is currently implementation
   specific, as there is no common ACL definition for LDAP, and hence
   will be dealt with in a separate document or later (TO BE DONE).

6.1.2.  Reading a dynamic group object

   When the member attributes of a dynamic group object is listed by the
   client using an LDAP search operation, the member values returned
   SHOULD contain both the static and dynamic members of the group
   object.  This functionality will not require a change to the
   protocol, and the clients need not be aware of dynamic groups to
   exploit this functionality.  This feature is useful for clients that
   determine access privileges to a resource by themselves, by reading
   the members of a group object.  It will also be useful to
   administrators who want to see the result of the query URL that they
   set on the dynamic group entry.  Note that this overloads the
   semantics of the 'member' and 'uniqueMember' attributes.  This could
   lead to some surprises for the client .

   for example: Clients that read the member attribute of a dynamic
   group object and then attempt to remove values (which were dynamic)
   could get an error specifying such a value was not there.

   Example:

   Let cn=dg1,o=myorg be a dynamic group object with the following
   attributes stored in the directory.







Haripriya, et al.         Expires July 9, 2007                 [Page 14]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


      member: cn=admin,o=myorg

      excludedMember: cn=guest,ou=finance,o=myorg

      excludedMember: cn=robin,ou=finance,o=myorg

      memberQueryURL:
      ldap:///ou=finance,o=myorg??sub?(objectclass=organizationalPerson)

   If there are 5 organizationalPerson objects under ou=finance,o=myorg
   with common names bob, alice, john, robin, and guest, then the output
   of a base-scope LDAP search at cn=dg1,o=myorg, with the attribute
   list containing 'member' will be as follows:

      dn: cn=dg1,o=myorg

      member: cn=admin,o=myorg

      member: cn=bob,ou=finance,o=myorg

      member: cn=alice,ou=finance,o=myorg

      member: cn=john,ou=finance,o=myorg

6.1.3.  'Is Member Of' functionality

   The LDAP compare operation allows one to discover whether a given DN
   is in the membership list of a dynamic group.  Again, the server
   SHOULD produce consistent results among different authorization
   identities when processing this request, as long as those identities
   have the same access to the member or uniqueMember attribute.  Using
   the data from the example in Section 6.1.2, a compare on
   cn=dg1,o=myorg, for the AVA member=cn=bob,ou=finance,o=myorg would
   result in a response of compareTrue (assuming the bound identity was
   authorized to compare the member attribute of cn=dg1,o=myorg).

   Likewise, a search operation that contains an equalityMatch or
   presence filter, naming the member or uniqueMember attribute as the
   attribute (such as (member= cn=bob,ou=finance,o=myorg), or
   (member=*)), will cause the server to evaluate this filter against
   the rules given in Section 4.2.1.3 in the event that the search is
   performed on a dynamic group object.  As of this writing, no other
   matching rules exist for the distinguished name syntax, thus no
   requirements beyond equalityMatch are given here.







Haripriya, et al.         Expires July 9, 2007                 [Page 15]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


6.2.  New Extensions

   The following new extensions are added for dynamic group support.

6.2.1.  Managing the static members of a dynamic group

   Because a dynamic group overloads the semantics of the member and
   uniqueMember attributes, a mechanism is needed to retrieve the static
   values found in these attributes for management purposes.  To serve
   this need, a new attribute option is defined here called 'x-static'.
   Attribute options are discussed in Section 2.5 of [2].  This option
   SHALL only be specified with the 'member' or 'uniqueMember'
   attribute.  When the LDAP server does not understand the semantics of
   this option on a given attribute, the option SHOULD be ignored.  This
   attribute option is only used to affect the transmitted values, and
   does not impose sub-typing semantics on the attribute.

   This option MAY be specified by a client during a search request in
   the list of attributes to be returned, i.e. member;x-static.  In this
   case, the server SHALL only return those members of the dynamic group
   that are statically listed as values of the member or uniqueMember
   attribute.  The evaluation process listed in Section 9 SHALL NOT be
   used to populate the values to be returned.

   This option MAY be specified is either an equalityMatch or presence
   search filter.  In this case, the server evaluates only the values
   statically listed in the member or uniqueMember attribute, and does
   not apply the evaluation process listed in Section 9.

   This option MAY be specified in update operations such as add and
   modify, but SHOULD be ignored, as its presence is semantically the
   same as its non-presence.

   Note to user: Performing a search to read a dynamic group, with a
   filter item such as (member=*), and specifying member;x-static, may
   result in a search result entry that has no member attribute.  This
   may seem counter-intuitive.














Haripriya, et al.         Expires July 9, 2007                 [Page 16]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


7.  Performance Considerations

   When the x-chain extension is present on the memberQueryURL, the
   server MUST follow any search continuation references to other
   servers while searching for dynamic members.  This may be expensive
   and slow in a true distributed environment.  The dynamicGroup
   implementation can consider a distributed caching feature to improve
   the performance.  An outline of such a distributed caching is given
   below.

7.1.  Caching of Dynamic Members

   Since the dynamic members of a group are computed every time the
   group is accessed, the performance could be affected.  An
   implementation of dynamic groups can get around this problem by
   caching the computed members of a dynamic group locally and using the
   cached data subsequently.  One way to do this is to create pseudo-
   objects for each dynamic group on every server that holds an object
   that is a dynamic member of the group.  With this, the computation of
   the dynamic members of a group reduces to the task of reading the
   pseudo-objects from each server.  These pseudo-objects need to be
   linked from the original dynamic group to speed up the member
   computation.  Also, since these are cached objects, appropriate
   timeouts need to be associated with the cache after which the cache
   should be invalidated or refreshed


























Haripriya, et al.         Expires July 9, 2007                 [Page 17]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


8.  Security Considerations

   This document discusses the use of one object as the identity
   (Section 4.5) with which to read information for another object.  If
   the creation of the dgIdentity attribute is uncontrolled, an intruder
   could potentially create a dynamic group with the identity of, say,
   the administrator, to be able to read the directory as the
   administrator, and see information which would be otherwise
   unavailable to him.  Thus, a person adding an object as identity of a
   dynamic group should have appropriate permissions on the object being
   added as identity.

   This document also discusses using dynamic memberships to provide
   access for resources in a directory.  As the dynamic members are not
   created by the administrator, there could be surprises for the
   administrator in the form of certain objects getting access to
   certain resources through dynamic membership, which the administrator
   never intended.  So the administrator should be wary of such
   problems.  The administrator could view the memberships and make sure
   that anybody who is not supposed to be a member of a group is added
   to the excludedMember list.

   Denial of service attacks can be launched on an LDAP server, by
   repeatedly searching for a dynamic group with a large membership list
   and listing the member attribute.  A more effective form of denial of
   service attack could be launched by making searches of the form
   (member="somedn") at the top of tree and closing the client
   connection as soon as the search starts.  Some administrative limits
   be imposed to avoid such situations.

   The dynamic groups feature could be potentially misused by a user to
   circumvent any administrative size-limit restriction placed on the
   server.  In order to search an LDAP server and obtain the names of
   all the objects on the server irrespective of admin size-limit
   restriction on the server, the LDAP user could create a dynamic group
   with a memberQueryURL which matches all objects in the tree, and list
   just that one object.














Haripriya, et al.         Expires July 9, 2007                 [Page 18]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


9.  IANA Considerations

   There are no IANA considerations.
















































Haripriya, et al.         Expires July 9, 2007                 [Page 19]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


10.  Conclusions

   This document discusses the syntax, semantics and usage of dynamic
   groups in LDAPv3.















































Haripriya, et al.         Expires July 9, 2007                 [Page 20]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


11.  Normative References

   [1]  Bradner, S., "Key words for use in RFCs to Indicate Requirement
        Levels", BCP 14, RFC 2119, March 1997.

   [2]  Zeilenga, K., "Lightweight Directory Access Protocol (LDAP):
        Directory Information Models", RFC 4512, June 2006.

   [3]  Smith, M. and T. Howes, "Lightweight Directory Access Protocol
        (LDAP): Uniform Resource Locator", RFC 4516, June 2006.

   [4]  Sciberras, A., "Lightweight Directory Access Protocol (LDAP):
        Schema for User Applications", RFC 4519, June 2006.






































Haripriya, et al.         Expires July 9, 2007                 [Page 21]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


Appendix A.  Example Values for memberQueryURL

   1.  This memberQueryURL value specifies the membership criteria for a
       dynamic group entry as "all inetorgperson entries that also have
       their title attribute set to 'manager', and are in the DIT-wide
       subtree under ou=hr,o=myorg ".

          memberQueryURL: ldap:///
          ou=hr,o=myorg??sub?(&
          (objectclass=inetorgperson)(title=manager))? x-chain

   2.  This value lets the user specify the membership criteria for a
       dynamic group entry as "all entries on the local server, that
       either have unix accounts or belong to the unix department, and
       are under the engineering container ".

          memberQueryURL: ldap:///ou=eng,o=myorg??sub?
          (|(objectclass=posixaccount)(department=unix))

   3.  These values let the user specify the membership criteria as "all
       inetorgperson entries on the local server, in either the
       ou=eng,o=myorg or ou=support,o=myorg" subtrees.

          memberQueryURL:
          ldap:///ou=eng,o=myorg??sub?(objectclass=inetorgperson)

          memberQueryURL:
          ldap:///ou=support,o=myorg??sub?(objectclass=inetorgperson)























Haripriya, et al.         Expires July 9, 2007                 [Page 22]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


Appendix B.  Acknowledgments

   Funding for the RFC Editor function is currently provided by the
   Internet Society.















































Haripriya, et al.         Expires July 9, 2007                 [Page 23]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


Authors' Addresses

   Haripriya S
   Novell, Inc.
   49/1 & 49/3 Garvebhavi Palya,
   7th Mile, Hosur Road
   Bangalore, Karnataka  560068
   India

   Email: sharipriya@novell.com


   Jaimon Jose (editor)
   Novell, Inc.
   49/1 & 49/3 Garvebhavi Palya,
   7th Mile, Hosur Road
   Bangalore, Karnataka  560068
   India

   Email: jjaimon@novell.com


   Jim Sermersheim
   Novell, Inc.
   1800 South Novell Place
   Provo, Utah  84606
   US

   Email: jimse@novell.com






















Haripriya, et al.         Expires July 9, 2007                 [Page 24]

Internet-Draft       LDAP: Dynamic Groups for LDAPv3        January 2007


Full Copyright Statement

   Copyright (C) The Internet Society (2007).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.


Acknowledgment

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).





Haripriya, et al.         Expires July 9, 2007                 [Page 25]

alt-openldap11-devel/drafts/draft-legg-ldap-acm-admin-xx.txt000064400000043065150410163320017625 0ustar00INTERNET-DRAFT                                                   S. Legg
draft-legg-ldap-acm-admin-03.txt                     Adacel Technologies
Intended Category: Standards Track                         June 16, 2004


             Lightweight Directory Access Protocol (LDAP):
                     Access Control Administration

    Copyright (C) The Internet Society (2004). All Rights Reserved.

   Status of this Memo


   This document is an Internet-Draft and is in full conformance with
   all provisions of Section 10 of RFC2026.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as
   Internet-Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress".

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   Distribution of this document is unlimited.  Comments should be sent
   to the author.

   This Internet-Draft expires on 16 December 2004.


Abstract

   This document adapts the X.500 directory administrative model, as it
   pertains to access control administration, for use by the Lightweight
   Directory Access Protocol.  The administrative model partitions the
   Directory Information Tree for various aspects of directory data
   administration, e.g., subschema, access control and collective
   attributes.  This document provides the particular definitions that
   support access control administration, but does not define a
   particular access control scheme.



Legg                    Expires 16 December 2004                [Page 1]

INTERNET-DRAFT        Access Control Administration        June 16, 2004


Table of Contents

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  2
   2.  Conventions. . . . . . . . . . . . . . . . . . . . . . . . . .  2
   3.  Access Control Administrative Areas. . . . . . . . . . . . . .  3
   4.  Access Control Scheme Indication . . . . . . . . . . . . . . .  3
   5.  Access Control Information . . . . . . . . . . . . . . . . . .  4
   6.  Access Control Subentries. . . . . . . . . . . . . . . . . . .  4
   7.  Applicable Access Control Information. . . . . . . . . . . . .  5
   8.  Security Considerations. . . . . . . . . . . . . . . . . . . .  5
   9.  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . .  6
   10. IANA Considerations. . . . . . . . . . . . . . . . . . . . . .  6
   11. References . . . . . . . . . . . . . . . . . . . . . . . . . .  6
       11.1.  Normative References. . . . . . . . . . . . . . . . . .  6
       11.2.  Informative References. . . . . . . . . . . . . . . . .  7
   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . .  7
   Full Copyright Statement . . . . . . . . . . . . . . . . . . . . .  7

1.  Introduction

   This document adapts the X.500 directory administrative model [X501],
   as it pertains to access control administration, for use by the
   Lightweight Directory Access Protocol (LDAP) [RFC3377].

   The administrative model [ADMIN] partitions the Directory Information
   Tree (DIT) for various aspects of directory data administration,
   e.g., subschema, access control and collective attributes.  The parts
   of the administrative model that apply to every aspect of directory
   data administration are described in [ADMIN].  This document
   describes the administrative framework for access control.

   An access control scheme describes the means by which access to
   directory information, and potentially to access rights themselves,
   may be controlled.  This document describes the framework for
   employing access control schemes but does not define a particular
   access control scheme.  Two access control schemes known as Basic
   Access Control and Simplified Access Control are defined by [BAC].
   Other access control schemes may be defined by other documents.

   This document is derived from, and duplicates substantial portions
   of, Sections 4 and 8 of X.501 [X501].

2.  Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and  "OPTIONAL" in this
   document are to be interpreted as described in BCP 14, RFC 2119
   [RFC2119].



Legg                    Expires 16 December 2004                [Page 2]

INTERNET-DRAFT        Access Control Administration        June 16, 2004


   Schema definitions are provided using LDAP description formats
   [RFC2252].  Note that the LDAP descriptions have been rendered with
   additional white-space and line breaks for the sake of readability.

3.  Access Control Administrative Areas

   The specific administrative area [ADMIN] for access control is termed
   an Access Control Specific Area (ACSA).  The root of the ACSA is
   termed an Access Control Specific Point (ACSP) and is represented in
   the DIT by an administrative entry [ADMIN] which includes
   accessControlSpecificArea as a value of its administrativeRole
   operational attribute [SUBENTRY].

   An ACSA MAY be partitioned into subtrees termed inner administrative
   areas [ADMIN].  Each such inner area is termed an Access Control
   Inner Area (ACIA).  The root of the ACIA is termed an Access Control
   Inner Point (ACIP) and is represented in the DIT by an administrative
   entry which includes accessControlInnerArea as a value of its
   administrativeRole operational attribute.

   An administrative entry can never be both an ACSP and an ACIP.  The
   corresponding values can therefore never be present simultaneously in
   the administrativeRole attribute.

   Each entry necessarily falls within one and only one ACSA.  Each such
   entry may also fall within one or more ACIAs nested inside the ACSA
   containing the entry.

   An ACSP or ACIP has zero, one or more subentries that contain Access
   Control Information (ACI).

4.  Access Control Scheme Indication

   The access control scheme (e.g., Basic Access Control [BAC]) in force
   in an ACSA is indicated by the accessControlScheme operational
   attribute contained in the administrative entry for the relevant
   ACSP.

   The LDAP description [RFC2252] for the accessControlScheme
   operational attribute is:

      ( 2.5.24.1 NAME 'accessControlScheme'
          EQUALITY objectIdentifierMatch
          SYNTAX 1.3.6.1.4.1.1466.115.121.1.38
          SINGLE-VALUE USAGE directoryOperation )

   An access control scheme conforming to the access control framework
   described in this document MUST define a distinct OBJECT IDENTIFIER



Legg                    Expires 16 December 2004                [Page 3]

INTERNET-DRAFT        Access Control Administration        June 16, 2004


   value to identify it through the accessControlScheme attribute.
   Object Identifier Descriptors for access control scheme identifiers
   may be registered with IANA [BCP64].

   Only administrative entries for ACSPs are permitted to contain an
   accessControlScheme attribute.  If the accessControlScheme attribute
   is absent from a given ACSP, the access control scheme in force in
   the corresponding ACSA, and its effect on operations, results and
   errors, is implementation defined.

   Any entry or subentry in an ACSA is permitted to contain ACI if and
   only if such ACI is permitted by, and consistent with, the access
   control scheme identified by the value of the accessControlScheme
   attribute of the ACSP.

5.  Access Control Information

   There are three categories of Access Control Information (ACI):
   entry, subentry and prescriptive.

   Entry ACI applies to only the entry or subentry in which it appears,
   and the contents thereof.  Subject to the access control scheme, any
   entry or subentry MAY hold entry ACI.

   Subentry ACI applies to only the subentries of the administrative
   entry in which it appears.  Subject to the access control scheme, any
   administrative entry, for any aspect of administration, MAY hold
   subentry ACI.

   Prescriptive ACI applies to all the entries within a subtree or
   subtree refinement of an administrative area (either an ACSA or an
   ACIA), as defined by the subtreeSpecification attribute of the
   subentry in which it appears.  Prescriptive ACI is only permitted in
   subentries of an ACSP or ACIP.  Prescriptive ACI in the subentries of
   a particular administrative point never applies to the same or any
   other subentry of that administrative point, but does apply to the
   subentries of subordinate administrative points, where those
   subentries are within the subtree or subtree refinement.

6.  Access Control Subentries

   Each subentry which contains prescriptive ACI MUST have
   accessControlSubentry as a value of its objectClass attribute.  Such
   a subentry is called an access control subentry.

   The LDAP description [RFC2252] for the accessControlSubentry
   auxiliary object class is:




Legg                    Expires 16 December 2004                [Page 4]

INTERNET-DRAFT        Access Control Administration        June 16, 2004


      ( 2.5.17.1 NAME 'accessControlSubentry' AUXILIARY )

   A subentry of this object class MUST contain at least one
   prescriptive ACI attribute of a type consistent with the value of the
   accessControlScheme attribute of the corresponding ACSP.

   The subtree or subtree refinement for an access control subentry is
   termed a Directory Access Control Domain (DACD).  A DACD can contain
   zero entries, and can encompass entries that have not yet been added
   to the DIT, but does not extend beyond the scope of the ACSA or ACIA
   with which it is associated.

   Since a subtreeSpecification may define a subtree refinement, DACDs
   within a given ACSA may arbitrarily overlap.

7.  Applicable Access Control Information

   Although particular items of ACI may specify attributes or values as
   the protected items, ACI is logically associated with entries.

   The ACI that is considered in access control decisions regarding an
   entry includes:

   (1) Entry ACI from that particular entry.

   (2) Prescriptive ACI from access control subentries whose DACDs
       contain the entry.  Each of these access control subentries is
       necessarily either a subordinate of the ACSP for the ACSA
       containing the entry, or a subordinate of the ACIP for an ACIA
       that contains the entry.

   The ACI that is considered in access control decisions regarding a
   subentry includes:

   (1) Entry ACI from that particular subentry.

   (2) Prescriptive ACI from access control subentries whose DACDs
       contain the subentry, excluding those belonging to the same
       administrative point as the subentry for which the decision is
       being made.

   (3) Subentry ACI from the administrative point associated with the
       subentry.

8.  Security Considerations

   This document defines a framework for employing an access control
   scheme, i.e., the means by which access to directory information and



Legg                    Expires 16 December 2004                [Page 5]

INTERNET-DRAFT        Access Control Administration        June 16, 2004


   potentially to access rights themselves may be controlled, but does
   not itself define any particular access control scheme.  The degree
   of protection provided, and any security risks, are determined by the
   provisions of the access control schemes (defined elsewhere) making
   use of this framework.

   Security considerations that apply to directory administration in
   general [ADMIN] also apply to access control administration.

9.  Acknowledgements

   This document is derived from, and duplicates substantial portions
   of, Sections 4 and 8 of X.501 [X501].

10.  IANA Considerations

   The Internet Assigned Numbers Authority (IANA) is requested to update
   the LDAP descriptors registry [BCP64] as indicated by the following
   templates:

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): accessControlScheme
      Object Identifier: 2.5.24.1
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: attribute type
      Specification: RFC XXXX
      Author/Change Controller: IESG

      Subject: Request for LDAP Descriptor Registration
      Descriptor (short name): accessControlSubentry
      Object Identifier: 2.5.17.1
      Person & email address to contact for further information:
        Steven Legg <steven.legg@adacel.com.au>
      Usage: object class
      Specification: RFC XXXX
      Author/Change Controller: IESG

11.  References

11.1.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2252]  Wahl, M., Coulbeck, A., Howes, T. and S. Kille,
              "Lightweight Directory Access Protocol (v3): Attribute
              Syntax Definitions", RFC 2252, December 1997.



Legg                    Expires 16 December 2004                [Page 6]

INTERNET-DRAFT        Access Control Administration        June 16, 2004


   [RFC3377]  Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

   [BCP64]    Zeilenga, K., "Internet Assigned Numbers Authority (IANA
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", BCP 64, RFC 3383, September 2002.

   [SUBENTRY] Zeilenga, K. and S. Legg, "Subentries in the Lightweight
              Directory Access Protocol (LDAP)", RFC 3672, December
              2003.

   [ADMIN]    Legg, S., "Lightweight Directory Access Protocol (LDAP):
              Directory Administrative Model",
              draft-legg-ldap-admin-xx.txt, a work in progress, June
              2004.

11.2.  Informative References

   [COLLECT]  Zeilenga, K., "Collective Attributes in the Lightweight
              Directory Access Protocol (LDAP)", RFC 3671, December
              2003.

   [BAC]      Legg, S., "Lightweight Directory Access Protocol (LDAP):
              Basic and Simplified Access Control",
              draft-legg-ldap-acm-bac-xx.txt, a work in progress, June
              2004.

   [X501]     ITU-T Recommendation X.501 (02/01) | ISO/IEC 9594-2:2001,
              Information technology - Open Systems Interconnection -
              The Directory: Models

Author's Address

   Steven Legg
   Adacel Technologies Ltd.
   250 Bay Street
   Brighton, Victoria 3186
   AUSTRALIA

   Phone: +61 3 8530 7710
     Fax: +61 3 8530 7888
   EMail: steven.legg@adacel.com.au

Full Copyright Statement

   Copyright (C) The Internet Society (2004).  This document is subject
   to the rights, licenses and restrictions contained in BCP 78, and



Legg                    Expires 16 December 2004                [Page 7]

INTERNET-DRAFT        Access Control Administration        June 16, 2004


   except as set forth therein, the authors retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.

Changes in Draft 01

   Section 4 has been extracted to become a separate Internet draft,
   draft-legg-ldap-admin-00.txt.  The subsections of Section 5 have
   become the new Sections 3 to 7.  Editorial changes have been made to
   accommodate this split.  No technical changes have been introduced.

Changes in Draft 02

   RFC 3377 replaces RFC 2251 as the reference for LDAP.

   An IANA Considerations section has been added.

Changes in Draft 03



Legg                    Expires 16 December 2004                [Page 8]

INTERNET-DRAFT        Access Control Administration        June 16, 2004


   The document has been reformatted in line with current practice.


















































Legg                    Expires 16 December 2004                [Page 9]


alt-openldap11-devel/drafts/README000064400000001316150410163320012522 0ustar00Internet-Drafts (I-Ds) are working documents of the Internet
Engineering Task Force (IETF), its areas, its working groups, and
individual contributors.

I-Ds are only valid for a maximum of six months and may be updated,
replaced, or obsoleted by other documents at any time.  It is
inappropriate to use I-Ds as reference material or to cite them
other than as "work in progress."

The OpenLDAP Project maintains copies of I-D for which we find
interesting.  Existance here does not necessarily imply any support
nor any plans to support for the I-D.  The I-Ds found in this
directory may be stale, expired, or otherwise out of date.

Please go to <http://www.ietf.org/> for latest revisions (and
status).

$OpenLDAP$
alt-openldap11-devel/drafts/draft-lachman-laser-ldap-mail-routing-xx.txt000064400000073571150410163320022204 0ustar00INTERNET-DRAFT                                                H. Lachman
Intended Category: Informational           Netscape Communications Corp.
Filename: draft-lachman-laser-ldap-mail-routing-02.txt        G. Shapiro
                                                          Sendmail, Inc.
Expires: July 2001                                          January 2001

                 LDAP Schema for Intranet Mail Routing

Status of this Memo

   This document is an Internet-Draft and is in full conformance with
   all provisions of Section 10 of RFC2026.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This draft is being discussed on the Laser mailing list at
   <laser@sunroof.eng.sun.com>.  Subscription requests can be sent to
   <laser-request@sunroof.eng.sun.com> (send an email message with the
   word "subscribe" in the body).  More information on the mailing list
   along with an archive of back messages is available at
   <http://playground.sun.com/laser/>.

   [[Section X will be removed before the document is submitted to the
     IESG.]]

Copyright Notice

   Copyright (C) The Internet Society (1999-2001).  All Rights Reserved.

Abstract

   This document defines an LDAP [1] object class called
   'inetLocalMailRecipient' and associated attributes that provide a way
   to designate an LDAP entry as one that represents a local (intra-
   organizational) email recipient, to specify the recipient's email
   address(es), and to provide routing information pertinent to the
   recipient.  This is intended to support SMTP [2] message transfer
   agents in routing RFC 822-based email [3] within a private enterprise
   only, and is not to be used in the process of routing email across
   the public Internet.

Lachman, et. al.                                                [Page 1]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

1.  Conventions Used in this Document

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this
   document are to be interpreted as described in [9].

2.  Background and Motivation

   LDAP-based directory services are currently being used in many
   organizations as a repository of information about users and other
   network entities (such as groups of users, network resources, etc.).
   In cases where LDAP entries are used to represent entities that are
   email recipients (e.g., a mail user or a mailing list), the LDAP
   entries provide a convenient place to store per-recipient data, such
   as a recipient's email address.

   In many organizations, an email recipient may have an email address
   (e.g., "joe@example.com") that does not specify the host that
   receives mail for that recipient (e.g., "host42.example.com").  A
   message transfer agent (MTA) responsible for routing mail within the
   organization needs some way to determine the appropriate target host
   for such a recipient.  A common solution is the sendmail "aliases"
   database which may contain a record that provides the necessary per-
   recipient routing information (e.g., "joe: joe@host42").  A drawback
   of this solution is that if the organization hosts more than one DNS
   domain (e.g., "example.com" and "example.org", with "joe" in each
   domain being different recipients), a more explicit mapping is
   desirable.  The schema defined in this document provides a way to
   represent such mappings in LDAP and X.500 [4] directory services.

   An LDAP entry that represents an email recipient could conceivably
   contain a variety of attributes related to email, such as disk quota
   and delivery preferences.  We consider here only attributes that
   specify address information and routing information; these attributes
   may be useful to multiple MTAs within the organization since one or
   more MTAs may be responsible for intra-organizational routing.  The
   various MTAs in an organization may have been developed by different
   implementors, so a common schema is desirable for such attributes.

3.  Overview

   Email systems deployed in large organizations must scale to support
   large numbers of users and email servers.  This means using email
   addresses that are independent of particular mailbox server hosts;
   thus an "email routing server" that receives mail sent to the
   host-independent (or high-level or top-level or domain ...) address
   and routes it to the appropriate mailbox server.  For scalability
   there should be many routing servers providing identical service.
   A set of such servers and the mailbox servers they route to form an
   "email domain".

Lachman, et. al.                                                [Page 2]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

   This specification describes the basic function of the routing
   server, including data elements to support per-recipient routing
   info, and use of LDAP-based directory service to support multiple
   servers sharing the routing info data.  The routing function is
   distinguished from other MTA-transfer operations.

   The 'inetLocalMailRecipient' object class and associated attributes
   identify an LDAP entry as representing an SMTP mail recipient (in the
   sense "recipient" is used in [2]).  A recipient may be a mail user, a
   mailing list, an auto-responder of some kind (e.g., a mailing list
   subscription program), a network device such as a printer or fax
   machine, or other recipient type.  Address attributes and routing
   attributes are provided to aid SMTP MTAs in routing mail within an
   organization to the appropriate target MTA for each recipient.

   Once on the target MTA, a message is handled according to local
   conventions (which may be specified using other auxiliary object
   classes and is outside the scope of this document).  For example, the
   message may be delivered to a user mailbox, or to a program or
   network device, and/or forwarded to another recipient.  Or, the
   target MTA may be a gateway to a non-SMTP mail routing and delivery
   system including non-SMTP MTAs.  Note that, in this discussion,
   "target MTA" refers to the final SMTP destination of messages for the
   recipient in question, as we are considering routing of mail only
   among the SMTP MTAs within an organization.

   Any domain that uses LDAP-based routing MUST support LDAP-based
   routing at all MTAs responsible for the domain.  All other MTAs that
   do not support LDAP-based routing MUST forward mail for that domain
   to MTAs that do, using MX records or other local conventions.

   The target MTA checks to see if the destination domain of the
   recipient address is one that it is responsible for and that uses
   LDAP-based routing.  If so, the MTA checks for matching e-mail
   addresses in LDAP by looking up the envelope recipient address in
   LDAP using the object class described in section 4.1 and the
   attribute discussed in section 4.2.  If an unambiguous match is
   returned, the MTA interprets the routing attributes as described in
   section 4.3.

   Routing of mail between different organizations across the public
   Internet is outside the scope of this document, as the mechanism for
   this is already standardized [5,6].  An 'inetLocalMailRecipient'
   entry represents a mail recipient that is local to the organization
   in question, not recipients in other organizations.  This means that
   the domain names that appear within the 'mailLocalAddress' and
   'mailHost' attribute values in an 'inetLocalMailRecipient' entry must
   be DNS domain names that are local to the organization.  (e.g.,
   within the organization's Intranet or by deemed local by other local
   conventions outside the scope of this standard).  An MTA should not
   look for or use 'inetLocalMailRecipient' entries or attributes if
   that MTA is not authoritative for the right-hand side of the
   recipient address in question.

Lachman, et. al.                                                [Page 3]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

   LDAP entries that are not 'inetLocalMailRecipient' entries should be
   ignored by MTAs for the purpose of routing.  An example is a
   conference room whose LDAP entry contains contact information (e.g.,
   email address and telephone number) for the person who books
   reservations for the room; the conference room is not a mail
   recipient, and can safely be ignored by MTAs doing route
   determination based on recipient address.

4.  Object Class and Attribute Definitions

   The 'inetLocalMailRecipient' object class and associated attributes
   are defined (using syntaxes given in [7]) as follows.

 4.1  The inetLocalMailRecipient Object Class

       ( 2.16.840.1.113730.3.2.[[TBD]]
           NAME 'inetLocalMailRecipient'
           SUP top
           AUXILIARY
           MAY ( mailLocalAddress $
               mailHost $ mailRoutingAddress
           )
       )

   The 'inetLocalMailRecipient' object class signifies that the entry
   represents an entity within the organization that can receive SMTP
   mail, such as a mail user or a mailing list.  In any case of an entry
   containing the 'inetLocalMailRecipient' object class, attributes
   defined in this document MUST be interpreted as specified in this
   document.

 4.2  Address Attribute

       ( 2.16.840.1.113730.3.1.13
           NAME 'mailLocalAddress'
           DESC 'RFC 822 email address of this recipient'
           EQUALITY caseIgnoreIA5Match
           SYNTAX '1.3.6.1.4.1.1466.115.121.1.26{256}'
       )

   The 'mailLocalAddress' attribute is used to specify email addresses,
   for the recipient; for example, "nickname@example.com".  The address
   conforms to the syntax of an 'addr-spec' as defined in [3].

   The 'mailLocalAddress' attribute MUST contain all local addresses
   that represent each recipient of the target MTA.  Commonly, the value
   of the 'mail' attribute should also be among the addresses listed in
   the 'mailLocalAddress' attribute if it is expected to be used for
   LDAP mail routing.

Lachman, et. al.                                                [Page 4]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

   When determining the disposition of a given message, MTAs using LDAP
   (directly or indirectly) to route mail MUST search for an entry with
   object class 'inetLocalMailRecipient' and a 'mailLocalAddress'
   attribute matching the message's recipient address.  If exactly one
   matching entry is found, MTAs MUST regard the message as being
   addressed to the entity that is represented by the directory entry.

   If multiple entries are found, the results of the lookup MUST be
   treated as unsuccessful and should be handled by the MTA in some
   locally-appropriate way, such as returning a DSN [10] to the sender.

   If there is no match found by the above, MTAs SHOULD have the
   capability of searching for the recipient domain against the
   'mailLocalAddress' attribute using the "wildcard domain" address
   "@<full-local-domain>" , e.g., "@example.org".  In other words, if
   mail arrives for "someone@example.org", and there is no recipient
   with that address specified as 'mailLocalAddress', then the recipient
   with the wildcard domain address should receive the mail.

   MTAs MAY do other searches but only after the above are done.

   In short, the address attribute 'mailLocalAddress' may be used by an
   LDAP entry to answer the question "what is/are this account's email
   address(es)?"

 4.3  Routing Attributes

       ( 2.16.840.1.113730.3.1.18
           NAME 'mailHost'
           DESC 'fully-qualified hostname of the MTA that is the final
               SMTP destination of messages to this recipient'
           EQUALITY caseIgnoreIA5Match
           SYNTAX '1.3.6.1.4.1.1466.115.121.1.26{256}'
           SINGLE-VALUE
       )

   The 'mailHost' attribute indicates which SMTP MTA considers the
   recipient's mail to be locally handleable.  This information can be
   used for routing, in that an intermediary MTA may take it to be the
   destination for messages addressed to this recipient.  Normal mail
   routing requirements (i.e., use of MX records [5]) apply to the
   specified hostname unless overridden by local conventions.  In other
   words, the mail should be sent to the specified host without changing
   the recipient address.  The hostname is specified as a
   fully-qualified DNS hostname with no trailing dot (e.g.,
   "host42.example.com").

   If the 'inetLocalMailRecipient' object class is present, the
   'mailHost' attribute for each entry MAY contain a value.  If it does,
   that value MUST be the fully qualified name of the server containing
   the host MTA for this person.  If 'mailHost' is present then it MUST
   be taken as the host for this user, and all mail to this user MUST be
   routed to this machine.

Lachman, et. al.                                                [Page 5]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

       ( 2.16.840.1.113730.3.1.47
           NAME 'mailRoutingAddress'
           DESC 'RFC 822 address to use when routing messages to
               the SMTP MTA of this recipient'
           EQUALITY caseIgnoreIA5Match
           SYNTAX '1.3.6.1.4.1.1466.115.121.1.26{256}'
           SINGLE-VALUE
       )

   The 'mailRoutingAddress' attribute indicates a routing address for
   the recipient.  The address MUST conform to the syntax of an
   'addr-spec' in [3].  An intermediary MTA MUST use this information to
   route the message to the MTA that handles mail for this recipient,
   e.g., the envelope address MUST be rewritten to this value.  This is
   useful in cases where, for a given recipient, the target MTA prefers
   a particular address to appear as the recipient address in the SMTP
   envelope.  'mailRoutingAddress' MAY be used as an alternative to
   'mailHost', and is intended to have the same effect as 'mailHost'
   except that 'mailRoutingAddress' is an address for rewriting the
   envelope.  With 'mailHost', the envelope address either is not
   rewritten, or is rewritten according to implementation-specific rules
   and/or configuration.

   If both 'mailHost' and 'mailRoutingAddress' are present, MTAs MUST
   interpret it to mean that messages are to be routed to the host
   indicated by 'mailHost', while rewriting the envelope as per
   'mailRoutingAddress'.  In theory, there could be peculiar cases where
   this is necessary, but this is not normally expected.

   Absence of both 'mailHost' and 'mailRoutingAddress' MAY be considered
   an error, unless "location-independent" recipient types are supported
   by the various MTAs within the organization.  This would allow any
   MTA in the organization to handle the processing of mail for, say, a
   mailing list.  This presumes that the various MTAs all recognize the
   recipient type in question, suggesting a need to standardize
   recipient types that could be "location-independent".

   In short, routing attributes may be used by an LDAP entry to answer
   the question "how should MTAs route mail to this account?"
   (analogous to using the sendmail "aliases" database for per-user
   routing within an organization).  This is in contrast with
   "forwarding"; forwarding and delivery options may be specified in an
   LDAP entry to answer the question "what happens to mail once it
   arrives at this account?", which may include forwarding to some other
   account within or outside the organization (analogous to using the
   sendmail ".forward" file).  Such options are outside the scope of the
   'inetLocalMailRecipient' schema definition.

Lachman, et. al.                                                [Page 6]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

   The following possibilities exist as a result of an LDAP lookup on an
   address:

        mailHost is     mailRoutingAddress is   Results in
        -----------     ---------------------   ----------
        set to a        set                     mail routed to
        "local" host                            mailRoutingAddress

        set to a        not set                 delivered to
        "local" host                            original address

        set to a        set                     relay to mailHost
        remote host                             using mailRoutingAddress

        set to a        not set                 original address
        remote host                             relayed to mailHost

        not set         set                     mail routed to
                                                mailRoutingAddress

        not set         not set                 error or
                                                "location-independent"

   The term "local" host above means the host specified is one that the
   local (target) MTA considers to be a local delivery.  The local MTA
   MAY rewrite the original address when mailRoutingAddress is not set
   if local conventions warrant the change.

5.  Examples

   The following examples illustrate possible uses of the
   'inetLocalMailRecipient' object class.  Note that the examples
   include attributes defined outside of this document to demonstrate a
   complete record.  The existence of these attributes in the example is
   not an indication that these attributes are used for LDAP-based mail
   routing (e.g., the 'mail' is not used for mail routing).

   Here is an example of an LDAP entry representing a mail user:

       dn: uid=joe,o=Example Corp,c=US
       objectClass: top
       objectClass: person
       objectClass: organizationalPerson
       objectClass: inetOrgPerson
       objectClass: inetLocalMailRecipient
       objectClass: nsMessagingServerUser
       cn: Joe User
       sn: User
       uid: joe
       userPassword: {crypt}y2KxtbzMYnApU
       mail: joe@example.com

Lachman, et. al.                                                [Page 7]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

       mailLocalAddress: joe@example.com
       mailLocalAddress: joe@another.example.com
       mailHost: nsmail1.example.com
       mailDeliveryOption: mailbox
       mailQuota: 1000000
       mailForwardingAddress: mary@example.com

   Joe User is a user of a hypothetical mail system called NS Messaging.
   Let's say mail arrives on an MTA called "mx.example.com", addressed
   to "joe@example.com".  That MTA searches the directory for a mail
   recipient with that address, using an LDAP search filter [8] such as:

       (&(objectClass=inetLocalMailRecipient)
         (mailLocalAddress=joe@example.com))

   It finds Joe's LDAP entry, and routes the message to the target MTA
   "nsmail1.example.com", while not rewriting the SMTP envelope
   recipient address.  Then, "nsmail1.example.com" receives the message,
   searches for and finds the recipient in the directory, ascertains
   that it is the recipient's target MTA, and handles the message as per
   other attributes in the recipient's entry and/or the MTA
   configuration (in this case, the message is delivered to a mailbox,
   and forwarded to another recipient).

   Note that this document does not specify the rules an MTA is to use
   to ascertain whether or not it is the target MTA for a given
   recipient (it could check the recipient's 'mailHost' value against
   its own hostname, or check the recipient's 'mailRoutingAddress', or
   check the MTA configuration, or some combination of these).

   Here is another example of an LDAP entry representing a mail user:

       dn: uid=john,o=Example Corp,c=US
       objectClass: top
       objectClass: person
       objectClass: organizationalPerson
       objectClass: inetOrgPerson
       objectClass: inetLocalMailRecipient
       objectClass: xyzMailUser
       cn: John Doe
       sn: Doe
       uid: john
       userPassword: {crypt}y2KxtbzMYnApU
       mail: john@example.com
       mailLocalAddress: john@example.com
       mailRoutingAddress: John_Doe@xyz-gw.example.com
       xyzPostOfficeName: PO_1
       xyzClusterNumber: 3
       xyzMessageStoreId: 9

Lachman, et. al.                                                [Page 8]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

   John Doe is a user of a hypothetical mail system called XYZ Mail.
   Let's say mail arrives on an MTA called "mx.example.com", addressed
   to "john@example.com".  That MTA searches the directory for a mail
   recipient with that address, and routes the message to "xyz-
   gw.example.com", rewriting the SMTP envelope recipient address to
   "John_Doe@xyz-gw.example.com", as per the 'mailRoutingAddress'.  On
   "xyz-gw.example.com", the message is gatewayed into the XYZ Mail
   system and then dealt with as per other attributes.

   Here is an example of an LDAP entry representing a mailing list:

       dn: cn=Scuba Group,o=Example Corp,c=US
       objectClass: top
       objectClass: groupOfUniqueNames
       objectClass: inetLocalMailRecipient
       objectClass: mailGroup
       cn: Scuba Group
       mail: scuba@example.com
       mailLocalAddress: scuba@example.com
       mailHost: host42.example.com
       mgrpRFC822MailMember: joe@example.com
       mgrpRFC822MailMember: john@example.com

   The Scuba Group is a mail group (mailing list) that includes two
   members.  A message addressed to "scuba@example.com" is routed to
   "host42.example.com" where it is then resent to the mailing list
   members.

   Here is an example of an LDAP entry representing a forwarding alias:

       dn: cn=Jane Roe Forwarding Alias,o=Example,c=US
       objectClass: top
       objectClass: inetLocalMailRecipient
       objectClass: mailForwardingAlias
       mail: janeroe@example.org
       mailLocalAddress: janeroe@example.org
       mailHost: mail.example.org
       mailForwardingAddress: janeroe@elsewhere.example.com
       cn: Jane Roe Forwarding Alias

   This entry uses a hypothetical object class 'mailForwardingAlias'
   that is not specified here, but is used as an example of how an LDAP
   entry might represent such a recipient type.  A message addressed to
   "janeroe@example.org" is routed to "mail.example.org" where it is
   then forwarded.  In this case, Jane Roe may be a former member of the
   Example Organization, and they are forwarding her mail to her new
   address elsewhere.

Lachman, et. al.                                                [Page 9]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

6.  Security Considerations

   As in all cases where account information is stored in an LDAP-based
   directory service, network administrators must be careful to ensure
   that their directory service controls users' access to the entries
   and attributes stored therein, according to site policy.  In
   particular, mail routing information should not be accessible from
   outside the organization, since it is intended for use only by MTAs
   within the organization.

7.  Acknowledgments

   The 'inetLocalMailRecipient' object class is based on an earlier
   design done by the Netscape Messaging and Directory Server teams,
   which was implemented and deployed to customers as part of Netscape
   Messaging Server.  Various team members contributed to the design,
   including Bill Fitler, Bruce Steinback, Prabhat Keni, Mike Macgirvin,
   John Myers, John Kristian, Tim Howes, Mark Smith, and Leif Hedstrom.
   Thanks also to Jeff Hodges of Stanford for contributing to the early
   design discussions, and to the other participants in the IETF LASER
   BOF, including, from Sun Microsystems, John Beck, Anil Srivastava,
   and Darryl Huff.

8.  References

   [1]  M. Wahl, T. Howes, S. Kille, "Lightweight Directory Access
   Protocol (v3)", RFC 2251, December 1997.

   [2]  J. Postel, "Simple Mail Transfer Protocol", STD 10, RFC 821,
   August 1982.

   [3]  D. Crocker, "Standard for the Format of ARPA Internet Text
   Messages", STD 11, RFC 822, August 1982.

   [4]  "Information Processing Systems - Open Systems Interconnection -
   The Directory: Overview of Concepts, Models and Service", ISO/IEC JTC
   1/SC21, International Standard 9594-1, 1988.

   [5]  C. Partridge, "Mail routing and the domain system", STD 14, RFC
   974, January 1986.

   [6]  R. Braden, "Requirements for Internet hosts - application and
   support", STD 3, RFC 1123, October 1989.

   [7]  M. Wahl, A. Coulbeck, T. Howes, S. Kille, "Lightweight X.500
   Directory Access Protocol (v3): Attribute Syntax Definitions", RFC
   2252, December 1997.

   [8]  T. Howes, "The String Representation of LDAP Search Filters",
   RFC 2254, December 1997.

Lachman, et. al.                                               [Page 10]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

   [9]  S. Bradner, "Key words for use in RFCs to Indicate Requirement
   Levels", BCP 14, RFC 2119, March 1997.

   [10]  K. Moore, "SMTP Service Extension for Delivery Status
   Notifications", RCP 1891, January 1996.

9.  Authors' Addresses

   Hans Lachman
   Netscape Communications Corp.
   501 East Middlefield Road
   Mountain View, CA  94043
   Phone: (650) 254-1900
   EMail: lachman@netscape.com

   Gregory Neil Shapiro
   Sendmail, Inc.
   6603 Shellmound Street
   Emeryville, CA 94608-1042
   Phone: +1 510-594-5522
   Fax:   +1 510-594-5411
   EMail: gshapiro@sendmail.org

X. Change Summary

X.1.1 Substantive changes between
      draft-lachman-laser-ldap-mail-routing-00.txt and
      draft-lachman-laser-ldap-mail-routing-01.txt

   (i)     Added Gregory Neil Shapiro as another author.
   (ii)    Changed Draft heaer.
   (iii)   Added "Conventions Used in this Document" section.
   (iv)    Replaced RFC mentions with reference numbers.
   (v)     Add new MUST/SHOULD/MAY sections to bring more in line with
           RFC documents.
   (vi)    Clarify job of MTA in Overview by adding third paragraph.
   (vii)   mailRoutingAddress can be outside of administrative control.
   (viii)  Eliminated use of 'mail' attribute for mail routing.
   (ix)    Changed name of 'mailAlternateAddress' to 'mailLocalAddress'.
   (x)     Remove "routable" from 'mailLocalAddress' description.
   (xi)    Clarify which addresses MUST be in 'mailLocalAddress'.
   (xii)   Allow for multiple responses if they all have the same
           routing attribute values.
   (xiii)  Clarify use of MX records on routing attributes.
   (xiv)   Add a table to clarify use of 'mailHost' and
           'mailRoutingAddress'.
   (xv)    Remove document weakening statements from section 5.
   (xvi)   Only use reserved domains (example.com, example.org) in
           examples.
   (xvii)  Clean up references
   (xviii) Added section X to list the changes between draft versions.

Lachman, et. al.                                               [Page 11]

INTERNET-DRAFT   LDAP Schema for Intranet Mail Routing      January 2001

X.1.2 Substantive changes between
      draft-lachman-laser-ldap-mail-routing-01.txt and
      draft-lachman-laser-ldap-mail-routing-02.txt

   (i)     Changed Intended Category from Standard Track to Informational.
   (ii)    Removed references to mailGroup document which has expired.
   (iii)   Add additional Overview text from RL 'Bob' Morgan.
   (iv)    If a domain uses LDAP-based routing, require all MTAs in that
           domain to either use LDAP for routing or forward mail to an
           MTA which uses LDAP for routing.
   (v)     Add more text regarding "local" domain.
   (vi)    Tighten rules for better interoperability.  Multiple,
           matching results is now treated as an unsuccessful lookup.
   (vii)   Tighten rules for better interoperability.  Change the action
           for a lookup which returns both a 'mailHost' and
           'mailRoutingAddress' to a MUST (from a MAY).
   (viii)  Point out that examples contain attributes which are not part of
           this spec and should not be used for mail routing
           (specifically, 'mail').
   (ix)    Clean up text.
   (x)     NOTE: Still need vendor-neutral OIDs for the objectClass and
                 attributes.

10.  Full Copyright Statement

   Copyright (C) The Internet Society (1999-2001).  All Rights Reserved.

   This document and translations of it may be copied and furnished
   to others, and derivative works that comment on or otherwise
   explain it or assist in its implementation may be prepared, copied,
   published and distributed, in whole or in part, without
   restriction of any kind, provided that the above copyright notice
   and this paragraph are included on all such copies and derivative
   works.  However, this document itself may not be modified in any
   way, such as by removing the copyright notice or references to the
   Internet Society or other Internet organizations, except as needed
   for the purpose of developing Internet standards in which case the
   procedures for copyrights defined in the Internet Standards
   process must be followed, or as required to translate it into
   languages other than English.

   The limited permissions granted above are perpetual and will not
   be revoked by the Internet Society or its successors or assigns.

   This document and the information contained herein is provided on
   an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Lachman, et. al.                                               [Page 12]
alt-openldap11-devel/drafts/draft-chu-ldap-xordered-xx.txt000064400000051465150410163320017457 0ustar00


Network Working Group                                             H. Chu
Internet-Draft                                               Symas Corp.
Intended status: Informational                                  May 2006
Expires: November 2, 2006


                   Ordered Entries and Values in LDAP
                     draft-chu-ldap-xordered-00.txt

Status of this Memo

   By submitting this Internet-Draft, each author represents that any
   applicable patent or other IPR claims of which he or she is aware
   have been or will be disclosed, and any of which he or she becomes
   aware will be disclosed, in accordance with Section 6 of BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on November 2, 2006.

Copyright Notice

   Copyright (C) The Internet Society (2006).














Chu                     Expires November 2, 2006                [Page 1]

Internet-Draft           LDAP Ordering Extension                May 2006


Abstract

   As LDAP is used more extensively for managing various kinds of data,
   one often encounters a need to preserve both the ordering and the
   content of data, despite the inherently unordered structure of
   entries and attribute values in the directory.  This document
   describes a scheme to attach ordering information to attributes in a
   directory so that the ordering may be preserved and propagated to
   other LDAP applications.


Table of Contents

   1.          Introduction . . . . . . . . . . . . . . . . . . . . .  3
   2.          Conventions  . . . . . . . . . . . . . . . . . . . . .  4
   3.          Ordering Extension . . . . . . . . . . . . . . . . . .  5
   3.1.        Overview . . . . . . . . . . . . . . . . . . . . . . .  5
   3.2.        Encoding . . . . . . . . . . . . . . . . . . . . . . .  5
   3.3.        Ordering Properties  . . . . . . . . . . . . . . . . .  6
   4.          Examples . . . . . . . . . . . . . . . . . . . . . . .  8
   4.1.        Sample Schema  . . . . . . . . . . . . . . . . . . . .  8
   4.2.        Ordered Values . . . . . . . . . . . . . . . . . . . .  8
   4.3.        Ordered Siblings . . . . . . . . . . . . . . . . . . . 10
   5.          Security Considerations  . . . . . . . . . . . . . . . 13
   6.          Normative References . . . . . . . . . . . . . . . . . 14
   Appendix A. IANA Considerations  . . . . . . . . . . . . . . . . . 15
               Author's Address . . . . . . . . . . . . . . . . . . . 16
               Intellectual Property and Copyright Statements . . . . 17























Chu                     Expires November 2, 2006                [Page 2]

Internet-Draft           LDAP Ordering Extension                May 2006


1.  Introduction

   Information in LDAP directories is usually handled by applications in
   the form of ordered lists, which tends to encourage application
   developers to assume they are maintained as such, i.e., it is assumed
   that information stored in a particular order will always be
   retrieved and presented in that same order.  The fact that directory
   attributes actually store sets of values, which are inherently
   unordered, often causes grief to users migrating their data into
   LDAP.  Similar concerns arise over the order in which entries
   themselves are stored and retrieved from the directory.

   This document describes a schema extension that may be used in LDAP
   attribute definitions to store ordering information along with the
   attribute values, so that the ordering can be recovered when
   retrieved by an LDAP client.  The extension also provides automated
   management of this ordering information to ease manipulation of the
   ordered values.

































Chu                     Expires November 2, 2006                [Page 3]

Internet-Draft           LDAP Ordering Extension                May 2006


2.  Conventions

   Imperative keywords defined in [RFC2119] are used in this document,
   and carry the meanings described there.















































Chu                     Expires November 2, 2006                [Page 4]

Internet-Draft           LDAP Ordering Extension                May 2006


3.  Ordering Extension

3.1.  Overview

   The "X-ORDERED" schema extension is added to an
   AttributeTypeDescription to signify the use of this ordering
   mechanism.  The extension has two variants, selected by either the
   'VALUES' or 'SIBLINGS' qdstrings.  In general this extension is only
   compatible with AttributeTypes that have a string-oriented syntax.

   The "X-ORDERED 'VALUES'" extension is used with multi-valued
   attributes to maintain the order of multiple values of a given
   attribute.  For example, this feature is useful for storing data such
   as access control rules, which must be evaluated in a specific order.
   If the access control information is stored in a multi-valued
   attribute without a means of preserving the the order of the rules,
   the access control rules cannot be evaluated properly.  As the use of
   LDAP to store security policy and access control information becomes
   more prevalent, the necessity of this feature continues to grow.

   The "X-ORDERED 'SIBLINGS'" extension is used with single-valued
   attributes to maintain the order of all the onelevel children of a
   parent entry.  That is, ordering will be maintained for all the child
   entries whose RDNs are all of the same AttributeType.  The motivation
   for this feature is much the same as for the 'VALUES' feature.
   Sometimes the information with the ordering dependency is too complex
   or highly structured to be conveniently stored in values of a multi-
   valued attribute.  For example, one could store a prioritized list of
   servers as a set of separate entries, each entry containing separate
   attributes for a URL, a set of authentication credentials, and
   various other parameters.  Using the 'SIBLINGS' feature with the
   attribute in the entries' RDNs would ensure that when obtaining the
   list of these entries, the list is returned in the intended order.

3.2.  Encoding

   Ordering information is encoded by prepending a value's ordinal index
   to each value, enclosed in braces.  The following BNF specifies the
   encoding.  It uses elements defined in [RFC2252].

      d = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"

      numericstring = 1*d

      ordering-prefix = "{" numericstring "}"

      value = <any sequence of octets>




Chu                     Expires November 2, 2006                [Page 5]

Internet-Draft           LDAP Ordering Extension                May 2006


      ordered-value = ordering-prefix value

   The ordinals are zero-based and increment by one for each value.

   Note that when storing ordered-values into the directory, the
   ordering-prefix can usually be omitted as it will be generated
   automatically.  But if the original value already begins with a
   sequence of characters in the form of an ordering-prefix, then an
   ordering-prefix must always be provided with that value, otherwise
   the value will be processed and stored incorrectly.

   Using this extension on an attribute requires that ordering-prefix is
   a legal value of the LDAP syntax of that attribute.

3.3.  Ordering Properties

   Since the ordering-prefix is stored with the attribute values, it
   will be propagated to any clients or servers that access the data.

   Servers implementing this scheme SHOULD sort the values according to
   their ordering-prefix before returning them in search results.

   The presence of the ordering extension alters the matching rules that
   apply to the attribute:

      When presented with an AssertionValue that does not have an
      ordering-prefix, the ordering-prefix in the AttributeValue is
      ignored.

      When presented with an AssertionValue that consists solely of an
      ordering-prefix, only the ordering-prefix of the AttributeValue is
      compared; the remainder of the value is ignored.

      When presented with an AssertionValue containing both the
      ordering-prefix and a value, both components are compared to
      determine a match.

   A side effect of these properties is that even attributes that
   normally would have no equality matching rule can be matched by an
   ordering-prefix.

   The ordering-prefix may also be used in Modification requests to
   specify which values to delete, and in which position values should
   be added.  When processing deletions and insertions, all of the
   ordinals are recounted after each individual modification.

   If a value being added does not have an ordering-prefix, it is simply
   appended to the list and the appropriate ordering-prefix is



Chu                     Expires November 2, 2006                [Page 6]

Internet-Draft           LDAP Ordering Extension                May 2006


   automatically generated.  Likewise if an ordering-prefix is provided
   that is greater than or equal to the number of existing values.

   See the examples in the next section.















































Chu                     Expires November 2, 2006                [Page 7]

Internet-Draft           LDAP Ordering Extension                May 2006


4.  Examples

4.1.  Sample Schema

   This schema is used for all of the examples:

   ( EXAMPLE_AT.1 NAME 'olcDatabase'
   EQUALITY caseIgnoreMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   SINGLE-VALUE X-ORDERED 'SIBLINGS' )

   ( EXAMPLE_AT.2 NAME 'olcSuffix'
   EQUALITY distinguishedNameMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
   X-ORDERED 'VALUES' )

   ( EXAMPLE_OC.1 NAME 'olcDatabaseConfig'
   SUP top STRUCTURAL
   MAY ( olcDatabase $ olcSuffix ) )

4.2.  Ordered Values

   Given this entry:

   dn: olcDatabase={1}bdb,cn=config
   olcDatabase: {1}bdb
   objectClass: olcDatabaseConfig
   olcSuffix: {0}dc=example,dc=com
   olcSuffix: {1}o=example.com
   olcSuffix: {2}o=The Example Company
   olcSuffix: {3}o=example,c=us

   We can perform these Modify operations:

   1.  dn: olcDatabase={1}bdb,cn=config
       changetype: modify
       delete: olcSuffix
       olcSuffix: {0}
       -
       This operation deletes the first olcSuffix, regardless of its
       value.  All other values are bumped up one position.  The
       olcSuffix attribute will end up containing:
       olcSuffix: {0}o=example.com
       olcSuffix: {1}o=The Example Company
       olcSuffix: {2}o=example,c=us

   2.  Starting from the original entry, we could issue this change
       instead:



Chu                     Expires November 2, 2006                [Page 8]

Internet-Draft           LDAP Ordering Extension                May 2006


       delete: olcSuffix
       olcSuffix: o=example.com
       -
       This operation deletes the olcSuffix that matches the value,
       regardless of its ordering-prefix.  The olcSuffix attribute will
       contain:
       olcSuffix: {0}dc=example,dc=com
       olcSuffix: {1}o=The Example Company
       olcSuffix: {2}o=example,c=us

   3.  Again, starting from the original entry, we could issue this
       change:
       delete: olcSuffix
       olcSuffix: {2}o=The Example Company
       -
       Here both the ordering-prefix and the value must match, otherwise
       the Modify would fail with noSuchAttribute.  In this case the
       olcSuffix attribute results in:
       olcSuffix: {0}dc=example,dc=com
       olcSuffix: {1}o=example.com
       olcSuffix: {2}o=example,c=us

   4.  Adding a new value without an ordering-prefix simply appends:
       add: olcSuffix
       olcSuffix: o=example.org
       -
       The resulting attribute would be:
       olcSuffix: {0}dc=example,dc=com
       olcSuffix: {1}o=example.com
       olcSuffix: {2}o=The Example Company
       olcSuffix: {3}o=example,c=us
       olcSuffix: {4}o=example.org

   5.  Adding a new value with an ordering-prefix inserts into the
       specified position:
       add: olcSuffix
       olcSuffix: {0}o=example.org
       -
       The resulting attribute would be:
       olcSuffix: {0}o=example.org
       olcSuffix: {1}dc=example,dc=com
       olcSuffix: {2}o=example.com
       olcSuffix: {3}o=The Example Company
       olcSuffix: {4}o=example,c=us

   6.  Modifying multiple values in one operation:
       add: olcSuffix
       olcSuffix: {0}ou=Dis,o=example.com



Chu                     Expires November 2, 2006                [Page 9]

Internet-Draft           LDAP Ordering Extension                May 2006


       olcSuffix: {0}ou=Dat,o=example,com
       -
       delete: olcSuffix:
       olcSuffix: {2}
       olcSuffix: {1}
       -
       The resulting attribute would be:
       olcSuffix: {0}ou=Dat,o=example,com
       olcSuffix: {1}dc=example,dc=com
       olcSuffix: {2}o=example.com
       olcSuffix: {3}o=The Example Company
       olcSuffix: {4}o=example,c=us

   7.  If the Adds and Deletes in the previous example were done in the
       opposite order:
       delete: olcSuffix:
       olcSuffix: {2}
       olcSuffix: {1}
       -
       add: olcSuffix
       olcSuffix: {0}ou=Dis,o=example.com
       olcSuffix: {0}ou=Dat,o=example,com
       -
       The result would be:
       olcSuffix: {0}ou=Dat,o=example,com
       olcSuffix: {1}ou=Dis,o=example.com
       olcSuffix: {2}o=example.org
       olcSuffix: {3}o=The Example Company
       olcSuffix: {4}o=example,c=us

   Note that matching against an ordering-prefix can also be done in
   Compare operations and Search filters.  E.g., the filter
   "(olcSuffix={4})" would match all entries with at least 5 olcSuffix
   values.

4.3.  Ordered Siblings

   The rules for Ordered Siblings are basically the same as for Ordered
   Values, except instead of working primarily with the Modify request,
   the operations of interest here are Add, Delete, and ModRDN.

   Given these entries:

   dn: olcDatabase={0}config,cn=config
   olcDatabase: {0}config
   objectClass: olcDatabaseConfig
   olcSuffix: {0}cn=config




Chu                     Expires November 2, 2006               [Page 10]

Internet-Draft           LDAP Ordering Extension                May 2006


   dn: olcDatabase={1}bdb,cn=config
   olcDatabase: {1}bdb
   objectClass: olcDatabaseConfig
   olcSuffix: {0}dc=example,dc=com

   We can perform these operations:

   1.  Add a new entry with no ordering-prefix:
       dn: olcDatabase=hdb,cn=config
       changetype: add
       olcDatabase: hdb
       objectClass: olcDatabaseConfig
       olcSuffix: {0}dc=example,dc=org
       The resulting entry will be:
       dn: olcDatabase={2}hdb,cn=config
       olcDatabase: {2}hdb
       objectClass: olcDatabaseConfig
       olcSuffix: {0}dc=example,dc=org

   2.  Continuing on with these three entries, we can add another entry
       with a specific ordering-prefix:
       dn: olcDatabase={1}ldif,cn=config
       changetype: add
       olcDatabase: {1}ldif
       objectClass: olcDatabaseConfig
       olcSuffix: {0}o=example.com
       This would give us four entries, whose DNs are:

          dn: olcDatabase={0}config,cn=config

          dn: olcDatabase={1}ldif,cn=config

          dn: olcDatabase={2}bdb,cn=config

          dn: olcDatabase={3}hdb,cn=config

   3.  Issuing a ModRDN request will cause multiple entries to be
       renamed:
       dn: olcDatabase={1}ldif,cn=config
       changetype: modrdn
       newrdn: olcDatabase={99}ldif
       deleteoldrdn: 1
       The resulting entries would be named:

          dn: olcDatabase={0}config,cn=config

          dn: olcDatabase={1}bdb,cn=config




Chu                     Expires November 2, 2006               [Page 11]

Internet-Draft           LDAP Ordering Extension                May 2006


          dn: olcDatabase={2}hdb,cn=config

          dn: olcDatabase={3}ldif,cn=config

   4.  As may be expected, a Delete request will also rename the
       remaining entries:
       dn: olcDatabase={1}bdb,cn=config
       changetype: delete
       The remaining entries would be named:

          dn: olcDatabase={0}config,cn=config

          dn: olcDatabase={1}hdb,cn=config

          dn: olcDatabase={2}ldif,cn=config




































Chu                     Expires November 2, 2006               [Page 12]

Internet-Draft           LDAP Ordering Extension                May 2006


5.  Security Considerations

   General LDAP security considerations [RFC3377] apply.
















































Chu                     Expires November 2, 2006               [Page 13]

Internet-Draft           LDAP Ordering Extension                May 2006


6.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2252]  Wahl, M., Coulbeck, A., Howes, T., and S. Kille,
              "Lightweight Directory Access Protocol (v3): Attribute
              Syntax Definitions", RFC 2252, December 1997.

   [RFC3377]  Hodges, J. and R. Morgan, "Lightweight Directory Access
              Protocol (v3): Technical Specification", RFC 3377,
              September 2002.

   [RFC3383]  Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
              Considerations for the Lightweight Directory Access
              Protocol (LDAP)", RFC 3383, September 2002.

   [X680]     International Telecommunications Union, "Abstract Syntax
              Notation One (ASN.1): Specification of basic notation",
              ITU-T Recommendation X.680, July 2002.































Chu                     Expires November 2, 2006               [Page 14]

Internet-Draft           LDAP Ordering Extension                May 2006


Appendix A.  IANA Considerations

   In accordance with [RFC3383] (what needs to be done here?) .  We
   probably need an OID for advertising in supportedFeatures.















































Chu                     Expires November 2, 2006               [Page 15]

Internet-Draft           LDAP Ordering Extension                May 2006


Author's Address

   Howard Chu
   Symas Corp.
   18740 Oxnard Street, Suite 313A
   Tarzana, California  91356
   USA

   Phone: +1 818 757-7087
   Email: hyc@symas.com









































Chu                     Expires November 2, 2006               [Page 16]

Internet-Draft           LDAP Ordering Extension                May 2006


Full Copyright Statement

   Copyright (C) The Internet Society (2006).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.


Acknowledgment

   Funding for the RFC Editor function is provided by the IETF
   Administrative Support Activity (IASA).





Chu                     Expires November 2, 2006               [Page 17]

alt-openldap11-devel/drafts/draft-masarati-ldap-deref-xx.txt000064400000036105150410163320017744 0ustar00


Network Working Group                                        P. Masarati
Internet-Draft                                     Politecnico di Milano
Intended status: Standards Track                                  H. Chu
Expires: May 23, 2009                                        Symas Corp.
                                                       November 19, 2008


                        LDAP Dereference Control
                    draft-masarati-ldap-deref-00.txt

Status of this Memo

   By submitting this Internet-Draft, each author represents that any
   applicable patent or other IPR claims of which he or she is aware
   have been or will be disclosed, and any of which he or she becomes
   aware will be disclosed, in accordance with Section 6 of BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF), its areas, and its working groups.  Note that
   other groups may also distribute working documents as Internet-
   Drafts.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   The list of current Internet-Drafts can be accessed at
   http://www.ietf.org/ietf/1id-abstracts.txt.

   The list of Internet-Draft Shadow Directories can be accessed at
   http://www.ietf.org/shadow.html.

   This Internet-Draft will expire on May 23, 2009.

















Masarati & Chu            Expires May 23, 2009                  [Page 1]

Internet-Draft                 LDAP Deref                  November 2008


Abstract

   This document describes the Dereference Control for LDAP.  This
   control is intended to provide a concise means to collect extra
   information related to cross-links present in entries returned as
   part of search responses.


Table of Contents

   1.  Background and Intended Use  . . . . . . . . . . . . . . . . .  3
   2.  The LDAP Dereference Control . . . . . . . . . . . . . . . . .  4
     2.1.  Control Semantics  . . . . . . . . . . . . . . . . . . . .  4
     2.2.  Control Request  . . . . . . . . . . . . . . . . . . . . .  5
     2.3.  Control Response . . . . . . . . . . . . . . . . . . . . .  5
   3.  Examples . . . . . . . . . . . . . . . . . . . . . . . . . . .  6
   4.  Implementation Notes . . . . . . . . . . . . . . . . . . . . .  7
   5.  Security Considerations  . . . . . . . . . . . . . . . . . . .  8
   6.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . .  9
     6.1.  Object Identifier Registration . . . . . . . . . . . . . .  9
   7.  Acknowledgments  . . . . . . . . . . . . . . . . . . . . . . . 10
   8.  Normative References . . . . . . . . . . . . . . . . . . . . . 11
   Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 12
   Intellectual Property and Copyright Statements . . . . . . . . . . 13



























Masarati & Chu            Expires May 23, 2009                  [Page 2]

Internet-Draft                 LDAP Deref                  November 2008


1.  Background and Intended Use

   Cross-links between entries are often used to describe relationships
   between entries.  To exploit the uniqueness of entries naming, these
   links are usually represented by the distinguished name (DN) of the
   linked entries.

   In many cases, DUAs need to collect information about linked entries.
   This requires to explicitly dereference each linked entry in order to
   collect the desired attributes, resulting in the need to perform a
   specific sequence of search operations, using the links as search
   base, with a SearchRequest.scope of baseObject [RFC4511].

   This document describes a LDAP Control [RFC4511] that allows a DUA to
   request the DSA to return specific attributes of linked entries along
   with the link, under the assumption that this operation can be
   performed by the DSA in a more efficient manner than the DUA would
   itself by performing the complete sequence of required search
   operations.

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
   document are to be interpreted as described in [RFC2119].




























Masarati & Chu            Expires May 23, 2009                  [Page 3]

Internet-Draft                 LDAP Deref                  November 2008


2.  The LDAP Dereference Control

2.1.  Control Semantics

   This control allows specifying a dereference attribute and a set of
   attributes to be dereferenced, as illustrated in Section 2.2.  The
   dereference attribute's syntax MUST be 1.3.6.1.4.1.1466.115.121.1.12
   (DN) [RFC4517].  Each value of the dereference attribute in a
   SearchResultEntry SHOULD result in dereferencing the corresponding
   entry, collecting the values of the attributes to be dereferenced,
   and returning them as part of the control value in the
   SearchResultEntry response, in the format detailed in Section 2.3.

   The control value may contain dereference attribute values without
   any dereferenced attribute values, as detailed in Section 2.3.  The
   control semantics does not specify whether this is a consequence of a
   dangling link or of the application of access restrictions on the
   values of the attributes to be dereferenced.

   Attribute description hierarchy [RFC4512] SHALL NOT be exploited when
   collecting the values of the attributes to be dereferenced.  On the
   contrary, all of the attribute descriptions in an attribute hierarchy
   SHOULD be treated as distinct and unrelated descriptions.

   This control is only appropriate for the search operation [RFC4511].

   The semantics of the criticality field are specified in [RFC4511].
   In detail, the criticality of the control determines whether the
   control will or will not be used, and if it will not be used, whether
   the operation will continue without returning the control in the
   response, or fail, returning unavailableCriticalExtension.  If the
   control is appropriate for an operation and, for any reason, it
   cannot be applied in its entirety to a single SearchResultEntry
   response, it MUST NOT be applied to that specific SearchResultEntry
   response, without affecting its application to any subsequent
   SearchResultEntry response.

   Servers implementing this technical specification SHOULD publish the
   object identifier deref-oid (IANA assigned; see Section 6) as a value
   of the 'supportedControl' attribute [RFC4512] in their root DSE.

   This control is totally unrelated to alias dereferencing [RFC4511].









Masarati & Chu            Expires May 23, 2009                  [Page 4]

Internet-Draft                 LDAP Deref                  November 2008


2.2.  Control Request

   The control type is deref-oid (IANA assigned; see Section 6).  The
   specification of the Dereference Control request is:

         controlValue ::= SEQUENCE OF derefSpec DerefSpec

         DerefSpec ::= SEQUENCE {
             derefAttr       attributeDescription,    ; with DN syntax
             attributes      AttributeList }

         AttributeList ::= SEQUENCE OF attr AttributeDescription

   Each derefSpec.derefAttr MUST be unique within controlValue.

2.3.  Control Response

   The control type is deref-oid (IANA assigned; see Section 6).  The
   specification of the Dereference Control response is:

         controlValue ::= SEQUENCE OF derefRes DerefRes

         DerefRes ::= SEQUENCE {
             derefAttr       AttributeDescription,
             derefVal        LDAPDN,
             attrVals        [0] PartialAttributeList OPTIONAL }

         PartialAttributeList ::= SEQUENCE OF
                        partialAttribute PartialAttribute

   PartialAttribute is defined in [RFC4511]; the definition is reported
   here for clarity:

         PartialAttribute ::= SEQUENCE {
             type       AttributeDescription,
             vals       SET OF value AttributeValue }

   If partialAttribute.vals is empty, the corresponding partialAttribute
   is omitted.  If all partialAttribute.vals in attrVals are empty, that
   derefRes.attrVals is omitted.











Masarati & Chu            Expires May 23, 2009                  [Page 5]

Internet-Draft                 LDAP Deref                  November 2008


3.  Examples

   Given these entries:

       dn: cn=Howard Chu,ou=people,dc=example,dc=org
       objectClass: inetOrgPerson
       cn: Howard Chu
       sn: Chu
       uid: hyc

       dn: cn=Pierangelo Masarati,ou=people,dc=example,dc=org
       objectClass: inetOrgPerson
       cn: Pierangelo Masarati
       sn: Masarati
       uid: ando

       dn: cn=Test Group,ou=groups,dc=example,dc=org
       objectClass: groupOfNames
       cn: Test Group
       member: cn=Howard Chu,ou=people,dc=example,dc=org
       member: cn=Pierangelo Masarati,ou=people,dc=example,dc=org

   A search could be performed with a Dereference request control value
   specified as

       { member, uid }

   and the "cn=Test Group" entry would be returned with the response
   control value

       { { member, cn=Howard Chu,ou=people,dc=example,dc=org,
           { { uid, [hyc] } } },
         { member, cn=Pierangelo Masarati,ou=people,dc=example,dc=org,
           { { uid, [ando] } } } }

















Masarati & Chu            Expires May 23, 2009                  [Page 6]

Internet-Draft                 LDAP Deref                  November 2008


4.  Implementation Notes

   This LDAP extension is currently implemented in OpenLDAP software
   using the temporary OID 1.3.6.1.4.1.4203.666.5.16 under OpenLDAP's
   experimental OID arc.














































Masarati & Chu            Expires May 23, 2009                  [Page 7]

Internet-Draft                 LDAP Deref                  November 2008


5.  Security Considerations

   The control result MUST NOT disclose information the client's
   identity could not have accessed by performing the related search
   operations.  The presence of a derefRes.derefVal in the response
   control, with no derefRes.attrVals, does not imply neither the
   existence of nor any access privilege to the corresponding entry.  It
   is merely a consequence of the read access the client's identity has
   on the corresponding value of the derefRes.derefAttr that would be
   returned as part of the attributes of a SearchResultEntry response
   [RFC4511].

   Security considerations described in documents listed in [RFC4510]
   apply.





































Masarati & Chu            Expires May 23, 2009                  [Page 8]

Internet-Draft                 LDAP Deref                  November 2008


6.  IANA Considerations

6.1.  Object Identifier Registration

   It is requested that IANA register upon Standards Action an LDAP
   Object Identifier for use in this technical specification.

         Subject: Request for LDAP OID Registration
         Person & email address to contact for further information:
             Pierangelo Masarati <ando@OpenLDAP.org>
         Specification: (I-D)
         Author/Change Controller: IESG
         Comments:
             Identifies the LDAP Dereference Control request
             and response




































Masarati & Chu            Expires May 23, 2009                  [Page 9]

Internet-Draft                 LDAP Deref                  November 2008


7.  Acknowledgments

   TBD
















































Masarati & Chu            Expires May 23, 2009                 [Page 10]

Internet-Draft                 LDAP Deref                  November 2008


8.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC4510]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Technical Specification Road Map", RFC 4510,
              June 2006.

   [RFC4511]  Sermersheim, J., "Lightweight Directory Access Protocol
              (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]  Zeilenga, K., "Lightweight Directory Access Protocol
              (LDAP): Directory Information Models", RFC 4512,
              June 2006.

   [RFC4517]  Legg, S., "Lightweight Directory Access Protocol (LDAP):
              Syntaxes and Matching Rules", RFC 4517, June 2006.

































Masarati & Chu            Expires May 23, 2009                 [Page 11]

Internet-Draft                 LDAP Deref                  November 2008


Authors' Addresses

   Pierangelo Masarati
   Politecnico di Milano
   Dipartimento di Ingegneria Aerospaziale
   via La Masa 34
   Milano  20156
   IT

   Phone: +39 02 2399 8309
   Fax:   +39 02 2399 8334
   Email: ando@OpenLDAP.org
   URI:   http://www.aero.polimi.it/masarati/


   Howard Y. Chu
   Symas Corporation
   18740 Oxnard St., Suite 313A
   Tarzana, California  91356
   USA

   Phone: +1 818 757-7087
   Email: hyc@symas.com
   URI:   http://www.symas.com/



























Masarati & Chu            Expires May 23, 2009                 [Page 12]

Internet-Draft                 LDAP Deref                  November 2008


Full Copyright Statement

   Copyright (C) The IETF Trust (2008).

   This document is subject to the rights, licenses and restrictions
   contained in BCP 78, and except as set forth therein, the authors
   retain all their rights.

   This document and the information contained herein are provided on an
   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Intellectual Property

   The IETF takes no position regarding the validity or scope of any
   Intellectual Property Rights or other rights that might be claimed to
   pertain to the implementation or use of the technology described in
   this document or the extent to which any license under such rights
   might or might not be available; nor does it represent that it has
   made any independent effort to identify any such rights.  Information
   on the procedures with respect to rights in RFC documents can be
   found in BCP 78 and BCP 79.

   Copies of IPR disclosures made to the IETF Secretariat and any
   assurances of licenses to be made available, or the result of an
   attempt made to obtain a general license or permission for the use of
   such proprietary rights by implementers or users of this
   specification can be obtained from the IETF on-line IPR repository at
   http://www.ietf.org/ipr.

   The IETF invites any interested party to bring to its attention any
   copyrights, patents or patent applications, or other proprietary
   rights that may cover technology that may be required to implement
   this standard.  Please address the information to the IETF at
   ietf-ipr@ietf.org.











Masarati & Chu            Expires May 23, 2009                 [Page 13]

alt-pcre2/ChangeLog000064400000313477150410167000010120 0ustar00Change Log for PCRE2
--------------------


Version 10.34 21-November-2019
------------------------------

1. The maximum number of capturing subpatterns is 65535 (documented), but no
check on this was ever implemented. This omission has been rectified; it fixes
ClusterFuzz 14376.

2. Improved the invalid utf32 support of the JIT compiler. Now it correctly
detects invalid characters in the 0xd800-0xdfff range.

3. Fix minor typo bug in JIT compile when \X is used in a non-UTF string.

4. Add support for matching in invalid UTF strings to the pcre2_match()
interpreter, and integrate with the existing JIT support via the new
PCRE2_MATCH_INVALID_UTF compile-time option.

5. Give more error detail for invalid UTF-8 when detected in pcre2grep.

6. Add support for invalid UTF-8 to pcre2grep.

7. Adjust the limit for "must have" code unit searching, in particular,
increase it substantially for non-anchored patterns.

8. Allow (*ACCEPT) to be quantified, because an ungreedy quantifier with a zero
minimum is potentially useful.

9. Some changes to the way the minimum subject length is handled:

   * When PCRE2_NO_START_OPTIMIZE is set, no minimum length is computed;
     pcre2test now omits this item instead of showing a value of zero.

   * An incorrect minimum length could be calculated for a pattern that
     contained (*ACCEPT) inside a qualified group whose minimum repetition was
     zero, for example /A(?:(*ACCEPT))?B/, which incorrectly computed a minimum
     of 2. The minimum length scan no longer happens for a pattern that
     contains (*ACCEPT).

   * When no minimum length is set by the normal scan, but a first and/or last
     code unit is recorded, set the minimum to 1 or 2 as appropriate.

   * When a pattern contains multiple groups with the same number, a back
     reference cannot know which one to scan for a minimum length. This used to
     cause the minimum length finder to give up with no result. Now it treats
     such references as not adding to the minimum length (which it should have
     done all along).

   * Furthermore, the above action now happens only if the back reference is to
     a group that exists more than once in a pattern instead of any back
     reference in a pattern with duplicate numbers.

10. A (*MARK) value inside a successful condition was not being returned by the
interpretive matcher (it was returned by JIT). This bug has been mended.

11. A bug in pcre2grep meant that -o without an argument (or -o0) didn't work
if the pattern had more than 32 capturing parentheses. This is fixed. In
addition (a) the default limit for groups requested by -o<n> has been raised to
50, (b) the new --om-capture option changes the limit, (c) an error is raised
if -o asks for a group that is above the limit.

12. The quantifier {1} was always being ignored, but this is incorrect when it
is made possessive and applied to an item in parentheses, because a
parenthesized item may contain multiple branches or other backtracking points,
for example /(a|ab){1}+c/ or /(a+){1}+a/.

13. For partial matches, pcre2test was always showing the maximum lookbehind
characters, flagged with "<", which is misleading when the lookbehind didn't
actually look behind the start (because it was later in the pattern). Showing
all consulted preceding characters for partial matches is now controlled by the
existing "allusedtext" modifier and, as for complete matches, this facility is
available only for non-JIT matching, because JIT does not maintain the first
and last consulted characters.

14. DFA matching (using pcre2_dfa_match()) was not recognising a partial match
if the end of the subject was encountered in a lookahead (conditional or
otherwise), an atomic group, or a recursion.

15. Give error if pcre2test -t, -T, -tm or -TM is given an argument of zero.

16. Check for integer overflow when computing lookbehind lengths. Fixes
Clusterfuzz issue 15636.

17. Implemented non-atomic positive lookaround assertions.

18. If a lookbehind contained a lookahead that contained another lookbehind
within it, the nested lookbehind was not correctly processed. For example, if
/(?<=(?=(?<=a)))b/ was matched to "ab" it gave no match instead of matching
"b".

19. Implemented pcre2_get_match_data_size().

20. Two alterations to partial matching:

    (a) The definition of a partial match is slightly changed: if a pattern
    contains any lookbehinds, an empty partial match may be given, because this
    is another situation where adding characters to the current subject can
    lead to a full match. Example: /c*+(?<=[bc])/ with subject "ab".

    (b) Similarly, if a pattern could match an empty string, an empty partial
    match may be given. Example: /(?![ab]).*/ with subject "ab". This case
    applies only to PCRE2_PARTIAL_HARD.

    (c) An empty string partial hard match can be returned for \z and \Z as it
    is documented that they shouldn't match.

21. A branch that started with (*ACCEPT) was not being recognized as one that
could match an empty string.

22. Corrected pcre2_set_character_tables() tables data type: was const unsigned
char * instead of const uint8_t *, as generated by pcre2_maketables().

23. Upgraded to Unicode 12.1.0.

24. Add -jitfast command line option to pcre2test (to make all the jit options
available directly).

25. Make pcre2test -C show if libreadline or libedit is supported.

26. If the length of one branch of a group exceeded 65535 (the maximum value
that is remembered as a minimum length), the whole group's length was
incorrectly recorded as 65535, leading to incorrect "no match" when start-up
optimizations were in force.

27. The "rightmost consulted character" value was not always correct; in
particular, if a pattern ended with a negative lookahead, characters that were
inspected in that lookahead were not included.

28. Add the pcre2_maketables_free() function.

29. The start-up optimization that looks for a unique initial matching
code unit in the interpretive engines uses memchr() in 8-bit mode. When the
search is caseless, it was doing so inefficiently, which ended up slowing down
the match drastically when the subject was very long. The revised code (a)
remembers if one case is not found, so it never repeats the search for that
case after a bumpalong and (b) when one case has been found, it searches only
up to that position for an earlier occurrence of the other case. This fix
applies to both interpretive pcre2_match() and to pcre2_dfa_match().

30. While scanning to find the minimum length of a group, if any branch has
minimum length zero, there is no need to scan any subsequent branches (a small
compile-time performance improvement).

31. Installed a .gitignore file on a user's suggestion. When using the svn
repository with git (through git svn) this helps keep it tidy.

32. Add underflow check in JIT which may occur when the value of subject
string pointer is close to 0.

33. Arrange for classes such as [Aa] which contain just the two cases of the
same character, to be treated as a single caseless character. This causes the
first and required code unit optimizations to kick in where relevant.

34. Improve the bitmap of starting bytes for positive classes that include wide
characters, but no property types, in UTF-8 mode. Previously, on encountering
such a class, the bits for all bytes greater than \xc4 were set, thus
specifying any character with codepoint >= 0x100. Now the only bits that are
set are for the relevant bytes that start the wide characters. This can give a
noticeable performance improvement.

35. If the bitmap of starting code units contains only 1 or 2 bits, replace it
with a single starting code unit (1 bit) or a caseless single starting code
unit if the two relevant characters are case-partners. This is particularly
relevant to the 8-bit library, though it applies to all. It can give a
performance boost for patterns such as [Ww]ord and (word|WORD). However, this
optimization doesn't happen if there is a "required" code unit of the same
value (because the search for a "required" code unit starts at the match start
for non-unique first code unit patterns, but after a unique first code unit,
and patterns such as a*a need the former action).

36. Small patch to pcre2posix.c to set the erroroffset field to -1 immediately
after a successful compile, instead of at the start of matching to avoid a
sanitizer complaint (regexec is supposed to be thread safe).

37. Add NEON vectorization to JIT to speed up matching of first character and
pairs of characters on ARM64 CPUs.

38. If a non-ASCII character was the first in a starting assertion in a
caseless match, the "first code unit" optimization did not get the casing
right, and the assertion failed to match a character in the other case if it
did not start with the same code unit.

39. Fixed the incorrect computation of jump sizes on x86 CPUs in JIT. A masking
operation was incorrectly removed in r1136. Reported by Ralf Junker.


Version 10.33 16-April-2019
---------------------------

1. Added "allvector" to pcre2test to make it easy to check the part of the
ovector that shouldn't be changed, in particular after substitute and failed or
partial matches.

2. Fix subject buffer overread in JIT when UTF is disabled and \X or \R has
a greater than 1 fixed quantifier. This issue was found by Yunho Kim.

3. Added support for callouts from pcre2_substitute(). After 10.33-RC1, but
prior to release, fixed a bug that caused a crash if pcre2_substitute() was
called with a NULL match context.

4. The POSIX functions are now all called pcre2_regcomp() etc., with wrapper
functions that use the standard POSIX names. However, in pcre2posix.h the POSIX
names are defined as macros. This should help avoid linking with the wrong
library in some environments while still exporting the POSIX names for
pre-existing programs that use them. (The Debian alternative names are also
defined as macros, but not documented.)

5. Fix an xclass matching issue in JIT.

6. Implement PCRE2_EXTRA_ESCAPED_CR_IS_LF (see Bugzilla 2315).

7. Implement the Perl 5.28 experimental alphabetic names for atomic groups and
lookaround assertions, for example, (*pla:...) and (*atomic:...). These are
characterized by a lower case letter following (* and to simplify coding for
this, the character tables created by pcre2_maketables() were updated to add a
new "is lower case letter" bit. At the same time, the now unused "is
hexadecimal digit" bit was removed. The default tables in
src/pcre2_chartables.c.dist are updated.

8. Implement the new Perl "script run" features (*script_run:...) and
(*atomic_script_run:...) aka (*sr:...) and (*asr:...).

9. Fixed two typos in change 22 for 10.21, which added special handling for
ranges such as a-z in EBCDIC environments. The original code probably never
worked, though there were no bug reports.

10. Implement PCRE2_COPY_MATCHED_SUBJECT for pcre2_match() (including JIT via
pcre2_match()) and pcre2_dfa_match(), but *not* the pcre2_jit_match() fast
path. Also, when a match fails, set the subject field in the match data to NULL
for tidiness - none of the substring extractors should reference this after
match failure.

11. If a pattern started with a subroutine call that had a quantifier with a
minimum of zero, an incorrect "match must start with this character" could be
recorded. Example: /(?&xxx)*ABC(?<xxx>XYZ)/ would (incorrectly) expect 'A' to
be the first character of a match.

12. The heap limit checking code in pcre2_dfa_match() could suffer from
overflow if the heap limit was set very large. This could cause incorrect "heap
limit exceeded" errors.

13. Add "kibibytes" to the heap limit output from pcre2test -C to make the
units clear.

14. Add a call to pcre2_jit_free_unused_memory() in pcre2grep, for tidiness.

15. Updated the VMS-specific code in pcre2test on the advice of a VMS user.

16. Removed the unnecessary inclusion of stdint.h (or inttypes.h) from
pcre2_internal.h as it is now included by pcre2.h. Also, change 17 for 10.32
below was unnecessarily complicated, as inttypes.h is a Standard C header,
which is defined to be a superset of stdint.h. Instead of conditionally
including stdint.h or inttypes.h, pcre2.h now unconditionally includes
inttypes.h. This supports environments that do not have stdint.h but do have
inttypes.h, which are known to exist. A note in the autotools documentation
says (November 2018) that there are none known that are the other way round.

17. Added --disable-percent-zt to "configure" (and equivalent to CMake) to
forcibly disable the use of %zu and %td in formatting strings because there is
at least one version of VMS that claims to be C99 but does not support these
modifiers.

18. Added --disable-pcre2grep-callout-fork, which restricts the callout support
in pcre2grep to the inbuilt echo facility. This may be useful in environments
that do not support fork().

19. Fix two instances of <= 0 being applied to unsigned integers (the VMS
compiler complains).

20. Added "fork" support for VMS to pcre2grep, for running an external program
via a string callout.

21. Improve MAP_JIT flag usage on MacOS. Patch by Rich Siegel.

22. If a pattern started with (*MARK), (*COMMIT), (*PRUNE), (*SKIP), or (*THEN)
followed by ^ it was not recognized as anchored.

23. The RunGrepTest script used to cut out the test of NUL characters for
Solaris and MacOS as printf and sed can't handle them. It seems that the *BSD
systems can't either. I've inverted the test so that only those OS that are
known to work (currently only Linux) try to run this test.

24. Some tests in RunGrepTest appended to testtrygrep from two different file
descriptors instead of redirecting stderr to stdout. This worked on Linux, but
it was reported not to on other systems, causing the tests to fail.

25. In the RunTest script, make the test for stack setting use the same value
for the stack as it needs for -bigstack.

26. Insert a cast in pcre2_dfa_match.c to suppress a compiler warning.

26. With PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL set, escape sequences such as \s
which are valid in character classes, but not as the end of ranges, were being
treated as literals. An example is [_-\s] (but not [\s-_] because that gave an
error at the *start* of a range). Now an "invalid range" error is given
independently of PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL.

27. Related to 26 above, PCRE2_BAD_ESCAPE_IS_LITERAL was affecting known escape
sequences such as \eX when they appeared invalidly in a character class. Now
the option applies only to unrecognized or malformed escape sequences.

28. Fix word boundary in JIT compiler. Patch by Mike Munday.

29. The pcre2_dfa_match() function was incorrectly handling conditional version
tests such as (?(VERSION>=0)...) when the version test was true. Incorrect
processing or a crash could result.

30. When PCRE2_UTF is set, allow non-ASCII letters and decimal digits in group
names, as Perl does. There was a small bug in this new code, found by
ClusterFuzz 12950, fixed before release.

31. Implemented PCRE2_EXTRA_ALT_BSUX to support ECMAScript 6's \u{hhh}
construct.

32. Compile \p{Any} to be the same as . in DOTALL mode, so that it benefits
from auto-anchoring if \p{Any}* starts a pattern.

33. Compile invalid UTF check in JIT test when only pcre32 is enabled.

34. For some time now, CMake has been warning about the setting of policy
CMP0026 to "OLD" in CmakeLists.txt, and hinting that the feature might be
removed in a future version. A request for CMake expertise on the list produced
no result, so I have now hacked CMakeLists.txt along the lines of some changes
I found on the Internet. The new code no longer needs the policy setting, and
it appears to work fine on Linux.

35. Setting --enable-jit=auto for an out-of-tree build failed because the
source directory wasn't in the search path for AC_TRY_COMPILE always. Patch
from Ross Burton.

36. Disable SSE2 JIT optimizations in x86 CPUs when SSE2 is not available.
Patch by Guillem Jover.

37. Changed expressions such as 1<<10 to 1u<<10 in many places because compiler
warnings were reported.

38. Using the clang compiler with sanitizing options causes runtime complaints
about truncation for statments such as x = ~x when x is an 8-bit value; it
seems to compute ~x as a 32-bit value. Changing such statements to x = 255 ^ x
gets rid of the warnings. There were also two missing casts in pcre2test.


Version 10.32 10-September-2018
-------------------------------

1. When matching using the the REG_STARTEND feature of the POSIX API with a
non-zero starting offset, unset capturing groups with lower numbers than a
group that did capture something were not being correctly returned as "unset"
(that is, with offset values of -1).

2. When matching using the POSIX API, pcre2test used to omit listing unset
groups altogether. Now it shows those that come before any actual captures as
"<unset>", as happens for non-POSIX matching.

3. Running "pcre2test -C" always stated "\R matches CR, LF, or CRLF only",
whatever the build configuration was. It now correctly says "\R matches all
Unicode newlines" in the default case when --enable-bsr-anycrlf has not been
specified. Similarly, running "pcre2test -C bsr" never produced the result
ANY.

4. Matching the pattern /(*UTF)\C[^\v]+\x80/ against an 8-bit string containing
multi-code-unit characters caused bad behaviour and possibly a crash. This
issue was fixed for other kinds of repeat in release 10.20 by change 19, but
repeating character classes were overlooked.

5. pcre2grep now supports the inclusion of binary zeros in patterns that are
read from files via the -f option.

6. A small fix to pcre2grep to avoid compiler warnings for -Wformat-overflow=2.

7. Added --enable-jit=auto support to configure.ac.

8. Added some dummy variables to the heapframe structure in 16-bit and 32-bit
modes for the benefit of m68k, where pointers can be 16-bit aligned. The
dummies force 32-bit alignment and this ensures that the structure is a
multiple of PCRE2_SIZE, a requirement that is tested at compile time. In other
architectures, alignment requirements take care of this automatically.

9. When returning an error from pcre2_pattern_convert(), ensure the error
offset is set zero for early errors.

10. A number of patches for Windows support from Daniel Richard G:

  (a) List of error numbers in Runtest.bat corrected (it was not the same as in
      Runtest).

  (b) pcre2grep snprintf() workaround as used elsewhere in the tree.

  (c) Support for non-C99 snprintf() that returns -1 in the overflow case.

11. Minor tidy of pcre2_dfa_match() code.

12. Refactored pcre2_dfa_match() so that the internal recursive calls no longer
use the stack for local workspace and local ovectors. Instead, an initial block
of stack is reserved, but if this is insufficient, heap memory is used. The
heap limit parameter now applies to pcre2_dfa_match().

13. If a "find limits" test of DFA matching in pcre2test resulted in too many
matches for the ovector, no matches were displayed.

14. Removed an occurrence of ctrl/Z from test 6 because Windows treats it as
EOF. The test looks to have come from a fuzzer.

15. If PCRE2 was built with a default match limit a lot greater than the
default default of 10 000 000, some JIT tests of the match limit no longer
failed. All such tests now set 10 000 000 as the upper limit.

16. Another Windows related patch for pcregrep to ensure that WIN32 is
undefined under Cygwin.

17. Test for the presence of stdint.h and inttypes.h in configure and CMake and
include whichever exists (stdint preferred) instead of unconditionally
including stdint. This makes life easier for old and non-standard systems.

18. Further changes to improve portability, especially to old and or non-
standard systems:

  (a) Put all printf arguments in RunGrepTest into single, not double, quotes,
      and use \0 not \x00 for binary zero.

  (b) Avoid the use of C++ (i.e. BCPL) // comments.

  (c) Parameterize the use of %zu in pcre2test to make it like %td. For both of
      these now, if using MSVC or a standard C before C99, %lu is used with a
      cast if necessary.

19. Applied a contributed patch to CMakeLists.txt to increase the stack size
when linking pcre2test with MSVC. This gets rid of a stack overflow error in
the standard set of tests.

20. Output a warning in pcre2test when ignoring the "altglobal" modifier when
it is given with the "replace" modifier.

21. In both pcre2test and pcre2_substitute(), with global matching, a pattern
that matched an empty string, but never at the starting match offset, was not
handled in a Perl-compatible way. The pattern /(<?=\G.)/ is an example of such
a pattern. Because \G is in a lookbehind assertion, there has to be a
"bumpalong" before there can be a match. The automatic "advance by one
character after an empty string match" rule is therefore inappropriate. A more
complicated algorithm has now been implemented.

22. When checking to see if a lookbehind is of fixed length, lookaheads were
correctly ignored, but qualifiers on lookaheads were not being ignored, leading
to an incorrect "lookbehind assertion is not fixed length" error.

23. The VERSION condition test was reading fractional PCRE2 version numbers
such as the 04 in 10.04 incorrectly and hence giving wrong results.

24. Updated to Unicode version 11.0.0. As well as the usual addition of new
scripts and characters, this involved re-jigging the grapheme break property
algorithm because Unicode has changed the way emojis are handled.

25. Fixed an obscure bug that struck when there were two atomic groups not
separated by something with a backtracking point. There could be an incorrect
backtrack into the first of the atomic groups. A complicated example is
/(?>a(*:1))(?>b)(*SKIP:1)x|.*/ matched against "abc", where the *SKIP
shouldn't find a MARK (because is in an atomic group), but it did.

26. Upgraded the perltest.sh script: (1) #pattern lines can now be used to set
a list of modifiers for all subsequent patterns - only those that the script
recognizes are meaningful; (2) #subject lines can be used to set or unset a
default "mark" modifier; (3) Unsupported #command lines give a warning when
they are ignored; (4) Mark data is output only if the "mark" modifier is
present.

27. (*ACCEPT:ARG), (*FAIL:ARG), and (*COMMIT:ARG) are now supported.

28. A (*MARK) name was not being passed back for positive assertions that were
terminated by (*ACCEPT).

29. Add support for \N{U+dddd}, but only in Unicode mode.

30. Add support for (?^) for unsetting all imnsx options.

31. The PCRE2_EXTENDED (/x) option only ever discarded space characters whose
code point was less than 256 and that were recognized by the lookup table
generated by pcre2_maketables(), which uses isspace() to identify white space.
Now, when Unicode support is compiled, PCRE2_EXTENDED also discards U+0085,
U+200E, U+200F, U+2028, and U+2029, which are additional characters defined by
Unicode as "Pattern White Space". This makes PCRE2 compatible with Perl.

32. In certain circumstances, option settings within patterns were not being
correctly processed. For example, the pattern /((?i)A)(?m)B/ incorrectly
matched "ab". (The (?m) setting lost the fact that (?i) should be reset at the
end of its group during the parse process, but without another setting such as
(?m) the compile phase got it right.) This bug was introduced by the
refactoring in release 10.23.

33. PCRE2 uses bcopy() if available when memmove() is not, and it used just to
define memmove() as function call to bcopy(). This hasn't been tested for a
long time because in pcre2test the result of memmove() was being used, whereas
bcopy() doesn't return a result. This feature is now refactored always to call
an emulation function when there is no memmove(). The emulation makes use of
bcopy() when available.

34. When serializing a pattern, set the memctl, executable_jit, and tables
fields (that is, all the fields that contain pointers) to zeros so that the
result of serializing is always the same. These fields are re-set when the
pattern is deserialized.

35. In a pattern such as /[^\x{100}-\x{ffff}]*[\x80-\xff]/ which has a repeated
negative class with no characters less than 0x100 followed by a positive class
with only characters less than 0x100, the first class was incorrectly being
auto-possessified, causing incorrect match failures.

36. Removed the character type bit ctype_meta, which dates from PCRE1 and is
not used in PCRE2.

37. Tidied up unnecessarily complicated macros used in the escapes table.

38. Since 10.21, the new testoutput8-16-4 file has accidentally been omitted
from distribution tarballs, owing to a typo in Makefile.am which had
testoutput8-16-3 twice. Now fixed.

39. If the only branch in a conditional subpattern was anchored, the whole
subpattern was treated as anchored, when it should not have been, since the
assumed empty second branch cannot be anchored. Demonstrated by test patterns
such as /(?(1)^())b/ or /(?(?=^))b/.

40. A repeated conditional subpattern that could match an empty string was
always assumed to be unanchored. Now it it checked just like any other
repeated conditional subpattern, and can be found to be anchored if the minimum
quantifier is one or more. I can't see much use for a repeated anchored
pattern, but the behaviour is now consistent.

41. Minor addition to pcre2_jit_compile.c to avoid static analyzer complaint
(for an event that could never occur but you had to have external information
to know that).

42. If before the first match in a file that was being searched by pcre2grep
there was a line that was sufficiently long to cause the input buffer to be
expanded, the variable holding the location of the end of the previous match
was being adjusted incorrectly, and could cause an overflow warning from a code
sanitizer. However, as the value is used only to print pending "after" lines
when the next match is reached (and there are no such lines in this case) this
bug could do no damage.


Version 10.31 12-February-2018
------------------------------

1. Fix typo (missing ]) in VMS code in pcre2test.c.

2. Replace the replicated code for matching extended Unicode grapheme sequences
(which got a lot more complicated by change 10.30/49) by a single subroutine
that is called by both pcre2_match() and pcre2_dfa_match().

3. Add idempotent guard to pcre2_internal.h.

4. Add new pcre2_config() options: PCRE2_CONFIG_NEVER_BACKSLASH_C and
PCRE2_CONFIG_COMPILED_WIDTHS.

5. Cut out \C tests in the JIT regression tests when NEVER_BACKSLASH_C is
defined (e.g. by --enable-never-backslash-C).

6. Defined public names for all the pcre2_compile() error numbers, and used
the public names in pcre2_convert.c.

7. Fixed a small memory leak in pcre2test (convert contexts).

8. Added two casts to compile.c and one to match.c to avoid compiler warnings.

9. Added code to pcre2grep when compiled under VMS to set the symbol
PCRE2GREP_RC to the exit status, because VMS does not distinguish between
exit(0) and exit(1).

10. Added the -LM (list modifiers) option to pcre2test. Also made -C complain
about a bad option only if the following argument item does not start with a
hyphen.

11. pcre2grep was truncating components of file names to 128 characters when
processing files with the -r option, and also (some very odd code) truncating
path names to 512 characters. There is now a check on the absolute length of
full path file names, which may be up to 2047 characters long.

12. When an assertion contained (*ACCEPT) it caused all open capturing groups
to be closed (as for a non-assertion ACCEPT), which was wrong and could lead to
misbehaviour for subsequent references to groups that started outside the
assertion. ACCEPT in an assertion now closes only those groups that were
started within that assertion. Fixes oss-fuzz issues 3852 and 3891.

13. Multiline matching in pcre2grep was misbehaving if the pattern matched
within a line, and then matched again at the end of the line and over into
subsequent lines. Behaviour was different with and without colouring, and
sometimes context lines were incorrectly printed and/or line endings were lost.
All these issues should now be fixed.

14. If --line-buffered was specified for pcre2grep when input was from a
compressed file (.gz or .bz2) a segfault occurred. (Line buffering should be
ignored for compressed files.)

15. Although pcre2_jit_match checks whether the pattern is compiled
in a given mode, it was also expected that at least one mode is available.
This is fixed and pcre2_jit_match returns with PCRE2_ERROR_JIT_BADOPTION
when the pattern is not optimized by JIT at all.

16. The line number and related variables such as match counts in pcre2grep
were all int variables, causing overflow when files with more than 2147483647
lines were processed (assuming 32-bit ints). They have all been changed to
unsigned long ints.

17. If a backreference with a minimum repeat count of zero was first in a
pattern, apart from assertions, an incorrect first matching character could be
recorded. For example, for the pattern /(?=(a))\1?b/, "b" was incorrectly set
as the first character of a match.

18. Characters in a leading positive assertion are considered for recording a
first character of a match when the rest of the pattern does not provide one.
However, a character in a non-assertive group within a leading assertion such
as in the pattern /(?=(a))\1?b/ caused this process to fail. This was an
infelicity rather than an outright bug, because it did not affect the result of
a match, just its speed. (In fact, in this case, the starting 'a' was
subsequently picked up in the study.)

19. A minor tidy in pcre2_match(): making all PCRE2_ERROR_ returns use "return"
instead of "RRETURN" saves unwinding the backtracks in these cases (only one
didn't).

20. Allocate a single callout block on the stack at the start of pcre2_match()
and set its never-changing fields once only. Do the same for pcre2_dfa_match().

21. Save the extra compile options (set in the compile context) with the
compiled pattern (they were not previously saved), add PCRE2_INFO_EXTRAOPTIONS
to retrieve them, and update pcre2test to show them.

22. Added PCRE2_CALLOUT_STARTMATCH and PCRE2_CALLOUT_BACKTRACK bits to a new
field callout_flags in callout blocks. The bits are set by pcre2_match(), but
not by JIT or pcre2_dfa_match(). Their settings are shown in pcre2test callouts
if the callout_extra subject modifier is set. These bits are provided to help
with tracking how a backtracking match is proceeding.

23. Updated the pcre2demo.c demonstration program, which was missing the extra
code for -g that handles the case when \K in an assertion causes the match to
end at the original start point. Also arranged for it to detect when \K causes
the end of a match to be before its start.

24. Similar to 23 above, strange things (including loops) could happen in
pcre2grep when \K was used in an assertion when --colour was used or in
multiline mode. The "end at original start point" bug is fixed, and if the end
point is found to be before the start point, they are swapped.

25. When PCRE2_FIRSTLINE without PCRE2_NO_START_OPTIMIZE was used in non-JIT
matching (both pcre2_match() and pcre2_dfa_match()) and the matched string
started with the first code unit of a newline sequence, matching failed because
it was not tried at the newline.

26. Code for giving up a non-partial match after failing to find a starting
code unit anywhere in the subject was missing when searching for one of a
number of code units (the bitmap case) in both pcre2_match() and
pcre2_dfa_match(). This was a missing optimization rather than a bug.

27. Tidied up the ACROSSCHAR macro to be like FORWARDCHAR and BACKCHAR, using a
pointer argument rather than a code unit value. This should not have affected
the generated code.

28. The JIT compiler has been updated.

29. Avoid pointer overflow for unset captures in pcre2_substring_list_get().
This could not actually cause a crash because it was always used in a memcpy()
call with zero length.

30. Some internal structures have a variable-length ovector[] as their last
element. Their actual memory is obtained dynamically, giving an ovector of
appropriate length. However, they are defined in the structure as
ovector[NUMBER], where NUMBER is large so that array bound checkers don't
grumble. The value of NUMBER was 10000, but a fuzzer exceeded 5000 capturing
groups, making the ovector larger than this. The number has been increased to
131072, which allows for the maximum number of captures (65535) plus the
overall match. This fixes oss-fuzz issue 5415.

31. Auto-possessification at the end of a capturing group was dependent on what
follows the group (e.g. /(a+)b/ would auto-possessify the a+) but this caused
incorrect behaviour when the group was called recursively from elsewhere in the
pattern where something different might follow. This bug is an unforseen
consequence of change #1 for 10.30 - the implementation of backtracking into
recursions. Iterators at the ends of capturing groups are no longer considered
for auto-possessification if the pattern contains any recursions. Fixes
Bugzilla #2232.


Version 10.30 14-August-2017
----------------------------

1. The main interpreter, pcre2_match(), has been refactored into a new version
that does not use recursive function calls (and therefore the stack) for
remembering backtracking positions. This makes --disable-stack-for-recursion a
NOOP. The new implementation allows backtracking into recursive group calls in
patterns, making it more compatible with Perl, and also fixes some other
hard-to-do issues such as #1887 in Bugzilla. The code is also cleaner because
the old code had a number of fudges to try to reduce stack usage. It seems to
run no slower than the old code.

A number of bugs in the refactored code were subsequently fixed during testing
before release, but after the code was made available in the repository. These
bugs were never in fully released code, but are noted here for the record.

  (a) If a pattern had fewer capturing parentheses than the ovector supplied in
      the match data block, a memory error (detectable by ASAN) occurred after
      a match, because the external block was being set from non-existent
      internal ovector fields. Fixes oss-fuzz issue 781.

  (b) A pattern with very many capturing parentheses (when the internal frame
      size was greater than the initial frame vector on the stack) caused a
      crash. A vector on the heap is now set up at the start of matching if the
      vector on the stack is not big enough to handle at least 10 frames.
      Fixes oss-fuzz issue 783.

  (c) Handling of (*VERB)s in recursions was wrong in some cases.

  (d) Captures in negative assertions that were used as conditions were not
      happening if the assertion matched via (*ACCEPT).

  (e) Mark values were not being passed out of recursions.

  (f) Refactor some code in do_callout() to avoid picky compiler warnings about
      negative indices. Fixes oss-fuzz issue 1454.

  (g) Similarly refactor the way the variable length ovector is addressed for
      similar reasons. Fixes oss-fuzz issue 1465.

2. Now that pcre2_match() no longer uses recursive function calls (see above),
the "match limit recursion" value seems misnamed. It still exists, and limits
the depth of tree that is searched. To avoid future confusion, it has been
renamed as "depth limit" in all relevant places (--with-depth-limit,
(*LIMIT_DEPTH), pcre2_set_depth_limit(), etc) but the old names are still
available for backwards compatibility.

3. Hardened pcre2test so as to reduce the number of bugs reported by fuzzers:

  (a) Check for malloc failures when getting memory for the ovector (POSIX) or
      the match data block (non-POSIX).

4. In the 32-bit library in non-UTF mode, an attempt to find a Unicode property
for a character with a code point greater than 0x10ffff (the Unicode maximum)
caused a crash.

5. If a lookbehind assertion that contained a back reference to a group
appearing later in the pattern was compiled with the PCRE2_ANCHORED option,
undefined actions (often a segmentation fault) could occur, depending on what
other options were set. An example assertion is (?<!\1(abc)) where the
reference \1 precedes the group (abc). This fixes oss-fuzz issue 865.

6. Added the PCRE2_INFO_FRAMESIZE item to pcre2_pattern_info() and arranged for
pcre2test to use it to output the frame size when the "framesize" modifier is
given.

7. Reworked the recursive pattern matching in the JIT compiler to follow the
interpreter changes.

8. When the zero_terminate modifier was specified on a pcre2test subject line
for global matching, unpredictable things could happen. For example, in UTF-8
mode, the pattern //g,zero_terminate read random memory when matched against an
empty string with zero_terminate. This was a bug in pcre2test, not the library.

9. Moved some Windows-specific code in pcre2grep (introduced in 10.23/13) out
of the section that is compiled when Unix-style directory scanning is
available, and into a new section that is always compiled for Windows.

10. In pcre2test, explicitly close the file after an error during serialization
or deserialization (the "load" or "save" commands).

11. Fix memory leak in pcre2_serialize_decode() when the input is invalid.

12. Fix potential NULL dereference in pcre2_callout_enumerate() if called with
a NULL pattern pointer when Unicode support is available.

13. When the 32-bit library was being tested by pcre2test, error messages that
were longer than 64 code units could cause a buffer overflow. This was a bug in
pcre2test.

14. The alternative matching function, pcre2_dfa_match() misbehaved if it
encountered a character class with a possessive repeat, for example [a-f]{3}+.

15. The depth (formerly recursion) limit now applies to DFA matching (as
of 10.23/36); pcre2test has been upgraded so that \=find_limits works with DFA
matching to find the minimum value for this limit.

16. Since 10.21, if pcre2_match() was called with a null context, default
memory allocation functions were used instead of whatever was used when the
pattern was compiled.

17. Changes to the pcre2test "memory" modifier on a subject line. These apply
only to pcre2_match():

  (a) Warn if null_context is set on both pattern and subject, because the
      memory details cannot then be shown.

  (b) Remember (up to a certain number of) memory allocations and their
      lengths, and list only the lengths, so as to be system-independent.
      (In practice, the new interpreter never has more than 2 blocks allocated
      simultaneously.)

18. Make pcre2test detect an error return from pcre2_get_error_message(), give
a message, and abandon the run (this would have detected #13 above).

19. Implemented PCRE2_ENDANCHORED.

20. Applied Jason Hood's patches (slightly modified) to pcre2grep, to implement
the --output=text (-O) option and the inbuilt callout echo.

21. Extend auto-anchoring etc. to ignore groups with a zero qualifier and
single-branch conditions with a false condition (e.g. DEFINE) at the start of a
branch. For example, /(?(DEFINE)...)^A/ and /(...){0}^B/ are now flagged as
anchored.

22. Added an explicit limit on the amount of heap used by pcre2_match(), set by
pcre2_set_heap_limit() or (*LIMIT_HEAP=xxx). Upgraded pcre2test to show the
heap limit along with other pattern information, and to find the minimum when
the find_limits modifier is set.

23. Write to the last 8 bytes of the pcre2_real_code structure when a compiled
pattern is set up so as to initialize any padding the compiler might have
included. This avoids valgrind warnings when a compiled pattern is copied, in
particular when it is serialized.

24. Remove a redundant line of code left in accidentally a long time ago.

25. Remove a duplication typo in pcre2_tables.c

26. Correct an incorrect cast in pcre2_valid_utf.c

27. Update pcre2test, remove some unused code in pcre2_match(), and upgrade the
tests to improve coverage.

28. Some fixes/tidies as a result of looking at Coverity Scan output:

    (a) Typo: ">" should be ">=" in opcode check in pcre2_auto_possess.c.
    (b) Added some casts to avoid "suspicious implicit sign extension".
    (c) Resource leaks in pcre2test in rare error cases.
    (d) Avoid warning for never-use case OP_TABLE_LENGTH which is just a fudge
        for checking at compile time that tables are the right size.
    (e) Add missing "fall through" comment.

29. Implemented PCRE2_EXTENDED_MORE and related /xx and (?xx) features.

30. Implement (?n: for PCRE2_NO_AUTO_CAPTURE, because Perl now has this.

31. If more than one of "push", "pushcopy", or "pushtablescopy" were set in
pcre2test, a crash could occur.

32. Make -bigstack in RunTest allocate a 64MiB stack (instead of 16MiB) so
that all the tests can run with clang's sanitizing options.

33. Implement extra compile options in the compile context and add the first
one: PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES.

34. Implement newline type PCRE2_NEWLINE_NUL.

35. A lookbehind assertion that had a zero-length branch caused undefined
behaviour when processed by pcre2_dfa_match(). This is oss-fuzz issue 1859.

36. The match limit value now also applies to pcre2_dfa_match() as there are
patterns that can use up a lot of resources without necessarily recursing very
deeply. (Compare item 10.23/36.) This should fix oss-fuzz #1761.

37. Implement PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL.

38. Fix returned offsets from regexec() when REG_STARTEND is used with a
starting offset greater than zero.

39. Implement REG_PEND (GNU extension) for the POSIX wrapper.

40. Implement the subject_literal modifier in pcre2test, and allow jitstack on
pattern lines.

41. Implement PCRE2_LITERAL and use it to support REG_NOSPEC.

42. Implement PCRE2_EXTRA_MATCH_LINE and PCRE2_EXTRA_MATCH_WORD for the benefit
of pcre2grep.

43. Re-implement pcre2grep's -F, -w, and -x options using PCRE2_LITERAL,
PCRE2_EXTRA_MATCH_WORD, and PCRE2_EXTRA_MATCH_LINE. This fixes two bugs:

    (a) The -F option did not work for fixed strings containing \E.
    (b) The -w option did not work for patterns with multiple branches.

44. Added configuration options for the SELinux compatible execmem allocator in
JIT.

45. Increased the limit for searching for a "must be present" code unit in
subjects from 1000 to 2000 for 8-bit searches, since they use memchr() and are
much faster.

46. Arrange for anchored patterns to record and use "first code unit" data,
because this can give a fast "no match" without searching for a "required code
unit". Previously only non-anchored patterns did this.

47. Upgraded the Unicode tables from Unicode 8.0.0 to Unicode 10.0.0.

48. Add the callout_no_where modifier to pcre2test.

49. Update extended grapheme breaking rules to the latest set that are in
Unicode Standard Annex #29.

50. Added experimental foreign pattern conversion facilities
(pcre2_pattern_convert() and friends).

51. Change the macro FWRITE, used in pcre2grep, to FWRITE_IGNORE because FWRITE
is defined in a system header in cygwin. Also modified some of the #ifdefs in
pcre2grep related to Windows and Cygwin support.

52. Change 3(g) for 10.23 was a bit too zealous. If a hyphen that follows a
character class is the last character in the class, Perl does not give a
warning. PCRE2 now also treats this as a literal.

53. Related to 52, though PCRE2 was throwing an error for [[:digit:]-X] it was
not doing so for [\d-X] (and similar escapes), as is documented.

54. Fixed a MIPS issue in the JIT compiler reported by Joshua Kinard.

55. Fixed a "maybe uninitialized" warning for class_uchardata in \p handling in
pcre2_compile() which could never actually trigger (code should have been cut
out when Unicode support is disabled).


Version 10.23 14-February-2017
------------------------------

1. Extended pcre2test with the utf8_input modifier so that it is able to
generate all possible 16-bit and 32-bit code unit values in non-UTF modes.

2. In any wide-character mode (8-bit UTF or any 16-bit or 32-bit mode), without
PCRE2_UCP set, a negative character type such as \D in a positive class should
cause all characters greater than 255 to match, whatever else is in the class.
There was a bug that caused this not to happen if a Unicode property item was
added to such a class, for example [\D\P{Nd}] or [\W\pL].

3. There has been a major re-factoring of the pcre2_compile.c file. Most syntax
checking is now done in the pre-pass that identifies capturing groups. This has
reduced the amount of duplication and made the code tidier. While doing this,
some minor bugs and Perl incompatibilities were fixed, including:

  (a) \Q\E in the middle of a quantifier such as A+\Q\E+ is now ignored instead
      of giving an invalid quantifier error.

  (b) {0} can now be used after a group in a lookbehind assertion; previously
      this caused an "assertion is not fixed length" error.

  (c) Perl always treats (?(DEFINE) as a "define" group, even if a group with
      the name "DEFINE" exists. PCRE2 now does likewise.

  (d) A recursion condition test such as (?(R2)...) must now refer to an
      existing subpattern.

  (e) A conditional recursion test such as (?(R)...) misbehaved if there was a
      group whose name began with "R".

  (f) When testing zero-terminated patterns under valgrind, the terminating
      zero is now marked "no access". This catches bugs that would otherwise
      show up only with non-zero-terminated patterns.

  (g) A hyphen appearing immediately after a POSIX character class (for example
      /[[:ascii:]-z]/) now generates an error. Perl does accept this as a
      literal, but gives a warning, so it seems best to fail it in PCRE.

  (h) An empty \Q\E sequence may appear after a callout that precedes an
      assertion condition (it is, of course, ignored).

One effect of the refactoring is that some error numbers and messages have
changed, and the pattern offset given for compiling errors is not always the
right-most character that has been read. In particular, for a variable-length
lookbehind assertion it now points to the start of the assertion. Another
change is that when a callout appears before a group, the "length of next
pattern item" that is passed now just gives the length of the opening
parenthesis item, not the length of the whole group. A length of zero is now
given only for a callout at the end of the pattern. Automatic callouts are no
longer inserted before and after explicit callouts in the pattern.

A number of bugs in the refactored code were subsequently fixed during testing
before release, but after the code was made available in the repository. Many
of the bugs were discovered by fuzzing testing. Several of them were related to
the change from assuming a zero-terminated pattern (which previously had
required non-zero terminated strings to be copied). These bugs were never in
fully released code, but are noted here for the record.

  (a) An overall recursion such as (?0) inside a lookbehind assertion was not
      being diagnosed as an error.

  (b) In utf mode, the length of a *MARK (or other verb) name was being checked
      in characters instead of code units, which could lead to bad code being
      compiled, leading to unpredictable behaviour.

  (c) In extended /x mode, characters whose code was greater than 255 caused
      a lookup outside one of the global tables. A similar bug existed for wide
      characters in *VERB names.

  (d) The amount of memory needed for a compiled pattern was miscalculated if a
      lookbehind contained more than one toplevel branch and the first branch
      was of length zero.

  (e) In UTF-8 or UTF-16 modes with PCRE2_EXTENDED (/x) set and a non-zero-
      terminated pattern, if a # comment ran on to the end of the pattern, one
      or more code units past the end were being read.

  (f) An unterminated repeat at the end of a non-zero-terminated pattern (e.g.
      "{2,2") could cause reading beyond the pattern.

  (g) When reading a callout string, if the end delimiter was at the end of the
      pattern one further code unit was read.

  (h) An unterminated number after \g' could cause reading beyond the pattern.

  (i) An insufficient memory size was being computed for compiling with
      PCRE2_AUTO_CALLOUT.

  (j) A conditional group with an assertion condition used more memory than was
      allowed for it during parsing, so too many of them could therefore
      overrun a buffer.

  (k) If parsing a pattern exactly filled the buffer, the internal test for
      overrun did not check when the final META_END item was added.

  (l) If a lookbehind contained a subroutine call, and the called group
      contained an option setting such as (?s), and the PCRE2_ANCHORED option
      was set, unpredictable behaviour could occur. The underlying bug was
      incorrect code and insufficient checking while searching for the end of
      the called subroutine in the parsed pattern.

  (m) Quantifiers following (*VERB)s were not being diagnosed as errors.

  (n) The use of \Q...\E in a (*VERB) name when PCRE2_ALT_VERBNAMES and
      PCRE2_AUTO_CALLOUT were both specified caused undetermined behaviour.

  (o) If \Q was preceded by a quantified item, and the following \E was
      followed by '?' or '+', and there was at least one literal character
      between them, an internal error "unexpected repeat" occurred (example:
      /.+\QX\E+/).

  (p) A buffer overflow could occur while sorting the names in the group name
      list (depending on the order in which the names were seen).

  (q) A conditional group that started with a callout was not doing the right
      check for a following assertion, leading to compiling bad code. Example:
      /(?(C'XX))?!XX/

  (r) If a character whose code point was greater than 0xffff appeared within
      a lookbehind that was within another lookbehind, the calculation of the
      lookbehind length went wrong and could provoke an internal error.

  (t) The sequence \E- or \Q\E- after a POSIX class in a character class caused
      an internal error. Now the hyphen is treated as a literal.

4. Back references are now permitted in lookbehind assertions when there are
no duplicated group numbers (that is, (?| has not been used), and, if the
reference is by name, there is only one group of that name. The referenced
group must, of course be of fixed length.

5. pcre2test has been upgraded so that, when run under valgrind with valgrind
support enabled, reading past the end of the pattern is detected, both when
compiling and during callout processing.

6. \g{+<number>} (e.g. \g{+2} ) is now supported. It is a "forward back
reference" and can be useful in repetitions (compare \g{-<number>} ). Perl does
not recognize this syntax.

7. Automatic callouts are no longer generated before and after callouts in the
pattern.

8. When pcre2test was outputing information from a callout, the caret indicator
for the current position in the subject line was incorrect if it was after an
escape sequence for a character whose code point was greater than \x{ff}.

9. Change 19 for 10.22 had a typo (PCRE_STATIC_RUNTIME should be
PCRE2_STATIC_RUNTIME). Fix from David Gaussmann.

10. Added --max-buffer-size to pcre2grep, to allow for automatic buffer
expansion when long lines are encountered. Original patch by Dmitry
Cherniachenko.

11. If pcre2grep was compiled with JIT support, but the library was compiled
without it (something that neither ./configure nor CMake allow, but it can be
done by editing config.h), pcre2grep was giving a JIT error. Now it detects
this situation and does not try to use JIT.

12. Added some "const" qualifiers to variables in pcre2grep.

13. Added Dmitry Cherniachenko's patch for colouring output in Windows
(untested by me). Also, look for GREP_COLOUR or GREP_COLOR if the environment
variables PCRE2GREP_COLOUR and PCRE2GREP_COLOR are not found.

14. Add the -t (grand total) option to pcre2grep.

15. A number of bugs have been mended relating to match start-up optimizations
when the first thing in a pattern is a positive lookahead. These all applied
only when PCRE2_NO_START_OPTIMIZE was *not* set:

    (a) A pattern such as (?=.*X)X$ was incorrectly optimized as if it needed
        both an initial 'X' and a following 'X'.
    (b) Some patterns starting with an assertion that started with .* were
        incorrectly optimized as having to match at the start of the subject or
        after a newline. There are cases where this is not true, for example,
        (?=.*[A-Z])(?=.{8,16})(?!.*[\s]) matches after the start in lines that
        start with spaces. Starting .* in an assertion is no longer taken as an
        indication of matching at the start (or after a newline).

16. The "offset" modifier in pcre2test was not being ignored (as documented)
when the POSIX API was in use.

17. Added --enable-fuzz-support to "configure", causing an non-installed
library containing a test function that can be called by fuzzers to be
compiled. A non-installed  binary to run the test function locally, called
pcre2fuzzcheck is also compiled.

18. A pattern with PCRE2_DOTALL (/s) set but not PCRE2_NO_DOTSTAR_ANCHOR, and
which started with .* inside a positive lookahead was incorrectly being
compiled as implicitly anchored.

19. Removed all instances of "register" declarations, as they are considered
obsolete these days and in any case had become very haphazard.

20. Add strerror() to pcre2test for failed file opening.

21. Make pcre2test -C list valgrind support when it is enabled.

22. Add the use_length modifier to pcre2test.

23. Fix an off-by-one bug in pcre2test for the list of names for 'get' and
'copy' modifiers.

24. Add PCRE2_CALL_CONVENTION into the prototype declarations in pcre2.h as it
is apparently needed there as well as in the function definitions. (Why did
nobody ask for this in PCRE1?)

25. Change the _PCRE2_H and _PCRE2_UCP_H guard macros in the header files to
PCRE2_H_IDEMPOTENT_GUARD and PCRE2_UCP_H_IDEMPOTENT_GUARD to be more standard
compliant and unique.

26. pcre2-config --libs-posix was listing -lpcre2posix instead of
-lpcre2-posix. Also, the CMake build process was building the library with the
wrong name.

27. In pcre2test, give some offset information for errors in hex patterns.
This uses the C99 formatting sequence %td, except for MSVC which doesn't
support it - %lu is used instead.

28. Implemented pcre2_code_copy_with_tables(), and added pushtablescopy to
pcre2test for testing it.

29. Fix small memory leak in pcre2test.

30. Fix out-of-bounds read for partial matching of /./ against an empty string
when the newline type is CRLF.

31. Fix a bug in pcre2test that caused a crash when a locale was set either in
the current pattern or a previous one and a wide character was matched.

32. The appearance of \p, \P, or \X in a substitution string when
PCRE2_SUBSTITUTE_EXTENDED was set caused a segmentation fault (NULL
dereference).

33. If the starting offset was specified as greater than the subject length in
a call to pcre2_substitute() an out-of-bounds memory reference could occur.

34. When PCRE2 was compiled to use the heap instead of the stack for recursive
calls to match(), a repeated minimizing caseless back reference, or a
maximizing one where the two cases had different numbers of code units,
followed by a caseful back reference, could lose the caselessness of the first
repeated back reference (example: /(Z)(a)\2{1,2}?(?-i)\1X/i should match ZaAAZX
but didn't).

35. When a pattern is too complicated, PCRE2 gives up trying to find a minimum
matching length and just records zero. Typically this happens when there are
too many nested or recursive back references. If the limit was reached in
certain recursive cases it failed to be triggered and an internal error could
be the result.

36. The pcre2_dfa_match() function now takes note of the recursion limit for
the internal recursive calls that are used for lookrounds and recursions within
the pattern.

37. More refactoring has got rid of the internal could_be_empty_branch()
function (around 400 lines of code, including comments) by keeping track of
could-be-emptiness as the pattern is compiled instead of scanning compiled
groups. (This would have been much harder before the refactoring of #3 above.)
This lifts a restriction on the number of branches in a group (more than about
1100 would give "pattern is too complicated").

38. Add the "-ac" command line option to pcre2test as a synonym for "-pattern
auto_callout".

39. In a library with Unicode support, incorrect data was compiled for a
pattern with PCRE2_UCP set without PCRE2_UTF if a class required all wide
characters to match (for example, /[\s[:^ascii:]]/).

40. The callout_error modifier has been added to pcre2test to make it possible
to return PCRE2_ERROR_CALLOUT from a callout.

41. A minor change to pcre2grep: colour reset is now "<esc>[0m" instead of
"<esc>[00m".

42. The limit in the auto-possessification code that was intended to catch
overly-complicated patterns and not spend too much time auto-possessifying was
being reset too often, resulting in very long compile times for some patterns.
Now such patterns are no longer completely auto-possessified.

43. Applied Jason Hood's revised patch for RunTest.bat.

44. Added a new Windows script RunGrepTest.bat, courtesy of Jason Hood.

45. Minor cosmetic fix to pcre2test: move a variable that is not used under
Windows into the "not Windows" code.

46. Applied Jason Hood's patches to upgrade pcre2grep under Windows and tidy
some of the code:

  * normalised the Windows condition by ensuring WIN32 is defined;
  * enables the callout feature under Windows;
  * adds globbing (Microsoft's implementation expands quoted args),
    using a tweaked opendirectory;
  * implements the is_*_tty functions for Windows;
  * --color=always will write the ANSI sequences to file;
  * add sequences 4 (underline works on Win10) and 5 (blink as bright
    background, relatively standard on DOS/Win);
  * remove the (char *) casts for the now-const strings;
  * remove GREP_COLOUR (grep's command line allowed the 'u', but not
    the environment), parsing GREP_COLORS instead;
  * uses the current colour if not set, rather than black;
  * add print_match for the undefined case;
  * fixes a typo.

In addition, colour settings containing anything other than digits and
semicolon are ignored, and the colour controls are no longer output for empty
strings.

47. Detecting patterns that are too large inside the length-measuring loop
saves processing ridiculously long patterns to their end.

48. Ignore PCRE2_CASELESS when processing \h, \H, \v, and \V in classes as it
just wastes time. In the UTF case it can also produce redundant entries in
XCLASS lists caused by characters with multiple other cases and pairs of
characters in the same "not-x" sublists.

49. A pattern such as /(?=(a\K))/ can report the end of the match being before
its start; pcre2test was not handling this correctly when using the POSIX
interface (it was OK with the native interface).

50. In pcre2grep, ignore all JIT compile errors. This means that pcre2grep will
continue to work, falling back to interpretation if anything goes wrong with
JIT.

51. Applied patches from Christian Persch to configure.ac to make use of the
AC_USE_SYSTEM_EXTENSIONS macro and to test for functions used by the JIT
modules.

52. Minor fixes to pcre2grep from Jason Hood:
    * fixed some spacing;
    * Windows doesn't usually use single quotes, so I've added a define
      to use appropriate quotes [in an example];
    * LC_ALL was displayed as "LCC_ALL";
    * numbers 11, 12 & 13 should end in "th";
    * use double quotes in usage message.

53. When autopossessifying, skip empty branches without recursion, to reduce
stack usage for the benefit of clang with -fsanitize-address, which uses huge
stack frames. Example pattern: /X?(R||){3335}/. Fixes oss-fuzz issue 553.

54. A pattern with very many explicit back references to a group that is a long
way from the start of the pattern could take a long time to compile because
searching for the referenced group in order to find the minimum length was
being done repeatedly. Now up to 128 group minimum lengths are cached and the
attempt to find a minimum length is abandoned if there is a back reference to a
group whose number is greater than 128. (In that case, the pattern is so
complicated that this optimization probably isn't worth it.) This fixes
oss-fuzz issue 557.

55. Issue 32 for 10.22 below was not correctly fixed. If pcre2grep in multiline
mode with --only-matching matched several lines, it restarted scanning at the
next line instead of moving on to the end of the matched string, which can be
several lines after the start.

56. Applied Jason Hood's new patch for RunGrepTest.bat that updates it in line
with updates to the non-Windows version.



Version 10.22 29-July-2016
--------------------------

1. Applied Jason Hood's patches to RunTest.bat and testdata/wintestoutput3
to fix problems with running the tests under Windows.

2. Implemented a facility for quoting literal characters within hexadecimal
patterns in pcre2test, to make it easier to create patterns with just a few
non-printing characters.

3. Binary zeros are not supported in pcre2test input files. It now detects them
and gives an error.

4. Updated the valgrind parameters in RunTest: (a) changed smc-check=all to
smc-check=all-non-file; (b) changed obj:* in the suppression file to obj:??? so
that it matches only unknown objects.

5. Updated the maintenance script maint/ManyConfigTests to make it easier to
select individual groups of tests.

6. When the POSIX wrapper function regcomp() is called, the REG_NOSUB option
used to set PCRE2_NO_AUTO_CAPTURE when calling pcre2_compile(). However, this
disables the use of back references (and subroutine calls), which are supported
by other implementations of regcomp() with RE_NOSUB. Therefore, REG_NOSUB no
longer causes PCRE2_NO_AUTO_CAPTURE to be set, though it still ignores nmatch
and pmatch when regexec() is called.

7. Because of 6 above, pcre2test has been modified with a new modifier called
posix_nosub, to call regcomp() with REG_NOSUB. Previously the no_auto_capture
modifier had this effect. That option is now ignored when the POSIX API is in
use.

8. Minor tidies to the pcre2demo.c sample program, including more comments
about its 8-bit-ness.

9. Detect unmatched closing parentheses and give the error in the pre-scan
instead of later. Previously the pre-scan carried on and could give a
misleading incorrect error message. For example, /(?J)(?'a'))(?'a')/ gave a
message about invalid duplicate group names.

10. It has happened that pcre2test was accidentally linked with another POSIX
regex library instead of libpcre2-posix. In this situation, a call to regcomp()
(in the other library) may succeed, returning zero, but of course putting its
own data into the regex_t block. In one example the re_pcre2_code field was
left as NULL, which made pcre2test think it had not got a compiled POSIX regex,
so it treated the next line as another pattern line, resulting in a confusing
error message. A check has been added to pcre2test to see if the data returned
from a successful call of regcomp() are valid for PCRE2's regcomp(). If they
are not, an error message is output and the pcre2test run is abandoned. The
message points out the possibility of a mis-linking. Hopefully this will avoid
some head-scratching the next time this happens.

11. A pattern such as /(?<=((?C)0))/, which has a callout inside a lookbehind
assertion, caused pcre2test to output a very large number of spaces when the
callout was taken, making the program appearing to loop.

12. A pattern that included (*ACCEPT) in the middle of a sufficiently deeply
nested set of parentheses of sufficient size caused an overflow of the
compiling workspace (which was diagnosed, but of course is not desirable).

13. Detect missing closing parentheses during the pre-pass for group
identification.

14. Changed some integer variable types and put in a number of casts, following
a report of compiler warnings from Visual Studio 2013 and a few tests with
gcc's -Wconversion (which still throws up a lot).

15. Implemented pcre2_code_copy(), and added pushcopy and #popcopy to pcre2test
for testing it.

16. Change 66 for 10.21 introduced the use of snprintf() in PCRE2's version of
regerror(). When the error buffer is too small, my version of snprintf() puts a
binary zero in the final byte. Bug #1801 seems to show that other versions do
not do this, leading to bad output from pcre2test when it was checking for
buffer overflow. It no longer assumes a binary zero at the end of a too-small
regerror() buffer.

17. Fixed typo ("&&" for "&") in pcre2_study(). Fortunately, this could not
actually affect anything, by sheer luck.

18. Two minor fixes for MSVC compilation: (a) removal of apparently incorrect
"const" qualifiers in pcre2test and (b) defining snprintf as _snprintf for
older MSVC compilers. This has been done both in src/pcre2_internal.h for most
of the library, and also in src/pcre2posix.c, which no longer includes
pcre2_internal.h (see 24 below).

19. Applied Chris Wilson's patch (Bugzilla #1681) to CMakeLists.txt for MSVC
static compilation. Subsequently applied Chris Wilson's second patch, putting
the first patch under a new option instead of being unconditional when
PCRE_STATIC is set.

20. Updated pcre2grep to set stdout as binary when run under Windows, so as not
to convert \r\n at the ends of reflected lines into \r\r\n. This required
ensuring that other output that is written to stdout (e.g. file names) uses the
appropriate line terminator: \r\n for Windows, \n otherwise.

21. When a line is too long for pcre2grep's internal buffer, show the maximum
length in the error message.

22. Added support for string callouts to pcre2grep (Zoltan's patch with PH
additions).

23. RunTest.bat was missing a "set type" line for test 22.

24. The pcre2posix.c file was including pcre2_internal.h, and using some
"private" knowledge of the data structures. This is unnecessary; the code has
been re-factored and no longer includes pcre2_internal.h.

25. A racing condition is fixed in JIT reported by Mozilla.

26. Minor code refactor to avoid "array subscript is below array bounds"
compiler warning.

27. Minor code refactor to avoid "left shift of negative number" warning.

28. Add a bit more sanity checking to pcre2_serialize_decode() and document
that it expects trusted data.

29. Fix typo in pcre2_jit_test.c

30. Due to an oversight, pcre2grep was not making use of JIT when available.
This is now fixed.

31. The RunGrepTest script is updated to use the valgrind suppressions file
when testing with JIT under valgrind (compare 10.21/51 below). The suppressions
file is updated so that is now the same as for PCRE1: it suppresses the
Memcheck warnings Addr16 and Cond in unknown objects (that is, JIT-compiled
code). Also changed smc-check=all to smc-check=all-non-file as was done for
RunTest (see 4 above).

32. Implemented the PCRE2_NO_JIT option for pcre2_match().

33. Fix typo that gave a compiler error when JIT not supported.

34. Fix comment describing the returns from find_fixedlength().

35. Fix potential negative index in pcre2test.

36. Calls to pcre2_get_error_message() with error numbers that are never
returned by PCRE2 functions were returning empty strings. Now the error code
PCRE2_ERROR_BADDATA is returned. A facility has been added to pcre2test to
show the texts for given error numbers (i.e. to call pcre2_get_error_message()
and display what it returns) and a few representative error codes are now
checked in RunTest.

37. Added "&& !defined(__INTEL_COMPILER)" to the test for __GNUC__ in
pcre2_match.c, in anticipation that this is needed for the same reason it was
recently added to pcrecpp.cc in PCRE1.

38. Using -o with -M in pcre2grep could cause unnecessary repeated output when
the match extended over a line boundary, as it tried to find more matches "on
the same line" - but it was already over the end.

39. Allow \C in lookbehinds and DFA matching in UTF-32 mode (by converting it
to the same code as '.' when PCRE2_DOTALL is set).

40. Fix two clang compiler warnings in pcre2test when only one code unit width
is supported.

41. Upgrade RunTest to automatically re-run test 2 with a large (64MiB) stack
if it fails when running the interpreter with a 16MiB stack (and if changing
the stack size via pcre2test is possible). This avoids having to manually set a
large stack size when testing with clang.

42. Fix register overwite in JIT when SSE2 acceleration is enabled.

43. Detect integer overflow in pcre2test pattern and data repetition counts.

44. In pcre2test, ignore "allcaptures" after DFA matching.

45. Fix unaligned accesses on x86. Patch by Marc Mutz.

46. Fix some more clang compiler warnings.


Version 10.21 12-January-2016
-----------------------------

1. Improve matching speed of patterns starting with + or * in JIT.

2. Use memchr() to find the first character in an unanchored match in 8-bit
mode in the interpreter. This gives a significant speed improvement.

3. Removed a redundant copy of the opcode_possessify table in the
pcre2_auto_possessify.c source.

4. Fix typos in dftables.c for z/OS.

5. Change 36 for 10.20 broke the handling of [[:>:]] and [[:<:]] in that
processing them could involve a buffer overflow if the following character was
an opening parenthesis.

6. Change 36 for 10.20 also introduced a bug in processing this pattern:
/((?x)(*:0))#(?'/. Specifically: if a setting of (?x) was followed by a (*MARK)
setting (which (*:0) is), then (?x) did not get unset at the end of its group
during the scan for named groups, and hence the external # was incorrectly
treated as a comment and the invalid (?' at the end of the pattern was not
diagnosed. This caused a buffer overflow during the real compile. This bug was
discovered by Karl Skomski with the LLVM fuzzer.

7. Moved the pcre2_find_bracket() function from src/pcre2_compile.c into its
own source module to avoid a circular dependency between src/pcre2_compile.c
and src/pcre2_study.c

8. A callout with a string argument containing an opening square bracket, for
example /(?C$[$)(?<]/, was incorrectly processed and could provoke a buffer
overflow. This bug was discovered by Karl Skomski with the LLVM fuzzer.

9. The handling of callouts during the pre-pass for named group identification
has been tightened up.

10. The quantifier {1} can be ignored, whether greedy, non-greedy, or
possessive. This is a very minor optimization.

11. A possessively repeated conditional group that could match an empty string,
for example, /(?(R))*+/, was incorrectly compiled.

12. The Unicode tables have been updated to Unicode 8.0.0 (thanks to Christian
Persch).

13. An empty comment (?#) in a pattern was incorrectly processed and could
provoke a buffer overflow. This bug was discovered by Karl Skomski with the
LLVM fuzzer.

14. Fix infinite recursion in the JIT compiler when certain patterns such as
/(?:|a|){100}x/ are analysed.

15. Some patterns with character classes involving [: and \\ were incorrectly
compiled and could cause reading from uninitialized memory or an incorrect
error diagnosis. Examples are: /[[:\\](?<[::]/ and /[[:\\](?'abc')[a:]. The
first of these bugs was discovered by Karl Skomski with the LLVM fuzzer.

16. Pathological patterns containing many nested occurrences of [: caused
pcre2_compile() to run for a very long time. This bug was found by the LLVM
fuzzer.

17. A missing closing parenthesis for a callout with a string argument was not
being diagnosed, possibly leading to a buffer overflow. This bug was found by
the LLVM fuzzer.

18. A conditional group with only one branch has an implicit empty alternative
branch and must therefore be treated as potentially matching an empty string.

19. If (?R was followed by - or + incorrect behaviour happened instead of a
diagnostic. This bug was discovered by Karl Skomski with the LLVM fuzzer.

20. Another bug that was introduced by change 36 for 10.20: conditional groups
whose condition was an assertion preceded by an explicit callout with a string
argument might be incorrectly processed, especially if the string contained \Q.
This bug was discovered by Karl Skomski with the LLVM fuzzer.

21. Compiling PCRE2 with the sanitize options of clang showed up a number of
very pedantic coding infelicities and a buffer overflow while checking a UTF-8
string if the final multi-byte UTF-8 character was truncated.

22. For Perl compatibility in EBCDIC environments, ranges such as a-z in a
class, where both values are literal letters in the same case, omit the
non-letter EBCDIC code points within the range.

23. Finding the minimum matching length of complex patterns with back
references and/or recursions can take a long time. There is now a cut-off that
gives up trying to find a minimum length when things get too complex.

24. An optimization has been added that speeds up finding the minimum matching
length for patterns containing repeated capturing groups or recursions.

25. If a pattern contained a back reference to a group whose number was
duplicated as a result of appearing in a (?|...) group, the computation of the
minimum matching length gave a wrong result, which could cause incorrect "no
match" errors. For such patterns, a minimum matching length cannot at present
be computed.

26. Added a check for integer overflow in conditions (?(<digits>) and
(?(R<digits>). This omission was discovered by Karl Skomski with the LLVM
fuzzer.

27. Fixed an issue when \p{Any} inside an xclass did not read the current
character.

28. If pcre2grep was given the -q option with -c or -l, or when handling a
binary file, it incorrectly wrote output to stdout.

29. The JIT compiler did not restore the control verb head in case of *THEN
control verbs. This issue was found by Karl Skomski with a custom LLVM fuzzer.

30. The way recursive references such as (?3) are compiled has been re-written
because the old way was the cause of many issues. Now, conversion of the group
number into a pattern offset does not happen until the pattern has been
completely compiled. This does mean that detection of all infinitely looping
recursions is postponed till match time. In the past, some easy ones were
detected at compile time. This re-writing was done in response to yet another
bug found by the LLVM fuzzer.

31. A test for a back reference to a non-existent group was missing for items
such as \987. This caused incorrect code to be compiled. This issue was found
by Karl Skomski with a custom LLVM fuzzer.

32. Error messages for syntax errors following \g and \k were giving inaccurate
offsets in the pattern.

33. Improve the performance of starting single character repetitions in JIT.

34. (*LIMIT_MATCH=) now gives an error instead of setting the value to 0.

35. Error messages for syntax errors in *LIMIT_MATCH and *LIMIT_RECURSION now
give the right offset instead of zero.

36. The JIT compiler should not check repeats after a {0,1} repeat byte code.
This issue was found by Karl Skomski with a custom LLVM fuzzer.

37. The JIT compiler should restore the control chain for empty possessive
repeats. This issue was found by Karl Skomski with a custom LLVM fuzzer.

38. A bug which was introduced by the single character repetition optimization
was fixed.

39. Match limit check added to recursion. This issue was found by Karl Skomski
with a custom LLVM fuzzer.

40. Arrange for the UTF check in pcre2_match() and pcre2_dfa_match() to look
only at the part of the subject that is relevant when the starting offset is
non-zero.

41. Improve first character match in JIT with SSE2 on x86.

42. Fix two assertion fails in JIT. These issues were found by Karl Skomski
with a custom LLVM fuzzer.

43. Correct the setting of CMAKE_C_FLAGS in CMakeLists.txt (patch from Roy Ivy
III).

44. Fix bug in RunTest.bat for new test 14, and adjust the script for the added
test (there are now 20 in total).

45. Fixed a corner case of range optimization in JIT.

46. Add the ${*MARK} facility to pcre2_substitute().

47. Modifier lists in pcre2test were splitting at spaces without the required
commas.

48. Implemented PCRE2_ALT_VERBNAMES.

49. Fixed two issues in JIT. These were found by Karl Skomski with a custom
LLVM fuzzer.

50. The pcre2test program has been extended by adding the #newline_default
command. This has made it possible to run the standard tests when PCRE2 is
compiled with either CR or CRLF as the default newline convention. As part of
this work, the new command was added to several test files and the testing
scripts were modified. The pcre2grep tests can now also be run when there is no
LF in the default newline convention.

51. The RunTest script has been modified so that, when JIT is used and valgrind
is specified, a valgrind suppressions file is set up to ignore "Invalid read of
size 16" errors because these are false positives when the hardware supports
the SSE2 instruction set.

52. It is now possible to have comment lines amid the subject strings in
pcre2test (and perltest.sh) input.

53. Implemented PCRE2_USE_OFFSET_LIMIT and pcre2_set_offset_limit().

54. Add the null_context modifier to pcre2test so that calling pcre2_compile()
and the matching functions with NULL contexts can be tested.

55. Implemented PCRE2_SUBSTITUTE_EXTENDED.

56. In a character class such as [\W\p{Any}] where both a negative-type escape
("not a word character") and a property escape were present, the property
escape was being ignored.

57. Fixed integer overflow for patterns whose minimum matching length is very,
very large.

58. Implemented --never-backslash-C.

59. Change 55 above introduced a bug by which certain patterns provoked the
erroneous error "\ at end of pattern".

60. The special sequences [[:<:]] and [[:>:]] gave rise to incorrect compiling
errors or other strange effects if compiled in UCP mode. Found with libFuzzer
and AddressSanitizer.

61. Whitespace at the end of a pcre2test pattern line caused a spurious error
message if there were only single-character modifiers. It should be ignored.

62. The use of PCRE2_NO_AUTO_CAPTURE could cause incorrect compilation results
or segmentation errors for some patterns. Found with libFuzzer and
AddressSanitizer.

63. Very long names in (*MARK) or (*THEN) etc. items could provoke a buffer
overflow.

64. Improve error message for overly-complicated patterns.

65. Implemented an optional replication feature for patterns in pcre2test, to
make it easier to test long repetitive patterns. The tests for 63 above are
converted to use the new feature.

66. In the POSIX wrapper, if regerror() was given too small a buffer, it could
misbehave.

67. In pcre2_substitute() in UTF mode, the UTF validity check on the
replacement string was happening before the length setting when the replacement
string was zero-terminated.

68. In pcre2_substitute() in UTF mode, PCRE2_NO_UTF_CHECK can be set for the
second and subsequent calls to pcre2_match().

69. There was no check for integer overflow for a replacement group number in
pcre2_substitute(). An added check for a number greater than the largest group
number in the pattern means this is not now needed.

70. The PCRE2-specific VERSION condition didn't work correctly if only one
digit was given after the decimal point, or if more than two digits were given.
It now works with one or two digits, and gives a compile time error if more are
given.

71. In pcre2_substitute() there was the possibility of reading one code unit
beyond the end of the replacement string.

72. The code for checking a subject's UTF-32 validity for a pattern with a
lookbehind involved an out-of-bounds pointer, which could potentially cause
trouble in some environments.

73. The maximum lookbehind length was incorrectly calculated for patterns such
as /(?<=(a)(?-1))x/ which have a recursion within a backreference.

74. Give an error if a lookbehind assertion is longer than 65535 code units.

75. Give an error in pcre2_substitute() if a match ends before it starts (as a
result of the use of \K).

76. Check the length of subpattern names and the names in (*MARK:xx) etc.
dynamically to avoid the possibility of integer overflow.

77. Implement pcre2_set_max_pattern_length() so that programs can restrict the
size of patterns that they are prepared to handle.

78. (*NO_AUTO_POSSESS) was not working.

79. Adding group information caching improves the speed of compiling when
checking whether a group has a fixed length and/or could match an empty string,
especially when recursion or subroutine calls are involved. However, this
cannot be used when (?| is present in the pattern because the same number may
be used for groups of different sizes. To catch runaway patterns in this
situation, counts have been introduced to the functions that scan for empty
branches or compute fixed lengths.

80. Allow for the possibility of the size of the nest_save structure not being
a factor of the size of the compiling workspace (it currently is).

81. Check for integer overflow in minimum length calculation and cap it at
65535.

82. Small optimizations in code for finding the minimum matching length.

83. Lock out configuring for EBCDIC with non-8-bit libraries.

84. Test for error code <= 0 in regerror().

85. Check for too many replacements (more than INT_MAX) in pcre2_substitute().

86. Avoid the possibility of computing with an out-of-bounds pointer (though
not dereferencing it) while handling lookbehind assertions.

87. Failure to get memory for the match data in regcomp() is now given as a
regcomp() error instead of waiting for regexec() to pick it up.

88. In pcre2_substitute(), ensure that CRLF is not split when it is a valid
newline sequence.

89. Paranoid check in regcomp() for bad error code from pcre2_compile().

90. Run test 8 (internal offsets and code sizes) for link sizes 3 and 4 as well
as for link size 2.

91. Document that JIT has a limit on pattern size, and give more information
about JIT compile failures in pcre2test.

92. Implement PCRE2_INFO_HASBACKSLASHC.

93. Re-arrange valgrind support code in pcre2test to avoid spurious reports
with JIT (possibly caused by SSE2?).

94. Support offset_limit in JIT.

95. A sequence such as [[:punct:]b] that is, a POSIX character class followed
by a single ASCII character in a class item, was incorrectly compiled in UCP
mode. The POSIX class got lost, but only if the single character followed it.

96. [:punct:] in UCP mode was matching some characters in the range 128-255
that should not have been matched.

97. If [:^ascii:] or [:^xdigit:] are present in a non-negated class, all
characters with code points greater than 255 are in the class. When a Unicode
property was also in the class (if PCRE2_UCP is set, escapes such as \w are
turned into Unicode properties), wide characters were not correctly handled,
and could fail to match.

98. In pcre2test, make the "startoffset" modifier a synonym of "offset",
because it sets the "startoffset" parameter for pcre2_match().

99. If PCRE2_AUTO_CALLOUT was set on a pattern that had a (?# comment between
an item and its qualifier (for example, A(?#comment)?B) pcre2_compile()
misbehaved. This bug was found by the LLVM fuzzer.

100. The error for an invalid UTF pattern string always gave the code unit
offset as zero instead of where the invalidity was found.

101. Further to 97 above, negated classes such as [^[:^ascii:]\d] were also not
working correctly in UCP mode.

102. Similar to 99 above, if an isolated \E was present between an item and its
qualifier when PCRE2_AUTO_CALLOUT was set, pcre2_compile() misbehaved. This bug
was found by the LLVM fuzzer.

103. The POSIX wrapper function regexec() crashed if the option REG_STARTEND
was set when the pmatch argument was NULL. It now returns REG_INVARG.

104. Allow for up to 32-bit numbers in the ordin() function in pcre2grep.

105. An empty \Q\E sequence between an item and its qualifier caused
pcre2_compile() to misbehave when auto callouts were enabled. This bug
was found by the LLVM fuzzer.

106. If both PCRE2_ALT_VERBNAMES and PCRE2_EXTENDED were set, and a (*MARK) or
other verb "name" ended with whitespace immediately before the closing
parenthesis, pcre2_compile() misbehaved. Example: /(*:abc )/, but only when
both those options were set.

107. In a number of places pcre2_compile() was not handling NULL characters
correctly, and pcre2test with the "bincode" modifier was not always correctly
displaying fields containing NULLS:

   (a) Within /x extended #-comments
   (b) Within the "name" part of (*MARK) and other *verbs
   (c) Within the text argument of a callout

108. If a pattern that was compiled with PCRE2_EXTENDED started with white
space or a #-type comment that was followed by (?-x), which turns off
PCRE2_EXTENDED, and there was no subsequent (?x) to turn it on again,
pcre2_compile() assumed that (?-x) applied to the whole pattern and
consequently mis-compiled it. This bug was found by the LLVM fuzzer. The fix
for this bug means that a setting of any of the (?imsxJU) options at the start
of a pattern is no longer transferred to the options that are returned by
PCRE2_INFO_ALLOPTIONS. In fact, this was an anachronism that should have
changed when the effects of those options were all moved to compile time.

109. An escaped closing parenthesis in the "name" part of a (*verb) when
PCRE2_ALT_VERBNAMES was set caused pcre2_compile() to malfunction. This bug
was found by the LLVM fuzzer.

110. Implemented PCRE2_SUBSTITUTE_UNSET_EMPTY, and updated pcre2test to make it
possible to test it.

111. "Harden" pcre2test against ridiculously large values in modifiers and
command line arguments.

112. Implemented PCRE2_SUBSTITUTE_UNKNOWN_UNSET and PCRE2_SUBSTITUTE_OVERFLOW_
LENGTH.

113. Fix printing of *MARK names that contain binary zeroes in pcre2test.


Version 10.20 30-June-2015
--------------------------

1. Callouts with string arguments have been added.

2. Assertion code generator in JIT has been optimized.

3. The invalid pattern (?(?C) has a missing assertion condition at the end. The
pcre2_compile() function read past the end of the input before diagnosing an
error. This bug was discovered by the LLVM fuzzer.

4. Implemented pcre2_callout_enumerate().

5. Fix JIT compilation of conditional blocks whose assertion is converted to
(*FAIL). E.g: /(?(?!))/.

6. The pattern /(?(?!)^)/ caused references to random memory. This bug was
discovered by the LLVM fuzzer.

7. The assertion (?!) is optimized to (*FAIL). This was not handled correctly
when this assertion was used as a condition, for example (?(?!)a|b). In
pcre2_match() it worked by luck; in pcre2_dfa_match() it gave an incorrect
error about an unsupported item.

8. For some types of pattern, for example /Z*(|d*){216}/, the auto-
possessification code could take exponential time to complete. A recursion
depth limit of 1000 has been imposed to limit the resources used by this
optimization. This infelicity was discovered by the LLVM fuzzer.

9. A pattern such as /(*UTF)[\S\V\H]/, which contains a negated special class
such as \S in non-UCP mode, explicit wide characters (> 255) can be ignored
because \S ensures they are all in the class. The code for doing this was
interacting badly with the code for computing the amount of space needed to
compile the pattern, leading to a buffer overflow. This bug was discovered by
the LLVM fuzzer.

10. A pattern such as /((?2)+)((?1))/ which has mutual recursion nested inside
other kinds of group caused stack overflow at compile time. This bug was
discovered by the LLVM fuzzer.

11. A pattern such as /(?1)(?#?'){8}(a)/ which had a parenthesized comment
between a subroutine call and its quantifier was incorrectly compiled, leading
to buffer overflow or other errors. This bug was discovered by the LLVM fuzzer.

12. The illegal pattern /(?(?<E>.*!.*)?)/ was not being diagnosed as missing an
assertion after (?(. The code was failing to check the character after (?(?<
for the ! or = that would indicate a lookbehind assertion. This bug was
discovered by the LLVM fuzzer.

13. A pattern such as /X((?2)()*+){2}+/ which has a possessive quantifier with
a fixed maximum following a group that contains a subroutine reference was
incorrectly compiled and could trigger buffer overflow. This bug was discovered
by the LLVM fuzzer.

14. Negative relative recursive references such as (?-7) to non-existent
subpatterns were not being diagnosed and could lead to unpredictable behaviour.
This bug was discovered by the LLVM fuzzer.

15. The bug fixed in 14 was due to an integer variable that was unsigned when
it should have been signed. Some other "int" variables, having been checked,
have either been changed to uint32_t or commented as "must be signed".

16. A mutual recursion within a lookbehind assertion such as (?<=((?2))((?1)))
caused a stack overflow instead of the diagnosis of a non-fixed length
lookbehind assertion. This bug was discovered by the LLVM fuzzer.

17. The use of \K in a positive lookbehind assertion in a non-anchored pattern
(e.g. /(?<=\Ka)/) could make pcre2grep loop.

18. There was a similar problem to 17 in pcre2test for global matches, though
the code there did catch the loop.

19. If a greedy quantified \X was preceded by \C in UTF mode (e.g. \C\X*),
and a subsequent item in the pattern caused a non-match, backtracking over the
repeated \X did not stop, but carried on past the start of the subject, causing
reference to random memory and/or a segfault. There were also some other cases
where backtracking after \C could crash. This set of bugs was discovered by the
LLVM fuzzer.

20. The function for finding the minimum length of a matching string could take
a very long time if mutual recursion was present many times in a pattern, for
example, /((?2){73}(?2))((?1))/. A better mutual recursion detection method has
been implemented. This infelicity was discovered by the LLVM fuzzer.

21. Implemented PCRE2_NEVER_BACKSLASH_C.

22. The feature for string replication in pcre2test could read from freed
memory if the replication required a buffer to be extended, and it was not
working properly in 16-bit and 32-bit modes. This issue was discovered by a
fuzzer: see http://lcamtuf.coredump.cx/afl/.

23. Added the PCRE2_ALT_CIRCUMFLEX option.

24. Adjust the treatment of \8 and \9 to be the same as the current Perl
behaviour.

25. Static linking against the PCRE2 library using the pkg-config module was
failing on missing pthread symbols.

26. If a group that contained a recursive back reference also contained a
forward reference subroutine call followed by a non-forward-reference
subroutine call, for example /.((?2)(?R)\1)()/, pcre2_compile() failed to
compile correct code, leading to undefined behaviour or an internally detected
error. This bug was discovered by the LLVM fuzzer.

27. Quantification of certain items (e.g. atomic back references) could cause
incorrect code to be compiled when recursive forward references were involved.
For example, in this pattern: /(?1)()((((((\1++))\x85)+)|))/. This bug was
discovered by the LLVM fuzzer.

28. A repeated conditional group whose condition was a reference by name caused
a buffer overflow if there was more than one group with the given name. This
bug was discovered by the LLVM fuzzer.

29. A recursive back reference by name within a group that had the same name as
another group caused a buffer overflow. For example: /(?J)(?'d'(?'d'\g{d}))/.
This bug was discovered by the LLVM fuzzer.

30. A forward reference by name to a group whose number is the same as the
current group, for example in this pattern: /(?|(\k'Pm')|(?'Pm'))/, caused a
buffer overflow at compile time. This bug was discovered by the LLVM fuzzer.

31. Fix -fsanitize=undefined warnings for left shifts of 1 by 31 (it treats 1
as an int; fixed by writing it as 1u).

32. Fix pcre2grep compile when -std=c99 is used with gcc, though it still gives
a warning for "fileno" unless -std=gnu99 us used.

33. A lookbehind assertion within a set of mutually recursive subpatterns could
provoke a buffer overflow. This bug was discovered by the LLVM fuzzer.

34. Give an error for an empty subpattern name such as (?'').

35. Make pcre2test give an error if a pattern that follows #forbud_utf contains
\P, \p, or \X.

36. The way named subpatterns are handled has been refactored. There is now a
pre-pass over the regex which does nothing other than identify named
subpatterns and count the total captures. This means that information about
named patterns is known before the rest of the compile. In particular, it means
that forward references can be checked as they are encountered. Previously, the
code for handling forward references was contorted and led to several errors in
computing the memory requirements for some patterns, leading to buffer
overflows.

37. There was no check for integer overflow in subroutine calls such as (?123).

38. The table entry for \l in EBCDIC environments was incorrect, leading to its
being treated as a literal 'l' instead of causing an error.

39. If a non-capturing group containing a conditional group that could match
an empty string was repeated, it was not identified as matching an empty string
itself. For example: /^(?:(?(1)x|)+)+$()/.

40. In an EBCDIC environment, pcretest was mishandling the escape sequences
\a and \e in test subject lines.

41. In an EBCDIC environment, \a in a pattern was converted to the ASCII
instead of the EBCDIC value.

42. The handling of \c in an EBCDIC environment has been revised so that it is
now compatible with the specification in Perl's perlebcdic page.

43. Single character repetition in JIT has been improved. 20-30% speedup
was achieved on certain patterns.

44. The EBCDIC character 0x41 is a non-breaking space, equivalent to 0xa0 in
ASCII/Unicode. This has now been added to the list of characters that are
recognized as white space in EBCDIC.

45. When PCRE2 was compiled without Unicode support, the use of \p and \P gave
an error (correctly) when used outside a class, but did not give an error
within a class.

46. \h within a class was incorrectly compiled in EBCDIC environments.

47. JIT should return with error when the compiled pattern requires
more stack space than the maximum.

48. Fixed a memory leak in pcre2grep when a locale is set.


Version 10.10 06-March-2015
---------------------------

1. When a pattern is compiled, it remembers the highest back reference so that
when matching, if the ovector is too small, extra memory can be obtained to
use instead. A conditional subpattern whose condition is a check on a capture
having happened, such as, for example in the pattern /^(?:(a)|b)(?(1)A|B)/, is
another kind of back reference, but it was not setting the highest
backreference number. This mattered only if pcre2_match() was called with an
ovector that was too small to hold the capture, and there was no other kind of
back reference (a situation which is probably quite rare). The effect of the
bug was that the condition was always treated as FALSE when the capture could
not be consulted, leading to a incorrect behaviour by pcre2_match(). This bug
has been fixed.

2. Functions for serialization and deserialization of sets of compiled patterns
have been added.

3. The value that is returned by PCRE2_INFO_SIZE has been corrected to remove
excess code units at the end of the data block that may occasionally occur if
the code for calculating the size over-estimates. This change stops the
serialization code copying uninitialized data, to which valgrind objects. The
documentation of PCRE2_INFO_SIZE was incorrect in stating that the size did not
include the general overhead. This has been corrected.

4. All code units in every slot in the table of group names are now set, again
in order to avoid accessing uninitialized data when serializing.

5. The (*NO_JIT) feature is implemented.

6. If a bug that caused pcre2_compile() to use more memory than allocated was
triggered when using valgrind, the code in (3) above passed a stupidly large
value to valgrind. This caused a crash instead of an "internal error" return.

7. A reference to a duplicated named group (either a back reference or a test
for being set in a conditional) that occurred in a part of the pattern where
PCRE2_DUPNAMES was not set caused the amount of memory needed for the pattern
to be incorrectly calculated, leading to overwriting.

8. A mutually recursive set of back references such as (\2)(\1) caused a
segfault at compile time (while trying to find the minimum matching length).
The infinite loop is now broken (with the minimum length unset, that is, zero).

9. If an assertion that was used as a condition was quantified with a minimum
of zero, matching went wrong. In particular, if the whole group had unlimited
repetition and could match an empty string, a segfault was likely. The pattern
(?(?=0)?)+ is an example that caused this. Perl allows assertions to be
quantified, but not if they are being used as conditions, so the above pattern
is faulted by Perl. PCRE2 has now been changed so that it also rejects such
patterns.

10. The error message for an invalid quantifier has been changed from "nothing
to repeat" to "quantifier does not follow a repeatable item".

11. If a bad UTF string is compiled with NO_UTF_CHECK, it may succeed, but
scanning the compiled pattern in subsequent auto-possessification can get out
of step and lead to an unknown opcode. Previously this could have caused an
infinite loop. Now it generates an "internal error" error. This is a tidyup,
not a bug fix; passing bad UTF with NO_UTF_CHECK is documented as having an
undefined outcome.

12. A UTF pattern containing a "not" match of a non-ASCII character and a
subroutine reference could loop at compile time. Example: /[^\xff]((?1))/.

13. The locale test (RunTest 3) has been upgraded. It now checks that a locale
that is found in the output of "locale -a" can actually be set by pcre2test
before it is accepted. Previously, in an environment where a locale was listed
but would not set (an example does exist), the test would "pass" without
actually doing anything. Also the fr_CA locale has been added to the list of
locales that can be used.

14. Fixed a bug in pcre2_substitute(). If a replacement string ended in a
capturing group number without parentheses, the last character was incorrectly
literally included at the end of the replacement string.

15. A possessive capturing group such as (a)*+ with a minimum repeat of zero
failed to allow the zero-repeat case if pcre2_match() was called with an
ovector too small to capture the group.

16. Improved error message in pcre2test when setting the stack size (-S) fails.

17. Fixed two bugs in CMakeLists.txt: (1) Some lines had got lost in the
transfer from PCRE1, meaning that CMake configuration failed if "build tests"
was selected. (2) The file src/pcre2_serialize.c had not been added to the list
of PCRE2 sources, which caused a failure to build pcre2test.

18. Fixed typo in pcre2_serialize.c (DECL instead of DEFN) that causes problems
only on Windows.

19. Use binary input when reading back saved serialized patterns in pcre2test.

20. Added RunTest.bat for running the tests under Windows.

21. "make distclean" was not removing config.h, a file that may be created for
use with CMake.

22. A pattern such as "((?2){0,1999}())?", which has a group containing a
forward reference repeated a large (but limited) number of times within a
repeated outer group that has a zero minimum quantifier, caused incorrect code
to be compiled, leading to the error "internal error: previously-checked
referenced subpattern not found" when an incorrect memory address was read.
This bug was reported as "heap overflow", discovered by Kai Lu of Fortinet's
FortiGuard Labs. (Added 24-March-2015: CVE-2015-2325 was given to this.)

23. A pattern such as "((?+1)(\1))/" containing a forward reference subroutine
call within a group that also contained a recursive back reference caused
incorrect code to be compiled. This bug was reported as "heap overflow",
discovered by Kai Lu of Fortinet's FortiGuard Labs. (Added 24-March-2015:
CVE-2015-2326 was given to this.)

24. Computing the size of the JIT read-only data in advance has been a source
of various issues, and new ones are still appear unfortunately. To fix
existing and future issues, size computation is eliminated from the code,
and replaced by on-demand memory allocation.

25. A pattern such as /(?i)[A-`]/, where characters in the other case are
adjacent to the end of the range, and the range contained characters with more
than one other case, caused incorrect behaviour when compiled in UTF mode. In
that example, the range a-j was left out of the class.


Version 10.00 05-January-2015
-----------------------------

Version 10.00 is the first release of PCRE2, a revised API for the PCRE
library. Changes prior to 10.00 are logged in the ChangeLog file for the old
API, up to item 20 for release 8.36.

The code of the library was heavily revised as part of the new API
implementation. Details of each and every modification were not individually
logged. In addition to the API changes, the following changes were made. They
are either new functionality, or bug fixes and other noticeable changes of
behaviour that were implemented after the code had been forked.

1. Including Unicode support at build time is now enabled by default, but it
can optionally be disabled. It is not enabled by default at run time (no
change).

2. The test program, now called pcre2test, was re-specified and almost
completely re-written. Its input is not compatible with input for pcretest.

3. Patterns may start with (*NOTEMPTY) or (*NOTEMPTY_ATSTART) to set the
PCRE2_NOTEMPTY or PCRE2_NOTEMPTY_ATSTART options for every subject line that is
matched by that pattern.

4. For the benefit of those who use PCRE2 via some other application, that is,
not writing the function calls themselves, it is possible to check the PCRE2
version by matching a pattern such as /(?(VERSION>=10)yes|no)/ against a
string such as "yesno".

5. There are case-equivalent Unicode characters whose encodings use different
numbers of code units in UTF-8. U+023A and U+2C65 are one example. (It is
theoretically possible for this to happen in UTF-16 too.) If a backreference to
a group containing one of these characters was greedily repeated, and during
the match a backtrack occurred, the subject might be backtracked by the wrong
number of code units. For example, if /^(\x{23a})\1*(.)/ is matched caselessly
(and in UTF-8 mode) against "\x{23a}\x{2c65}\x{2c65}\x{2c65}", group 2 should
capture the final character, which is the three bytes E2, B1, and A5 in UTF-8.
Incorrect backtracking meant that group 2 captured only the last two bytes.
This bug has been fixed; the new code is slower, but it is used only when the
strings matched by the repetition are not all the same length.

6. A pattern such as /()a/ was not setting the "first character must be 'a'"
information. This applied to any pattern with a group that matched no
characters, for example: /(?:(?=.)|(?<!x))a/.

7. When an (*ACCEPT) is triggered inside capturing parentheses, it arranges for
those parentheses to be closed with whatever has been captured so far. However,
it was failing to mark any other groups between the highest capture so far and
the currrent group as "unset". Thus, the ovector for those groups contained
whatever was previously there. An example is the pattern /(x)|((*ACCEPT))/ when
matched against "abcd".

8. The pcre2_substitute() function has been implemented.

9. If an assertion used as a condition was quantified with a minimum of zero
(an odd thing to do, but it happened), SIGSEGV or other misbehaviour could
occur.

10. The PCRE2_NO_DOTSTAR_ANCHOR option has been implemented.

****
alt-pcre2/NEWS000064400000026635150410167000007042 0ustar00News about PCRE2 releases
-------------------------


Version 10.34 21-November-2019
------------------------------

Another release with a few enhancements as well as bugfixes and tidies. The
main new features are:

1. There is now some support for matching in invalid UTF strings.

2. Non-atomic positive lookarounds are implemented in the pcre2_match()
interpreter, but not in JIT.

3. Added two new functions: pcre2_get_match_data_size() and
pcre2_maketables_free().

4. Upgraded to Unicode 12.1.0.


Version 10.33 16-April-2019
---------------------------

Yet more bugfixes, tidies, and a few enhancements, summarized here (see
ChangeLog for the full list):

1. Callouts from pcre2_substitute() are now available.

2. The POSIX functions are now all called pcre2_regcomp() etc., with wrapper
functions that use the standard POSIX names. However, in pcre2posix.h the POSIX
names are defined as macros. This should help avoid linking with the wrong
library in some environments, while still exporting the POSIX names for
pre-existing programs that use them.

3. Some new options:

   (a) PCRE2_EXTRA_ESCAPED_CR_IS_LF makes \r behave as \n.

   (b) PCRE2_EXTRA_ALT_BSUX enables support for ECMAScript 6's \u{hh...}
       construct.

   (c) PCRE2_COPY_MATCHED_SUBJECT causes a copy of a matched subject to be
       made, instead of just remembering a pointer.

4. Some new Perl features:

   (a) Perl 5.28's experimental alphabetic names for atomic groups and
       lookaround assertions, for example, (*pla:...) and (*atomic:...).

   (b) The new Perl "script run" features (*script_run:...) and
       (*atomic_script_run:...) aka (*sr:...) and (*asr:...).

   (c) When PCRE2_UTF is set, allow non-ASCII letters and decimal digits in
       capture group names.

5. --disable-percent-zt disables the use of %zu and %td in formatting strings
in pcre2test. They were already automatically disabled for VC and older C
compilers.

6. Some changes related to callouts in pcre2grep:

   (a) Support for running an external program under VMS has been added, in
       addition to Windows and fork() support.

   (b) --disable-pcre2grep-callout-fork restricts the callout support in
       to the inbuilt echo facility.


Version 10.32 10-September-2018
-------------------------------

This is another mainly bugfix and tidying release with a few minor
enhancements. These are the main ones:

1. pcre2grep now supports the inclusion of binary zeros in patterns that are
read from files via the -f option.

2. ./configure now supports --enable-jit=auto, which automatically enables JIT
if the hardware supports it.

3. In pcre2_dfa_match(), internal recursive calls no longer use the stack for
local workspace and local ovectors. Instead, an initial block of stack is
reserved, but if this is insufficient, heap memory is used. The heap limit
parameter now applies to pcre2_dfa_match().

4. Updated to Unicode version 11.0.0.

5. (*ACCEPT:ARG), (*FAIL:ARG), and (*COMMIT:ARG) are now supported.

6. Added support for \N{U+dddd}, but only in Unicode mode.

7. Added support for (?^) to unset all imnsx options.


Version 10.31 12-February-2018
------------------------------

This is mainly a bugfix and tidying release (see ChangeLog for full details).
However, there are some minor enhancements.

1. New pcre2_config() options: PCRE2_CONFIG_NEVER_BACKSLASH_C and
PCRE2_CONFIG_COMPILED_WIDTHS.

2. New pcre2_pattern_info() option PCRE2_INFO_EXTRAOPTIONS to retrieve the
extra compile time options.

3. There are now public names for all the pcre2_compile() error numbers.

4. Added PCRE2_CALLOUT_STARTMATCH and PCRE2_CALLOUT_BACKTRACK bits to a new
field callout_flags in callout blocks.


Version 10.30 14-August-2017
----------------------------

The full list of changes that includes bugfixes and tidies is, as always, in
ChangeLog. These are the most important new features:

1. The main interpreter, pcre2_match(), has been refactored into a new version
that does not use recursive function calls (and therefore the system stack) for
remembering backtracking positions. This makes --disable-stack-for-recursion a
NOOP. The new implementation allows backtracking into recursive group calls in
patterns, making it more compatible with Perl, and also fixes some other
previously hard-to-do issues. For patterns that have a lot of backtracking, the
heap is now used, and there is an explicit limit on the amount, settable by
pcre2_set_heap_limit() or (*LIMIT_HEAP=xxx). The "recursion limit" is retained,
but is renamed as "depth limit" (though the old names remain for
compatibility).

There is also a change in the way callouts from pcre2_match() are handled. The
offset_vector field in the callout block is no longer a pointer to the
actual ovector that was passed to the matching function in the match data
block. Instead it points to an internal ovector of a size large enough to hold
all possible captured substrings in the pattern.

2. The new option PCRE2_ENDANCHORED insists that a pattern match must end at
the end of the subject.

3. The new option PCRE2_EXTENDED_MORE implements Perl's /xx feature, and
pcre2test is upgraded to support it. Setting within the pattern by (?xx) is
also supported.

4. (?n) can be used to set PCRE2_NO_AUTO_CAPTURE, because Perl now has this.

5. Additional compile options in the compile context are now available, and the
first two are: PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES and
PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL.

6. The newline type PCRE2_NEWLINE_NUL is now available.

7. The match limit value now also applies to pcre2_dfa_match() as there are
patterns that can use up a lot of resources without necessarily recursing very
deeply.

8. The option REG_PEND (a GNU extension) is now available for the POSIX
wrapper. Also there is a new option PCRE2_LITERAL which is used to support
REG_NOSPEC.

9. PCRE2_EXTRA_MATCH_LINE and PCRE2_EXTRA_MATCH_WORD are implemented for the
benefit of pcre2grep, and pcre2grep's -F, -w, and -x options are re-implemented
using PCRE2_LITERAL, PCRE2_EXTRA_MATCH_WORD, and PCRE2_EXTRA_MATCH_LINE. This
is tidier and also fixes some bugs.

10. The Unicode tables are upgraded from Unicode 8.0.0 to Unicode 10.0.0.

11. There are some experimental functions for converting foreign patterns
(globs and POSIX patterns) into PCRE2 patterns.


Version 10.23 14-February-2017
------------------------------

1. ChangeLog has the details of a lot of bug fixes and tidies.

2. There has been a major re-factoring of the pcre2_compile.c file. Most syntax
checking is now done in the pre-pass that identifies capturing groups. This has
reduced the amount of duplication and made the code tidier. While doing this,
some minor bugs and Perl incompatibilities were fixed (see ChangeLog for
details.)

3. Back references are now permitted in lookbehind assertions when there are
no duplicated group numbers (that is, (?| has not been used), and, if the
reference is by name, there is only one group of that name. The referenced
group must, of course be of fixed length.

4. \g{+<number>} (e.g. \g{+2} ) is now supported. It is a "forward back
reference" and can be useful in repetitions (compare \g{-<number>} ). Perl does
not recognize this syntax.

5. pcre2grep now automatically expands its buffer up to a maximum set by
--max-buffer-size.

6. The -t option (grand total) has been added to pcre2grep.

7. A new function called pcre2_code_copy_with_tables() exists to copy a
compiled pattern along with a private copy of the character tables that is
uses.

8. A user supplied a number of patches to upgrade pcre2grep under Windows and
tidy the code.

9. Several updates have been made to pcre2test and test scripts (see
ChangeLog).


Version 10.22 29-July-2016
--------------------------

1. ChangeLog has the details of a number of bug fixes.

2. The POSIX wrapper function regcomp() did not used to support back references
and subroutine calls if called with the REG_NOSUB option. It now does.

3. A new function, pcre2_code_copy(), is added, to make a copy of a compiled
pattern.

4. Support for string callouts is added to pcre2grep.

5. Added the PCRE2_NO_JIT option to pcre2_match().

6. The pcre2_get_error_message() function now returns with a negative error
code if the error number it is given is unknown.

7. Several updates have been made to pcre2test and test scripts (see
ChangeLog).


Version 10.21 12-January-2016
-----------------------------

1. Many bugs have been fixed. A large number of them were provoked only by very
strange pattern input, and were discovered by fuzzers. Some others were
discovered by code auditing. See ChangeLog for details.

2. The Unicode tables have been updated to Unicode version 8.0.0.

3. For Perl compatibility in EBCDIC environments, ranges such as a-z in a
class, where both values are literal letters in the same case, omit the
non-letter EBCDIC code points within the range.

4. There have been a number of enhancements to the pcre2_substitute() function,
giving more flexibility to replacement facilities. It is now also possible to
cause the function to return the needed buffer size if the one given is too
small.

5. The PCRE2_ALT_VERBNAMES option causes the "name" parts of special verbs such
as (*THEN:name) to be processed for backslashes and to take note of
PCRE2_EXTENDED.

6. PCRE2_INFO_HASBACKSLASHC makes it possible for a client to find out if a
pattern uses \C, and --never-backslash-C makes it possible to compile a version
PCRE2 in which the use of \C is always forbidden.

7. A limit to the length of pattern that can be handled can now be set by
calling pcre2_set_max_pattern_length().

8. When matching an unanchored pattern, a match can be required to begin within
a given number of code units after the start of the subject by calling
pcre2_set_offset_limit().

9. The pcre2test program has been extended to test new facilities, and it can
now run the tests when LF on its own is not a valid newline sequence.

10. The RunTest script has also been updated to enable more tests to be run.

11. There have been some minor performance enhancements.


Version 10.20 30-June-2015
--------------------------

1. Callouts with string arguments and the pcre2_callout_enumerate() function
have been implemented.

2. The PCRE2_NEVER_BACKSLASH_C option, which locks out the use of \C, is added.

3. The PCRE2_ALT_CIRCUMFLEX option lets ^ match after a newline at the end of a
subject in multiline mode.

4. The way named subpatterns are handled has been refactored. The previous
approach had several bugs.

5. The handling of \c in EBCDIC environments has been changed to conform to the
perlebcdic document. This is an incompatible change.

6. Bugs have been mended, many of them discovered by fuzzers.


Version 10.10 06-March-2015
---------------------------

1. Serialization and de-serialization functions have been added to the API,
making it possible to save and restore sets of compiled patterns, though
restoration must be done in the same environment that was used for compilation.

2. The (*NO_JIT) feature has been added; this makes it possible for a pattern
creator to specify that JIT is not to be used.

3. A number of bugs have been fixed. In particular, bugs that caused building
on Windows using CMake to fail have been mended.


Version 10.00 05-January-2015
-----------------------------

Version 10.00 is the first release of PCRE2, a revised API for the PCRE
library. Changes prior to 10.00 are logged in the ChangeLog file for the old
API, up to item 20 for release 8.36. New programs are recommended to use the
new library. Programs that use the original (PCRE1) API will need changing
before linking with the new library.

****
alt-pcre2/AUTHORS000064400000001330150410167000007374 0ustar00THE MAIN PCRE2 LIBRARY CODE
---------------------------

Written by:       Philip Hazel
Email local part: ph10
Email domain:     cam.ac.uk

University of Cambridge Computing Service,
Cambridge, England.

Copyright (c) 1997-2019 University of Cambridge
All rights reserved


PCRE2 JUST-IN-TIME COMPILATION SUPPORT
--------------------------------------

Written by:       Zoltan Herczeg
Email local part: hzmester
Emain domain:     freemail.hu

Copyright(c) 2010-2019 Zoltan Herczeg
All rights reserved.


STACK-LESS JUST-IN-TIME COMPILER
--------------------------------

Written by:       Zoltan Herczeg
Email local part: hzmester
Emain domain:     freemail.hu

Copyright(c) 2009-2019 Zoltan Herczeg
All rights reserved.

####
alt-pcre2/COPYING000064400000000141150410167000007356 0ustar00PCRE2 LICENCE

Please see the file LICENCE in the PCRE2 distribution for licensing details.

End
alt-pcre2/LICENCE000064400000006600150410167000007316 0ustar00PCRE2 LICENCE
-------------

PCRE2 is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.

Releases 10.00 and above of PCRE2 are distributed under the terms of the "BSD"
licence, as specified below, with one exemption for certain binary
redistributions. The documentation for PCRE2, supplied in the "doc" directory,
is distributed under the same terms as the software itself. The data in the
testdata directory is not copyrighted and is in the public domain.

The basic library functions are written in C and are freestanding. Also
included in the distribution is a just-in-time compiler that can be used to
optimize pattern matching. This is an optional feature that can be omitted when
the library is built.


THE BASIC LIBRARY FUNCTIONS
---------------------------

Written by:       Philip Hazel
Email local part: ph10
Email domain:     cam.ac.uk

University of Cambridge Computing Service,
Cambridge, England.

Copyright (c) 1997-2019 University of Cambridge
All rights reserved.


PCRE2 JUST-IN-TIME COMPILATION SUPPORT
--------------------------------------

Written by:       Zoltan Herczeg
Email local part: hzmester
Email domain:     freemail.hu

Copyright(c) 2010-2019 Zoltan Herczeg
All rights reserved.


STACK-LESS JUST-IN-TIME COMPILER
--------------------------------

Written by:       Zoltan Herczeg
Email local part: hzmester
Email domain:     freemail.hu

Copyright(c) 2009-2019 Zoltan Herczeg
All rights reserved.


THE "BSD" LICENCE
-----------------

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notices,
      this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notices, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    * Neither the name of the University of Cambridge nor the names of any
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.


EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES
------------------------------------------

The second condition in the BSD licence (covering binary redistributions) does
not apply all the way down a chain of software. If binary package A includes
PCRE2, it must respect the condition, but if package B is software that
includes package A, the condition is not imposed on package B unless it uses
PCRE2 independently.

End
alt-ruby22/COPYING.ja000064400000005100150411235440010066 0ustar00本プログラムはフリーソフトウェアです.2-clause BSDL
または以下に示す条件で本プログラムを再配布できます
2-clause BSDLについてはBSDLファイルを参照して下さい.

  1. 複製は制限なく自由です.

  2. 以下の条件のいずれかを満たす時に本プログラムのソースを
     自由に変更できます.

     (a) ネットニューズにポストしたり,作者に変更を送付する
         などの方法で,変更を公開する.

     (b) 変更した本プログラムを自分の所属する組織内部だけで
         使う.

     (c) 変更点を明示したうえ,ソフトウェアの名前を変更する.
         そのソフトウェアを配布する時には変更前の本プログラ
         ムも同時に配布する.または変更前の本プログラムのソー
         スの入手法を明示する.

     (d) その他の変更条件を作者と合意する.

  3. 以下の条件のいずれかを満たす時に本プログラムをコンパイ
     ルしたオブジェクトコードや実行形式でも配布できます.

     (a) バイナリを受け取った人がソースを入手できるように,
         ソースの入手法を明示する.

     (b) 機械可読なソースコードを添付する.

     (c) 変更を行ったバイナリは名前を変更したうえ,オリジナ
         ルのソースコードの入手法を明示する.

     (d) その他の配布条件を作者と合意する.

  4. 他のプログラムへの引用はいかなる目的であれ自由です.た
     だし,本プログラムに含まれる他の作者によるコードは,そ
     れぞれの作者の意向による制限が加えられる場合があります.

     それらファイルの一覧とそれぞれの配布条件などに付いては
     LEGALファイルを参照してください.

  5. 本プログラムへの入力となるスクリプトおよび,本プログラ
     ムからの出力の権利は本プログラムの作者ではなく,それぞ
     れの入出力を生成した人に属します.また,本プログラムに
     組み込まれるための拡張ライブラリについても同様です.

  6. 本プログラムは無保証です.作者は本プログラムをサポート
     する意志はありますが,プログラム自身のバグあるいは本プ
     ログラムの実行などから発生するいかなる損害に対しても責
     任を持ちません.
alt-ruby22/LEGAL000064400000062232150411235440007222 0ustar00LEGAL NOTICE INFORMATION
------------------------

All the files in this distribution are covered under either the Ruby's
license (see the file COPYING) or public-domain except some files
mentioned below.

ccan/build_assert/build_assert.h
ccan/check_type/check_type.h
ccan/container_of/container_of.h
ccan/str/str.h

  These files are licensed under the CC0.

    http://creativecommons.org/choose/zero/

ccan/list/list.h

  This file is licensed under the MIT License.

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.

include/ruby/oniguruma.h:
regcomp.c:
regenc.[ch]:
regerror.c:
regexec.c:
regint.h:
regparse.[ch]:
enc/ascii.c
enc/big5.c
enc/cp949.c
enc/emacs_mule.c
enc/encdb.c
enc/euc_jp.c
enc/euc_kr.c
enc/euc_tw.c
enc/gb18030.c
enc/gb2312.c
enc/gbk.c
enc/iso_8859_1.c
enc/iso_8859_10.c
enc/iso_8859_11.c
enc/iso_8859_13.c
enc/iso_8859_14.c
enc/iso_8859_15.c
enc/iso_8859_16.c
enc/iso_8859_2.c
enc/iso_8859_3.c
enc/iso_8859_4.c
enc/iso_8859_5.c
enc/iso_8859_6.c
enc/iso_8859_7.c
enc/iso_8859_8.c
enc/iso_8859_9.c
enc/koi8_r.c
enc/koi8_u.c
enc/shift_jis.c
enc/unicode.c
enc/us_ascii.c
enc/utf_16be.c
enc/utf_16le.c
enc/utf_32be.c
enc/utf_32le.c
enc/utf_8.c
enc/windows_1251.c

Oniguruma  ----   (C) K.Kosako <sndgk393 AT ybb DOT ne DOT jp>

http://www.geocities.jp/kosako3/oniguruma/
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/oniguruma/
http://www.freebsd.org/cgi/cvsweb.cgi/ports/devel/oniguruma/

   When this software is partly used or it is distributed with Ruby,
   this of Ruby follows the license of Ruby.

configure:

  This file is free software.

    Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.

    This configure script is free software; the Free Software Foundation
    gives unlimited permission to copy, distribute and modify it.

tool/config.guess:
tool/config.sub:

  As long as you distribute these files with the file configure, they
  are covered under the Ruby's license.

      Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
      Free Software Foundation, Inc.

    This file is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 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, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    As a special exception to the GNU General Public License, if you
    distribute this file as part of a program that contains a
    configuration script generated by Autoconf, you may include it under
    the same distribution terms that you use for the rest of that program.

parse.c:

  This file is licensed under the GPL, but is incorporated into Ruby and
  redistributed under the terms of the Ruby license, as permitted by the
  exception to the GPL below.

     Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
     Free Software Foundation, Inc.

     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2, or (at your option)
     any later version.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 51 Franklin Street, Fifth Floor,
     Boston, MA 02110-1301, USA.  */

  /* As a special exception, you may create a larger work that contains
     part or all of the Bison parser skeleton and distribute that work
     under terms of your choice, so long as that work isn't itself a
     parser generator using the skeleton or a modified version thereof
     as a parser skeleton.  Alternatively, if you modify or redistribute
     the parser skeleton itself, you may (at your option) remove this
     special exception, which will cause the skeleton and the resulting
     Bison output files to be licensed under the GNU General Public
     License without this special exception.

     This special exception was added by the Free Software Foundation in
     version 2.2 of Bison.  */

util.c (partly):

    Copyright (c) 1991, 2000, 2001 by Lucent Technologies.

    Permission to use, copy, modify, and distribute this software for any
    purpose without fee is hereby granted, provided that this entire notice
    is included in all copies of any software which is or includes a copy
    or modification of this software and in all copies of the supporting
    documentation for such software.

    THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
    WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
    REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
    OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.

win32/win32.[ch]:

  You can apply the Artistic License to these files. (or GPL,
  alternatively)

    Copyright (c) 1993, Intergraph Corporation

    You may distribute under the terms of either the GNU General Public
    License or the Artistic License, as specified in the perl README file.

util.c (partly):

   Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   SUCH DAMAGE.

random.c

  This file is under the new-style BSD license.

    A C-program for MT19937, with initialization improved 2002/2/10.
    Coded by Takuji Nishimura and Makoto Matsumoto.
    This is a faster version by taking Shawn Cokus's optimization,
    Matthe Bellew's simplification, Isaku Wada's real version.

    Before using, initialize the state by using init_genrand(seed)
    or init_by_array(init_key, key_length).

    Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

      1. Redistributions of source code must retain the above copyright
	 notice, this list of conditions and the following disclaimer.

      2. Redistributions in binary form must reproduce the above copyright
	 notice, this list of conditions and the following disclaimer in the
	 documentation and/or other materials provided with the distribution.

      3. The names of its contributors may not be used to endorse or promote
	 products derived from this software without specific prior written
	 permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


    Any feedback is very welcome.
    http://www.math.keio.ac.jp/matumoto/emt.html
    email: matumoto@math.keio.ac.jp

vm_dump.c:procstat_vm

 * Copyright (c) 2007 Robert N. M. Watson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: head/usr.bin/procstat/procstat_vm.c 261780 2014-02-11 21:57:37Z jhb $

vsnprintf.c:

  This file is under the old-style BSD license.  Note that the
  paragraph 3 below is now null and void.

    Copyright (c) 1990, 1993
         The Regents of the University of California.  All rights reserved.

    This code is derived from software contributed to Berkeley by
    Chris Torek.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
    3. Neither the name of the University nor the names of its contributors
       may be used to endorse or promote products derived from this software
       without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    SUCH DAMAGE.

    IMPORTANT NOTE:
    --------------
    From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
    paragraph 3 above is now null and void.

st.[ch]:
missing/alloca.c:
missing/dup2.c:
missing/erf.c:
missing/finite.c:
missing/hypot.c:
missing/isinf.c:
missing/isnan.c:
missing/lgamma_r.c:
missing/memcmp.c:
missing/memmove.c:
missing/strchr.c:
missing/strstr.c:
missing/strtol.c:
missing/tgamma.c:
ext/digest/sha1/sha1.[ch]:

  These files are all under public domain.

missing/crypt.c:

  This file is under the old-style BSD license.  Note that the
  paragraph 3 below is now null and void.

    Copyright (c) 1989, 1993
    	The Regents of the University of California.  All rights reserved.

    This code is derived from software contributed to Berkeley by
    Tom Truscott.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
    3. Neither the name of the University nor the names of its contributors
       may be used to endorse or promote products derived from this software
       without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    SUCH DAMAGE.

missing/setproctitle.c

  This file is under the old-style BSD license.  Note that the
  paragraph 3 below is now null and void.

    Copyright 2003 Damien Miller
    Copyright (c) 1983, 1995-1997 Eric P. Allman
    Copyright (c) 1988, 1993
    	The Regents of the University of California.  All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
    3. Neither the name of the University nor the names of its contributors
       may be used to endorse or promote products derived from this software
       without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    SUCH DAMAGE.

missing/strlcat.c
missing/strlcpy.c

  These files are under the new-style BSD license.

   Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
   3. The name of the author may not be used to endorse or promote products
      derived from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
   THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

missing/langinfo.c

  This file is from http://www.cl.cam.ac.uk/~mgk25/ucs/langinfo.c.
  Ruby uses a modified version. The file contains the following
  author/copyright notice:

  Markus.Kuhn@cl.cam.ac.uk -- 2002-03-11
  Permission to use, copy, modify, and distribute this software
  for any purpose and without fee is hereby granted. The author
  disclaims all warranties with regard to this software.

ext/digest/md5/md5.[ch]:

  These files are under the following license.  Ruby uses modified
  versions of them.

    Copyright (C) 1999, 2000 Aladdin Enterprises.  All rights reserved.

    This software is provided 'as-is', without any express or implied
    warranty.  In no event will the authors be held liable for any damages
    arising from the use of this software.

    Permission is granted to anyone to use this software for any purpose,
    including commercial applications, and to alter it and redistribute it
    freely, subject to the following restrictions:

    1. The origin of this software must not be misrepresented; you must not
       claim that you wrote the original software. If you use this software
       in a product, an acknowledgment in the product documentation would be
       appreciated but is not required.
    2. Altered source versions must be plainly marked as such, and must not be
       misrepresented as being the original software.
    3. This notice may not be removed or altered from any source distribution.

    L. Peter Deutsch
    ghost@aladdin.com

ext/digest/rmd160/rmd160.[ch]:

  These files have the following copyright information, and by the
  author we are allowed to use it under the new-style BSD license.

    AUTHOR:   Antoon Bosselaers, ESAT-COSIC
              (Arranged for libc by Todd C. Miller)
    DATE:     1 March 1996

    Copyright (c) Katholieke Universiteit Leuven
    1996, All Rights Reserved

ext/digest/sha2/sha2.[ch]:

  These files are under the new-style BSD license.

    Copyright 2000 Aaron D. Gifford.  All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of contributors
       may be used to endorse or promote products derived from this software
       without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    SUCH DAMAGE.

ext/nkf/nkf-utf8/config.h:
ext/nkf/nkf-utf8/nkf.c:
ext/nkf/nkf-utf8/utf8tbl.c:

  These files are under the following license.  So to speak, it is
  copyrighted semi-public-domain software.

    Copyright (C) 1987, Fujitsu LTD. (Itaru ICHIKAWA)
       Everyone is permitted to do anything on this program
       including copying, modifying, improving,
       as long as you don't try to pretend that you wrote it.
       i.e., the above copyright notice has to appear in all copies.
       Binary distribution requires original version messages.
       You don't have to ask before copying, redistribution or publishing.
       THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.

ext/socket/addrinfo.h:
ext/socket/getaddrinfo.c:
ext/socket/getnameinfo.c:

  These files are under the new-style BSD license.

    Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
    3. Neither the name of the project nor the names of its contributors
       may be used to endorse or promote products derived from this software
       without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    SUCH DAMAGE.

ext/win32ole/win32ole.c:

  You can apply the Artistic License to this file. (or GPL,
  alternatively)

    (c) 1995 Microsoft Corporation. All rights reserved.
    Developed by ActiveWare Internet Corp., http://www.ActiveWare.com

    Other modifications Copyright (c) 1997, 1998 by Gurusamy Sarathy
    <gsar@umich.edu> and Jan Dubois <jan.dubois@ibm.net>

    You may distribute under the terms of either the GNU General Public
    License or the Artistic License, as specified in the README file
    of the Perl distribution.
alt-ruby22/BSDL000064400000002402150411235440007113 0ustar00Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
alt-ruby22/COPYING000064400000004710150411235440007503 0ustar00Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
You can redistribute it and/or modify it under either the terms of the
2-clause BSDL (see the file BSDL), or the conditions below:

  1. You may make and give away verbatim copies of the source form of the
     software without restriction, provided that you duplicate all of the
     original copyright notices and associated disclaimers.

  2. You may modify your copy of the software in any way, provided that
     you do at least ONE of the following:

       a) place your modifications in the Public Domain or otherwise
          make them Freely Available, such as by posting said
	  modifications to Usenet or an equivalent medium, or by allowing
	  the author to include your modifications in the software.

       b) use the modified software only within your corporation or
          organization.

       c) give non-standard binaries non-standard names, with
          instructions on where to get the original software distribution.

       d) make other distribution arrangements with the author.

  3. You may distribute the software in object code or binary form,
     provided that you do at least ONE of the following:

       a) distribute the binaries and library files of the software,
	  together with instructions (in the manual page or equivalent)
	  on where to get the original distribution.

       b) accompany the distribution with the machine-readable source of
	  the software.

       c) give non-standard binaries non-standard names, with
          instructions on where to get the original software distribution.

       d) make other distribution arrangements with the author.

  4. You may modify and include the part of the software into any other
     software (possibly commercial).  But some files in the distribution
     are not written by the author, so that they are not under these terms.

     For the list of those files and their copying conditions, see the
     file LEGAL.

  5. The scripts and library files supplied as input to or produced as 
     output from the software do not automatically fall under the
     copyright of the software, but belong to whomever generated them, 
     and may be sold commercially, and may be aggregated with this
     software.

  6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE.
alt-ruby22/GPL000064400000043254150411235440007023 0ustar00                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  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
this service 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 make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  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.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the 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 a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE 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.

                     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
convey 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 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision 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, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This 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.
alt-ruby22-rubygems/LICENSE.txt000064400000004331150411235440012125 0ustar00RubyGems is copyrighted free software by Chad Fowler, Rich Kilmer, Jim
Weirich and others.  You can redistribute it and/or modify it under
either the terms of the MIT license (see the file MIT.txt), or the
conditions below:

1. You may make and give away verbatim copies of the source form of the
   software without restriction, provided that you duplicate all of the
   original copyright notices and associated disclaimers.

2. You may modify your copy of the software in any way, provided that
   you do at least ONE of the following:

   a. place your modifications in the Public Domain or otherwise
      make them Freely Available, such as by posting said
      modifications to Usenet or an equivalent medium, or by allowing
      the author to include your modifications in the software.

   b. use the modified software only within your corporation or
      organization.

   c. give non-standard executables non-standard names, with
      instructions on where to get the original software distribution.

   d. make other distribution arrangements with the author.

3. You may distribute the software in object code or executable
   form, provided that you do at least ONE of the following:

   a. distribute the executables and library files of the software,
      together with instructions (in the manual page or equivalent)
      on where to get the original distribution.

   b. accompany the distribution with the machine-readable source of
      the software.

   c. give non-standard executables non-standard names, with
      instructions on where to get the original software distribution.

   d. make other distribution arrangements with the author.

4. You may modify and include the part of the software into any other
   software (possibly commercial).

5. The scripts and library files supplied as input to or produced as
   output from the software do not automatically fall under the
   copyright of the software, but belong to whomever generated them,
   and may be sold commercially, and may be aggregated with this
   software.

6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   PURPOSE.

pear/Structures_LinkedList/CHANGELOG000064400000001737150413447410013225 0ustar000.2.1
* Apply patch from Bertrand Zuchuat to avoid inheritance strictness alerts

0.2.0
* Adhere to CS (thanks PHP_CodeSniffer!)
* Fix docblocks for Double vs. Single confusion
* One change to API in that the protected method _getTailNode() has been renamed to getTailNode() per CS

0.0.8
* Add destructors to avoid holding onto way too much memory

0.0.7
* Correct examples
* Convert to PEAR_Exception for error handling

0.0.6

0.0.5
* Create a singly linked list (Structures_LinkedList_Single)
* Refactor Structures_LinkedList_Double to extend _Single

0.0.4
* Move most globals into class constants

0.0.3
* Separate addNode method into insertNode, appendNode, prependNode
* Prevent current node from becoming invalid when adding a new node
* Type hinting and avoiding moving current pointer with addNode()

0.0.2
* Implement basic error-handling using PEAR_ErrorStack
* Adjust "link" terminology and API to "node"

0.0.1
* First attempt at a separate package for Structures_Linked_List
pear/Structures_LinkedList/examples/single_link_example.php000064400000005270150413447420020350 0ustar00<?php

require 'Structures/LinkedList/Single.php';

/* To do anything useful with a linked list, you need to
 * extend the Node class to hold data associated with the
 * node. In this case, we're just going to hold a single
 * integer in the $_my_number property.
 */
class LinkNodeTester extends Structures_LinkedList_SingleNode {
    protected $_my_number;
    protected $_my_letter;

    function __construct($num, $letter) {
        $this->_my_number = $num;
        $this->_my_letter = $letter;
    }

    function getNumber() {
        return $this->_my_number;
    }

    function getLetter() {
        return $this->_my_letter;
    }

    function setNumb($numb) {
        $this->_my_number = $numb;
    }

    function __toString() {
        return "{$this->getNumber()}";
    }
}

/* To enable key=>value iteration, we must override the default key()
 * method in Structures_LinkedList_Single to return a meaningful value */
class LinkListTester extends Structures_LinkedList_Single {
    function key() {
        return $this->current()->getLetter();
    }
}

/* Now we'll create some instances of the new class */
$node1 = new LinkNodeTester(1, 'a');
$node2 = new LinkNodeTester(2, 'b');
$node3 = new LinkNodeTester(3, 'c');
$node4 = new LinkNodeTester(4, 'd');
$node5 = new LinkNodeTester(5, 'e');

/* Start by instantiating a list object.
 * You can either pass the first node to the constructor,
 * or leave it null and add nodes later.
 */
$list = new LinkListTester($node1); // 1

/* appendNode() adds a node to the end of the list */
$list->appendNode($node2); // 1-2

/* prependNode() adds a node to the start of the list */
$list->prependNode($node3); // 3-1-2

/* insertNode($new_node, $reference_node, $before) adds a node
 * before the reference node if the third parameter is true,
 * or after the reference node if the third parameter is false
 */
$list->insertNode($node4, $node2, true); // 3-1-4-2

/* current() returns the current pointer node in the list */
$link = $list->current(); // 1

/* You can iterate through a list with the next() method */
do {
    print $link->getNumber();
} while ($link = $list->next()); // 1-4-2

/* rewind() resets the pointer to the root node of the list */
$link = $list->rewind(); // 3

/* You can also iterate through a list with foreach() */
foreach ($list as $bull) {
  print $bull->getNumber();
} // 3-1-4-2

/* Override the key() method to enable $key=>$value iteration */
foreach ($list as $key=>$value) {
  print "$key => $value\n";
}

/* end() resets the pointer to the last node of the list */
$link = $list->end(); // 2

/* You can iterate backwards through a list with previous() */
do {
    print $link->getNumber();
} while ($link = $list->previous()); // 2-4-1-3
?>
pear/Structures_LinkedList/examples/double_link_example.php000064400000005574150413447420020350 0ustar00<?php

require 'Structures/LinkedList/Double.php';

/* To do anything useful with a linked list, you need to
 * extend the Node class to hold data associated with the
 * node. In this case, we're just going to hold a single
 * integer in the $_my_number property.
 */
class LinkNodeTester extends Structures_LinkedList_DoubleNode {
    protected $_my_number;
    protected $_my_letter;

    function __construct($number, $letter) {
        $this->_my_number = $number;
        $this->_my_letter = $letter;
    }

    function getNumber() {
        return $this->_my_number;
    }

    function getLetter() {
        return $this->_my_letter;
    }

    function setNumb($number) {
        $this->_my_number = $number;
    }

    function __toString() {
        return "{$this->getNumber()}";
    }
}

/* To enable key=>value iteration, we must override the default key()
 * method in Structures_LinkedList_Double to return a meaningful value */
class LinkListTester extends Structures_LinkedList_Double {
    function key() {
        return $this->current()->getLetter();
    }
}

/* Now we'll create some instances of the new class */
$node1 = new LinkNodeTester(1, 'a');
$node2 = new LinkNodeTester(2, 'b');
$node3 = new LinkNodeTester(3, 'c');
$node4 = new LinkNodeTester(4, 'd');
$node5 = new LinkNodeTester(5, 'e');

/* Start by instantiating a list object.
 * You can either pass the first node to the constructor,
 * or leave it null and add nodes later.
 */
$list = new LinkListTester($node1); // 1

/* appendNode() adds a node to the end of the list */
$list->appendNode($node2);                        // 1-2

/* prependNode() adds a node to the start of the list */
$list->prependNode($node3);                       // 3-1-2

/* insertNode($new_node, $reference_node, $before) adds a node
 * before the reference node if the third parameter is true,
 * or after the reference node if the third parameter is false
 */
$list->insertNode($node4, $node1);              // 3-1-4-2
$list->insertNode($node5, $node1, true);        // 3-5-1-4-2

/* current() returns the current pointer node in the list */
$link = $list->current();
print $link->getNumber(); // "1"

/* rewind() resets the pointer to the root node of the list */
$link = $list->rewind();
print $link->getNumber(); // "3"

// iterate through the list with do...while()
do {
    print $link->getNumber();
} while ($link = $list->next()); // "35142"

/* You can also iterate through a list with foreach() */
foreach ($list as $bull) {
  print $bull->getNumber();
} // 3-1-4-2

/* Override the key() method to enable $key=>$value iteration */
foreach ($list as $key=>$value) {
  print "$key => $value\n";
}

/* end() resets the pointer to the last node of the list */
$link = $list->end();
print $link->getNumber(); // "2"

/* You can iterate backwards through a list with previous() */
do {
    print $link->getNumber();
} while ($link = $list->previous()); // "24153"

?>
pear/Structures_LinkedList/LICENSE000064400000026136150413447420013021 0ustar00
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
pear/Mail/LICENSE000064400000002742150413447420007373 0ustar00Copyright (c) 1997-2017, Chuck Hagenbuch
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pear/Net_Socket/README.md000064400000001753150413447430011023 0ustar00# Net_Socket - Network Socket Interface

[![Build Status](https://travis-ci.org/pear/Net_Socket.svg?branch=master)](https://travis-ci.org/pear/Net_Socket)
    

Net_Socket is a class interface to TCP sockets. It provides blocking
and non-blocking operation, with different reading and writing modes
(byte-wise, block-wise, line-wise and special formats like network
byte-order ip addresses).

[Homepage](http://pear.php.net/package/Net_Socket/)


## Installation
For a PEAR installation that downloads from the PEAR channel:

`$ pear install pear/net_socket`

For a PEAR installation from a previously downloaded tarball:

`$ pear install Net_Socket-*.tgz`

For a PEAR installation from a code clone:

`$ pear install package.xml`

For a local composer installation:

`$ composer install`

To add as a dependency to your composer-managed application:

`$composer require pear/net_socket`


## Tests
Run  the tests from a local composer installation:

`$ ./vendor/bin/phpunit`


## License
BSD-2 license
pear/Net_Socket/LICENSE000064400000002367150413447430010553 0ustar00Copyright 1997-2017 The PHP Group

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pear/Structures_Graph/LICENSE000064400000016725150413447430012024 0ustar00		   GNU LESSER 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.


  This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.

  0. Additional Definitions.

  As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.

  "The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.

  An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.

  A "Combined Work" is a work produced by combining or linking an
Application with the Library.  The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".

  The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.

  The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.

  1. Exception to Section 3 of the GNU GPL.

  You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.

  2. Conveying Modified Versions.

  If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:

   a) under this License, provided that you make a good faith effort to
   ensure that, in the event an Application does not supply the
   function or data, the facility still operates, and performs
   whatever part of its purpose remains meaningful, or

   b) under the GNU GPL, with none of the additional permissions of
   this License applicable to that copy.

  3. Object Code Incorporating Material from Library Header Files.

  The object code form of an Application may incorporate material from
a header file that is part of the Library.  You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:

   a) Give prominent notice with each copy of the object code that the
   Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the object code with a copy of the GNU GPL and this license
   document.

  4. Combined Works.

  You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:

   a) Give prominent notice with each copy of the Combined Work that
   the Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the Combined Work with a copy of the GNU GPL and this license
   document.

   c) For a Combined Work that displays copyright notices during
   execution, include the copyright notice for the Library among
   these notices, as well as a reference directing the user to the
   copies of the GNU GPL and this license document.

   d) Do one of the following:

       0) Convey the Minimal Corresponding Source under the terms of this
       License, and the Corresponding Application Code in a form
       suitable for, and under terms that permit, the user to
       recombine or relink the Application with a modified version of
       the Linked Version to produce a modified Combined Work, in the
       manner specified by section 6 of the GNU GPL for conveying
       Corresponding Source.

       1) Use a suitable shared library mechanism for linking with the
       Library.  A suitable mechanism is one that (a) uses at run time
       a copy of the Library already present on the user's computer
       system, and (b) will operate properly with a modified version
       of the Library that is interface-compatible with the Linked
       Version.

   e) Provide Installation Information, but only if you would otherwise
   be required to provide such information under section 6 of the
   GNU GPL, and only to the extent that such information is
   necessary to install and execute a modified version of the
   Combined Work produced by recombining or relinking the
   Application with a modified version of the Linked Version. (If
   you use option 4d0, the Installation Information must accompany
   the Minimal Corresponding Source and Corresponding Application
   Code. If you use option 4d1, you must provide the Installation
   Information in the manner specified by section 6 of the GNU GPL
   for conveying Corresponding Source.)

  5. Combined Libraries.

  You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:

   a) Accompany the combined library with a copy of the same work based
   on the Library, uncombined with any other library facilities,
   conveyed under the terms of this License.

   b) Give prominent notice with the combined library that part of it
   is a work based on the Library, and explaining where to find the
   accompanying uncombined form of the same work.

  6. Revised Versions of the GNU Lesser General Public License.

  The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser 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
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.

  If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
pear/Structures_Graph/docs/tutorials/Structures_Graph/Structures_Graph.pkg000064400000007714150413447440023307 0ustar00<refentry id="{@id package.database.structures_graph.tutorial}">
 <refnamediv>
  <refname><classname>Structures_Graph</classname> Tutorial</refname>
  <refpurpose>A first tour of graph datastructure manipulation</refpurpose>
 </refnamediv>
 <refsect1 id="{@id package.database.structures_graph.tutorial.intro}">
  <title>Introduction</title>
  <para>
  Structures_Graph is a package for creating and manipulating graph datastructures. A graph is a set of objects, called nodes, connected by arcs. When used as a datastructure, usually nodes contain data, and arcs represent relationships between nodes. When arcs have a direction, and can be travelled only one way, graphs are said to be directed. When arcs have no direction, and can always be travelled both ways, graphs are said to be non directed.
  </para>
  <para>
  Structures_Graph provides an object oriented API to create and directly query a graph, as well as a set of Manipulator classes to extract information from the graph.
  </para>
 </refsect1>
 <refsect1 id="{@id package.database.structures_graph.tutorial.creation}">
  <title>Creating a Graph</title>
  <para>
   Creating a graph is done using the simple constructor:
   <programlisting>
    <![CDATA[
require_once 'Structures/Graph.php';

$directedGraph =& new Structures_Graph(true);
$nonDirectedGraph =& new Structures_Graph(false);
    ]]>
   </programlisting>
   and passing the constructor a flag telling it whether the graph should be directed. A directed graph will always be directed during its lifetime. It's a permanent characteristic.
  </para>
  <para>
  To fill out the graph, we'll need to create some nodes, and then call Graph::addNode.
   <programlisting>
    <![CDATA[
require_once 'Structures/Graph/Node.php';

$nodeOne =& new Structures_Graph_Node();
$nodeTwo =& new Structures_Graph_Node();
$nodeThree =& new Structures_Graph_Node();

$directedGraph->addNode(&$nodeOne);
$directedGraph->addNode(&$nodeTwo);
$directedGraph->addNode(&$nodeThree);
    ]]>
   </programlisting>
   and then setup the arcs:
   <programlisting>
    <![CDATA[
$nodeOne->connectTo($nodeTwo);
$nodeOne->connectTo($nodeThree);
    ]]>
   </programlisting>
   Note that arcs can only be created after the nodes have been inserted into the graph. 
  </para>
 </refsect1>
 <refsect1 id="{@id package.database.structures_graph.tutorial.nodesanddata}">
  <title>Associating Data</title>
  <para>
  Graphs are only useful as datastructures if they can hold data. Structure_Graph stores data in nodes. Each node contains a setter and a getter for its data.
   <programlisting>
    <![CDATA[
$nodeOne->setData("Node One's Data is a String");
$nodeTwo->setData(1976);
$nodeThree->setData('Some other string');

print("NodeTwo's Data is an integer: " . $nodeTwo->getData());
    ]]>
   </programlisting>
  </para>
  <para>
  Structure_Graph nodes can also store metadata, alongside with the main data. Metadata differs from regular data just because it is stored under a key, making it possible to store more than one data reference per node. The metadata getter and setter need the key to perform the operation:
   <programlisting>
    <![CDATA[
$nodeOne->setMetadata('example key', "Node One's Sample Metadata");
print("Metadata stored under key 'example key' in node one: " . $nodeOne->getMetadata('example key'));
$nodeOne->unsetMetadata('example key');
    ]]>
   </programlisting>
  </para>
 </refsect1>
 <refsect1 id="{@id package.database.structures_graph.tutorial.querying}">
  <title>Querying a Graph</title>
  <para>
  Structures_Graph provides for basic querying of the graph:
   <programlisting>
    <![CDATA[
// Nodes are able to calculate their indegree and outdegree
print("NodeOne's inDegree: " . $nodeOne->inDegree());
print("NodeOne's outDegree: " . $nodeOne->outDegree());

// and naturally, nodes can report on their arcs
$arcs = $nodeOne->getNeighbours();
for ($i=0;$i<sizeof($arcs);$i++) {
    print("NodeOne has an arc to " . $arcs[$i]->getData());
}
    ]]>
   </programlisting>
  </para>
 </refsect1>
</refentry>
pear/PEAR/INSTALL000064400000004170150413447440007263 0ustar00PEAR - The PEAR Installer
=========================
Installing the PEAR Installer.

You should install PEAR on a local development machine first.  Installing
PEAR on a remote production machine should only be done after you are
familiar with PEAR and have tested code using PEAR on your development
machine.

There are two methods of installing PEAR
 - PEAR bundled in PHP
 - go-pear

We will first examine how to install PEAR that is bundled with PHP.

Microsoft Windows
=================
If you are running PHP 5.2.0 or newer, simply download and
run the windows installer (.msi) and PEAR can be automatically
installed.

Otherwise, for older PHP versions, download the .zip of windows,
there is a script included with your PHP distribution that is called
"go-pear".  You must open a command box in order to run it.  Click
"start" then click "Run..." and type "cmd.exe" to open a command box.
Use "cd" to change directory to the location of PHP where you unzipped it,
and run the go-pear command.

Unix
====
When compiling PHP from source, you simply need to include the
--with-pear directive on the "./configure" command.  This is "on"
by default in most PHP versions, but it doesn't hurt to list it
explicitly.  You should also consider enabling the zlib extension via
--enable-zlib, so that the PEAR installer will be able to handle gzipped
files (i.e. smaller package files for faster downloads).  Later, when you
run "make install" to install PHP itself, part of the process will be
prompts that ask you where you want PEAR to be installed.

go-pear
=======
For users who cannot perform the above steps, or who wish to obtain the
latest PEAR with a slightly higher risk of failure, use go-pear.  go-pear
is obtained by downloading http://pear.php.net/go-pear and saving it as go-pear.php.
After downloading, simply run "php go-pear.php" or open it in a web browser
(windows only) to download and install PEAR.

You can always ask general installation questions on pear-general@lists.php.net,
a public mailing list devoted to support for PEAR packages and installation-
related issues.

Happy PHPing, we hope PEAR will be a great tool for your development work!
pear/PEAR/README.rst000064400000004342150413447450007723 0ustar00*************************
PEAR - The PEAR Installer
*************************
.. image:: https://travis-ci.org/pear/pear-core.svg?branch=stable
    :target: https://travis-ci.org/pear/pear-core

=========================================
What is the PEAR Installer? What is PEAR?
=========================================
PEAR is the PHP Extension and Application Repository, found at
http://pear.php.net.

The **PEAR Installer** is this software, which contains executable
files and PHP code that is used to **download and install** PEAR code
from pear.php.net.

PEAR contains useful **software libraries and applications** such as
MDB2 (database abstraction), HTML_QuickForm (HTML forms management),
PhpDocumentor (auto-documentation generator), DB_DataObject
(Data Access Abstraction), and many hundreds more.
Browse all available packages at http://pear.php.net, the list is
constantly growing and updating to reflect improvements in the PHP language.

.. warning::
  Do not run PEAR without installing it - if you downloaded this
  tarball manually, you MUST install it.  Read the instructions in INSTALL
  prior to use.


=============
Documentation
=============
Documentation for PEAR can be found at http://pear.php.net/manual/.
Installation documentation can be found in the INSTALL file included
in this tarball.


=====
Tests
=====
Run the tests without installation as follows::

  $ ./scripts/pear.sh run-tests -r tests

You should have the ``Text_Diff`` package installed to get nicer error output.

To run the tests with another PHP version, modify ``php_bin`` and set the
``PHP_PEAR_PHP_BIN`` environment variable::

  $ pear config-set php_bin /usr/local/bin/php7
  $ PHP_PEAR_PHP_BIN=/usr/local/bin/php7 ./scripts/pear.sh run-tests -r tests

Happy PHPing, we hope PEAR will be a great tool for your development work!


Test dependencies
=================
* ``zlib``


=========
Releasing
=========
Create a PEAR package, as well as phars for pear-less installation,
simply run ``build-release.sh``).

``go-pear.phar`` contains the PEAR installer installer that asks where to install it.
It is available from http://pear.php.net/go-pear.phar.

``install-pear-nozlib.phar`` installs PEAR automatically without asking anything.
It is shipped with PHP itself.
pear/PEAR/LICENSE000064400000002705150413447450007242 0ustar00Copyright (c) 1997-2009,
 Stig Bakken <ssb@php.net>,
 Gregory Beaver <cellog@php.net>,
 Helgi Þormar Þorbjörnsson <helgi@php.net>,
 Tomas V.V.Cox <cox@idecnet.com>,
 Martin Jansen <mj@php.net>.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pear/Archive_Tar/docs/Archive_Tar.txt000064400000045246150413447450013564 0ustar00Documentation for class Archive_Tar
===================================
Last update : 2001-08-15



Overview :
----------

  The Archive_Tar class helps in creating and managing GNU TAR format
  files compressed by GNU ZIP or not. 
  The class offers basic functions like creating an archive, adding
  files in the archive, extracting files from the archive and listing
  the archive content. 
  It also provide advanced functions that allow the adding and
  extraction of files with path manipulation. 


Sample :
--------

  // ----- Creating the object (uncompressed archive)
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object->setErrorHandling(PEAR_ERROR_PRINT);

  // ----- Creating the archive
  $v_list[0]="file.txt";
  $v_list[1]="data/";
  $v_list[2]="file.log";
  $tar_object->create($v_list);

  // ----- Adding files
  $v_list[0]="dev/file.txt";
  $v_list[1]="dev/data/";
  $v_list[2]="log/file.log";
  $tar_object->add($v_list);

  // ----- Adding more files
  $tar_object->add("release/newfile.log release/readme.txt");

  // ----- Listing the content
  if (($v_list  =  $tar_object->listContent()) != 0)
    for ($i=0; $i<sizeof($v_list); $i++)
    {
      echo "Filename :'".$v_list[$i][filename]."'<br>";
      echo " .size :'".$v_list[$i][size]."'<br>";
      echo " .mtime :'".$v_list[$i][mtime]."' (".date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")<br>";
      echo " .mode :'".$v_list[$i][mode]."'<br>";
      echo " .uid :'".$v_list[$i][uid]."'<br>";
      echo " .gid :'".$v_list[$i][gid]."'<br>";
      echo " .typeflag :'".$v_list[$i][typeflag]."'<br>";
    }

  // ----- Extracting the archive in directory "install"
  $tar_object->extract("install");


Public arguments :
------------------

None


Public Methods :
----------------

Method : Archive_Tar($p_tarname, $compress = null)
Description :
  Archive_Tar Class constructor. This flavour of the constructor only
  declare a new Archive_Tar object, identifying it by the name of the
  tar file.
  If the compress argument is set the tar will be read or created as a
  gzip or bz2 compressed TAR file. 
Arguments :
  $p_tarname : A valid filename for the tar archive file.
  $p_compress : can be null, 'gz' or 'bz2'. For
                compatibility reason it can also be true. This
                parameter indicates if gzip or bz2 compression
                is required. 
Return value :
  The Archive_Tar object.
Sample :
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object_compressed = new Archive_Tar("tarname.tgz", true);
How it works :
  Initialize the object.

Method : create($p_filelist)
Description :
  This method creates the archive file and add the files / directories
  that are listed in $p_filelist. 
  If the file already exists and is writable, it is replaced by the
  new tar. It is a create and not an add. If the file exists and is
  read-only or is a directory it is not replaced. The method return
  false and a PEAR error text. 
  The $p_filelist parameter can be an array of string, each string
  representing a filename or a directory name with their path if
  needed. It can also be a single string with names separated by a
  single blank. 
  See also createModify() method for more details.
Arguments :
  $p_filelist : An array of filenames and directory names, or a single
  string with names separated by a single blank space. 
Return value :
  true on success, false on error.
Sample 1 :
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  $v_list[0]="file.txt";
  $v_list[1]="data/"; (Optional '/' at the end)
  $v_list[2]="file.log";
  $tar_object->create($v_list);
Sample 2 :
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  $tar_object->create("file.txt data/ file.log");
How it works :
  Just calling the createModify() method with the right parameters.

Method : createModify($p_filelist, $p_add_dir, $p_remove_dir = "")
Description :
  This method creates the archive file and add the files / directories
  that are listed in $p_filelist. 
  If the file already exists and is writable, it is replaced by the
  new tar. It is a create and not an add. If the file exists and is
  read-only or is a directory it is not replaced. The method return
  false and a PEAR error text. 
  The $p_filelist parameter can be an array of string, each string
  representing a filename or a directory name with their path if
  needed. It can also be a single string with names separated by a
  single blank. 
  The path indicated in $p_remove_dir will be removed from the
  memorized path of each file / directory listed when this path
  exists. By default nothing is removed (empty path "") 
  The path indicated in $p_add_dir will be added at the beginning of
  the memorized path of each file / directory listed. However it can
  be set to empty "". The adding of a path is done after the removing
  of path. 
  The path add/remove ability enables the user to prepare an archive
  for extraction in a different path than the origin files are. 
  See also addModify() method for file adding properties.
Arguments :
  $p_filelist : An array of filenames and directory names, or a single
                string with names separated by a single blank space.
  $p_add_dir : A string which contains a path to be added to the
               memorized path of each element in the list. 
  $p_remove_dir : A string which contains a path to be removed from
                  the memorized path of each element in the list, when
		  relevant.
Return value :
  true on success, false on error.
Sample 1 :
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  $v_list[0]="file.txt";
  $v_list[1]="data/"; (Optional '/' at the end)
  $v_list[2]="file.log";
  $tar_object->createModify($v_list, "install");
  // files are stored in the archive as :
  //   install/file.txt
  //   install/data
  //   install/data/file1.txt
  //   install/data/... all the files and sub-dirs of data/
  //   install/file.log
Sample 2 :
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  $v_list[0]="dev/file.txt";
  $v_list[1]="dev/data/"; (Optional '/' at the end)
  $v_list[2]="log/file.log";
  $tar_object->createModify($v_list, "install", "dev");
  // files are stored in the archive as :
  //   install/file.txt
  //   install/data
  //   install/data/file1.txt
  //   install/data/... all the files and sub-dirs of data/
  //   install/log/file.log
How it works :
  Open the file in write mode (erasing the existing one if one),
  call the _addList() method for adding the files in an empty archive,
  add the tar footer (512 bytes block), close the tar file.


Method : addModify($p_filelist, $p_add_dir, $p_remove_dir="")
Description :
  This method add the files / directories listed in $p_filelist at the
  end of the existing archive. If the archive does not yet exists it
  is created.
  The $p_filelist parameter can be an array of string, each string
  representing a filename or a directory name with their path if
  needed. It can also be a single string with names separated by a
  single blank. 
  The path indicated in $p_remove_dir will be removed from the
  memorized path of each file / directory listed when this path
  exists. By default nothing is removed (empty path "") 
  The path indicated in $p_add_dir will be added at the beginning of
  the memorized path of each file / directory listed. However it can
  be set to empty "". The adding of a path is done after the removing
  of path. 
  The path add/remove ability enables the user to prepare an archive
  for extraction in a different path than the origin files are. 
  If a file/dir is already in the archive it will only be added at the
  end of the archive. There is no update of the existing archived
  file/dir. However while extracting the archive, the last file will
  replace the first one. This results in a none optimization of the
  archive size. 
  If a file/dir does not exist the file/dir is ignored. However an
  error text is send to PEAR error. 
  If a file/dir is not readable the file/dir is ignored. However an
  error text is send to PEAR error. 
  If the resulting filename/dirname (after the add/remove option or
  not) string is greater than 99 char, the file/dir is
  ignored. However an error text is send to PEAR error. 
Arguments :
  $p_filelist : An array of filenames and directory names, or a single
                string with names separated by a single blank space. 
  $p_add_dir : A string which contains a path to be added to the
               memorized path of each element in the list. 
  $p_remove_dir : A string which contains a path to be removed from
                  the memorized path of each element in the list, when
		  relevant.
Return value :
  true on success, false on error.
Sample 1 :
  $tar_object = new Archive_Tar("tarname.tar");
  [...]
  $v_list[0]="dev/file.txt";
  $v_list[1]="dev/data/"; (Optional '/' at the end)
  $v_list[2]="log/file.log";
  $tar_object->addModify($v_list, "install");
  // files are stored in the archive as :
  //   install/file.txt
  //   install/data
  //   install/data/file1.txt
  //   install/data/... all the files and sub-dirs of data/
  //   install/file.log
Sample 2 :
  $tar_object = new Archive_Tar("tarname.tar");
  [...]
  $v_list[0]="dev/file.txt";
  $v_list[1]="dev/data/"; (Optional '/' at the end)
  $v_list[2]="log/file.log";
  $tar_object->addModify($v_list, "install", "dev");
  // files are stored in the archive as :
  //   install/file.txt
  //   install/data
  //   install/data/file1.txt
  //   install/data/... all the files and sub-dirs of data/
  //   install/log/file.log
How it works :
  If the archive does not exists it create it and add the files.
  If the archive does exists and is not compressed, it open it, jump
  before the last empty 512 bytes block (tar footer) and add the files
  at this point.
  If the archive does exists and is compressed, a temporary copy file
  is created. This temporary file is then 'gzip' read block by block
  until the last empty block. The new files are then added in the
  compressed file.
  The adding of files is done by going through the file/dir list,
  adding files per files, in a recursive way through the
  directory. Each time a path need to be added/removed it is done
  before writing the file header in the archive.

Method : add($p_filelist)
Description :
  This method add the files / directories listed in $p_filelist at the
  end of the existing archive. If the archive does not yet exists it
  is created. 
  The $p_filelist parameter can be an array of string, each string
  representing a filename or a directory name with their path if
  needed. It can also be a single string with names separated by a
  single blank. 
  See addModify() method for details and limitations.
Arguments :
  $p_filelist : An array of filenames and directory names, or a single
  string with names separated by a single blank space. 
Return value :
  true on success, false on error.
Sample 1 :
  $tar_object = new Archive_Tar("tarname.tar");
  [...]
  $v_list[0]="dev/file.txt";
  $v_list[1]="dev/data/"; (Optional '/' at the end)
  $v_list[2]="log/file.log";
  $tar_object->add($v_list);
Sample 2 :
  $tar_object = new Archive_Tar("tarname.tgz", true);
  [...]
  $v_list[0]="dev/file.txt";
  $v_list[1]="dev/data/"; (Optional '/' at the end)
  $v_list[2]="log/file.log";
  $tar_object->add($v_list);
How it works :
  Simply call the addModify() method with the right parameters.

Method : addString($p_filename, $p_string, $p_datetime, $p_params)
Description :
  This method add a single string as a file at the
  end of the existing archive. If the archive does not yet exists it
  is created.
Arguments :
  $p_filename : A string which contains the full filename path
                that will be associated with the string.
  $p_string :   The content of the file added in the archive.
  $p_datetime : (Optional) Timestamp of the file (default = now)
  $p_params :   (Optional) Various file metadata:
                    stamp - As above, timestamp of the file
                    mode - UNIX-style permissions (default 0600)
                    type - Is this a regular file or link (see TAR
                           format spec for how to create a hard/symlink)
                    uid - UNIX-style user ID (default 0 = root)
                    gid - UNIX-style group ID (default 0 = root)
Return value :
  true on success, false on error.
Sample 1 :
  $v_archive = & new Archive_Tar($p_filename);
  $v_archive->setErrorHandling(PEAR_ERROR_PRINT);
  $v_result = $v_archive->addString('data/test.txt', 'This is the text of the string');
  $v_result = $v_archive->addString(
                  'data/test.sh',
                  "#!/bin/sh\necho 'Hello'",
                  time(),
                  array( "mode" => 0755, "uid" => 34 )
              );


Method : extract($p_path = "")
Description :
  This method extract all the content of the archive in the directory
  indicated by $p_path.If $p_path is optional, if not set the archive
  is extracted in the current directory. 
  While extracting a file, if the directory path does not exists it is
  created. 
  See extractModify() for details and limitations.
Arguments :
  $p_path : Optional path where the files/dir need to by extracted.
Return value :
  true on success, false on error.
Sample :
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object->extract();
How it works :
  Simply call the extractModify() method with appropriate parameters.

Method : extractModify($p_path, $p_remove_path)
Description :
  This method extract all the content of the archive in the directory
  indicated by $p_path. When relevant the memorized path of the
  files/dir can be modified by removing the $p_remove_path path at the
  beginning of the file/dir path. 
  While extracting a file, if the directory path does not exists it is
  created. 
  While extracting a file, if the file already exists it is replaced
  without looking for last modification date. 
  While extracting a file, if the file already exists and is write
  protected, the extraction is aborted. 
  While extracting a file, if a directory with the same name already
  exists, the extraction is aborted. 
  While extracting a directory, if a file with the same name already
  exists, the extraction is aborted. 
  While extracting a file/directory if the destination directory exist
  and is write protected, or does not exist but can not be created,
  the extraction is aborted. 
  If after extraction an extracted file does not show the correct
  stored file size, the extraction is aborted. 
  When the extraction is aborted, a PEAR error text is set and false
  is returned. However the result can be a partial extraction that may
  need to be manually cleaned. 
Arguments :
  $p_path : The path of the directory where the files/dir need to by
            extracted. 
  $p_remove_path : Part of the memorized path that can be removed if
                   present at the beginning of the file/dir path. 
Return value :
  true on success, false on error.
Sample :
  // Imagine tarname.tar with files :
  //   dev/data/file.txt
  //   dev/data/log.txt
  //   readme.txt
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object->extractModify("install", "dev");
  // Files will be extracted there :
  //   install/data/file.txt
  //   install/data/log.txt
  //   install/readme.txt
How it works :
  Open the archive and call a more generic function that can extract
  only a part of the archive or all the archive. 
  See extractList() method for more details.

Method : extractInString($p_filename)
Description :
  This method extract from the archive one file identified by $p_filename.
  The return value is a string with the file content, or NULL on error. 
Arguments :
  $p_filename : The path of the file to extract in a string. 
Return value :
  a string with the file content or NULL.
Sample :
  // Imagine tarname.tar with files :
  //   dev/data/file.txt
  //   dev/data/log.txt
  //   dev/readme.txt
  $v_archive = & new Archive_Tar('tarname.tar');
  $v_archive->setErrorHandling(PEAR_ERROR_PRINT);
  $v_string = $v_archive->extractInString('dev/readme.txt');
  echo $v_string;

Method : listContent()
Description :
  This method returns an array of arrays that describe each
  file/directory present in the archive. 
  The array is not sorted, so it show the position of the file in the
  archive. 
  The file informations are :
    $file[filename] : Name and path of the file/dir.
    $file[mode] : File permissions (result of fileperms())
    $file[uid] : user id
    $file[gid] : group id
    $file[size] : filesize
    $file[mtime] : Last modification time (result of filemtime())
    $file[typeflag] : "" for file, "5" for directory
Arguments :
Return value :
  An array of arrays or 0 on error.
Sample :
  $tar_object = new Archive_Tar("tarname.tar");
  if (($v_list  =  $tar_object->listContent()) != 0)
    for ($i=0; $i<sizeof($v_list); $i++)
    {
      echo "Filename :'".$v_list[$i][filename]."'<br>";
      echo " .size :'".$v_list[$i][size]."'<br>";
      echo " .mtime :'".$v_list[$i][mtime]."' (".
           date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")<br>";
      echo " .mode :'".$v_list[$i][mode]."'<br>";
      echo " .uid :'".$v_list[$i][uid]."'<br>";
      echo " .gid :'".$v_list[$i][gid]."'<br>";
      echo " .typeflag :'".$v_list[$i][typeflag]."'<br>";
    }
How it works :
  Call the same function as an extract however with a flag to only go
  through the archive without extracting the files. 

Method : extractList($p_filelist, $p_path = "", $p_remove_path = "")
Description :
  This method extract from the archive only the files indicated in the
  $p_filelist. These files are extracted in the current directory or
  in the directory indicated by the optional $p_path parameter. 
  If indicated the $p_remove_path can be used in the same way as it is
  used in extractModify() method. 
Arguments :
  $p_filelist : An array of filenames and directory names, or a single
                string with names separated by a single blank space. 
  $p_path : The path of the directory where the files/dir need to by
            extracted. 
  $p_remove_path : Part of the memorized path that can be removed if
                   present at the beginning of the file/dir path. 
Return value :
  true on success, false on error.
Sample :
  // Imagine tarname.tar with files :
  //   dev/data/file.txt
  //   dev/data/log.txt
  //   readme.txt
  $tar_object = new Archive_Tar("tarname.tar");
  $tar_object->extractList("dev/data/file.txt readme.txt", "install",
                           "dev");
  // Files will be extracted there :
  //   install/data/file.txt
  //   install/readme.txt
How it works :
  Go through the archive and extract only the files present in the
  list. 

pear/XML_Util/examples/example2.php000064400000011353150413447460013207 0ustar00<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * Examples (file #2)
 *
 * several examples for the methods of XML_Util
 * 
 * PHP versions 4 and 5
 *
 * LICENSE:
 *
 * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * The name of the author may not be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @category   XML
 * @package    XML_Util
 * @subpackage Examples
 * @author     Stephan Schmidt <schst@php.net>
 * @copyright  2003-2008 Stephan Schmidt <schst@php.net>
 * @license    http://opensource.org/licenses/bsd-license New BSD License
 * @version    CVS: $Id$
 * @link       http://pear.php.net/package/XML_Util
 */

    /**
     * set error level
     */
    error_reporting(E_ALL);

    require_once 'XML/Util.php';

    /**
     * creating a start element
     */
    print 'creating a start element:<br>';
    print htmlentities(XML_Util::createStartElement('myNs:myTag', 
        array('foo' => 'bar'), 'http://www.w3c.org/myNs#'));
    print "\n<br><br>\n";


    /**
     * creating a start element
     */
    print 'creating a start element:<br>';
    print htmlentities(XML_Util::createStartElement('myTag', 
        array(), 'http://www.w3c.org/myNs#'));
    print "\n<br><br>\n";

    /**
     * creating a start element
     */
    print 'creating a start element:<br>';
    print '<pre>';
    print htmlentities(XML_Util::createStartElement('myTag', 
        array('foo' => 'bar', 'argh' => 'tomato'), 
        'http://www.w3c.org/myNs#', true));
    print '</pre>';
    print "\n<br><br>\n";


    /**
     * creating an end element
     */
    print 'creating an end element:<br>';
    print htmlentities(XML_Util::createEndElement('myNs:myTag'));
    print "\n<br><br>\n";

    /**
     * creating a CData section
     */
    print 'creating a CData section:<br>';
    print htmlentities(XML_Util::createCDataSection('I am content.'));
    print "\n<br><br>\n";

    /**
     * creating a comment
     */
    print 'creating a comment:<br>';
    print htmlentities(XML_Util::createComment('I am a comment.'));
    print "\n<br><br>\n";

    /**
     * creating an XML tag with multiline mode
     */
    $tag = array(
        'qname'        => 'foo:bar',
        'namespaceUri' => 'http://foo.com',
        'attributes'   => array('key' => 'value', 'argh' => 'fruit&vegetable'),
        'content'      => 'I\'m inside the tag & contain dangerous chars'
    );

    print 'creating a tag with qualified name and namespaceUri:<br>';
    print '<pre>';
    print htmlentities(XML_Util::createTagFromArray($tag, 
        XML_UTIL_REPLACE_ENTITIES, true));
    print '</pre>';
    print "\n<br><br>\n";

    /**
     * create an attribute string without replacing the entities
     */
    $atts = array('series' => 'Starsky &amp; Hutch', 'channel' => 'ABC');
    print 'creating a attribute string, '
        . 'entities in values already had been replaced:<br>';
    print htmlentities(XML_Util::attributesToString($atts, 
        true, false, false, false, XML_UTIL_ENTITIES_NONE));
    print "\n<br><br>\n";

    /**
     * using the array-syntax for attributesToString()
     */
    $atts = array('series' => 'Starsky &amp; Hutch', 'channel' => 'ABC');
    print 'using the array-syntax for attributesToString()<br>';
    print htmlentities(XML_Util::attributesToString($atts, 
        array('entities' => XML_UTIL_ENTITIES_NONE)));
    print "\n<br><br>\n";


?>
pear/XML_Util/examples/example.php000064400000021710150413447460013123 0ustar00<?php

/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * Examples (file #1)
 *
 * several examples for the methods of XML_Util
 * 
 * PHP versions 4 and 5
 *
 * LICENSE:
 *
 * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * The name of the author may not be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @category   XML
 * @package    XML_Util
 * @subpackage Examples
 * @author     Stephan Schmidt <schst@php.net>
 * @copyright  2003-2008 Stephan Schmidt <schst@php.net>
 * @license    http://opensource.org/licenses/bsd-license New BSD License
 * @version    CVS: $Id$
 * @link       http://pear.php.net/package/XML_Util
 */

    /**
     * set error level
     */
    error_reporting(E_ALL);

    require_once 'XML/Util.php';
    
    /**
     * replacing XML entities
     */
    print 'replace XML entities:<br>';
    print XML_Util::replaceEntities('This string contains < & >.');
    print "\n<br><br>\n";

    /**
     * reversing XML entities
     */
    print 'replace XML entities:<br>';
    print XML_Util::reverseEntities('This string contains &lt; &amp; &gt;.');
    print "\n<br><br>\n";

    /**
     * building XML declaration
     */
    print 'building XML declaration:<br>';
    print htmlspecialchars(XML_Util::getXMLDeclaration());
    print "\n<br><br>\n";

    print 'building XML declaration with additional attributes:<br>';
    print htmlspecialchars(XML_Util::getXMLDeclaration('1.0', 'UTF-8', true));
    print "\n<br><br>\n";

    /**
     * building document type declaration
     */
    print 'building DocType declaration:<br>';
    print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', 
        'http://pear.php.net/dtd/package-1.0'));
    print "\n<br><br>\n";

    print 'building DocType declaration with public ID (does not exist):<br>';
    print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', 
        array('uri' => 'http://pear.php.net/dtd/package-1.0', 
            'id' => '-//PHP//PEAR/DTD PACKAGE 0.1')));
    print "\n<br><br>\n";

    print 'building DocType declaration with internal DTD:<br>';
    print '<pre>';
    print htmlspecialchars(XML_Util::getDocTypeDeclaration('package', 
        'http://pear.php.net/dtd/package-1.0', 
        '<!ELEMENT additionalInfo (#PCDATA)>'));
    print '</pre>';
    print "\n<br><br>\n";

    /**
     * creating an attribute string
     */
    $att = array(
        'foo'  => 'bar',
        'argh' => 'tomato'
    );

    print 'converting array to string:<br>';
    print XML_Util::attributesToString($att);
    print "\n<br><br>\n";


    /**
     * creating an attribute string with linebreaks
     */
    $att = array(
        'foo'  => 'bar',
        'argh' => 'tomato'
    );

    print 'converting array to string (including line breaks):<br>';
    print '<pre>';
    print XML_Util::attributesToString($att, true, true);
    print '</pre>';
    print "\n<br><br>\n";


    /**
     * splitting a qualified tag name
     */
    print 'splitting qualified tag name:<br>';
    print '<pre>';
    print_r(XML_Util::splitQualifiedName('xslt:stylesheet'));
    print '</pre>';
    print "\n<br>\n";


    /**
     * splitting a qualified tag name (no namespace)
     */
    print 'splitting qualified tag name (no namespace):<br>';
    print '<pre>';
    print_r(XML_Util::splitQualifiedName('foo'));
    print '</pre>';
    print "\n<br>\n";

    /**
     * splitting a qualified tag name (no namespace, but default namespace specified)
     */
    print 'splitting qualified tag name '
        . '(no namespace, but default namespace specified):<br>';
    print '<pre>';
    print_r(XML_Util::splitQualifiedName('foo', 'bar'));
    print '</pre>';
    print "\n<br>\n";

    /**
     * verifying XML names
     */
    print 'verifying \'My private tag\':<br>';
    print '<pre>';
    print_r(XML_Util::isValidname('My Private Tag'));
    print '</pre>';
    print "\n<br><br>\n";
    
    print 'verifying \'-MyTag\':<br>';
    print '<pre>';
    print_r(XML_Util::isValidname('-MyTag'));
    print '</pre>';
    print "\n<br><br>\n";

    /**
     * creating an XML tag
     */
    $tag = array(
        'namespace'  => 'foo',
        'localPart'  => 'bar',
        'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
        'content'    => 'I\'m inside the tag'
    );

    print 'creating a tag with namespace and local part:<br>';
    print htmlentities(XML_Util::createTagFromArray($tag));
    print "\n<br><br>\n";

    /**
     * creating an XML tag
     */
    $tag = array(
        'qname'        => 'foo:bar',
        'namespaceUri' => 'http://foo.com',
        'attributes'   => array('key' => 'value', 'argh' => 'fruit&vegetable'),
        'content'      => 'I\'m inside the tag'
    );

    print 'creating a tag with qualified name and namespaceUri:<br>';
    print htmlentities(XML_Util::createTagFromArray($tag));
    print "\n<br><br>\n";

    /**
     * creating an XML tag
     */
    $tag = array(
        'qname'        => 'bar',
        'namespaceUri' => 'http://foo.com',
        'attributes'   => array('key' => 'value', 'argh' => 'fruit&vegetable')
    );

    print 'creating an empty tag without namespace but namespace Uri:<br>';
    print htmlentities(XML_Util::createTagFromArray($tag));
    print "\n<br><br>\n";

    /**
     * creating an XML tag with more namespaces
     */
    $tag = array(
        'namespace'   => 'foo',
        'localPart'   => 'bar',
        'attributes'  => array('key' => 'value', 'argh' => 'fruit&vegetable'),
        'content'     => 'I\'m inside the tag',
        'namespaces'  => array(
            'bar'  => 'http://bar.com',
            'pear' => 'http://pear.php.net',
        )
    );

    print 'creating an XML tag with more namespaces:<br />';
    print htmlentities(XML_Util::createTagFromArray($tag));
    print "\n<br><br>\n";

    /**
     * creating an XML tag with a CData Section
     */
    $tag = array(
        'qname'      => 'foo',
        'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
        'content'    => 'I\'m inside the tag'
    );

    print 'creating a tag with CData section:<br>';
    print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_CDATA_SECTION));
    print "\n<br><br>\n";

    /**
     * creating an XML tag with a CData Section
     */
    $tag = array(
        'qname'      => 'foo',
        'attributes' => array('key' => 'value', 'argh' => 't�t�'),
        'content'    => 
            'Also XHTML-tags can be created '
            . 'and HTML entities can be replaced � � � � <>.'
    );

    print 'creating a tag with HTML entities:<br>';
    print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_ENTITIES_HTML));
    print "\n<br><br>\n";

    /**
    * creating an XML tag with createTag
    */
    print 'creating a tag with createTag:<br>';
    print htmlentities(XML_Util::createTag('myNs:myTag', 
        array('foo' => 'bar'), 
        'This is inside the tag', 
        'http://www.w3c.org/myNs#'));
    print "\n<br><br>\n";

    
    /**
     * trying to create an XML tag with an array as content
     */
    $tag = array(
        'qname'   => 'bar',
        'content' => array('foo' => 'bar')
    );
    print 'trying to create an XML tag with an array as content:<br>';
    print '<pre>';
    print_r(XML_Util::createTagFromArray($tag));
    print '</pre>';
    print "\n<br><br>\n";
    
    /**
     * trying to create an XML tag without a name
     */
    $tag = array(
        'attributes' => array('foo' => 'bar'),
    );
    print 'trying to create an XML tag without a name:<br>';
    print '<pre>';
    print_r(XML_Util::createTagFromArray($tag));
    print '</pre>';
    print "\n<br><br>\n";
?>
pear/Net_SMTP/examples/basic.php000064400000002030150413447460012477 0ustar00<?php

require 'Net/SMTP.php';

$host = 'mail.example.com';
$from = 'user@example.com';
$rcpt = array('recipient1@example.com', 'recipient2@example.com');
$subj = "Subject: Test Message\n";
$body = "Body Line 1\nBody Line 2";

/* Create a new Net_SMTP object. */
if (! ($smtp = new Net_SMTP($host))) {
    die("Unable to instantiate Net_SMTP object\n");
}

/* Connect to the SMTP server. */
if (PEAR::isError($e = $smtp->connect())) {
    die($e->getMessage() . "\n");
}
$smtp->auth('username','password');
/* Send the 'MAIL FROM:' SMTP command. */
if (PEAR::isError($smtp->mailFrom($from))) {
    die("Unable to set sender to <$from>\n");
}

/* Address the message to each of the recipients. */
foreach ($rcpt as $to) {
    if (PEAR::isError($res = $smtp->rcptTo($to))) {
        die("Unable to add recipient <$to>: " . $res->getMessage() . "\n");
    }
}

/* Set the body of the message. */
if (PEAR::isError($smtp->data($subj . "\r\n" . $body))) {
    die("Unable to send data\n");
}

/* Disconnect from the SMTP server. */
$smtp->disconnect();
pear/Net_SMTP/README.rst000064400000022652150413447460010572 0ustar00======================
 The Net_SMTP Package
======================

--------------------
 User Documentation
--------------------

:Author:    Jon Parise
:Contact:   jon@php.net

.. contents:: Table of Contents
.. section-numbering::

Dependencies
============

The ``PEAR_Error`` Class
------------------------

The Net_SMTP package uses the `PEAR_Error`_ class for all of its `error
handling`_.

The ``Net_Socket`` Package
--------------------------

The Net_Socket_ package is used as the basis for all network communications.
Connection options can be specified via the `$socket_options` construction
parameter::

    $socket_options = array('ssl' => array('verify_peer_name' => false));
    $smtp = new Net_SMTP($host, null, null, false, 0, $socket_options);

**Note:** PHP 5.6 introduced `OpenSSL changes`_. Peer certificate verification
is now enabled by default. Although not recommended, `$socket_options` can be
used to disable peer verification (as shown above).

.. _OpenSSL changes: https://php.net/manual/en/migration56.openssl.php

The ``Auth_SASL`` Package
-------------------------

The `Auth_SASL`_ package is an optional dependency.  If it is available, the
Net_SMTP package will be able to support the DIGEST-MD5_ and CRAM-MD5_ SMTP
authentication methods.  Otherwise, only the LOGIN_ and PLAIN_ methods will
be available.

Error Handling
==============

All of the Net_SMTP class's public methods return a PEAR_Error_ object if an
error occurs.  The standard way to check for a PEAR_Error object is by using
`PEAR::isError()`_::

    if (PEAR::isError($error = $smtp->connect())) {
        die($error->getMessage());
    }

.. _PEAR::isError(): https://pear.php.net/manual/en/core.pear.pear.iserror.php

SMTP Authentication
===================

The Net_SMTP package supports the SMTP authentication standard (as defined
by RFC-2554_).  The Net_SMTP package supports the following authentication
methods, in order of preference:

.. _RFC-2554: https://www.ietf.org/rfc/rfc2554.txt

GSSAPI
------

The GSSAPI authentication method uses Kerberos 5 protocol (RFC-4120_).
Does not use user/password.
Requires Service Principal ``gssapi_principal`` parameter and
has an optional Credentials Cache ``gssapi_cname`` parameter.
Requires DNS and Key Distribution Center (KDC) setup.
It is considered the most secure method of SMTP authentication.

**Note:** The GSSAPI authentication method is only supported
if the krb5_ php extension is available.

.. _RFC-4120: https://tools.ietf.org/html/rfc4120
.. _krb5: https://pecl.php.net/package/krb5

DIGEST-MD5
----------

The DIGEST-MD5 authentication method uses `RSA Data Security Inc.`_'s MD5
Message Digest algorithm.  It is considered a more secure method of SMTP
authentication than PLAIN or LOGIN, while still vulnerable to MitM attacks
without TLS/SSL.

**Note:** The DIGEST-MD5 authentication method is only supported if the
AUTH_SASL_ package is available.

.. _RSA Data Security Inc.: https://www.rsasecurity.com/

CRAM-MD5
--------

The CRAM-MD5 authentication method has been superseded by the DIGEST-MD5_
method in terms of security.  It is provided here for compatibility with
older SMTP servers that may not support the newer DIGEST-MD5 algorithm.

**Note:** The CRAM-MD5 authentication method is only supported if the
AUTH_SASL_ package is available.

LOGIN
-----

The LOGIN authentication method encrypts the user's password using the
Base64_ encoding scheme.  Because decrypting a Base64-encoded string is
trivial, LOGIN is not considered a secure authentication method and should
be avoided.

.. _Base64: https://www.php.net/manual/en/function.base64-encode.php

PLAIN
-----

The PLAIN authentication method sends the user's password in plain text.
This method of authentication is not secure and should be avoided.

XOAUTH2
-------

The XOAUTH2 authentication method sends a username and an OAuth2 access token
as per `Gmail's SASL XOAUTH2 documentation`__.

.. __: https://developers.google.com/gmail/imap/xoauth2-protocol#smtp_protocol_exchange

Secure Connections
==================

If `secure socket transports`_ have been enabled in PHP, it is possible to
establish a secure connection to the remote SMTP server::

    $smtp = new Net_SMTP('ssl://mail.example.com', 465);

This example connects to ``mail.example.com`` on port 465 (a common SMTPS
port) using the ``ssl://`` transport.

TLS/SSL is enabled for authenticated connections by default (via the ``auth()``
method's ``$tls`` parameter), but the |STARTTLS|_ command can also be sent
manually using the ``starttls()`` method.

.. _secure socket transports: https://www.php.net/transports
.. |STARTTLS| replace:: ``STARTTLS``
.. _STARTTLS: https://tools.ietf.org/html/rfc3207

Sending Data
============

Message data is sent using the ``data()`` method.  The data can be supplied
as a single string or as an open file resource.

If a string is provided, it is passed through the `data quoting`_ system and
sent to the socket connection as a single block.  These operations are all
memory-based, so sending large messages may result in high memory usage.

If an open file resource is provided, the ``data()`` method will read the
message data from the file line-by-line.  Each chunk will be quoted and sent
to the socket connection individually, reducing the overall memory overhead of
this data sending operation.

Header data can be specified separately from message body data by passing it
as the optional second parameter to ``data()``.  This is especially useful
when an open file resource is being used to supply message data because it
allows header fields (like *Subject:*) to be built dynamically at runtime.

::

    $smtp->data($fp, "Subject: My Subject");

Data Quoting
============

By default, all outbound string data is quoted in accordance with SMTP
standards.  This means that all native Unix (``\n``) and Mac (``\r``) line
endings are converted to Internet-standard CRLF (``\r\n``) line endings.
Also, because the SMTP protocol uses a single leading period (``.``) to signal
an end to the message data, single leading periods in the original data
string are "doubled" (e.g. "``..``").

These string transformation can be expensive when large blocks of data are
involved.  For example, the Net_SMTP package is not aware of MIME parts (it
just sees the MIME message as one big string of characters), so it is not
able to skip non-text attachments when searching for characters that may
need to be quoted.

Because of this, it is possible to extend the Net_SMTP class in order to
implement your own custom quoting routine.  Just create a new class based on
the Net_SMTP class and reimplement the ``quotedata()`` method::

    require 'Net_SMTP.php';

    class Net_SMTP_custom extends Net_SMTP
    {
        function quotedata($data)
        {
            /* Perform custom data quoting */
        }
    }

Note that the ``$data`` parameter will be passed to the ``quotedata()``
function `by reference`_.  This means that you can operate directly on
``$data``.  It also the overhead of copying a large ``$data`` string to and
from the ``quotedata()`` method.

.. _by reference: https://www.php.net/manual/en/language.references.pass.php

Server Responses
================

The Net_SMTP package retains the server's last response for further
inspection.  The ``getResponse()`` method returns a 2-tuple (two element
array) containing the server's response code as an integer and the response's
arguments as a string.

Upon a successful connection, the server's greeting string is available via
the ``getGreeting()`` method.

Debugging
=========

The Net_SMTP package contains built-in debugging output routines (disabled by
default).  Debugging output must be explicitly enabled via the ``setDebug()``
method::

    $smtp->setDebug(true);

The debugging messages will be sent to the standard output stream by default.
If you need more control over the output, you can optionally install your own
debug handler.

::

    function debugHandler($smtp, $message)
    {
        echo "[$smtp->host] $message\n";
    }

    $smtp->setDebug(true, "debugHandler");


Examples
========

Basic Use
---------

The following script demonstrates how a simple email message can be sent
using the Net_SMTP package::

    require 'Net/SMTP.php';

    $host = 'mail.example.com';
    $from = 'user@example.com';
    $rcpt = array('recipient1@example.com', 'recipient2@example.com');
    $subj = "Subject: Test Message\n";
    $body = "Body Line 1\nBody Line 2";

    /* Create a new Net_SMTP object. */
    if (! ($smtp = new Net_SMTP($host))) {
        die("Unable to instantiate Net_SMTP object\n");
    }

    /* Connect to the SMTP server. */
    if (PEAR::isError($e = $smtp->connect())) {
        die($e->getMessage() . "\n");
    }

    /* Send the 'MAIL FROM:' SMTP command. */
    if (PEAR::isError($smtp->mailFrom($from))) {
        die("Unable to set sender to <$from>\n");
    }

    /* Address the message to each of the recipients. */
    foreach ($rcpt as $to) {
        if (PEAR::isError($res = $smtp->rcptTo($to))) {
            die("Unable to add recipient <$to>: " . $res->getMessage() . "\n");
        }
    }

    /* Set the body of the message. */
    if (PEAR::isError($smtp->data($subj . "\r\n" . $body))) {
        die("Unable to send data\n");
    }

    /* Disconnect from the SMTP server. */
    $smtp->disconnect();

.. _PEAR_Error: https://pear.php.net/manual/en/core.pear.pear-error.php
.. _Net_Socket: https://pear.php.net/package/Net_Socket
.. _Auth_SASL: https://pear.php.net/package/Auth_SASL

.. vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=78 ft=rst:
pear/Net_SMTP/LICENSE000064400000002450150413447470010103 0ustar00Copyright 2002-2017 Jon Parise and Chuck Hagenbuch.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution..

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pear/File_MARC/CHANGELOG000064400000013441150413447470010402 0ustar001.4.1
  * Reintroduce include_path to composer.json

1.4.0
  * Update File_MARC_Lint to match MARC::Lint 1.52 (thanks Demian Katz)
  * Warn about out-of-range skip indicators (thanks Demian Katz)
  * Support initialization from SimpleXMLELement object (thanks Dan Michael O. Heggø)
  * Fix Travis-CI support (thanks Daniel O'Connor)
  * Tweak composer.json to support Composer 2.0
  * Silence PEAR style errors and warnings in File/MARCBASE.php

1.3.0
  * Support reading MARC-in-JSON serializations
  * Fix positions using MARC_List's appendNode method (thanks Waldemar Bartikowski!)

1.2.0
  * Support injection of extended Record class (thanks Dan Michael O. Heggø!)
  * Support regular expression matching of subfields (thanks Waldemar Bartikowski!)
  * Fix deletion of multiple subfields at once (thanks Dan Michael O. Heggø!)

1.1.5
  * Drop support for PHP 5.3 and 5.4

1.1.4
  * Fix insertField() behaviour, which could truncate records (reported by Andreas Roussos)
  * Docs correction for Data_Field (thanks Daniel Walter)

1.1.3
  * Add a getContents() convenience method, contributed by Carsten Klee

1.1.2
  * Fetch pear_exception from Packagist [danmichaelo]

1.1.1
  * Add MARC-in-JSON serialization fix for subfield 0 json_encode() limitation
    (thanks to Bill Dueber for reporting the bug)

1.1.0
  * Enable namespaces in MARCXML handling (thanks Carsten Klee!)
  * Remove skip check for Structures/Linked_List

1.0.2
* Update MARC_Lint set of rules (thanks Demian Katz!) 

1.0.1
* Fix bug in MARC binary serialization of subfields with value '0'.
  Thanks to Mark Jordan (mjordan@sfu.ca) for the bug report.

1.0.0
* First stable release!

0.8.0-beta
* Drop Structures_LinkedList dependency in favour of SplDoublyLinkedList.
  This bumps the minimum PHP version up to 5.2.0.

0.7.3-beta
* Merge patch from Karen Coombs (librarywebchic@gmail.com) adding default
  namespace to record elements

0.7.2-beta
* Fix bug #19845 - Record::toXML() returns nothing

0.7.1-beta
* Make Validate_ISPN an optional dependency

0.6.2-beta
* Improve handling of bad leader data, including declared length and overly
  long leaders in MARCXML

0.6.1-beta
* Correct layout per bug #17704

0.6.0-beta
* Add two flavours of JSON output from File_MARC_Record: toJSON() and
  toJSONHash()

0.5.2-beta
* Enable File_MARC_Record to be invoked with a null constructor again, useful
  for building MARC records from scratch
* Add a test to check that the null constructor works to avoid future
  regressions

0.5.1-beta
* Explicitly cast results to strings to avoid returning XML objects when
  File_MARCXML is in effect; problem doesn't show up in the PHP CLI, but does
  cause problems on the Web

0.5.0-beta
* Drop MARCFLAT as it is unmaintained and, to my knowledge, unused
* Add the ability to generate a proper collection of MARCXML records
* Factor out some of the common toXML()-related methods to a new base class
* Add tests of the new toXML() functionality for both MARC and MARCXML sources

0.4.4-beta
* Enable MARCXML to handle bad tags, to match MARC
* Handle corner case where only one indicator might have been provided

0.4.3-beta
* Fix bug #16783 - handle bad MARC tags via warnings instead of bubbling an
  exception all the way up

0.4.2-beta
* Fix bug #16642 - MARCXML files return keys of an invalid type

0.4.1-beta
* Fix suggested by Dan Field (surfrdan @ gmail.com) for addWarnings() typo

0.4.0-beta
* Add formatField() convenience method to File_MARC_Field (courtesy Mark
  Matienzo @ matienzo.org)
* Move from split() to explode() to avoid PHP 5.3 deprecation warning
  (courtesy bertrand.zuchuat @ rero.ch

0.3.0-beta
* Add isControlField() and isDataField() convenience methods to File_MARC_Field

0.2.3-beta
* Handle single-record MARC21XML files with "record" as the root element

0.1.1-alpha
* Add File_MARC_Record::toXML() method for generating MARCXML output
* Add File_MARCXML class for reading MARCXML source
* Add tests for MARCXML methods

0.1.0-alpha
* Split each class out into its own file
* Do not return anything from constructors

0.0.9-alpha
* Separate getFields() from getField(), getSubfields() from getSubfield()
  to avoid forcing users to test is_array() after every call
* Add addWarnings() / getWarnings() for records to avoid throwing an
  exception for a non-fatal error
* Fix examples, touch up phpdoc in preparation for call for votes

0.0.8-alpha
* Switch to PEAR_Exception for error handling

0.0.7-alpha
* Implement useful key() overrides for key=>value iteration through
  fields and subfields 
* Adjust to new Structures_LinkedList_Double names

0.0.6-alpha
* Remove package globals, define class constants & static vars instead
* Change addField/Subfield() to append..(), prepend...(), and insert...()

0.0.5-alpha
* Work towards a more consistent API (delete getAllSubfields)
* Make PCRE expressions in getFields() and deleteFields() optional.
* Make duplicate() actually return a deep copy of a record.
* Stronger, better, faster (now with typehints)
* Iterate with foreach() everywhere now

0.0.4-alpha
* Adjust to Structures_Linked_List package name change and minor API changes
* Adhere to PEAR CS (thanks PHP_CodeSniffer!)
* Correct sloppy use of references (thanks E_STRICT!)
* Okay, this time real error handling using PEAR_ErrorStack
* Prepare first package for PEPR

0.0.3-alpha
* Split MARC into separate File_MARC and Structure_Linked_List packages (with corresponding renaming of classes and constants)
* Adopt PEAR naming conventions (s/MARC/File_MARC/)
* Initial stab at PEAR_ErrorStack error handling

0.0.2-alpha
* Fix marc_004.phpt: explicitly compare object references with === operator
* Document all constants.
* Fix MARC_Field::deleteSubfield() function
* Add this ChangeLog

0.0.1-alpha
* First publicly available release, based on MARC decoding algorithm from
the emilda.org php-marc package with a completely new API and class hierarchy
pear/File_MARC/examples/read.php000064400000002273150413447470012433 0ustar00<?php

require 'File/MARC.php';

// Read MARC records from a stream (a file, in this case)
$marc_source = new File_MARC('example.mrc');

// Retrieve the first MARC record from the source
$marc_record = $marc_source->next();

// Retrieve a personal name field from the record
$names = $marc_record->getFields('100');

foreach ($names as $name_field) {
    // Now print the $a subfield
    switch ($name_field->getIndicator(1)) {
    case 0:
        print "Forename: ";
        break;

    case 1:
        print "Surname: ";
        break;

    case 2:
        print "Family name: ";
        break;
    }

    $name = $name_field->getSubfields('a');

    if (count($name) == 1) {
        print $name[0]->getData() . "\n";
    } else {
        print "Error -- \$a subfield appears more than once in this field!";
    }
}

print "\nPrint all series statement fields (4xx):\n";
// Retrieve all series statement fields
// Series statement fields start with a 4 (PCRE)
$subjects = $marc_record->getFields('^4', true);

// Iterate through all of the returned series statement fields
foreach ($subjects as $field) {
    // print with File_MARC_Field_Data's magic __toString() method
    print $field;
}

print "\n";

?>
pear/File_MARC/examples/subfields.php000064400000002401150413447470013471 0ustar00<?php
require 'File/MARC.php';

// File_MARC offers the ability to add subfields at any point within
// an existing set of subfields

// First, create some subfields
$subfields[] = new File_MARC_Subfield('a', 'nothing');
$subfields[] = new File_MARC_Subfield('z', 'everything');

// Then, create a field including those subfields
$field = new File_MARC_Data_Field('100', $subfields, '0');

// Create some new subfields
$subfield1 = new File_MARC_Subfield('g', 'a little');
$subfield2 = new File_MARC_Subfield('k', 'a bit more');
$subfield3 = new File_MARC_Subfield('t', 'a lot');

// Append a new subfield to the existing set of subfields
// Expected order: a-z-g
$field->appendSubfield($subfield1);

// Insert a new subfield after the first subfield with code 'z'
// Expected order: a-z-k-g
$sf = $field->getSubfields('z');
// getSubfields() always returns an array; we just want the first subfield
if (count($sf) > 0) {
    $field->insertSubfield($subfield2, $sf[0]);
}

// Insert a new subfield prior to the first subfield with code 'z'
// Expected order: a-t-z-k-g
$sf = $field->getSubfield('z');
// getSubfield() simply returns the first matching subfield
if ($sf) {
    $field->insertSubfield($subfield3, $sf, true);
}

// let's see the results
print $field;
print "\n";

?>
pear/File_MARC/examples/marc_yaz.php000064400000002325150413447470013323 0ustar00<?php
$dir = dirname(__FILE__);
require 'File/MARC.php';

// Define the usable fields for our CCL query
$ccl_fields = array(
    "ti" => "1=4",
    "au"  => "1=1",
    "isbn" => "1=7"
);

// Declare the array that will hold the parsed results
$ccl_results = array();

// Connect to the laurentian.ca Z39.50 server
$conn = yaz_connect('142.51.8.7:2200/UNICORN');
yaz_ccl_conf($conn, $ccl_fields);

// Define our query for a most excellent text
$ccl_query = "ti='derby' and au='scott'";

// Parse the CCL query into yaz's native format
$result = yaz_ccl_parse($conn, $ccl_query, $ccl_results);
if (!$result) {
    echo "Error: " . $ccl_results['errorstring'];
    exit();
}

// Submit the query
$rpn = $ccl_results['rpn'];
yaz_search($conn, 'rpn', $rpn);
yaz_wait();

// Any errors trying to retrieve this record?
$error = yaz_error($conn);
if ($error) {
    print "Error: $error\n";
    exit();
}

// Retrieve the first MARC record as raw MARC
$rec = yaz_record($conn, 1, "raw");
if (!$rec) {
    print "Error: Retrieved no results.\n";
    exit();
}

// Parse the retrieved MARC record
$marc_file = new File_MARC($rec, File_MARC::SOURCE_STRING); 

while ($marc_record = $marc_file->next()) {
    print $marc_record;
    print "\n";
}
?>
pear/File_MARC/examples/example.mrc000064400000003472150413447500013141 0ustar0001850     2200517   45000010011000000030007000110080039000180200026000570350015000830400007000980420012001050840018001170840018001350840021001530840022001741000030001962450062002262500013002882600058003013000033003594400037003925000023004295990010004527400024004627750034004868410048005208410049005688410047006178410048006648410047007128410047007598520038008068520021008448520013008658520016008788520028008948520021009229000056009439000060009999000057010599000056011169000057011729000060012299760026012890050017013150000000044EMILDA980120s1998    fi     j      000 0 swe  a9515008808cFIM 72:00  99515008808  aNB  9NB9SEE  aHcd,u2kssb/6  5NBauHc2kssb  5SEEaHcf2kssb/6  5QaHcd,uf2kssb/61 aJansson, Tove,d1914-200104aDet osynliga barnet och andra ber�ttelser /cTove Jansson  a7. uppl.  aHelsingfors :bSchildt,c1998 ;e(Falun :fScandbook)  a166, [4] s. :bill. ;c21 cm 0aMumin-biblioteket,x99-0698931-9  aOriginaluppl. 1962  aLi: S4 aDet osynliga barnet1 z951-50-0385-7w9515003857907  5Liaxab0201080u    0   4000uu   |000000e1  5SEEaxab0201080u    0   4000uu   |000000e1  5Laxab0201080u    0   4000uu   |000000e1  5NBaxab0201080u    0   4000uu   |000000e1  5Qaxab0201080u    0   4000uu   |000000e1  5Saxab0201080u    0   4000uu   |000000e1  5NBbNBcNB98:12hpliktjR, 980520  5LibLicCNBhh,u  5SEEbSEE  5QbQj98947  5LbLc0100h98/j3043 H  5SbShSv97j72351saYanson, Tobe,d1914-2001uJansson, Tove,d1914-20011saJanssonov�, Tove,d1914-2001uJansson, Tove,d1914-20011saJansone, Tuve,d1914-2001uJansson, Tove,d1914-20011saJanson, Tuve,d1914-2001uJansson, Tove,d1914-20011saJansson, Tuve,d1914-2001uJansson, Tove,d1914-20011saJanssonova, Tove,d1914-2001uJansson, Tove,d1914-2001 2aHcd,ubSk�nlitteratur20050204111518.0pear/File_MARC/LICENSE000064400000063504150413447500010174 0ustar00		  GNU LESSER GENERAL PUBLIC LICENSE
		       Version 2.1, February 1999

 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.

  This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it.  You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.

  When we speak of free software, we are referring to freedom of use,
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 this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.

  To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights.  These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.

  For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you.  You must make sure that they, too, receive or can get the source
code.  If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it.  And you must show them these terms so they know their rights.

  We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.

  To protect each distributor, we want to make it very clear that
there is no warranty for the free library.  Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.

  Finally, software patents pose a constant threat to the existence of
any free program.  We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder.  Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.

  Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License.  This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License.  We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.

  When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library.  The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom.  The Lesser General
Public License permits more lax criteria for linking other code with
the library.

  We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License.  It also provides other free software developers Less
of an advantage over competing non-free programs.  These disadvantages
are the reason we use the ordinary General Public License for many
libraries.  However, the Lesser license provides advantages in certain
special circumstances.

  For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard.  To achieve this, non-free programs must be
allowed to use the library.  A more frequent case is that a free
library does the same job as widely used non-free libraries.  In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.

  In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software.  For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.

  Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.

  The precise terms and conditions for copying, distribution and
modification follow.  Pay close attention to the difference between a
"work based on the library" and a "work that uses the library".  The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.

		  GNU LESSER GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".

  A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.

  The "Library", below, refers to any such software library or work
which has been distributed under these terms.  A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language.  (Hereinafter, translation is
included without limitation in the term "modification".)

  "Source code" for a work means the preferred form of the work for
making modifications to it.  For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.

  Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it).  Whether that is true depends on what the Library does
and what the program that uses the Library does.
  
  1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.

  You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.

  2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) The modified work must itself be a software library.

    b) You must cause the files modified to carry prominent notices
    stating that you changed the files and the date of any change.

    c) You must cause the whole of the work to be licensed at no
    charge to all third parties under the terms of this License.

    d) If a facility in the modified Library refers to a function or a
    table of data to be supplied by an application program that uses
    the facility, other than as an argument passed when the facility
    is invoked, then you must make a good faith effort to ensure that,
    in the event an application does not supply such function or
    table, the facility still operates, and performs whatever part of
    its purpose remains meaningful.

    (For example, a function in a library to compute square roots has
    a purpose that is entirely well-defined independent of the
    application.  Therefore, Subsection 2d requires that any
    application-supplied function or table used by this function must
    be optional: if the application does not supply it, the square
    root function must still compute square roots.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.

In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library.  To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License.  (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.)  Do not make any other change in
these notices.

  Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.

  This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.

  4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.

  If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.

  5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library".  Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.

  However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library".  The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.

  When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library.  The
threshold for this to be true is not precisely defined by law.

  If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work.  (Executables containing this object code plus portions of the
Library will still fall under Section 6.)

  Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.

  6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.

  You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License.  You must supply a copy of this License.  If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License.  Also, you must do one
of these things:

    a) Accompany the work with the complete corresponding
    machine-readable source code for the Library including whatever
    changes were used in the work (which must be distributed under
    Sections 1 and 2 above); and, if the work is an executable linked
    with the Library, with the complete machine-readable "work that
    uses the Library", as object code and/or source code, so that the
    user can modify the Library and then relink to produce a modified
    executable containing the modified Library.  (It is understood
    that the user who changes the contents of definitions files in the
    Library will not necessarily be able to recompile the application
    to use the modified definitions.)

    b) Use a suitable shared library mechanism for linking with the
    Library.  A suitable mechanism is one that (1) uses at run time a
    copy of the library already present on the user's computer system,
    rather than copying library functions into the executable, and (2)
    will operate properly with a modified version of the library, if
    the user installs one, as long as the modified version is
    interface-compatible with the version that the work was made with.

    c) Accompany the work with a written offer, valid for at
    least three years, to give the same user the materials
    specified in Subsection 6a, above, for a charge no more
    than the cost of performing this distribution.

    d) If distribution of the work is made by offering access to copy
    from a designated place, offer equivalent access to copy the above
    specified materials from the same place.

    e) Verify that the user has already received a copy of these
    materials or that you have already sent this user a copy.

  For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it.  However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.

  It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system.  Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.

  7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:

    a) Accompany the combined library with a copy of the same work
    based on the Library, uncombined with any other library
    facilities.  This must be distributed under the terms of the
    Sections above.

    b) Give prominent notice with the combined library of the fact
    that part of it is a work based on the Library, and explaining
    where to find the accompanying uncombined form of the same work.

  8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License.  Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License.  However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.

  9. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Library or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.

  10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.

  11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all.  For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded.  In such case, this License incorporates the limitation as if
written in the body of this License.

  13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation.  If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.

  14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission.  For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this.  Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.

			    NO WARRANTY

  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

		     END OF TERMS AND CONDITIONS

           How to Apply These Terms to Your New Libraries

  If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change.  You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).

  To apply these terms, attach the following notices to the library.  It is
safest to attach them to the start of each source file to most effectively
convey 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 library's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  library `Frob' (a library for tweaking knobs) written by James Random Hacker.

  <signature of Ty Coon>, 1 April 1990
  Ty Coon, President of Vice

That's all there is to it!


alt-php82-ioncube-loader/USER-GUIDE.txt000064400000026060150413447510013333 0ustar00ionCube Loader 14.4 User Guide
=====================================

This document describes the available php.ini configuration options of the
ionCube Loader that relate to processing of PHP encoded files, and also the
ionCube24 service. It also describes which encoded files can be run by each
ionCube Loader.

PERFORMANCE OF ENCODED FILES
----------------------------

We recommend that the encoded paths feature (see below) is used 
with encoded files in order to maximise performance.

ENCODED FILES  
-------------

INI entry: ioncube.loader.encoded_paths

Purpose:   Specify the locations of encoded files

  The ionCube Loader will normally examine a PHP file before processing
  to test whether it is encoded, and will run the file itself if necessary.
  Although this checking is very efficient, restricting which files the
  Loader tests for being encoded may give extra performance. If set to 
  a series of paths or files, only files in those locations are tested.

  Entries should be separated by a : on Unix and ; on Windows. 
  A path may be prefixed with + or - to add or remove that path from
  the possible locations. + is assumed if no character is given.


Examples: (... means ioncube.loader.encoded_paths)

  * Site with a single encoded module in /var/www/html/modules/RSS

... = "/var/www/html/modules/RSS"


  * As above, with a site configuration file encoded too.

... = "/var/www/html/modules/RSS:/var/www/html/config/config.php"


  * Encoded files may be anywhere except for /var/www/html/framework

... = "/:-/var/www/html/framework"


  * Site with most modules encoded except for one

... = "/var/www/html/modules:-/var/www/html/modules/plain"


  * As above, with an encoded config file in the plain directory

... = "/site/modules:-/site/modules/plain:/site/modules/plain/config.php"


Locations:

  The ioncube.loader.encoded_paths property can be set in a php.ini
  file, in a .htaccess file (when using Apache), in a .user.ini file
  (when using CGI PHP 5.3+) or using ini_set within a PHP script. In ini
  files only the last value will be used for the encoded_paths property. If
  you wish to build up the value in several lines then, for PHP 5.1+, you
  can use the following syntax:

ioncube.loader.encoded_paths = "/path1"  
ioncube.loader.encoded_paths = ${ioncube.loader.encoded_paths}":/path2"  
; etc...

LIMITATIONS OF LOADERS AND ENCODED FILES
----------------------------------------

Encoded files can, in general, run on versions of PHP equal to
or greater than the source language of the Encoder used to
produce them. So a file produced by the Encoder for PHP 7.2
can be run by the Loaders for PHP 7.2, 7.3 and 7.4, but 7.1. This 
means that the Loaders offer good backwards compatibility, 
however there are the following limitations:

  * The Loader for PHP 8.3 can run files produced by the PHP 8.2 and
    8.3 Encoders.

  * The Loader for PHP 8.2 can only run files produced for
    PHP 8.2. Updates for files produced for PHP 8.1 should
    be obtained to use them with PHP 8.2.

  * The Loader for PHP 8.1 can only run files produced for
    PHP 8.1.

  * The Loaders for PHP 7.1 through 7.4 can only run files 
    produced by the Encoders for PHP 7. 

  * The Loader for PHP 7.0 can only run files produced by the
    Encoder for PHP 5.6.

  * The Loaders for PHP 5.5 and PHP 5.6 cannot run files 
    produced by the PHP 4 Encoder.


IONCUBE24 : real-time intrusion protection and PHP error reporting
---------
### (Available for Linux 32 and 64 bit x86 servers using PHP 7)

ionCube24 (https://ioncube24.com) is an ionCube service that uses the
ionCube Loader to provide both real-time protection against the exploit of
website vulnerabilities and alerting of website errors.

Vulnerabilities in PHP applications are common, particularly in sites using 
Wordpress and other plugin based systems. Exploits result in website
defacement or customer data being compromised, and ionCube24 provides a 
uniquely powerful defense. 

PHP errors can cause intermittent or even persistent blank pages or errors for
visitors until discovered, and without active monitoring this could go
undetected indefinitely. ionCube24 active monitoring ensures you are always
aware of problems in your website code.

ionCube24 is free to try, with the server side support built into the Linux
Loaders as standard. With the Loader installed, ionCube24 can be activated
at any time to give active intrusion protection and error reporting.

## php.ini settings

ionCube24 has a powerful real-time web interface to configure, monitor and
manage things, and there are also settings that can be used in a php.ini
file as summarised below.

The setup process at https://ioncube24.com automatically gives the settings
that you need to get started, but you may wish to make changes yourself
once setup. The default values are given with each example.

### Global settings

INI entry: ic24.enable ; default 0

Purpose: Enable or disable all ionCube24 features. 

This defaults to 0 (off), and in this case no ionCube24 behaviour is
activated.

Example:

  ic24.enable = 1

----------

INI entry: ic24.api_access_key ; provided during setup

Purpose: An authentication key for adminstration requests. 

  This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.api_check_ip ; default 1

Purpose: Specify whether the IP for admin requests should be validated

  If set, ionCube24 refuses access to API functions unless the calling IP
  is a known ionCube IP address. This option should be left with the
  default setting unless web requests pass through a proxy and your site
  appears to be accessed from the IP of the proxy instead of ionCube. Note
  that access to API functions will still be authenticated by access key.

----------

INI entry: ic24.api_max_timeout ; default 7

Purpose: Maximum timeout period when sending notifications to ionCube24.

  The actual period is adaptive so that a brief increase in typical latency
  will favour a timeout followed by a retry rather than a longer than usual
  timeout.

----------

INI entry: ic24.home_dir ; no default

Purpose: The home directory for ionCube24 related system files. 

  A location outside of the web root is recommended.  It should be writable
  by the web server during startup.

Example:

ic24.home_dir = /var/www/ic24_home

----------

INI entry: ic24.update_domains_retry_interval ; default 30

Purpose: The number of seconds to wait before retrying a fetch of the set
of domains being managed.


### Security related settings

INI entry: ic24.sec.enable ; default "auto"

Purpose: Enable the intrusion protection feature of ionCube24.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

INI entry: ic24.sec.initial_state ; default 1

Purpose: The default for whether security should be enabled or
disabled. The default is to enable protection. Any files on a protected
domain will become blocked if they are changed, so setting this to 0 will
avoid accidental blocking when using ionCube24 for the first time.
Protection may be enabled and disabled using the ionCube24 control panel and
also via the User API.

Accepted values:

   * 1 : protection will be active when ionCube24 initialises.
   * 0 : protection will be disabled.

----------

INI entry: ic24.sec.initial_action ; default "block"

Purpose: The initial setting for how new and modified files should be
treated when about to execute. The default is to block. The action is taken
only if protection is enabled, and the setting may be changed via the
ionCube24 control panel.

Accepted values:

   * "block" : prevent execution of new or modified files
   * "allow" : allow execution of new or modified files

Note that depending on the notification settings, a notification may still
be generated when a new or modified file is about to execute even if it is
not blocked.

----------

INI entry: ic24.sec.initial_notify ; default "always"

Purpose: The initial setting for whether a notification is generated the 
first time an unacknowledged new or modified file is attempted to be
executed. This setting can be changed via the ionCube24 control panel.

Accepted values:

   * "always" : always notify of a new modification 
   * "once"   : only the first detected modification is reported
   * "never"  : never notify of new and modified files

----------

INI entry: ic24.sec.exclusion_key ; provided during setup

Purpose: A key that if present at the start of a file, will identify the
file as trusted. This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.sec.trusted_include_paths ; no default

Purpose: List paths from where files can be included and automatically
trusted.

Example:

ic24.sec.trusted_include_paths = "/var/cache:/var/cache2"

Directories can be excluded from the list by prefixing with a minus
character -. e.g.

"/var/cache:-/var/cache/subdir"

This is useful if your site creates and/or modifies files by itself from
time to time, e.g. in a cache directory. Requests that *directly* access
files on a trusted include path will be blocked but the file itself will
not be blocked, so requests that use the file as intended will still work.
See ioncube24.com for more details once signed up.  As an alternative, if
possible we recommend producing files that include the exclusion key.

----------

INI entry: ic24.sec.block_uploaded_files ; default 1

Purpose: If set, block any uploaded files in ionCube24 that are processed
using the standard PHP mechanism for uploaded files. This applies even if
the file is subsequently included and where included files being
automatically approved with the previous setting.

----------

INI entry: ic24.sec.block_stdin ; default 1

Purpose: Refuse code that PHP sees via stdin.  If disabled, code via
stdin will run without security checking as there is no filepath. This
setting should be left on as PHP would normally never receive a script via
stdin.

### PHP Error reporting settings

INI entry: ic24.phperr.enable ; default "auto"

Purpose: Enable reporting of PHP errors to ionCube24.  When enabled, any
non-ignored errors are reported to ionCube24 in realtime, triggering
alerting so errors can be investigated as necessary.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

### Deprecated settings

Deprecated settings are subject to removal in a future
release.

INI entry: ic24.phperr.ignore ; default 0

Purpose: Specify default error levels to always ignore for all domains.

Note that default and per-domain errors to ignore can also be set via the
web interface, and are combined with this setting. Leaving this unset and
using the web interface is recommended for maximum flexibility.

Example: 

ic24.phperr.ignore = E_NOTICE | E_DEPRECATED

(c) ionCube Ltd. 2025
alt-php82-ioncube-loader/USER-GUIDE.pdf000064400000115466150413447510013276 0ustar00%PDF-1.4
1 0 obj
<<
/Title (��Markdown To PDF)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20250130155421Z)
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 33  
813.500000  0]
endobj
9 0 obj
[0 /XYZ 33  
749.750000  0]
endobj
10 0 obj
[0 /XYZ 33  
700.250000  0]
endobj
11 0 obj
[0 /XYZ 33  
131.750000  0]
endobj
12 0 obj
[0 /XYZ 33  
296  0]
endobj
13 0 obj
[0 /XYZ 33  
97.2500000  0]
endobj
14 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [71.2500000  66.5000000  144.750000  75.5000000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 15 0 R
/Resources 17 0 R
/Annots 18 0 R
/MediaBox [0 0 595 842]
>>
endobj
17 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
18 0 obj
[ 14 0 R ]
endobj
15 0 obj
<<
/Length 16 0 R
/Filter /FlateDecode
>>
stream
x��][��8v~�_��FI���@w� �0l A�l���8;��Ϗ.TU�򱪾�(���H�\lR���_�ۗo��#y����|�r�RSd�I���ej�'�P�{��Ï�����s�����~�n�|���{ޡ������/�ɿ��{�_�]��.���#L�,/������Sd�Nu%���=������O�o�>���2)�T������魞�eZ	�s�e�]y��J7ߕ�5X��}�I.����/�ߟ���ㄪ�>Oʰ�WVEXx
=��12����E��?�fy���C���}�5eH��5�^���k���N��%y����׿tjJ!����َ�"�t��ӈ�Gre�s�n�L��)�s��ӈ�GL��=�FL7���,�#��u5yNկ�������|�[�k��ҎTi�=�]<>g<�
G>�#&UE���w ���D�o*D����
aϧ�����Ont)�}���o��ɻ�����/_���ɇ��Ǘ���xy��y�������sf}��6��&-��.#�wV�-�Ϡ��7��t�w�i5����Av
u٣�N5����}�i9>wQ�9�z�v-�-�Ң{��y�TM�K�պ9j
�M�0D0�p?O�|Lg��Y�����a`�9�
�����SL�I7�H˞]��
B�a�X���x�ρ��s,�WSJ�*xs�`����q���-��}���;�ۈqS7���i/ƪ@���~��S1���[^o&�'�^�/8ާ�s�B�+y�����q��6s�1��1w&8�co�����&��:���b�"��eBѷ��R�)g#�fW���x�c׌��H��s0�������ɮ�EVv�:�a�Y
�|��>2��ءӜ�ַ֊��El��|�_w�{�N��A<����v�V)a��-�ë��lr
�E
��Z��-e�`�->S��Y��xݵT�^k�;�
�1M�{�v��w��:I#�(@�(Yw\-t�9]�����4b�Tr:��9cG�<:�&� ^�CQ�j�t�U��	S|�3A�8g��M�^���c�@8Vðf���c��5;�s��@�9�>!�ٽ�5{�����%)�&ěpW7aMW�g7c�R��<����&M��o�ףO��{�Y��Ms���|�tFs�Z-��`�b|����~��z�?��^���{��G~�����o���bN�ҝ[�V���5t��8�q�f5*؈p�:H��a��K�u���–n_��99��F���] p�9��\rSݟ�LfG��Օ�6��` 1|���=ę0 <dz���#��ص�.�#��1J���*K�|�ɔU��T}���=��(��DT��?6��3��)Z���1��xG69Qp$�#�p���T�<��gbo/Į�j��2��|�#��?����������8*I�d�.6��u4r��Y&iRqC�
c���
��PF\Ƥń�<N"H�����,�U�щ�d�>L��N���L����4�шy��w�!�5a<t��k���2���g?�W�g��e�-镫��� @'-��~�7�?�$�h0W�.��-��m@$
�XL�^�3�
��ǁ��L�T(A����e�n����v�W��7����U��\KL�q,����j�^Y!��D���a�M����`p	n��$N&$0�J5��?",�~}�����3��d츮�M���rb�#�($fR��>m��~��E�ofw(n�K�ox,��ŰƄ�H�Z�)&�X�c�n�
3L]0�|�5���x� �b�X�Zڈ��׏��r�_��TK�WL$�W��p���,�9�&F�Q6ܾ����*u��կ9���?���{Z�ߙ���5� �u�_�9��L�O�!h��IH�˴{UN=K�$���ue��B&Bm?ץ��9���b$k�<Я��l���t�!:98"�D�Ah��� ���i㣗4J�r
�v�<b�x�U���9ۊ����E*��__�_ߚ�Y�a�T��[�b{h�l	������"���/MV
��L�/Y����1��1�s~�1�
��Ռ"�׿�Pu�ٰQΫ�p5ח/0oe2J�.�)�^��i�9�TM�&��cE�JkY�?��~��2/Êaeq��r4n).c<C��fD�P�L���ע��φʋc<8�½0�p��Y�k���7�х�k �Ţ7s֍�ni��;�%�҉���vF�c���ե����t��Y��oZ�Se�f��L'r18�X�.��s��K�)Y
8�\�`��v+�i+�$�RɯݗZ���BW��[^��(i���RiY�ʺ��T�V�W�a�2��Z����gԿ��$c���OA����cp�TG�_ ����7N�k����I�a��ğ�-�v)� P�H��\�0;�d��"h�2�W�� �x1��Ȓl�fpıF�âO�s�
(T;�⁀��#�L�I^�l��֯�hT�߮K��J(;�@A9ҒHKV�%Gߪ�T��<���y*��)��<��j0I�ku:OY��<eծUu��w3�d�ZK�<U�k�<��|�5�ɡ{�˯�JiCX�b��dži����~�,�җ��6<rf� �"Kr�7R#��,�(�F�7����aq4�R�.�7p��*�j��vPL��jx�ձ�M�:y9�:��Q��������T�V�:y1�:m|d�1P���`��k-�:���L���
2�g�C�w��߮T�6��5��cr3����-gtR4�7�r�J�4�9ጲZ8Y�!��(,�3Z�m���&E�KV&�n�������)�;����L�2o�2�iP�Vm~��
Jg��z������T�V�A�L�hP�M�o?T��L2v��5�ZH��i��¶8�8
��n�q)p����e!R�<i�B��*�iE�����Y���U��
;�p���� ��U~�m#���ԺS4�(b��]
&�v�Ni)�"�_۵�Q�`��L2v���#O#�MT�ՇQ6���r��֧r@��0p`/~Sj���B(��pձ��0�}�����9b��`�8/�M(��j�S�?Մ��xpx�6���|�v�E3R���.��,�Bԇ4y_�ƶ�03��؝yqY��f�Njj��豤��XǒZ^RK6U�Ϯ�ߖ�a�m�Y	�ӓ`f�ud��s�k߳�hޚ*�
�k�qo�����z�5$�����W��3�k���L*m��|�75/:QT��QS�i����T��bANx��(,~��VLW	'�;�l%�Z8��fn1WGe*^�v�3�s��ֶ�l�Uc�1�cKR��vC�u9��ܤ�;��~��M
[&��g��%_Y8P������IM5V�;��Sk�pT�3]��ϱxw6�j�SL��F��
|� S=`�=��k��T*GsT��b��i�V2T7��j&��G�	#�ln2�R�s�@�i<z����ʉ~����d�0�bB�O��m��"pC0�bN���K=���$���"m���F�{�|��C�P�	�8*��W6
����u��C�����W�2��gn����׳B�
��2_��a�*B\칺 k�@Fv�2FpL���g̼��L�C�1ta��3�Y�H���-�Ӊ��"!�*O>�9�.�[�J��c�p@���K��:u�%�ʑ]�E.j�4�WaY�W�R(�j����׃O�q)��1WF:����i*��=�ƛ��X�-��g1f޽����ύ��J
'V�%����ȓ��UO)���"�0R�s$<�O!ެx���fI3����A0	�?��^뵽�f��i��'�}���a�&lM�42,��
]ji��2�>t���ˠ��`�j�S�c)����;���&U�ݑ�2U���c�慜T���B����֡��ӉM��Y��ϱ���Y�XA�st�bނ6����s ��s?b]Gc�^?����)zLF���S��v<�|�����ݦ0��2�qc�w��왎(û/��-y�>y��~�����#y�!��!y��r0in-���D
)H� ��?�\_�سtY�b����1@ԭ_��)����($����Y3�`���D29K^˕1p�5�b����Mo����7��I~����`�ôue
�1��op��0�`�!�n3QA�V
���P!%��fxp(:�6-Æ��+E{��~���{~�W�v4 d�'pSI�o3ɳ��"�)�1I0�"pN�ΰ*�WRw!�}4�
!����9wV�4�a+d�6�u���S�x�w�1�1;���(��F�}3�s��Q&#�)�@�)LUbc���e�oQ��D���y����lQ�7"�
fQw0<�B3�yaX3�>C6�Ҭ��[fF%`�lw0D�z�fb܁��o]�G
�c� 
�a�"_��gS���`��d^����7#m^z��f��X|1}�sa�HP���,㛹W�욹W��i�^�YӀ��4soW�I�]�m�^=�̽��]��4so7�IƮ�p3��T�`��l;��~s��������n:�0��6m����f�.�,��h�>��J1�vw�x$���G�7+���G���j�ρ�ԍ��<խ��H�7���p��멡�ԍ��<ӯ���T?�/�((�'���ի}GQ�D�H��q^fv�f��
c>9����� ҃M�G0�-��gxැ�ߐ9�>�9�e�o��c�YX���*|��T��;�7�
��M�F?c*Py��ן#SA3��T��5�l�T�2�^66t>��y�_oqS��+'FSA�� �
�j�h��.��E�l�Ekѱ�sĢ�5����,�.��.�w�0c݌��<ӯ�8��}٭Ȣ7n��pBżm�!��84F����z\UjD�F��g��݅`D��Mp-u/��fNp-�N�,˱�ڌ��<խg�2�\Kk�*��ڌ��<ӯ���Z)
��z9�,��D1��Ĭ��-Eq(�8�@T�h��^.�y��$�������$D�
6��PPjG�`�������A��Ϯ'F�R;b�L��҂�&
Joc�欞�i�a"J��#8{��)�pb��:=��Q<ݴx�6:�/ة�|���jѲ��~[�&26N���ĝ>�#CnԒ�#�<;�F��&�rA1���d}5����w0���~$���
�t5�ڟ�$����r�PI��(�2U5�f��9�V7
{̰�c���q�1�v ����r�M�j��p��	�~�t�X:)�v��f1�:��=�#�3ŧp�!R�`�h��x|K�ix��"9����o�R���_ds��E6�\ds��m��{N��0
�Fy,�!{J�O��������I���ޜr�gK�Z�p���jڎ��~s�;g�;UZ���0XLM-Y�g�s�i5D��s�9ֽQ���s��Kp&����gT��nE�k�f���=���33#�7�g�����z�x�w���J�����	JR����zB�v�)�ka���
Ʒⵃ0�����X��Y����Ǟ�NL�G���9ܩ�O��e!�E�Fd�aD��X��\0�$�����S�kk�qo�"��Ҋ��q��|�5�������Yϭ��T59(j�p仼��W���=��A;�Nw<.=�A5�]�<���kF<�j��+��y�*�GT�'e���w�����7bo[&�L�.*���SN[����k#/���53c����.l9H:T96�a�=����#Bm�"T&L�`ج��T��M�p�f����)�
�L�VA���h��@����[Y�9֬SLu
�VC4ᢚVy��{��$�5.U��!�������Sl�)����ɫ��t��k��$��RzQ����x��{ʤ���3΂��������'��H�@����EaJ�%0F6c�JnJ�H�]~=���z$�K��o�=	�R�4�yp`<�k��i�R�@�u�[�ނ�@���< ��p�g��XL���Nل��ݴ>���׮�pc���_j�1�g|`LQ�L�)�Ѷ�>rS0��e�E)��*F�,�^���Y�ê����2X��j��wai�EU]�!�1~T�4^�E"�n���4��ӳ���W�1��r"�Fg&��2��oh�>#.<kU˗��ŀwP�ptk��]�s0l�Zk�����	�F��+����S�>��K~8�|z;�*�~N>�I�˙
endstream
endobj
16 0 obj
6379
endobj
20 0 obj
[1 /XYZ 33  
760.250000  0]
endobj
21 0 obj
[1 /XYZ 33  
672.500000  0]
endobj
22 0 obj
[1 /XYZ 33  
158.750000  0]
endobj
23 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [102  696.500000  175.500000  705.500000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
19 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 24 0 R
/Resources 26 0 R
/Annots 27 0 R
/MediaBox [0 0 595 842]
>>
endobj
26 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
27 0 obj
[ 23 0 R ]
endobj
24 0 obj
<<
/Length 25 0 R
/Filter /FlateDecode
>>
stream
x��][k�H~�_��Ȫ*�.`�maaL���C�dv���d��+�JmK꯺��QIrk㶫���:��\��o>F��#����-zr?o>l�8�I�_T�{������P�}���l�G�7����7���x���h��4�p���"�����_��~�����e��<�_�l��痿�$��TeQ�=�Z���?��V�H�"I�6ڨf,��߽x��=��K�gi�آ��mZ&����&o~���JuE5�迟6�V�?w]�X]���\�؎��:)�Ĕ��]�&�vm�w]X=Q�:Iҩ�V:��k3ݬm�w�~� ���c[׏���,R:z�5j���X��2���KtYq�۫��M�L[�C]�ݶ�b�iV�5:�LRl[t\6��hɷ-YlR�k�ٶ�q���Ӣ�ۊ�ߦ�{F5C;f�ʺgt�t����Ūf�[�kɒ�tG-ۏE�xf�w�j[��768S��c�<CЁʶ-*iሱ�Pccf�W��^�d��;�z�L=���h�N��z�n�gf��ZU“Ep�RU�7�����#P7��6�{C��Y˟k�6�	c���Sg��ʡVKM���ⳍ�vݞ���·u
�֔�􆟁3U�n��h(�.�����u+�d����pl�,`���L��Cڡ�CU�Wam���@��Ң��ū����[��k�G��YQ<6QY�5֞�:�������aLT��W�je�~Ō��%xl��q�4sd���{��p>�}��ӆ��q^�9 >-�B«������lY%�IBʾ��S/��2r�s�	�Jiӌ�Ϝ9��߆׍�q?�؄W�uX�1���0(>?��Q{��P�@s<���
�,���9Ƣ �A�=���fzռ��!Y����2��68��#��`��,����5�ش,�ʌs�72#���-<Z�!��y�(���&��H��1)�3�5�H�㑍p�L��i�׎
�(���(�Ö#�_�������LM߶�I�&��X��Ԝ�Y棢t��=,�O]�`��Lg�c��~��||�Dc<c��]����+F�y����L���M���*y,+S��<�V'T���і��1��P���o������"�yZK𹓃r���;u�Z+ĩS�wwF����윪�o��g܊�=�C�������i^w�3-������-o���
��ma�s�=-�|��[k7��V]|���kty]�����Ϗ���]^EWW��Me��Ԭ[:�-�����@z�x
Yj��$�S����x%�Q��Pnj,T��	.U��9%A�itzSQ6�`֩���qf9J�ך�����!v�Ѐ���=Ϻ1#M=�*�h�ŒӠ�]K��J�^��b''�U���@/Lo�N��:�dD00�h`��]�i�c��P�t!*��IE��|1�I���a*Ɣ���Hr	v�^�ƊNmՎ�9i��lL(�:D�d0�a�ztZ�дCr��H��uW}N�_]��.f�"�=���i�zi]iӥv,�-�#'���̽��AP%n�Ex=�;=���dG���lt��ӬC���Ɣ�8�'Iq
O%,&�
%#�F(�u���u�Y���%Ťp�"_�!r�* �	k	�L��̙�i�H*�S�h�u��u�OMYf�2�5��L��Z0e����u
_�ܨ�I �F�Dcӈ��Ri���U����х���"!���S�J�T#F�I��c��>ƶ��ƒ�k���-�u��Ze7}խ���q�Ͳ
eh��E�'��QO?E{
�	����`7�8z����6`�;���f\?.�w����:�昬7��M m�z���k�۽�た��'Z��^:~z�5����6*���06{�-0��S6/+ΚD�[�vL�'SJZM��RԢ3ؒ÷�?c`�{�Ƕ+Yp�v���
?��CN�=��X���~q��cv��Q�������>;�={C{����-����kf�:�EA�2\�c�(�py� �\}E^G���̉�t\&f'��e| ��Ӣ�ZZhDiaܢ�( %Q�2XQ�h�Y_��2��s�*︨_&N���.����?ӗ
UR+�n���Ƕ͜��"�! �TD*+�H%��0&UcLy�bLnj��1ݞ���0�|��б�ɔtn�H�zI�a@?��>�w��ZO?p���P��p���h��u�?�
����׀���3�����mx>pv�){J�vDxfzD�;��8"J7Ӂ�\8��Ԧ�eo{f��ɫ�2!�TBR�[̙��P�P5��LgL;�[ô���
=�`� �G��n�w�L<
�N�g�O�^��ee�,f��w�2�eW��:���F>���QO�u<gY.N+��
N��Q��xu���g�����5�s�5�iM�2E�y�!���!ѬvFV�t��)X���9'���5�i����j%VPa����%�.����z•���4��D&
��у��PQ��WӔ�K�	D��S�%�S��7f�Dtc(z���c(8���R��#�C�YSl"��S���)�CY��n"���N�}��1o����A�pd���%IJp���T���N�(:ĈR�2��Rr���o���[Ӭ_q��8N�_!��zb��I��b.\�\W5gj��AK�� 2��P9���R�����:5]~��2֣	�)U{}r4P��9㫢!�]�	N���Q:a��H2��ZF�Jx`8c��R�B�<�������L֑��ߕ3k���
ߜߐ��D�R"��rԱ��|��	��Ռ�]�����хSC$�褲�I�59f��]�*�jq�1/�|�cN��#�xl8����*4D�,\�œ�B����6�R���I�3��'զiQI||�OQD��a8���"56,v���f`{�1f�"��)Мq��
 ������E��dZ&\;��:)�:��.�-����I�zc�#X(7��&�J�Ya�sm������5)���r���6�U
�	˘v0T��|�:Õ�3�p4AUA�QSz��l����}���PWN0�o�f&
=P��$p-ҁ$�N-꘠�F��YWa�zeyqJ(�䭭5S@`r�D$�w�eʛ ��ں��k�K��]�ʚH��s-?��eO�C|����`�ū�]��NZ|�^�%�|�f�e{���oCA�L�;%���b\p�q�@�D��Y__q>.+Y�6��dwA��REsj�p�-�Fvi�+���75���g2���t"C��@������iA/L]&&�;ZTa4/J'c¢�u(Cp��"�ra�!,Z��|*Hyx���g�|�!�K��Ҥ���Ɋe^��9��[8P0*e0�D� :ZF�O�+Yu{�4�	�Ǻ7��8,��k�

��֙���%!�F�u�"�{8�؈;N4����\���p��sL�'%�]�G��f��n`竩�ʗ$
��W3���CwӟƼ1�NDY�
<j�?ؕKd=c!�Y��8C�s% vM3��%#v�L�j�|4n��
�3̮���!Z&����C���'�u�>��a`��_E�d��dM�*Ü���C��'�)ܽHת��J�b�	#8��%g��3�e���C�ݭ��$���t��s�;���?����i��fH�MUv�4�2N�~�Y�bE[dg���y�[��u�dE
�pL\���x��5p��_����G�gZ��%-��'�~�q?��i:p>�G{�;<86Ϩ�Z�)E{�Z����Ňo�F�����~������Utu]�����I�Ļ���{��MO(l���>H"=�������.��gڿ�tJ�/~�ǯ�߆Qc�~b&�^`�`�36<S쩹{f1#��<k�;�1��(���*�mN�]*�?�5���P	@�_\!�dR�2LX��%g�$H�&�@#|��
L�B�DR�T-���e��1��r�<Ӄ�#mu}q��O*��d͇2��ZD��S�|ژʒ.mj�c:ϙ�}���Oi��T�ޗ����T����}�m����-q�vY�b0�e�e3!��*u�2bh,�m}ߎ��s�ަ,�)���Z ���w���]�g�z�
S��p"e�0.L��>w$!�S�
�T�����Ϟ�ߊ��s�y����'�Mټ����uK�y.o�7��Ow	0��7�v0����bJcȂ��0��<��Q�;���Ս�Ӎ�@7�N7����tc�W7�N7���:��vtcD7�vd�u�<�=+r��E߽;2��d�=l��S
endstream
endobj
25 0 obj
4362
endobj
29 0 obj
[2 /XYZ 33  
122.750000  0]
endobj
28 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 30 0 R
/Resources 32 0 R
/Annots 33 0 R
/MediaBox [0 0 595 842]
>>
endobj
32 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
33 0 obj
[ ]
endobj
30 0 obj
<<
/Length 31 0 R
/Filter /FlateDecode
>>
stream
x��]߯۶~�_��QDR% ����A�a�C��+��h�
۟?ɢl�G��=�$�-��k]Q$ux~~����}��?��O�>��O7E�l��u��:�B׹�������/����͇͇�߯�a��?>��y�?k�����f:�s��/����������S.�V�����_UQVyը�n�/����߾�~k�Q�uQhm�Q�\F���EcrS��u�'}�޼����)U����\U��sS4ua�F�8�:Ӯ6Y]����������L�6j�U�v��z�-˹]٣G��4�i
�w�6���L���OY?�W��Oݤ_�J�٧�7�����/�k�cd�ʷ�+-+��ck�+��^�y��rp�m�T�)���T����NSTz|��J�'s�G�y���Q��NF�g���}{�iZb)lKC�g�m���>��c��P�mYE�������.�~��J��P����Ŗ芮�G���g�G�s��	���<�|�4��wľ���{�[PO�
�Q|O��RK�����liBQ`�0��R\n{�xf�',3b5����h�>;��\#>.��3��S�˕=�G�p�X�a�7P���]1�z�w�dn{�Tǣ����;�
�
�SL!�9��8^)�~�J��M���k5�S]���&NcO	��J1+
�5���g��A9�U̩'T�نs���;�g;0L���̿o�����$��E!�-�`�_��{��4|����w��s�Ѱ·�~�	֍?����ϡ�)>��,œj��h�,���Jg|^i�]T1l�5o�9�mc
���ŋ�|���kF�3r�
����R/~�hS{?��x^������#�1��+�s���O�!��7�K5Bã�xLU�v��5���`���ю
�C�d���L��L;w�s�<�Hfn�aC�Q
"�,��)d���u�=��D�ak��Q���X�c�/���r����X�a_�����a�8�!4�
a<�8��d�\���!�nʒH�����̬3ұJ��1��v���q4·&�!�:����坨�)�	{K�g�mh|�HD,����vCx�(l�|a�/~��i�*/Ϟ�h�S	O��P��/�DL�c��o���:M&1.Ӯ��T�(m����ДݷMfl���Ƙ�nli
��1��L?^�w�'�q6���l�w�'�W��>7�����7�v�%�R
�b��� v)��:î�����e�?�	̸(0�"f��eR�9�Ue����b�sZs���DZ=�AkΉA[�b��y$�+ft����b��Ġ-�xű쮸�}nor1��ދ4"��`�F�7o^˫��&%��f=G�i��.'~u��{J��$��D�hxw�Y��-����=
����'�m?����+)=Vڙ�R��q��@=Djh����F�ר�D
��$��0f��
f,8
*�<��v�̕#��=&U�EgM�W��:�D���R�wJ���hIK��H�C�T�X�w�J�dV�@� ]SPeF�L!�i�zj_JU���g�0)��l�X�{�q�2%c�)܏�M؟�%���?NȾ1=$��Uy�X���X��-���9F�m���}��G�5�<�k���G(��7��
�M�k��-9��5�I��6L���a��t%�2�0%u���l@1Ʀ	��X5!��	�V�l�F��HuW��>ӏ煐n�	!�gu?��Pwō�s�x��vJ=�:I�'|Xc	��W�J(I��'P�a�[N[���d.��=1Hٸ06>q&��u���O�sc�W���C��J1�2����Ʀ%ƣ�H(��*S�����4Ʉ`��.�:x � 6+�l��`� R"r��k�uJdu�%ci��Ho�Ա�t�3$қ���\۵%�PJ�? �u%��Y��jb�8%]�Y�D���Dz�B�x8Z��͛bo�ԁ��JJ��;��)���Q;����N�Kn�i��o�$x�#��G�:�DG�K��D��z�R�R�BZ���C(=�x�B�����l`bс�K����K��f'�����ޛ]��\OJqN)�aJL)α��M3�CJq��g��o��~:���v����9�.믘�}�o�]�~:���֏w����F��a����ڧUvd��F+�S�İ伳X{�d'6U�F6�l���%;Vdx1�����4�k�mz�|���bF��~<���5����cF�7�;��
�M��w��,��C	��"ӞR���͠d��u��o[p���Od\�L�FYe<I�E����7�(p�xJ|�t�;3�\?��[oF�쯘�}��K�s��o�x'f��f��Q1�	e�0�����dV�;�&J�ξ��Ғ~?�c�#�����0:���=r��VE��\]��~�6�p4�4d�0�"�R|�h�3fp������q�9!��;
��"��Ce��<�յ����N�s�s��J�d��ld����P���'[l��+D�8Z-aѽ��=ӆ�rO-8�("�q��XE�0�%��i��$Yr�E{����ej����A0ώ׊��'۴���2��ފ���_��������HA�̖�hG�
5�&7t1��wZ�zO@��.1��c\�9�33P��)*%�V�ܶx=Li"\	;Zq�!Y�:Q$kՅ��z��x��n�Kkԕ*�p�
"�qkPvk0�d�2���N���iķ���)����1���$�� *���s�E��f�p��:�W�4�Z�p�^��>q��f�w�/!x�a�jD����ڬ�V�\W�Q�Np�&zΚ)6��	�������%�X���v'�a��.��4G�]^۫�Ԉ�d�����i���D���ɋ�i���d!���(`E
�S05��d���0�	�<Z�;���l>�%�Clk�T63�j��U�˥�C�-M��z�D8�8Z�=�B1uK/e�i�*�A�_�C��d��=/i�B{��B؏�W�=<�9�<"Sۮ��
���a�����|�sD�����@t����x���M�E���h��D��<�=8��R�i���X
Y�e=3�G������b5�����Z��8�mw�u�xkd=I҄��0>t&Qg��%hG[��{�|�J��?M�-�N���rs�Ө�M��ȾZ2�_D�Mh�VM1�'&1X����{�e뙊�~Y4���p�q1���l���7�
Y�-07l�0�3eO��=?z`�����pNe+�&~jsK��e�zu��H���$|?�Q7�\S�e�R6��e�D�[`w?X@b0~��9.W7�`٬M٦DK)>s�M4�� ���yͮ���,���5b�p¨�!:FP�.ք������I�{Sp��)pS{��u��|kY�1�@ٜs�$u�U��������&�Z@c�h�jA�{�h��0o�;)�e���'�-b�2�#��E#���/���~I*:gAP�T�]��t�mA�==P9��K��Pxw�zp)�K]z�f��uD{2��T�}�+�	C��~.�P�M������R�C�q�{b�K�L�����`���h�
�>A��ݡ�'�*2�*���K6�R��H&�(T9VP�1�e_� !LX_�l.C�'��OW?�2hiLЖI|`����Zp�<�!��U�uHgL!�DJ��FHe�Dʞ{��%�����e�#tsʏ 
Hf\�E�W�[p˄%�y����C6%���~��@���jx�=p�O`�5�ҿ��0>O�r����lS�/
ܣj��d�s�=�Ze�rmp�=%�G���K��LJ"��Aհ����y��~�`рl����d�쌚|�nRluE�23N�Y����sƸ�rB��+3ZٜY��jFs���Q5�9�'K6�K������qn�\��ŝr�RUc.��JL�A&�ɸ�M�q�1u2���x=Tg5�
��y�@L���ك�Tp��)��0�?��*�P+
50�UYY�)Q�n(��2��F
��s��3����>T�X��H�e�
�@D%*�π�ek��j�8��L�,�Ra,�{�Ehk���u+�Eh[����"t�G+;c�iBUu�]�qY�y��������*+(�w��dmelj�륱RyY�x�?I�Y�fl��r��'�ɟ��<�]d�?�W����y��@��m7���@���u��'�M�gpZy�	�
�?�P�8�X��>&������͛�����������y��}����S#��t�Q����/OGKX-yu'qzO��9q�uQfz]j�W�'��q��PR��8.��g�Qp�
�5~���q�#�F0��v���BLj���ui���#��u� �<Ǫ<L�Lj�x���B��$eG�}S~R��1~s�Q`����]��g�F��A\����2�|&�Ō�JL`��tL�
�c�f��I���!�Ʌ���*��h�B6�?�5�r������9S�N1�_89�-�G;2Z���ឪ���LQ��\�S{b�Q�]�u���T�T�I5,�T�J����N�z(��_�����2�'Y-�WF����6�kO��C����T�}�T���V���M�}�3c���7��ucKS�o��g��k?u���订��k�w������~޼�f�l���U�m-w�c�UG+0�,?�
�i*v�2{@(��y���.���DTIej��Տ�"����s�T��T1,���i{̘ژv���D:����y��נ�;���C�a��l��
endstream
endobj
31 0 obj
4897
endobj
35 0 obj
[3 /XYZ 33  
765.500000  0]
endobj
36 0 obj
<<
/__WKANCHOR_2 8 0 R
/__WKANCHOR_4 9 0 R
/__WKANCHOR_6 10 0 R
/__WKANCHOR_a 11 0 R
/__WKANCHOR_8 12 0 R
/__WKANCHOR_c 13 0 R
/__WKANCHOR_e 20 0 R
/__WKANCHOR_g 21 0 R
/__WKANCHOR_i 22 0 R
/__WKANCHOR_k 29 0 R
/__WKANCHOR_m 35 0 R
>>
endobj
39 0 obj
<</Title (��PERFORMANCE OF ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_4
  /Count 0
  /Next 40 0 R
>>
endobj
40 0 obj
<</Title (��ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_6
  /Count 0
  /Next 41 0 R
  /Prev 39 0 R
>>
endobj
41 0 obj
<</Title (��LIMITATIONS OF LOADERS AND ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_8
  /Count 0
  /Next 42 0 R
  /Prev 40 0 R
>>
endobj
44 0 obj
<</Title (��\(Available for Linux 32 and 64 bit x86 servers using PHP 7\))
  /Parent 42 0 R
  /Dest /__WKANCHOR_c
  /Count 0
>>
endobj
42 0 obj
<</Title (��IONCUBE24 : real-time intrusion protection and PHP error reporting)
  /Parent 38 0 R
  /Dest /__WKANCHOR_a
  /Count 0
  /Next 43 0 R
  /Prev 41 0 R
  /First 44 0 R
  /Last 44 0 R
>>
endobj
45 0 obj
<</Title (��Global settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_g
  /Count 0
  /Next 46 0 R
>>
endobj
46 0 obj
<</Title (��Security related settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_i
  /Count 0
  /Next 47 0 R
  /Prev 45 0 R
>>
endobj
47 0 obj
<</Title (��PHP Error reporting settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_k
  /Count 0
  /Next 48 0 R
  /Prev 46 0 R
>>
endobj
48 0 obj
<</Title (��Deprecated settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_m
  /Count 0
  /Prev 47 0 R
>>
endobj
43 0 obj
<</Title (��php.ini settings)
  /Parent 38 0 R
  /Dest /__WKANCHOR_e
  /Count 0
  /Prev 42 0 R
  /First 45 0 R
  /Last 48 0 R
>>
endobj
38 0 obj
<</Title (��ionCube Loader 14.4 User Guide)
  /Parent 37 0 R
  /Dest /__WKANCHOR_2
  /Count 0
  /First 39 0 R
  /Last 43 0 R
>>
endobj
37 0 obj
<</Type /Outlines /First 38 0 R
/Last 38 0 R>>
endobj
49 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/Outlines 37 0 R
/PageMode /UseOutlines
/Dests 36 0 R
>>
endobj
34 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 50 0 R
/Resources 52 0 R
/Annots 53 0 R
/MediaBox [0 0 595 842]
>>
endobj
52 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
53 0 obj
[ ]
endobj
50 0 obj
<<
/Length 51 0 R
/Filter /FlateDecode
>>
stream
x��[mk�8��_��u�jIP
M��AI�>��d�X�e�����?9gc'��L��^wj'�F�g4�������MLf�/bI�ټ��w��'�g�_�Pҽ�нX��ⱸ-n��Ǣm���|(&M_E��|�{��Gh�k��I��W��%�����+_�M+�>~�����*�����~�c����e�Rk��jl�|>3��Rz]=���-C���hU}�.�W֧�(c�&j�ixO�0��F|}W��=v�a��a�:7:�Lsg��xW	S57��ߦ?��.��H��I���3M{�s��l]-I���NOI�;z�m�c1}�c���:]��J(-�E�γ沸/lHތ����<���B,>U�5u��O5����2Va;k�Q�DV�#�:�qʭ��QkZ�$��}ܚ6+�++�Bg<J�N�0�=�s6$�$��=�A�d�Z���>�X0m[���ܬ$׋Y�	��*6�
h�k/Tj��虦=
�v��uԞ�J-�=߶w�Pq����H��'���i±TU���N�X<�����i�j86���e����
+��=J۟guI�m�h����Zs$1Dt��Op�.����}�~h�w-�
�M]�E��w
�-c�"–�t��6C�@V�'~2�r� ����r���ϋw�~���BL�f�o���	�����f�s�i�9�E�/��3�h�69l�B�-%9~Hk�$��A�Ϸ�%���I�x<ж��8�C�Hە�9�'|Ɯ�<��H1尚���o����:��	ýÊ���4u,P��:r��������kF�Lɣ�2o�9�5JX8��o<ی�o��0w�5;j��V��-7q}�a�q�����U�'7�+�wr��^�t}ﵳ1A��o�qi{����"�� �LSZ�����T� ق��dž[-��
J<l-@�5�(�����l5��V(���H�Q���&��Xpu.��AI����X.�D+[K�h{A�y�4��T���8�7=����T���l�p5R�XX�Dl5&[��a	
��g�8&[X��=�$�A�2�A9[Ƒ�>/�U�F�=�l}8��l�q���kΜ���x��yo��Z�)�`Te���/m�(�%N���b(c�S|=Y
[�WN!��a�a�i�:��x‘|�����̄���.Y��3?��>r��b$�f�8�9ebNfb�-�Xqkx�F-��r=^�Y3�U74�}��GʚG{����ɚo��9��L��É�qW
�	���Ki�������i�G?X��8��3��N������돶*��)#�<��������aX�*N�{<��-2��sh�Q�aU?�T/�T2���F��a���F����g�.����13�ގS������ [�'�Y�����B֬�^:�� ��F�_�U�o��u��|˾V���-W��h�#�D���D��~3���
[�Gj�8�18��<���Lk�o�6��L?��K��]bT[^����'_0��ls��K��[��Y{XE�얞�]�^u�����H��Ȍ��d��}����jz�
endstream
endobj
51 0 obj
1581
endobj
54 0 obj
<< /Type /FontDescriptor
/FontName /QCCAAA+Roboto-Regular
/Flags 4 
/FontBBox [-736.816406 -270.996093 1148.43750 1056.15234 ]
/ItalicAngle 0 
/Ascent 927.734375 
/Descent -244.140625 
/CapHeight 927.734375 
/StemV 48.8281250 
/FontFile2 55 0 R
>>
endobj
55 0 obj
<<
/Length1 6976 
/Length 58 0 R
/Filter /FlateDecode
>>
stream
x�}X	\G����{�F�1+Ȍ�`�P`&�7�)ry" �9ܠ� ry+(*�&��&Fr�I0�$���[s=�xd�M6	0��g0׾���ꪯ���5B�
�L8B����j�=���bI��_�y=�����Н����q!l!���';Ư������삲*���`�B`l�1-���#d~&��UE$�,�v#�U����7�	Bh;��`:Rp����$��V,�-BGb�j���!K�������eD$$S�A�e�x?�4�C��Hm�9"'���B�j��S{5�A�M3ϥ����a����F9QG�5��S��rs���R�*Z9�%M1�_��$���Wq
{��Q�87���K��0Q.�LպA��t�'�蝝���>��y?p��rqQ�r����j���G�J�����J��˴HF���t4x�o��v�\�j��b��͍s�Kv�����}{\,�'�4��Sm��MAA;��Vo���m�����3�((D���'�.�J��^�Q�Y�˱
���˰�3Q�޸* ���5k�z�f����6�~�R��]�}��ȲF�uS��F7�� U
R�)u��Ͽ�c�}��q�C�O}��2��_b��LY9ik�=��W���h:�ցCq�[�x::��ip���V=��m���@��Z��)&���p�
�>�r���ө�͐��O��A����.I�C��dg����i�D���Q�Т�5(	�c^UR�w�h�m*�����x~I™��aT�s��=52b~������Y�%���,\'	���y2�� C.���
(����*����z�����<����zy�Yï\ޒ�]�$~X��Sl�&ž]�O=�ych0���b���4�>m���Ҹ=�GG2u�_8������
��g��_<r�9%���7ȝ+�Dv��4ȡ���	�P���*�����R�t�)lk�9��
[6}s�Ͽ(- z��7-��7/GpZ��->	����W��HNJH�O]pLTĬ�����8~�r�������Ӌq�9��~�-���e�B��ՙ�%�J�ʊ/Mݶ�K/TT� *��'6�(�ˁ�Z�=Hʚu�,7eew�wsr�^@�q��!�-@�,����<��t�[�w�3�Of�05�a���Y�L�{A画�-t�3���kȽ��"C�#e��	����B�5�shk�y�;�����[�}7�K�1�v���*�-�ta@#Q�$u�����;�	�i����s����E�1g�
@5E��c7��
N���7��7�aD�w�M[n�ݱ^Z��c�@85<��k���͟s���:���e�:���d���(%���z�r栱
�o�me�Ĝɀ�Q0��l���N�b�se%��f���[�fN(-?_��a�5�!A%ً�KČi.SfL���ٺz���}zf��5ST3f��Oܓ�`��ؔ$�Gf�`��C	���e�����S��7����h�Qy��j�Fx}CϳM�Qh&����fU�A���P\t!�R��C�.����:���g�C�����R��=0i�/�f�7��96Ԓ��|�8���g
�:Gc0���:���l�ε�!��j�C����_�!Ӻ���@lx�e�@L秅���榦ܬ�C�,���*���М��Q�us�L�O��{�ȎTo��q2_�}��3��-�Ȫpu��Ip)�y�f4��xk-i�O�x�8�e	��&7��Ouv@И��g0�T���� 6�gҁR�y��^��@��7�lc;r�&
��Y7s��R p���Wh�:l�<y��ox`����Bqp�9u��zl�Ĉ�fzt'HrS��{�,6\�75X���/���Ū��C�,k2�&� Β�Y^�I9DL���-9Ē�-�	�Aa�O��⋗�L]�E���	ډ�ا�c�-Y����!�`�^q�?����C�򲑃��܀́�Z���8�\��ҁ��O&%u/\0��{%��m�ɝƧ��ص�z����N@����{�y
�i��J����t��K�4L�Yf�)�e/_2�vU�\+/*�K�8�a�PV�|DĶ����Eb�5��h��um�z��\n܋Ѹ9i�:��s�w�^*e�>�M��8Z���U�8`XG
9}�M���-v���q��q;����|I8�ֿ���28����6:���;��>$i�y��:��yj_��"=nNN�w��,~��#b���bRӱ�r���<�ďCk[��;�b㫑[F'�#��caP�5��%�����f�6GF��n���}q=�h+���X�r��:7��{�{�
������*��l��H��F8-ԞY(3R{{��I�o!m�����.q��o�~��r3p����¹vH�R�V�W��`@;�?|I�ʸ�	�Z��i���an搋�=7��ws�,�g[�C�E����
w��Do�q{��e:�x�S��zE�Ͽ�3��Xc��Ajd�a��^�/�g?6ԇE�B�s!hw$�Ò�v�Ce~V8UT�NSz���m,�&<�f[h��4W��/q�H�`��i��\ø�ܔ��lQo�0I��ѰȲ����AK����	�	����[{N�7�F��5ԟ�i�z���?���A^��73��]�u���ĸ��Wr�?�,!>���w(������w삦ъ�d��9���
{�'��pn��_�&�S��{T��j��j��C��Q��Ć(8K�e�?������2w6]��NP�~s|�3T��x����]��[fa ��_h.^��\��u��,�o��!����Z��r"�s
ӡ��.8�Ҟ�K�钘��_�>p�fK�©���C�'�w���x&�47�$����1)� �.A�X�eV5<@�Q$!��H��$ǣ�?��o�,_��b|����1q�Lv��gs��ں���kSo�]I��s�<U\�矑��.*�-0��7_��7?6��tn�?����>2j���ܹR̟����2�����Ar@�\��;M�_�i.�]����P*��{�c}�F�I��a�S�r_��F��GLs@��t�,�L��Y	��e��Ξr-�
��VUmqۓ�l������%�^}��+d}�#~� ֈ_v���@<��
HqҨm�1����-M������_��N{09���Y�1����y~4��W�:V\��Oࡺz���K�û�z�
R���nc�C��

���?�;������@�|��@��k�M�/�Q
U2m@�Z����������{<�?����v�ֱ��1F���L]���2�)
�~*��w?�׉�22�\	��\s3�ف���ѠF�1�p���a4�bW�IH~%�~c~vVn�k���6|��
v=va!�[�Ö�ԯ��w�K@��O>�Ry�/�,X�b���+���4\��k~A�b��G�$���߁|T>SG���z��@CKmd�Ⱥ�Pl��[����V-^�i�[W6m鍈ظ����{[8/(�EO��^LY�r����1k�g�� $�nS`���d�͟��z+jU�h'����b.��r�zDox�XD�Gr8�'8�;0���koG��y5A��G`�_-�A�5�^�K�������~I��\���a`���Po�,���}F�nS�����1Q
O,[q�aIuٿoK�����mz1�v@n�,
-�킁D\����x���˽/��&`�6���G]��W
��5 �Y�ꖳ�{�5�ؑ�A�kX���.޴��k7â�%k
�Be��}�����O'�au��a ~S�8�ޅ�s���+^,*����k��$&���k����H���P\�
*-


(*	F���yi�C�<�,'&Noga[±Z]��1����3��19��;.������-{�t�)�'Xt�p��qw�s�����]�0/�\��uN���c�s��J���l����G���d���ؗ\~	q4��~�*`��w-eI��Ҙ��a�.�>"l��U[�]�t۶�G����u����/!��ի�ڒV�&�FF�F)�;�S�NB��Q_d���;W���4�.�q�����*��o�����K"A�L샩5Q�!;�/����ˌ��1u՚M��b�]� $h=Ƞc����G}��R:��eŌ��'�Wԥ�}�0R��Y���4��F�_�f��ZO1��]3�m���z0Ƃ�	T��x	9q{���0��0�=�*��7��� F�
��qęat;�T��b�?�����s�ϛ���<Y?��s2�7&^���4�8�yp����P��m��'?<�G�����1CvO�<S�����E����8�PvO���+�k%�����"��\�*�I%��r�!��<�C(�h�ů$|I��a�FҍEO'�]��U$Y(%�Kē�ƶY-�H=Bl�[D��3z�52�)�X�%�!]��8#�$�N��82�{�8��=r���1�I�lߏ'6^X��.��#d}�l������$
�x��Fҁe
�D��Ä��d:�Kƾ(,EXJ���C���+I&J�Dw�F�z��Ë$���,��x�O�D:�.��t#�;�rq\%w�����Z^�g�����`/L��B���p_��"d�&�Q��Z./���$����M�M��36l�ٺ��l�m���4f՘�1c��<6�IKd�#i�/;r�A��b�3�wZ���s�:��oX�<�oY�����u����d�
g�^@�HX?��)�z�Z�Ek��5k] n䶵.#N���Ǔx��IYGJH�"٤��P��o	��F��'�
#�$����"���w�Y�R+�H���8��֕�de���<<=U!FcV~�*�0m�jQ~�*�}*U�f�f�Td��X\o-�2,$ָ�X��H.��㒩H��fd�秖����Cg��V)�k�M�-��
��?�0���c��k�����x6�����x�p��EJ�-b����8�K~��'f��|d'
{
%��bO$�8�!‰ç�Ħ-++�3���rvjQjZv�lcI֜�����Ҍ�9�aA�qA�^�q��G+�
endstream
endobj
58 0 obj
5244
endobj
56 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Roboto-Regular
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 54 0 R
/CIDToGIDMap /Identity
/W [0 [440 241 566 547 646 547 557 526 246 534 540 559 336 557 557 261 643 512 676 592 546 519 869 324 481 241 557 344 557 626 707 195 557 270 745 469 564 611 548 682 866 647 707 651 589 880 339 345 492 240 503 557 557 562 448 210 564 557 557 557 557 618 274 409 631 317 237 ]
]
>>
endobj
57 0 obj
<< /Length 826 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0042> [<0069> <006F> <006E> <0043> <0075> <0062> <0065> <0020> <004C> <0061> <0064> <0072> <0031> <0034> <002E> <0055> <0073> <0047> <0054> <0068> <0063> <006D> <0074> <0076> <006C> <0070> <0066> <0067> <0050> <0048> <002C> <0032> <0049> <0077> <0079> <0045> <0052> <0046> <004F> <004D> <0041> <004E> <0044> <0053> <0057> <0028> <0029> <0078> <003A> <006B> <0035> <0033> <002B> <005F> <003B> <0071> <0037> <0038> <0030> <0036> <0042> <002D> <002F> <0056> <0022> <006A> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
6 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Roboto-Regular
/Encoding /Identity-H
/DescendantFonts [56 0 R]
/ToUnicode 57 0 R>>
endobj
59 0 obj
<< /Type /FontDescriptor
/FontName /QHCAAA+Consolas
/Flags 4 
/FontBBox [-432.128906 -302.246093 677.246093 1011.23046 ]
/ItalicAngle 0 
/Ascent 742.675781 
/Descent -257.324218 
/CapHeight 742.675781 
/StemV 70.3125000 
/FontFile2 60 0 R
>>
endobj
60 0 obj
<<
/Length1 11900 
/Length 63 0 R
/Filter /FlateDecode
>>
stream
x��yytǙgW7�� �H$��M���/�%ID @�hZ�%��x��-;vd[����$���x2Il����;M6;���y��y����Yٱw=~�l�W�
�e�X�+tuu�W���jR����8�P�������`����%Vf�Ux�o������c�hde��e��X�<�L�=<�����}���u<�<�6�����ߚ(ʌ�/.��[�ڨ'(ʢ�g6^��ێ��\MQ�a�͢�(1E��(
�;�kj��

i����E-�J�7��՛@��c�R]TwS���'hZ:E�)�o���bލ2S"j��D��̀�
8EJ�7;��J��:\��`��_G0P���K���f�$��Pe�_���!frMD��*U��@p@���h����.�;�c{��~Ra�K
d�R���D)SH*�*d����5��n��g���x�mv����5FCqQ�`�r����`tnZZ�T�*�R��^�����A6{��*'CN�r��`�>��{�#�3j7��2�L&/S�f���T��j��L=���S�ĔL�R���Xƿ,3�-f�N���(�c��"�Q6����*�uא����w���4j~<��+���wN�[L�M���X���}�d:1>��b���TZgecS��PsyE�R�r9C�};�B�e��[
��8]�a��
<��90��r"�����L
���Zde���[�o��k���}��:u4�&��Rt��k�e�R��ܳR����rW�<32|y�'X+˖;]����
�r��P���ڽ���!T(��ܭk�x��n~¼���sb�
`}h�?�(��üпep���@�}�����������7���V�3�N������4*�щ��	��W:�Ln�hW��~�ď�M!�,e1���NY(��pI6,R��I�y󌤦ʍ�yvx�|��Zv����ݡ�J�ԾW���x��Z���~|�������LTӆo`i]���.~!U�9s�,�o�޽���s�`���XOW�W�}�c���^�pT�ܾ@������Se������� n�x�;�j�[�*�]�������g6�r�F���3hd
�V�x�
b�΂f>O��:���
~B���yv�I�(�IN�cD����oyk�g\Nvpr���[������D|d�)d1��⨫�i�Ֆ;�Z��5ώ�AbF")�>��:��g��Ӄ[����clr����]��ju.w�	�3����_�V��h*l5�kg�:MqQQ�Fge��U�+*F��H��ZQkQ�����q��Vi���7�xt��壍�G�P�:���1?'�F�<�`����(�
�+ǝ��q����o�t+����;���yi|dϤB����~���@����;=�Z�����P���j�vn�xh���.g0������PR�˟S(d�B�!�����1��])*�����`Vi
T�؅�I���9�n�(U>恟���p�Q=�*�#�b�Q��9�/�ռxF24:>3������!�3�u�r��;w���b��^g9�H���G~z�>PQ�ӵ��/�xr_k��*�0[�
d?)hؐ�2�+RG�-(v�y�����3#���*�pEy������\�Ku~������(6Z<�mkG�.�͊f��p
��,���x�}k�7�܀=�T0/�hw(y@�k���PwV�������.?+���X��5L|5���Ţ"nJ����y����~:���k�6X��6�W)��\i���z}�~�}d��~���֦{����%�4>�Z�8R�p?{��$�L��bdU6���|fh�7/{�G�=�.W��eI���$�'��OdZ��3��$7w��Cj)������5�Ȇ��6���F���]��Lks�ɿ����ll��W[W��=911��BPf xO_s�ۣ׫U���ᕖ��;�5�xkL�B.���{&;�+���˂��\�+)�R"��Qc�F�F��hL*��Q�u{�몽����Y��P&/Ui�&�V�Ҫ4P�X�+�5���������OT<�"�V�Y�.V(����ʚ,j�m�B���ػ�c���Xs��-���%��������Kp��r��q��Ľ��V:tZTTR�**)���A��6�����֎�S˨�.r����t���
:�����j�]Q��ZSӾg�Ζ�r�x�"j�j��hJ���W@i�q�/p��k/����p���i�$wg��w�4�ɡ3�v�Gw�T榛�~��ysm�E����]���ij@5S�O�����ןC���;�7�����o���\'�큹e�8�~�5�G��[�,��u��h����Ք�d���х�7��O�(�=��"���)��]�ʆM�_���Fy�-�^j*�L�K
eE��R�J�5؞��EQiY��t�����Qo4����G�Ӛ
v��u��>���N	
����Z;B���aW�H�4��lY;�\�Y��e�C�@
�T��e1�Kp�9�/�&8/9�z�ZL0�r�|N��rhR�ĥ���/tZ��dc]�/��{����2UyECco��t�D]����Xg��Y�Q��~֊�Ck��McuMg���`��g���}�aZ2l�v�Y͞*����5��1xȫV�E�N�$T�	�6�h�p�
�!����`&X�=�����:�\NU)Bf���������3[����2}�	(��.��|��OZ�u���v��jF3�1C��"\��^��(�x2\���jƶd�������:�ƈDi���hktVZ�0�hc��M�`����\e	�\��ru�3���'8���4�%#��
�k�`�g�҉��v��)J3A7:
΂$d���^'2}-r��p�?�^G�}k��wf��K��B�S�cHI���M��Խ�zh3P�]�U'�t�[Q���v��5(WF��)�Ѩ$<�ug�}LƤ,1[�C㝡&���@Ն
��;jk�d��uLM�l<Ԥ7�45`T��
��u���D�I,�`���
G�%֘��'w��)�����q7���H$���bv���X+U�-.wm��6Y�J�i���qgW��Vo,.R��Zi0"SZf����}�m5�F�Z��c�`S(�(S�4z��+�^�5�f����Z0n�W��6{I�Q����Huj�F��i���
6-V��R�����b���#��k	�x�G?"u

 ��\�e�|��ܴq�=���3�\�LJ����v�{���xg�������B�A�W/}㟿8�}#uS�\�M5C����`d6e9��ʅ�NU�q6 ��ñ�R5�8�SƆ`CMS������'�`��r������G�5vn�:����YWoc���ͪ�6�"��@@�PG{Q���t5���DZ({�H.s�F+[�in�ꮩ1�D}$Q�J.�JD�
���q55�h�h���6�S
_��-�'Z^5���&*,f�s�4v��1'�ߥ� =�^G��;��z@�@TK�ԣ�Co�?���5Y�k���Alt�
���P��߼��͢�����:��l�{X!7�+��G�z�>���W?�W�f����6�5��9R�rt�X�w獡S�sTB��ǵ��:0
�������
F�NKꚚ�C�Cm�͵6�w�M���zg��\T��B�7:+��>X�hߧV�ڵk��'�M>���BB^懰+�4��x�v���o�ݻ�
�\VTl4y�[G{��n�9x|bp~�U���!}�ڵ��
�
�j8��U�ʖ��ZBc]����m]�ݽ}#��J��Q�QF�.ɈAP����}y�a��ƻ\�kFo";�.�?̈́W��_Y�~?q�CQ1He�s�P�wɝ�9!A�u�pb�G��M�b��깕/��ї�#���:���XG��B��v�N[n�V5�6�\.�f�d�]����U�@_�	�ҏ<u���^=B��=#Ǐ]~��N�]�=ǎ���ag�X�[
ٹ�n��9p\�ZY3z:�q�Ve)��w���vl��Zf�%U�D
!�ڲp�Cͽ}û"F�ƀ1�頻he��_s���
��_�D:�-Vi�1�Ev[}� .�Μ��{n�aO9�/��0����>�>��Nr��&�6�:Ɲ@��O�Пq�v	���W�ז8�~���7��&+Z��!��y,�8�
�ܕW��o+�{�vÁ��3��T��x�j�@��ׇ�;۷�����P(��궎�'��R��%]W���-��.g��嬘�5l0��[#�z��ҨG��o�j�����\")+-��ڂ�*����Q�,���=�q���\^P {<mm��ݶ��@�wV���K��S�E�o�Kk���_Ҷ��tPlz�;���I��p��
%�"H�T���=��x
z�"S�$kܴش����K��k��%1�y{uwˑ��t�[�ET��<[������juW
���=�������J�\����Ѷ�J�J���\Ύ��=m�J��~��N��r�ښ�G��|���nO��vt�ȑ�dNo��U��S旦ý[�pb��O�!����ƩGT��!w�yU��GE�����k��&������b�-T��P���SO��N�S7���N�\�{�C�Tn>Ư+c�����~���'�tW�؞H|���;��ػ붆�ɂ��ߌ��>X׍��m�w���~���|����g��
w�W�Y��d������������������� �z ~�q��"**������‘/s�G#���S�!���qxW���u�́���Cm�j�^lz�,������
hU���}���~��2��"mX?�0�[��]�p�e��;���ze��o���sc�ûv�j�t�8�ؤ�������]{�����F4E�H*"\<`1�h�{���+��O��yY�߁#�'���~��)ķط�ׅ%m����v��ȳ�K��F��5���D�Ǐ�YB)�/c��^��s��
wܖD�����]�F	�;���`�3p�m�p�@�愶�%h)a-�B�П��S	��C��	h^��Vh[x~��К��o�
<bd�����D����>A���oL#s��>�D�!J�>��.�'��şK�%A�i���NH�)}��t�
�>Q�O�JY�짲��Z�G~^���mE�bX1���⇊�ElQ+�n�z��۟%��멜=�B���B���ӧB_D ��S
�.�%0>%�TzW�PzP�R��q�/��'�&��W���WPy��/Bۋ� �ƒK�	�F	W���R�i�Oì
}������Q��@�)=r}	�	})u�	��C��~!���B_&�M��rj\���WP�J�ѧ�cB��J��Q߃J�j�:*�T��Pi*Ee��RY�^|��a$�$ԉ,�M%�b��06G�ûy��=��oW��c�uvG<�NeR�Y�7�^L���x*�c�	vw|n>�aw�2���X��m0	�6�d&�C�0�~�����R"�۹o����:-�ͻl7N����PJ�@YxKg@6��Ja�+h��0�,Qk�X ��1�<~3�w6�y^��fG��a�)NL��`��g�0�M����p���e��<�̥SK�x8�ZX'㱌�N��c�@�Ѵ�X�PUDh7�������/E��7���T*{7]�A>�P,���g�x���,�s��������~�҄�y�
4��^J�u��ό���%s"D�,Y���`�B��=��]�(�������2�[�'4Ä���=�%c��>9/��b��8���𔀧Cdk,JV����V|�f5�7ssz��ě�9�7)b�X��X�0�:��bLk(#�a��(C�����=*�'ފmrX�����eBiC�Q��E�+dw�;<�_\+C�()�k(����ܕ�3A,�[=}��2M�� c1�>���#���uZ�ܻ{B�;���M_H��$��9�2y�_ ��z��
҄A�	���狷-�	<�1�՘�9�x,ː��9��ab�$p��!F}I�)mX{KB8���;-ț\K�x��%�J+ٛ��y�[5�!���Uy��*�*)�Fn~�{zR���B�`��s��s4#؟�WΧp��lI�ov=��=8A�&�s���2#D���躟�OY�_�̟!=LPae]�9��3dn>�-�q{�/Ģ�l*�.ebl<�.�Ss���B<9�ƒ���Tr!��\NF�d�4��#K�l8�e�e�A6YH%S��p��Kf1��b,��C�&I=2N�#YȒ�|�p���Lx!�.ǣ�j6?cS�(�]Y�-��xf5�>�y�ga��T*
dR�H��3R�p�07���'c��t:�YL%��C;
��@0�$؉x2�Z��<F��Dx�
'�ex�ē��%���<V�.���f"��M��Tzv���˂�$I�q<F7)!��ԛZJ�ci�	V9�,C�_H�� �B?�I����i!��X2
��NPVd"�X���Xr4�����%��I,A�n���4�Ľ��B,NdZ�|>�f��l�
D�?�������$dk0Of>��cB3 ?�5����[�,6��D*�����e����6�
g�1vf�=N�`�lО	�yG[��%�<��E(�j�Z&����[����B���E���8�n�/5��.���.//�r���P���q~�6�%��C��,A�4A���9�x�lx&?��R�^��|�]ɫS��8����G��Wr���@.�1(���P,���pQRje׫�e�W��;���o ���ǕE����r<-���ȸYn���OU��M2�]�?�U�6�~mP�Ȅ|���#�T��r�f��3
���%K�˕˜>/+_�$I~�QIy=�o�i�ߍ�k{�P
�H=|*Erp�[�����_W�g16T���'8��c�l{7���]�dq�X��G�����ш�:�BL/��0!� ����ީ$�^U���������w�L'`	�M�#<P����i��V�]��|I�aWH�D*��)��9ň�2^j)���"vg�3K,n�XmU-1.��%R���/BY��0`���lx)���3���;�	
endstream
endobj
63 0 obj
7274
endobj
61 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Consolas
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 59 0 R
/CIDToGIDMap /Identity
/DW 545 >>
endobj
62 0 obj
<< /Length 742 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0036> [<0069> <006F> <006E> <0063> <0075> <0062> <0065> <002E> <006C> <0061> <0064> <0072> <005F> <0070> <0074> <0068> <0073> <003A> <003B> <002B> <002D> <002F> <0076> <0077> <006D> <0052> <0053> <0020> <003D> <0022> <0066> <0067> <006B> <0031> <0024> <007B> <007D> <0032> <0034> <0030> <0079> <0078> <0037> <0033> <0045> <004E> <004F> <0054> <0049> <0043> <007C> <0044> <0050> <0041> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Consolas
/Encoding /Identity-H
/DescendantFonts [61 0 R]
/ToUnicode 62 0 R>>
endobj
2 0 obj
<<
/Type /Pages
/Kids 
[
5 0 R
19 0 R
28 0 R
34 0 R
]
/Count 4
/ProcSet [/PDF /Text /ImageB /ImageC]
>>
endobj
xref
0 64
0000000000 65535 f 
0000000009 00000 n 
0000038255 00000 n 
0000000187 00000 n 
0000000282 00000 n 
0000000756 00000 n 
0000029337 00000 n 
0000038121 00000 n 
0000000319 00000 n 
0000000362 00000 n 
0000000405 00000 n 
0000000449 00000 n 
0000000493 00000 n 
0000000530 00000 n 
0000000574 00000 n 
0000001080 00000 n 
0000007535 00000 n 
0000000877 00000 n 
0000001053 00000 n 
0000007863 00000 n 
0000007556 00000 n 
0000007600 00000 n 
0000007644 00000 n 
0000007688 00000 n 
0000008188 00000 n 
0000012626 00000 n 
0000007985 00000 n 
0000008161 00000 n 
0000012691 00000 n 
0000012647 00000 n 
0000013009 00000 n 
0000017982 00000 n 
0000012813 00000 n 
0000012989 00000 n 
0000020361 00000 n 
0000018003 00000 n 
0000018047 00000 n 
0000020194 00000 n 
0000020020 00000 n 
0000018298 00000 n 
0000018452 00000 n 
0000018591 00000 n 
0000018987 00000 n 
0000019859 00000 n 
0000018784 00000 n 
0000019263 00000 n 
0000019391 00000 n 
0000019554 00000 n 
0000019723 00000 n 
0000020257 00000 n 
0000020679 00000 n 
0000022336 00000 n 
0000020483 00000 n 
0000020659 00000 n 
0000022357 00000 n 
0000022621 00000 n 
0000027977 00000 n 
0000028459 00000 n 
0000027956 00000 n 
0000029477 00000 n 
0000029735 00000 n 
0000037122 00000 n 
0000037327 00000 n 
0000037101 00000 n 
trailer
<<
/Size 64
/Info 1 0 R
/Root 49 0 R
>>
startxref
38374
%%EOF
alt-php82-ioncube-loader/LICENSE.txt000064400000025020150413447520013000 0ustar00LICENCE AGREEMENT FOR THE IONCUBE PHP LOADER, PROVIDED TO ENABLE THE USE
OF IONCUBE ENCODED FILES AND AS PART OF THE IONCUBE24 SERVICE (ioncube24.com)

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING THE
LOADER SOFTWARE. THE INSTALLATION AND/OR USE OR COPYING OF THE IONCUBE PHP
LOADER SOFTWARE INDICATES YOUR ACCEPTANCE OF THIS LICENCE AGREEMENT.  IF YOU
DO NOT ACCEPT THE TERMS OF THIS LICENCE AGREEMENT, DO NOT INSTALL, COPY
AND/OR USE THE LOADER SOFTWARE.

DEFINITIONS

The following definitions shall apply in this document:

LOADER shall mean the ionCube PHP Loader software package or collection 
of Loaders, including any modifications or upgrades to the software, used for
executing PHP scripts previously encoded with the ionCube PHP Encoder
software to render them non-humanly readable, and any associated
documentation or electronic or online materials relating to the software.

ENCODER shall mean any ionCube PHP Encoder software or service used for the
purpose of producing non-humanly readable encoded files from PHP scripts.

ENCODED FILE shall mean a non-humanly readable file produced by the 
Encoder and being derived from humanly readable PHP script source.

PROVIDER shall mean ionCube Ltd.

USER/YOU shall mean any entity who has downloaded or obtained through any
other means a version of the Loader software.


1 LICENSE ENTITLEMENT 

1.1 The Loader is provided without charge.  Title to the Loader does not pass
to the user in any circumstances.  The Loader is supplied as object code.

1.2 The provider grants a personal, non-transferable, non-exclusive licence to
use the Loader in accordance with the terms and conditions of this Licence
Agreement.

1.3 The installation or downloading and use of the Loader entitles the user
to install and use the Loader for its own internal lawful purposes.


2 DISTRIBUTION 

2.1 The Loader may be freely distributed to third parties alone or as 
part of a distribution containing other items provided that this license
is also included. 

2.2 The Loader may under no circumstances be branded as another product, 
whether distributed or not. 

2.3 Distribution as part of a commercial product is permitted provided such
distribution is in accordance with clauses 2.1 and 2.2 with respect to the 
Loader.


3 ANALYSIS / REVERSE ENGINEERING / MODIFICATION 

Except insofar as the user is permitted to do so in accordance with applicable
law:

3.1 Any analysis of the Loader and embedded data by any means and by
any entity whether human or otherwise and including but without limitation to
discover details of internal operation, to reverse engineer, to de-compile
object code, or to modify for the purposes of modifying behaviour is
forbidden.

3.2 Any analysis of encoded files by any means and by any entity whether human
or otherwise and including but without limitation to discover details of file
format or for the purposes of modifying behaviour or scope of their usage is
forbidden.


4 WARRANTY

THE LOADER SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
WARRANTIES INCLUDING BUT WITHOUT LIMITATION THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE ARE
DISCLAIMED. THE PROVIDER DOES NOT WARRANT THAT THE LOADER IS UNINTERRUPTED
OR ERROR FREE, NOR THAT THE OPERATION OF THE LOADER WILL FUNCTION IN
CONJUNCTION WITH ANY OTHER PRODUCT.  


5 LIMITATION OF LIABILITY 

5.1 IN NO EVENT WILL THE PROVIDER OF THE LOADER BE LIABLE TO THE USER OR ANY
PARTY FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR OTHER
CONSEQUENTIAL DAMAGES ARISING DIRECTLY OR INDIRECTLY FROM THIS LICENCE
AGREEMENT OR ANY USE OF THE LOADER OR ENCODED FILES, EVEN IF THE PROVIDER IS
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

5.2 THE LOADER IS PROVIDED ON AN "AS IS" BASIS.  THE PROVIDER EXCLUDES ALL
WARRANTIES, CONDITIONS, TERMS, UNDERTAKINGS AND REPRESENTATIONS (EXCLUDING
FRAUDULENT MISREPRESENTATION) OF ANY KIND, EXPRESS OR IMPLIED, STATUTORY OR
OTHERWISE IN CONNECTION WITH THE LOADER TO THE FULLEST EXTENT PERMITTED BY
LAW.

5.3 DOWNLOADING THE LOADER IS AT YOUR OWN RISK AND THE PROVIDER DOES NOT
ACCEPT LIABILITY FOR ANY DIRECT OR INDIRECT LOSS OR DAMAGE HOWSOEVER CAUSED AS
A RESULT OF ANY COMPUTER VIRUSES, BUGS, TROJAN HORSES, WORMS, SOFTWARE BOMBS
OR OTHER SIMILAR PROGRAMS ARISING FROM YOUR USE OF THE LOADER.  WHILST THE
PROVIDER WILL DO ITS BEST TO ENSURE THAT THE LOADER IS FREE FROM SUCH
DESTRUCTIVE PROGRAMS, IT IS YOUR RESPONSIBILITY TO TAKE REASONABLE PRECAUTIONS
TO SCAN FOR SUCH DESTRUCTIVE PROGRAMS DOWNLOADED FROM THE INTERNET.

5.4 THE PROVIDER'S MAXIMUM LIABILITY FOR ANY LOSS OR DAMAGE ARISING FROM THIS
LICENCE AGREEMENT SHALL IN ANY EVENT BE LIMITED IN THE SOLE DISCRETION OF THE
PROVIDER TO THE REPLACEMENT OF THE LOADER PRODUCT.

5.5 DUE TO THE NATURE OF THE INTERNET, THE PROVIDER CANNOT GUARANTEE THAT ANY
E-MAILS OR OTHER ELECTRONIC TRANSMISSIONS WILL BE SENT TO YOU OR RECEIVED BY
THE PROVIDER OR THAT THE CONTENT OF SUCH TRANSMISSIONS WILL BE SECURE DURING
TRANSMISSION.


6 BUG FIXING AND PRODUCT SUPPORT 

6.1 The provider will use reasonable endeavours to provide support to users.
The provider will at their discretion only provide support for the latest
release.

6.2 Support comprises of fault reporting via tickets and fault diagnosis,
recommendations on workarounds, and where reasonably possible a timely
resolution.

6.3 The user accepts that on occasion the ability of the provider to meet
anticipated or published support schedules may be impaired due to, but without
limitation, Internet service provider failures or software failures that
affect the ability to communicate for an indeterminate period.

6.4 The provider reserves the right to refuse to provide support at any time.

6.5 The provider wishes to maintain and offer a product of the highest
possible quality, and accordingly may from time to time and at its discretion
make product changes for the purpose of correcting behaviour in variance to
the published specification or the user's reasonable expectations. 

6.6 The provider reserves the right to charge for support where the user does
not have a valid support plan in place, or where the support offered exceeds
the scope of the active support plan.


7 PRODUCT UPGRADES

7.1 The provider may from time to time release product upgrades. These will
be provided free of charge and attempts made to provide a timely notification
to customers of the existence of any new release.


8 ERRORS AND OMISSIONS

Whilst reasonable endeavours are made to ensure the accuracy of documentation
concerning the details of the Loader, the user accepts the possibility of
inaccuracies in information presented in any format, including email
communications and online services. The provider shall under no circumstances
be liable for any events that arise as a result of unintentional inaccuracies
or omissions.


9 USER INDEMNITY

You agree to fully indemnify, defend and hold the provider harmless
immediately upon demand from and against all actions, liability, claims,
losses, damages, costs and expenses (including legal/attorney fees) incurred
by the provider arising directly or indirectly as a result of your breach of
this Licence Agreement.


10 INTELLECTUAL PROPERTY RIGHTS

10.1 The user acknowledges that the Loader and associated documentation and
materials contain proprietary information of the provider and are and shall
remain the exclusive property of the provider and/or its licensors and all
title, copyright, trade marks, trade names, patents and other intellectual
property rights therein of whatever nature shall remain the sole property of
the provider and/or its licensors.

10.2 No title to or rights of ownership, copyright or other intellectual
property in the Loader is transferred to the user (other than the licence
rights expressly granted in this Licence Agreement).


11 TERMINATION

11.1 The provider reserves the right to terminate this Licence Agreement
immediately by notice in writing against the user if the user is in breach of
any terms and conditions of this Licence Agreement.

11.2 Termination of this Licence Agreement for any reason shall be without
prejudice to any other rights or remedies of the provider which may have
arisen on or before the date of termination under this Licence Agreement or in
law.

11.3 The provisions of the following clauses shall survive any termination of
this agreement; clause 3, 5, 10 and 13.


12 GENERAL

12.1 The provider reserves the right to transfer or assign all or any of its
rights and duties and responsibilities set out in this Licence Agreement to
another party.

12.2 Headings have been included for convenience only and will not be used in
construing any provision of this Licence Agreement.

12.3 No delay or failure by the provider to exercise any powers, rights or
remedies under this Licence Agreement will operate as a waiver of them nor
will any single or partial exercise of any such powers, rights or remedies
include any other or further exercise of them.

12.4 If any part of this Licence Agreement is found by a court of competent
jurisdiction or other competent authority to be invalid, unlawful or
unenforceable then such part shall be severed from the remainder of this
Licence Agreement which will continue to be valid and enforceable to the
fullest extent permitted by applicable law.

12.5 This Licence Agreement including the documents or other sources referred
to herein supersede all prior representations, understandings and agreements
between the user and the provider relating to the Loader and sets forth the
entire agreement and understanding between the user and the provider relating
to the Loader.

12.6 Nothing in this Licence Agreement shall be deemed to constitute a
partnership between you and the provider nor constitute either party being an
agent of the other party.

12.7 This Agreement does not create any rights or benefits enforceable by any
person not a party to it (within the meaning of the U.K.Contracts (Rights of
Third Parties) Act 1999) except that a person who under clause 12.1 is a
permitted successor or assignee of the rights or benefits of the provider may
enforce such rights or benefits.


13 GOVERNING LAW AND JURISDICTION

This License Agreement and any issues relating thereto shall be construed and
interpreted in accordance with the laws of England and subject to the
exclusive jurisdiction of the English courts.

Copyright (c) 2002-2024 ionCube Ltd.          Last revised 23-April-2015
alt-php82-ioncube-loader/loader-wizard.php000064400000541746150413447520014454 0ustar00<?php // -*- c++ -*-

/** 
 * ionCube Loader install Wizard
 *
 * ionCube is a registered trademark of ionCube Ltd. 
 *
 * Copyright (c) ionCube Ltd. 2002-2022
 */


 

define ('ERROR_UNKNOWN_OS',1);
define ('ERROR_UNSUPPORTED_OS',2);
define ('ERROR_UNKNOWN_ARCH',3);
define ('ERROR_UNSUPPORTED_ARCH',4);
define ('ERROR_UNSUPPORTED_ARCH_OS',5);
define ('ERROR_WINDOWS_64_BIT',6);
define ('ERROR_PHP_UNSUPPORTED',7);
define ('ERROR_PHP_DEBUG_BUILD',8);
define ('ERROR_RUNTIME_EXT_DIR_NOT_FOUND',101);
define ('ERROR_RUNTIME_LOADER_FILE_NOT_FOUND',102);
define ('ERROR_INI_NOT_FIRST_ZE',201);
define ('ERROR_INI_WRONG_ZE_START',202);
define ('ERROR_INI_ZE_LINE_NOT_FOUND',203);
define ('ERROR_INI_LOADER_FILE_NOT_FOUND',204);
define ('ERROR_INI_NOT_FULL_PATH',205);
define ('ERROR_INI_NO_PATH',206);
define ('ERROR_INI_NOT_FOUND',207);
define ('ERROR_INI_NOT_READABLE',208);
define ('ERROR_INI_MULTIPLE_IC_LOADER_LINES',209);
define ('ERROR_INI_USER_INI_NOT_FOUND',210);
define ('ERROR_INI_USER_CANNOT_CREATE',211);
define ('ERROR_LOADER_UNEXPECTED_NAME',301);
define ('ERROR_LOADER_NOT_READABLE',302);
define ('ERROR_LOADER_PHP_MISMATCH',303);
define ('ERROR_LOADER_NONTS_PHP_TS',304);
define ('ERROR_LOADER_TS_PHP_NONTS',305);
define ('ERROR_LOADER_WRONG_OS',306);
define ('ERROR_LOADER_WRONG_ARCH',307);
define ('ERROR_LOADER_WRONG_GENERAL',308);
define ('ERROR_LOADER_WIN_SERVER_NONWIN',321);
define ('ERROR_LOADER_WIN_NONTS_PHP_TS',322);
define ('ERROR_LOADER_WIN_TS_PHP_NONTS',323);
define ('ERROR_LOADER_WIN_PHP_MISMATCH',324);
define ('ERROR_LOADER_WIN_COMPILER_MISMATCH',325);
define ('ERROR_LOADER_NOT_FOUND',380);
define ('ERROR_LOADER_PHP_VERSION_UNKNOWN',390);


define ('SERVER_UNKNOWN',0);
define ('HAS_PHP_INI',1);
define ('SERVER_SHARED',2); 
define ('SERVER_VPS',5); 
define ('SERVER_DEDICATED',7); 
define ('SERVER_LOCAL',9);

define ('IONCUBE_IP_ADDRESS',
			'94.101.154.134');
define  ('IONCUBE_ACCESS_ADDRESS',
			'lwaccess.ioncube.com');
define ('LOADERS_PAGE',
            'https://loaders.ioncube.com/'); 
define ('SUPPORT_SITE',
            'https://support.ioncube.com/');                                 
define ('WIZARD_SUPPORT_TICKET_DEPARTMENT',
			'3');
define ('LOADER_FORUM_URL',
            'https://forum.ioncube.com/viewforum.php?f=4');                  
define ('LOADERS_FAQ_URL',
            'https://www.ioncube.com/faqs/loaders.php');                     
define ('UNIX_ERRORS_URL',
            'https://www.ioncube.com/loaders/unix_startup_errors.php');      
define ('LOADER_WIZARD_URL',
            LOADERS_PAGE);                                                  
define ('ENCODER_URL',
            'https://www.ioncube.com/sa_encoder.php');                       
define ('LOADER_VERSION_URL',
            'https://www.ioncube.com/feeds/product_info/versions.php');    
define ('WIZARD_LATEST_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-wizard'); 
define ('PHP_COMPILERS_URL',
            LOADER_VERSION_URL . '?item=php-compilers');
define ('LOADER_PLATFORM_URL',
            LOADER_VERSION_URL . '?item=loader-platforms-all');   
define ('LOADER_LATEST_VERSIONS_URL',
            LOADER_VERSION_URL . '?item=loader-versions'); 
define ('LOADER_PHP_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-php-support'); 
define ('WIZARD_STATS_URL',
            'https://www.ioncube.com/feeds/stats/wizard.php');    
define ('IONCUBE_DOWNLOADS_SERVER',
            'https://downloads.ioncube.com/loader_downloads');          
define ('IONCUBE24_URL',
			'https://ioncube24.com');
define ('IONCUBE_CONNECT_TIMEOUT',4);

define ('DEFAULT_SELF','/ioncube/loader-wizard.php');
define ('LOADER_NAME_CHECK',true);
define ('LOADER_EXTENSION_NAME','ionCube Loader');
define ('LOADER_SUBDIR','ioncube');
define ('WINDOWS_IIS_LOADER_DIR', 'system32');
define ('ADDITIONAL_INI_FILE_NAME','00-ioncube.ini');
define ('UNIX_SYSTEM_LOADER_DIR','/usr/local/ioncube');
define ('RECENT_LOADER_VERSION','4.0.7');
define ('LATEST_LOADER_MAJOR_VERSION',12);
define ('LOADERS_PACKAGE_PREFIX','ioncube_loaders_');
define ('SESSION_LIFETIME_MINUTES',360);
define ('WIZARD_EXPIRY_MINUTES',2880);
define ('IONCUBE_WIZARD_EXPIRY_MINUTES',10080);
define ('MIN_INITIALISE_TIME',4);
define ('IC24_ENABLED_INI_PROPERTY',"ic24.enable");

    run();


function php4_http_build_query($formdata, $numeric_prefix = null, $key = null ) {
    $res = array();
    foreach ((array)$formdata as $k=>$v) {
        $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
        if ($key) $tmp_key = $key.'['.$tmp_key.']';
        if ( is_array($v) || is_object($v) ) {
            $res[] = php4_http_build_query($v, null , $tmp_key);
        } else {
            $res[] = $tmp_key."=".urlencode($v);
        }
   }
   $separator = ini_get('arg_separator.output');
   return implode($separator, $res);
}


function script_version()
{
    return "2.73";
}

function retrieve_latest_wizard_version()
{
    $v = false;

    $s = trim(remote_file_contents(WIZARD_LATEST_VERSION_URL));
    if (preg_match('/^\d+([.]\d+)*$/', $s)) {
        $v = $s;
    }

    return $v;
}

function latest_wizard_version()
{
    if (!isset($_SESSION['latest_wizard_version'])) {
        $_SESSION['latest_wizard_version'] = retrieve_latest_wizard_version();
    } 
    return $_SESSION['latest_wizard_version'];
}

function update_is_available($lv)
{
    if (is_numeric($lv)) {
        $lv_parts = explode('.',$lv);
        $script_parts = explode('.',script_version());
        return ($lv_parts[0] > $script_parts[0] || ($lv_parts[0] == $script_parts[0] && $lv_parts[1] > $script_parts[1]));
    } else {
        return null;
    }
}

function check_for_wizard_update($echo_message = false)
{
    $latest_version = latest_wizard_version();
    $update_available = update_is_available($latest_version);

    if ($update_available) {
        if ($echo_message) {
            echo '<p class="alert">An updated version of this Wizard script is available <a href="' . LOADER_WIZARD_URL . '">here</a>.</p>';
        }
        return $latest_version;
    } else {
        return $update_available;
    }
}


function remote_file_contents($url)
{
    $remote_file_opening = ini_get('allow_url_fopen');
    $contents = false;
    if (isset($_SESSION['timing_out']) && $_SESSION['timing_out']) {
        return false;
    }
    @session_write_close();
    $timing_out = 0;
    if ($remote_file_opening) {
        $fh = @fopen($url,'rb');
        if ($fh) {
            stream_set_blocking($fh,0);
            stream_set_timeout($fh,IONCUBE_CONNECT_TIMEOUT);
            while (!feof($fh)) {
                $result = fread($fh, 8192);
                $info = stream_get_meta_data($fh);
                $timing_out = $info['timed_out']?1:0;
                if ($timing_out) {
                    break;
                }
                if ($result !== false) {
                    $contents .= $result;
                } else {
                    break;
                }
            }
            fclose($fh);
        } else {
            $timing_out = 1;
        }
    } elseif (extension_loaded('curl')) {
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,IONCUBE_CONNECT_TIMEOUT);
            $output = curl_exec($ch);
            $info = curl_getinfo($ch);
            $timing_out = ($info['http_code'] >= 400)?1:0;
            curl_close($ch);

            if (is_string($output)) {
                $contents = $output;
            }
    } else {
        $timing_out = 1;
    }
    @session_start();
    $_SESSION['timing_out'] = $timing_out;
    return $contents;
}

function php_version()
{
    $v = explode('.',PHP_VERSION);

    return array(
           'major'      =>  $v[0],
           'minor'      =>  $v[1],
           'release'    =>  $v[2]);
}

function php_version_maj_min()
{
    $vprts = php_version();
    return ($vprts['major'] . '.' . $vprts['minor']);
}

function is_supported_php_version()
{
    $v = php_version(); 

    return ((($v['major'] == 4) && ($v['minor'] >= 1)) ||
      (($v['major'] == 5) && (($v['minor'] >= 1) || ($v['release'] >= 3))) ||
	  $v['major'] == 7 || ($v['major'] == 8 && $v['minor'] >= 1));
}

function is_php_version_or_greater($major,$minor,$release = 0)
{
    $version = php_version();
    return ($version['major'] > $major || 
            ($version['major'] == $major && $version['minor'] > $minor) ||
            ($version['major'] == $major && $version['minor'] == $minor && $version['release'] >= $release));
}

function ini_file_name()
{
    $sysinfo = get_sysinfo();
    return (!empty($sysinfo['PHP_INI'])?$sysinfo['PHP_INI_BASENAME']:'php.ini');
}

function get_remote_session_value($session_var,$remote_url,$default_function)
{
    if (!isset($_SESSION[$session_var])) {
        $serialised_res = remote_file_contents($remote_url);
        $unserialised_res = @unserialize($serialised_res);
        if (empty($unserialised_res)) {
            $unserialised_res = call_user_func($default_function);
        } else {
			$_SESSION['remote_access_successful'] = 1;
		}
        if (false === $unserialised_res) {
            $unserialised_res = '';
        }
        $_SESSION[$session_var] = $unserialised_res;
    }
    return $_SESSION[$session_var];
}

function get_file_contents($file)
{
    if (function_exists('file_get_contents')) {
        $strs = @file_get_contents($file);
    } else {
        $lines = @file($file);
        $strs = join(' ',$lines);
    }
    return $strs;
}

function default_platform_list()
{
    $platforms = array();


    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6', 'is_legacy' => 1,       'os_mod' => '_vc6',     'arch'=>'x86',  'dirname'=>'win32', 'us1-dir'=>'windows_vc6/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6 (Non-TS)',   'is_legacy' => 1,  'os_mod' => '_nonts_vc6',   'arch'=>'x86',  'dirname'=>'win32-nonts', 'us1-dir'=>'windows_vc6/x86-nonts' );

    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9',        'os_mod' => '_vc9',     'arch'=>'x86',  'dirname'=>'win32_vc9', 'us1-dir'=>'windows_vc9/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9 (Non-TS)',   'os_mod' => '_nonts_vc9',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc9', 'us1-dir'=>'windows_vc9/x86-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86',  'dirname'=>'win32_vc11', 'us1-dir'=>'windows_vc11/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc11', 'us1-dir'=>'windows_vc11/x86-nonts' );
	
	$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86-64',  'dirname'=>'win64_vc11', 'us1-dir'=>'windows_vc11/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc11', 'us1-dir'=>'windows_vc11/amd64-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86',  'dirname'=>'win32_vc14', 'us1-dir'=>'windows_vc14/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc14', 'us1-dir'=>'windows_vc14/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86-64',  'dirname'=>'win64_vc14', 'us1-dir'=>'windows_vc14/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc14', 'us1-dir'=>'windows_vc14/amd64-nonts' );
	
		 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86',  'dirname'=>'win32_vc15', 'us1-dir'=>'windows_vc15/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc15', 'us1-dir'=>'windows_vc15/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86-64',  'dirname'=>'win64_vc15', 'us1-dir'=>'windows_vc15/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc15', 'us1-dir'=>'windows_vc15/amd64-nonts' );

    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86',      'dirname'=>'linux_i686-glibc2.3.4', 'us1-dir'=>'linux/x86');
    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86-64',   'dirname'=>'linux_x86_64-glibc2.3.4', 'us1-dir'=>'linux/x86_64');
$platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc',      'dirname'=>'linux_ppc-glibc2.3.4','us1-dir'=>'linux/ppc');
            $platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc64',    'dirname'=>'linux_ppc64-glibc2.5','us1-dir'=>'linux/ppc64');
    

$platforms[] = array('os'=>'dra', 'os_human'=>'DragonFly', 'arch'=>'x86',      'dirname'=>'dragonfly_i386-1.7', 'us1-dir'=>'Dragonfly/x86');

$platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 4', 'os_mod'=>'_4',  'arch'=>'x86',      'dirname'=>'freebsd_i386-4.8', 'us1-dir'=>'FreeBSD/v4');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86',      'dirname'=>'freebsd_i386-6.2', 'us1-dir'=>'FreeBSD/v6/x86');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-6.2', 'us1-dir'=>'FreeBSD/v6/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86',      'dirname'=>'freebsd_i386-7.3', 'us1-dir'=>'FreeBSD/v7/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-7.3', 'us1-dir'=>'FreeBSD/v7/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86',      'dirname'=>'freebsd_i386-8.0', 'us1-dir'=>'FreeBSD/v8/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-8.0', 'us1-dir'=>'FreeBSD/v8/AMD64');
    
    $platforms[] = array('os'=>'bsd', 'os_human'=>'BSDi',     'is_legacy' => 1,           'arch'=>'x86',      'dirname'=>'bsdi_i386-4.3.1');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86',      'dirname'=>'netbsd_i386-2.1','us1-dir'=>'NetBSD/x86');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86-64',   'dirname'=>'netbsd_amd64-2.0','us1-dir'=>'NetBSD/x86_64');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.2', 'os_mod'=>'_4.2',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.2', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.5', 'os_mod'=>'_4.5',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.5', 'us1-dir'=>'OpenBSD/x86');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.6', 'os_mod'=>'_4.6',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.6', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.7', 'os_mod'=>'_4.7',  'arch'=>'x86-64', 'dirname'=>'openbsd_amd64-4.7', 'us1-dir' => 'OpenBSD/x86_64');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',    'is_legacy' => 1, 'arch'=>'ppc',      'dirname'=>'osx_powerpc-8.5','us1-dir'=>'OSX/ppc');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86',      'dirname'=>'osx_i386-8.11','us1-dir'=>'OSX/x86');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86-64',       'dirname'=>'osx_x86-64-10.2','us1-dir'=>'OSX/x86_64');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',  'is_legacy' => 1,          'arch'=>'sparc',    'dirname'=>'solaris_sparc-5.9', 'us1-dir'=>'Solaris/sparc');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',            'arch'=>'x86',      'dirname'=>'solaris_i386-5.10','us1-dir'=>'Solaris/x86');

    return $platforms;
}

function get_loader_platforms()
{
    return get_remote_session_value('loader_platform_info',LOADER_PLATFORM_URL,'default_platform_list');
}

function get_platforminfo()
{
    static $platforminfo;

    if (empty($platforminfo)) {
        $platforminfo = get_loader_platforms();
    }
    return $platforminfo;
}

function default_php_versions()
{
	return array();
}

function get_php_versions()
{
	return get_remote_session_value('php_version_info',LOADER_PHP_VERSION_URL,'default_php_versions');
}


function get_max_php_version_supported()
{
	static $max_php_version;
	
	if (empty($max_php_version)) {
		$php_versions = get_php_versions();
		
		$dirname = calc_dirname();
		
		if (array_key_exists($dirname,$php_versions)) {
			$max_php_version = $php_versions[$dirname];
		} else {
			$max_php_version = NULL;
		}
	}
	
	return $max_php_version;
}

function is_after_max_php_version_supported()
{
	$is_too_recent_php = false;
	
	$supported_php_version = get_max_php_version_supported();
	
	if (!is_null($supported_php_version)) {
		$pversion = php_version();
		
		$supported_parts = explode('.',$supported_php_version);
		$is_too_recent_php = ($supported_parts[0] < $pversion['major'] || ($supported_parts[0] == $pversion['major'] && $supported_parts[1] < $pversion['minor']));
	}
	
	if ($is_too_recent_php) {
		return $supported_php_version;
	} else {
		return false;
	}
}

function supported_os_variants($os_code,$arch_code)
{
    if (empty($os_code)) {
        return ERROR_UNKNOWN_OS;
    }
    if (empty($arch_code)) {
        return ERROR_UNKNOWN_ARCH;
    }

    $os_found = false;
    $arch_found = false;
    $os_arch_matches = array();
    $pinfo = get_platforminfo();

    foreach ($pinfo as $p) {
        if ($p['os'] == $os_code && $p['arch'] == $arch_code) {
            $os_arch_matches[$p['os_human']] = (isset($p['os_mod']))?(0 + (int) str_replace('_','',$p['os_mod'])):'';
        } 
        if ($p['os'] == $os_code) {
            $os_found = true;
        } elseif ($p['arch'] == $arch_code) {
            $arch_found = true;
        }
    }
    if (!empty($os_arch_matches)) {
        asort($os_arch_matches);
        return $os_arch_matches;
    } elseif (!$os_found) {
        return ERROR_UNSUPPORTED_OS;
    } elseif (!$arch_found) {
        return ERROR_UNSUPPORTED_ARCH;
    } else {
        return ERROR_UNSUPPORTED_ARCH_OS;
    }
}

function default_win_compilers()
{
    return array('VC6','VC9','VC11','VC14','VC15', 'VC16');
}

function supported_win_compilers()
{
    static $win_compilers;

    if (empty($win_compilers)) {
        $win_compilers = find_win_compilers();
    }
    return $win_compilers;
}

function find_win_compilers()
{
    return get_remote_session_value('php_compilers_info',PHP_COMPILERS_URL,'default_win_compilers');
}

function server_software_info()
{
    $ss = array('full' => '','short' => '');
    $ss['full'] = $_SERVER['SERVER_SOFTWARE'];

    if (preg_match('/apache/i', $ss['full'])) {
        $ss['short'] = 'Apache';
    } else if (preg_match('/IIS/',$ss['full'])) {
        $ss['short'] = 'IIS';
    } else {
        $ss['short'] = '';
    }
    return $ss;
}

function match_arch_pattern($str)
{
    $arch = null;
    $arch_patterns = array(
             'i.?86'        => 'x86',
             'x86[-_]64'    => 'x86',
             'x86'          => 'x86',
             'amd64'        => 'x86',
             'SMP Tue Jan 01 00:00:00 CEST 2000 all GNU\/Linux' => 'x86',
             'ppc64'        => 'ppc',
             'ppc'          => 'ppc',
             'powerpc'      => 'ppc',
             'sparc'        => 'sparc',
             'sun'          => 'sparc',
			 'armv7l'       => 'armv7l',
             'aarch64'      => 'aarch64'
         );

    foreach ($arch_patterns as $token => $a) {
        if (preg_match("/$token/i", $str)) {
          $arch = $a;
          break;
        }
    }
    return $arch;
}

function required_loader_arch($mach_info,$os_code,$wordsize)
{
    if ($os_code == 'win') {
        $arch = ($wordsize == 32)?'x86':'x86-64';
    } elseif (!empty($os_code)) {
        $arch = match_arch_pattern($mach_info);
        if ($wordsize == 64) {
            if ($arch == 'x86') {
                $arch = 'x86-64';
            } elseif ($arch == 'ppc') {
                $arch = 'ppc64';
            }
        }
    } else {
        $arch = ERROR_UNKNOWN_ARCH;
    }
    return $arch;
}

function uname($part = 'a')
{
    $result = '';
    if (!function_is_disabled('php_uname')) {
        $result = @php_uname($part);
    } elseif (function_exists('posix_uname') && !function_is_disabled('posix_uname')) {
        $posix_equivs = array(
                     'm' => 'machine',
                     'n' => 'nodename',
                     'r' => 'release',
                     's' => 'sysname'
                 );
        $puname = @posix_uname();
        if ($part == 'a' || !array_key_exists($part,$posix_equivs)) {
           $result = join(' ',$puname);
        } else {
           $result = $puname[$posix_equivs[$part]];
        }
    } else {
        if (!function_is_disabled('phpinfo')) {
            ob_start();
            phpinfo(INFO_GENERAL);
            $pinfo = ob_get_contents();
            ob_end_clean();
            if (preg_match('~System.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$match)) {
                $uname = $match[2];
                if ($part == 'r') {
                    if (!empty($uname) && preg_match('/\S+\s+\S+\s+([0-9.]+)/',$uname,$matchver)) {
                        $result = $matchver[1];
                    } else {
                        $result = '';
                    }
                } else {
                    $result = $uname;
                }
            }
        } else {
            $result = '';
        }
    }
    return $result;
}

function calc_word_size($os_code)
{
    $wordsize = null;
    if ('win' === $os_code) {
        ob_start();
        phpinfo(INFO_GENERAL);
        $pinfo = ob_get_contents();
        ob_end_clean();
        if (preg_match('~Compiler.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$compmatch)) {
            if (preg_match("/(VC[0-9]+)/i",$compmatch[2],$vcmatch)) {
                $compiler = strtoupper($vcmatch[1]);
            } elseif (stripos(trim($compmatch[2]),"Visual C++ 2019") === 0) {
                $compiler = 'VC16';
            } else {
                $compiler = 'VC6';
            }
        } else {
            $compiler = 'VC6';
        }
        if ($compiler === 'VC9' || $compiler === 'VC11' || $compiler === 'VC14' 
                || $compiler === 'VC15' || $compiler === 'VC16') {
			if (preg_match('~Architecture.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$archmatch)) {
				if (preg_match("/x64/i",$archmatch[2])) {
					$wordsize = 64;
				} else {
					$wordsize = 32;
				}
            } elseif (isset($_ENV['PROCESSOR_ARCHITECTURE']) && preg_match('~(amd64|x86-64|x86_64)~i',$_ENV['PROCESSOR_ARCHITECTURE'])) {
                if (preg_match('~Configure Command.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$confmatch)) {
                    if (preg_match('~(x64|lib64|system64)~i',$confmatch[2])) {
                        $wordsize = 64;
                    }
                }
            } else {
				$wordsize = 32;
			}
        }
    }
    if (empty($wordsize)) {
        $wordsize = ((-1^0xffffffff)?64:32);
    }
    return $wordsize;
}

function required_loader($unamestr = '')
{
    $un = empty($unamestr)?uname():$unamestr;

    $php_major_version = substr(PHP_VERSION,0,3);

    $os_name = substr($un,0,strpos($un,' '));
    $os_code = empty($os_name)?'':strtolower(substr($os_name,0,3));

    $wordsize = calc_word_size($os_code);

	if ($os_code == 'win' && $wordsize == 64 && $php_major_version < '5.5') {
        $arch = ERROR_WINDOWS_64_BIT;
	} else {
		$arch = required_loader_arch($un,$os_code,$wordsize);
	}
    if (!is_string($arch)) {
        return $arch;
    }
    $os_variants = supported_os_variants($os_code,$arch);
    if (!is_array($os_variants)) {
        return $os_variants;
    }

    $os_ver = '';
    if (preg_match('/([0-9.]+)/',uname('r'),$match)) {
        $os_ver = $match[1];
    }
    $os_ver_parts = preg_split('@\.@',$os_ver);

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $loader_sfix = (($os_code == 'win') ? 'dll' : 'so');
    $file = "ioncube_loader_{$os_code_h}_{$php_major_version}.{$loader_sfix}";

    if ($os_code == 'win') {
        $os_name = 'Windows';
        $file_ts = $file;
        $os_name_qual = 'Windows';
    } else {
        $os_names = array_keys($os_variants);
        if (count($os_variants) > 1) {
            $parts = explode(" ",$os_names[0]); 
            $os_name = $parts[0];
            $os_name_qual = $os_name . ' ' . $os_ver_parts[0] . '.' . $os_ver_parts[1];
        } else {
            $os_name = $os_names[0];
            $os_name_qual = $os_name;
        }
        $file_ts = "ioncube_loader_{$os_code_h}_{$php_major_version}_ts.{$loader_sfix}";
    }

    return array(
           'uname'      =>  $un,
           'arch'       =>  $arch,
           'oscode'     =>  $os_code,
           'oscode_h'   =>  $os_code_h,
           'osname'     =>  $os_name,
           'osnamequal' =>  $os_name_qual,
           'osvariants' =>  $os_variants,
           'osver'      =>  $os_ver,
           'osver2'     =>  $os_ver_parts,
           'file'       =>  $file,
           'file_ts'    =>  $file_ts,
           'wordsize'   =>  $wordsize
       );
}

function ic_system_info()
{
    $thread_safe = null;
    $debug_build = null;
    $cgi_cli = false;
	$is_fpm = false;
    $is_cgi = false;
    $is_cli = false;
    $php_ini_path = '';
    $php_ini_dir = '';
    $php_ini_add = '';
    $is_supported_compiler = true;
    $php_compiler = is_ms_windows()?'VC6':'';

    ob_start();
    phpinfo(INFO_GENERAL);
    $php_info = ob_get_contents();
    ob_end_clean();

    $breaker = (php_sapi_name() == 'cli')?"\n":'</tr>';
    $lines = explode($breaker,$php_info);
    foreach ($lines as $line) {
        if (preg_match('/command/i',$line)) {
          continue;
        }

        if (preg_match('/thread safety/i', $line)) {
          $thread_safe = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('/debug build/i', $line)) {
          $debug_build = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('~configuration file.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
          $php_ini_path = $match[2];

          if (!@file_exists($php_ini_path)) {
                $php_ini_path = '';
          }
        }
        if (preg_match('~dir for additional \.ini files.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_dir = $match[2];
            if (!@file_exists($php_ini_dir)) {
                $php_ini_dir = '';
            }
        }
        if (preg_match('~additional \.ini files parsed.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_add = $match[2];
        }
        if (preg_match('/compiler/i',$line)) {
            $supported_match = join('|',supported_win_compilers());
            $is_supported_compiler = preg_match("/($supported_match)/i",$line);
            if (preg_match("/(VC[0-9]+)/i",$line,$match)) {
                $php_compiler = strtoupper($match[1]);
            } elseif (preg_match("/Visual C\+\+ 2017/i",$line)) {
				$php_compiler = "VC15";
				$is_supported_compiler = true;
            } elseif (preg_match("/Visual C\+\+ 2019/i",$line)) {
				$php_compiler = "VC16";
				$is_supported_compiler = true;
			} else {
                $php_compiler = '';
            }
        }
    }
    $is_cgi = strpos(php_sapi_name(),'cgi') !== false;
    $is_cli = strpos(php_sapi_name(),'cli') !== false;
	$is_fpm = strpos(php_sapi_name(),'fpm-fcgi') !== false;
    $cgi_cli = $is_cgi || $is_cli;

    $ss = server_software_info();
	
	if ($is_fpm) {
		$ss['short'] = 'PHP-FPM';
		$ss['full'] = 'PHP-FPM ' . $ss['full'];
	}

    if (!$php_ini_path && function_exists('php_ini_loaded_file')) {
        $php_ini_path = php_ini_loaded_file();
        if ($php_ini_path === false) {
            $php_ini_path = '';
        }
    }
    if (!empty($php_ini_path)) {
        $real_path = @realpath($php_ini_path);
        if (false !== $real_path) {
            $php_ini_path = $real_path;
        }
    }

    $php_ini_basename = basename($php_ini_path);

    return array(
           'THREAD_SAFE'        => $thread_safe,
           'DEBUG_BUILD'        => $debug_build,
           'PHP_INI'            => $php_ini_path,
           'PHP_INI_BASENAME'   => $php_ini_basename,
           'PHP_INI_DIR'        => $php_ini_dir,
           'PHP_INI_ADDITIONAL' => $php_ini_add,
           'PHPRC'              => getenv('PHPRC'),
           'CGI_CLI'            => $cgi_cli,
           'IS_CGI'             => $is_cgi,
           'IS_CLI'             => $is_cli,
		   'IS_FPM'				=> $is_fpm,
           'PHP_COMPILER'       => $php_compiler,
           'SUPPORTED_COMPILER' => $is_supported_compiler,
           'FULL_SS'            => $ss['full'],
           'SS'                 => $ss['short']);
}

function is_possibly_dedicated_or_local()
{
    $sys = get_sysinfo();

    return (empty($sys['PHP_INI']) || !@file_exists($sys['PHP_INI']) || (is_readable($sys['PHP_INI']) && (0 !== strpos($sys['PHP_INI'],$_SERVER['DOCUMENT_ROOT']))));
}

function is_local()
{
    $ret = false;
    if ($_SERVER["SERVER_NAME"] == 'localhost') {
        $ret = true;
    } else {
        $ip_address = strtolower($_SERVER["REMOTE_ADDR"]);
        if (strpos(':',$ip_address) === false) {
            $ip_parts = explode('.',$ip_address);
            $ret = (($ip_parts[0] == 10) || 
                    ($ip_parts[0] == 172 && $ip_parts[1] >= 16 &&  $ip_parts[1] <= 31) ||
                    ($ip_parts[0] == 192 && $ip_parts[1] == 168));
        } else {
            $ret = ($ip_address == '::1') || (($ip_address[0] == 'f') && ($ip_address[1] >= 'c' && $ip_address[1] <= 'f'));
        }
    }
    return $ret;
}

function is_shared()
{
    return !is_local() && !is_possibly_dedicated_or_local();
}

function find_server_type($chosen_type = '',$type_must_be_chosen = false,$set_session = false)
{
    $server_type = SERVER_UNKNOWN;
    if (empty($chosen_type)) {
        if ($type_must_be_chosen) {
            $server_type = SERVER_UNKNOWN;
        } else {
            if (isset($_SESSION['server_type']) && $_SESSION['server_type'] != SERVER_UNKNOWN) {
                $server_type = $_SESSION['server_type'];
            } elseif (is_local()) {
                $server_type = SERVER_LOCAL;
            } elseif (!is_possibly_dedicated_or_local()) {
                $server_type = SERVER_SHARED;
            } else {
                $server_type = SERVER_UNKNOWN;
            } 
        }
    } else {
        switch ($chosen_type)  {
            case 's':
                $server_type = SERVER_SHARED;
                break;
            case 'd':
                $server_type = SERVER_DEDICATED;
                break;
            case 'l':
                $server_type = SERVER_LOCAL;
                break;
            default:
                $server_type = SERVER_UNKNOWN;
                break;
        }
    }
    if ($set_session) {
        $_SESSION['server_type'] = $server_type;
    }
    return $server_type;
}

function server_type_string()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_string = 'SHARED';
            break;
        case SERVER_LOCAL:
            $server_string = 'LOCAL';
            break;
        case SERVER_DEDICATED:
            $server_string = 'DEDICATED';
            break;
        default:
            $server_string = 'UNKNOWN';
            break;
    }
    return $server_string;
}

function server_type_code()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_char = 's';
            break;
        case SERVER_LOCAL:
            $server_char = 'l';
            break;
        case SERVER_DEDICATED:
            $server_char = 'd';
            break;
        default:
            $server_char = '';
            break;
    }
    return $server_char;
}

function get_sysinfo()
{
    static $sysinfo;

    if (empty($sysinfo)) {
        $sysinfo = ic_system_info();
    }
    return $sysinfo;
}

function get_loaderinfo()
{
    static $loader;

    if (empty($loader)) {
        $loader = required_loader();
    }
    return $loader;
}

function is_ms_windows()
{
    $loader_info = get_loaderinfo();
    return ($loader_info['oscode'] == 'win');
}

function function_is_disabled($fn_name)
{
    $disabled_functions=explode(',',ini_get('disable_functions'));
    return in_array($fn_name, $disabled_functions);
}

function selinux_is_enabled()
{
    $se_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('sestatus');
        $se_enabled = preg_match('/enabled/i',$cmd);
    }

    return $se_enabled;
}

function grsecurity_is_enabled()
{
    $gr_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('gradm -S');
        $gr_enabled = preg_match('/enabled/i',$cmd);
    }

    return $gr_enabled;
}

function threaded_and_not_cgi()
{
    $sys = get_sysinfo();
    return($sys['THREAD_SAFE'] && !$sys['IS_CGI']);
}

function is_restricted_server($only_safe_mode = false)
{
    $disable_functions = ini_get('disable_functions');
    $open_basedir = ini_get('open_basedir');
    $php_restrictions = !empty($disable_functions) || !empty($open_basedir);
    $system_restrictions = selinux_is_enabled() || grsecurity_is_enabled();
    $non_safe_mode_restrictions = $php_restrictions || $system_restrictions;
    return (ini_get('safe_mode') || (!$only_safe_mode && $non_safe_mode_restrictions));
}

function server_restriction_warnings()
{
    $warnings = array();

    if (find_server_type() == SERVER_SHARED) {
        if (is_restricted_server()) {
            $warnings[] = "Server restrictions are in place which might affect the operation of this Loader Wizard or prevent the installation of the Loader.";
        }
    } else {
        $warning_suffix = "This may affect the operation of this Loader Wizard.";
        if (ini_get('safe_mode')) {
            $warnings[] = "Safe mode is in effect on the server. " . $warning_suffix;
        } 
        $disabled_functions = ini_get('disable_functions');
        if (!empty($disabled_functions)) {
            $warnings[] = "Some functions are disabled through disable_functions. " . $warning_suffix;
        }
        $open_basedir = ini_get('open_basedir');
        if (!empty($open_basedir)) {
            $warnings[] = "Open basedir restrictions are in effect. " . $warning_suffix;
        }
    }
    return $warnings;
}

function own_php_ini_possible($only_safe_mode = false)
{
    $sysinfo = get_sysinfo();
    return ($sysinfo['CGI_CLI'] && !is_ms_windows() && !is_restricted_server($only_safe_mode));
}

function extension_dir()
{
    $extdir = ini_get('extension_dir');
    if ($extdir == './' || ($extdir == '.\\' && is_ms_windows())) {
        $extdir = '.';
    }
    return $extdir;
}

function possibly_selinux()
{
    $loaderinfo = get_loaderinfo();
    $se_env = (getenv("SELINUX_INIT"));
    return (strtolower($loaderinfo['osname']) == 'linux' && $se_env && ($se_env == 'Yes' || $se_env == '1'));
}

function ini_same_dir_as_wizard()
{
    $sys = get_sysinfo();
    return dirname($sys['PHP_INI']) == dirname(__FILE__); 
}

function extension_dir_path()
{
    $ext_dir = extension_dir();
    if ($ext_dir == '.' || (dirname($ext_dir) == '.')) {
        $ext_dir_path = @realpath($ext_dir);
    } else {
        $ext_dir_path = $ext_dir;
    }
    return $ext_dir_path;
}

function get_loader_name()
{
    $u = uname();
    $sys = get_sysinfo();
    $os = substr($u,0,strpos($u,' '));
    $os_code = strtolower(substr($u,0,3));

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $php_version = phpversion();
    $php_family = substr($php_version,0,3);

    $loader_sfix = (($os_code == 'win') ? '.dll' : (($sys['THREAD_SAFE'])?'_ts.so':'.so'));
    $loader_name="ioncube_loader_{$os_code_h}_{$php_family}{$loader_sfix}";

    return $loader_name;
}

function get_reqd_version($variants)
{
    $exact_match = false;
    $nearest_version = 0;
    $loader_info = get_loaderinfo();
    $os_version = $loader_info['osver2'][0] . '.' . $loader_info['osver2'][1];
    $os_version_major = $loader_info['osver2'][0];
    foreach ($variants as $v) {
        if ($v == $os_version || (is_int($v) && $v == $os_version_major)) {
            $exact_match = true;
            $nearest_version = $v;
            break;
        } elseif ($v > $os_version) {
            break;
        } else {
            $nearest_version = $v;
        }
    }
    return (array($nearest_version,$exact_match));
}

function get_default_loader_dir_webspace()
{
    return ($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . LOADER_SUBDIR);
}

function get_loader_location($loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = get_default_loader_dir_webspace();
    }
    $loader_name = get_loader_name(); 
    return ($loader_dir . DIRECTORY_SEPARATOR . $loader_name);
}

function get_loader_location_from_ini($php_ini = '')
{
    $errors = array();
    if (empty($php_ini)) {
        $sysinfo = get_sysinfo();
        $php_ini = $sysinfo['PHP_INI'];
    }
    if (!@file_exists($php_ini)) {
        if (empty($php_ini)) {
            $errors[ERROR_INI_NOT_FOUND] = "The configuration file could not be found.";
        } else {
            $errors[ERROR_INI_NOT_FOUND] = "The $php_ini file could not be found.";
        }
    } elseif (!is_readable($php_ini)) {
        $errors[ERROR_INI_NOT_READABLE] = "The $php_ini file could not be read.";
    }
    if (!empty($errors)) {
        return array('location' => '', 'errors' => $errors);
    } 
    $lines = file($php_ini);
    $ext_start = zend_extension_line_start();
    $wrong_ext_start = ($ext_start == 'zend_extension')?'zend_extension_ts':'zend_extension';
    $loader_path = '';
    $loader_name_match = "ioncube_loader";
    foreach ($lines as $l) {
        if (preg_match("/^\s*$ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$corr_matches)) {
            if (preg_match("/$loader_name_match/i",$corr_matches[1])) {
                if (!empty($loader_path)) {
                    $errors[ERROR_INI_MULTIPLE_IC_LOADER_LINES] = "It appears that multiple $ext_start lines for the ionCube Loader have been included in the configuration file, $php_ini.";
                }
                $loader_path = $corr_matches[1];
            } else {
                if (empty($loader_path)) {
                    $errors[ERROR_INI_NOT_FIRST_ZE] = "The ionCube Loader must be the first Zend extension listed in the configuration file, $php_ini.";
                }
            }
        }
        if (empty($loader_path)) {
            if (preg_match("/^\s*$wrong_ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$bad_start_matches)) {
                if (preg_match("/$loader_name_match/i",$bad_start_matches[1])) {
                    $bad_zend_ext_msg = "The line for the ionCube Loader in the configuration file, $php_ini, should start with $ext_start and <b>not</b> $wrong_ext_start.";
                    $errors[ERROR_INI_WRONG_ZE_START] = $bad_zend_ext_msg;
                    $loader_path = $bad_start_matches[1];
                }
            }
        }
    }
    $loader_path = trim($loader_path);
    if ($loader_path === '') {
        $errors[ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration file, $php_ini.";
    } elseif (!@file_exists($loader_path)) {
        $errors[ERROR_INI_LOADER_FILE_NOT_FOUND] = "The loader file  $loader_path, listed in the configuration file, $php_ini, does not exist or is not accessible.";
    } elseif (basename($loader_path) == $loader_path) {
        $errors[ERROR_INI_NOT_FULL_PATH] = "A full path must be specified for the loader file in the configuration file, $php_ini.";
    }
    return array('location' => $loader_path, 'errors' => $errors);
}

function zend_extension_line_missing($ini_path)
{
    $loader_loc = get_loader_location_from_ini($ini_path);
    return (!empty($loader_loc['errors']) && array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$loader_loc['errors']));
}

function find_additional_ioncube_ini()
{
    $sys = get_sysinfo();
    $ioncube_ini = '';

    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
        foreach ($ini_files as $f) {
            $fn = trim($f);
            $bfn = basename($fn);
            if (preg_match('/ioncube/i',$bfn)) {
                $ioncube_ini = $fn;
                break;
            }
        }
    }
    return $ioncube_ini;
}

function get_additional_ini_files()
{
    $sys = get_sysinfo();
    $ini_files = array();
    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
    }
    return (array_map('trim',$ini_files));
}

function all_ini_contents()
{
    $sys = get_sysinfo();
    $output = '';

    $output .= ";;; *MAIN INI FILE AT ${sys['PHP_INI']}* ;;;" . PHP_EOL;
    $output .= get_file_contents($sys['PHP_INI']);
    $other_inis = get_additional_ini_files();
    foreach ($other_inis as $inif) {
        $output .= ";;; *Additional ini file at $inif* ;;;" . PHP_EOL;
        $output .= get_file_contents($inif);
    }
    $here = unix_path_dir();
    $unrec_ini_files = unrecognised_inis_webspace($here);
    foreach ($unrec_ini_files as $urinif) {
        $output .= ";;; *UNRECOGNISED INI FILE at $urinif* ;;;" . PHP_EOL;
        $output .= get_file_contents($urinif);
    }
    return $output;
}

function scan_inis_for_loader()
{
    $ldloc = array('location' => '', 'errors' => array());
    $sysinfo = get_sysinfo();
    if (empty($sysinfo['PHP_INI'])) {
        $ini_files_not_found = array("Main ini file");
        $ini_file_list = get_additional_ini_files();
    } else {
        $ini_files_not_found = array();
        $ini_file_list = array_merge(array($sysinfo['PHP_INI']),get_additional_ini_files());
    }
    $server_type = find_server_type();
    $shared_server = SERVER_SHARED == $server_type;
    foreach ($ini_file_list as $f) {
        $ldloc = get_loader_location_from_ini($f);
        if (array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$ldloc['errors'])) {
            unset($ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND]);
        } 
        if ($shared_server && array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            if (false == user_ini_space_path($f)) {
                $ldloc['errors'][ERROR_INI_NOT_FOUND] = "A system ini file cannot be found or read by the Wizard - you cannot do anything about this on your shared server.";
            } else {
                $ldloc['errors'][ERROR_INI_USER_INI_NOT_FOUND] = $ldloc['errors'][ERROR_INI_NOT_FOUND];
            }
        } elseif (array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            $ini_files_not_found[] = $f;
        }
        if (!empty($ldloc['location'])) {
            break;
        }
    }
    if (!empty($ini_files_not_found)) {
        $plural = (count($ini_files_not_found) > 1)?"s":"";
        $ldloc['errors'][ERROR_INI_NOT_FOUND] = "The following ini file$plural could not be found by the Wizard: " . join(',',$ini_files_not_found);
        if (is_restricted_server()) {
            $ldloc['errors'][ERROR_INI_NOT_FOUND] .= "<br> This may be due to server restrictions in place.";
        }
    }
    if (empty($ldloc['location'])) {
        $ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration.";
    }
    return $ldloc;
}

function find_loader_filesystem()
{
    $ld_inst_dir = loader_install_dir(find_server_type());
    $loader_name = get_loader_name();
    $suggested_loader_path = $ld_inst_dir . DIRECTORY_SEPARATOR . $loader_name;
    if (@file_exists($suggested_loader_path)) {
        $location = $suggested_loader_path;
    } elseif (@file_exists($loader_name)) {
        $location = @realpath($loader_name);
    } else {
        $ld_loc = get_loader_location();
        if (@file_exists($ld_loc)) {
            $location = $ld_loc;
        } else {
            $location = '';
        }
    }
    return $location;
}

function find_loader($search_directories_if_not_ini = false)
{
    $sysinfo = get_sysinfo();
    $php_ini = $sysinfo['PHP_INI'];
    $rtl_path = get_runtime_loading_path_if_applicable();
    $location = '';
    $errors = array();

    if (!empty($rtl_path)) {
        $location = $rtl_path;
    } else {
        $loader_ini = scan_inis_for_loader();
        $location = $loader_ini['location'];
        $errors = $loader_ini['errors'];
    }
    if (empty($location) && (empty($errors) || $search_directories_if_not_ini)) {
        $errors = array(); 
        $location = find_loader_filesystem();
        if (empty($location)) {
            $errors[ERROR_LOADER_NOT_FOUND] = 'The loader file could not be found in standard locations.';
        }
    }
    if (!empty($errors)) {
        return $errors;
    } else {
        return $location;
    }
}

function zend_extension_line_start()
{
    $sysinfo = get_sysinfo();
    $is_53_or_later = is_php_version_or_greater(5,3);
    return (is_bool($sysinfo['THREAD_SAFE']) && $sysinfo['THREAD_SAFE'] && !$is_53_or_later ? 'zend_extension_ts' : 'zend_extension');
}

function ioncube_loader_version_information()
{
    $old_version = true;
    $liv = "";
    $lv = "";
    $mv = 0;
    if (function_exists('ioncube_loader_iversion')) {
        $liv = ioncube_loader_iversion();
        $lv = sprintf("%d.%d.%d", $liv / 10000, ($liv / 100) % 100, $liv % 100);

        $latest_version =  get_latestversion();

        $lat_parts = explode('.',$latest_version);
        $cur_parts = explode('.',$lv);

        if (($cur_parts[0] > $lat_parts[0]) || 
            ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] > $lat_parts[1]) ||
             ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] == $lat_parts[1] && $cur_parts[2] >= $lat_parts[2])) {
            $old_version = false;
        } else {
            $old_version = $latest_version;
        }
        $mv = $cur_parts[0];
    }
    return array($lv,$mv,$old_version);
}

function default_loader_version_info()
{
    return array();
}

function get_loader_version_info()
{
    return get_remote_session_value('loader_version_info',LOADER_LATEST_VERSIONS_URL,'default_loader_version_info');
}

function calc_platform()
{
    $platform = array();
    $platform_info = get_platforminfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($osvar,$exact_match) = get_reqd_version($loader['osvariants']);
    } else {
        $osvar = null;
        if (is_ms_windows()) {
            $sys = get_sysinfo();
            $phpc = (empty($sys['PHP_COMPILER']))?'vc6':strtolower($sys['PHP_COMPILER']); 
            $osvar = ($sys['THREAD_SAFE']?'':'nonts_') . $phpc;
        }
    }
    foreach ($platform_info as $p) {
        if ($p['os'] == $loader['oscode'] && $p['arch'] == $loader['arch'] && (empty($osvar) || $p['os_mod'] == "_" . $osvar)) {
            $platform = $p;
            break;
        }
    }
    return $platform;
}

function get_platform()
{
    static $this_platform;

    if (!isset($this_platform)) {
        $this_platform = calc_platform();
    }

    return $this_platform;
}

function is_legacy_platform()
{
    $platform = get_platform();
    return array_key_exists('is_legacy',$platform);
}

function calc_dirname()
{
    $dirname = '';
    $platform = get_platform();
    if (!empty($platform)) {
        $dirname = $platform['dirname'];
    }
    return $dirname;
}

function calc_loader_latest_version()
{
    $lv_info = get_loader_version_info();
    $latest_version = RECENT_LOADER_VERSION;
    if (!empty($lv_info)) {
        $dirname = calc_dirname();
      
        if (!empty($dirname)) {
            $compiler_specific_version = false;
            if (is_ms_windows()) {
                $sys = get_sysinfo();
                $phpc = strtolower($sys['PHP_COMPILER']);
                if (!empty($phpc)) {
                    $dirname_comp = $dirname . "_" . $phpc;
                    if (array_key_exists($dirname_comp,$lv_info)) {
                        $latest_version = $lv_info[$dirname_comp];
                        $compiler_specific_version = true;
                    }
                }
            }
            if (!$compiler_specific_version && array_key_exists($dirname,$lv_info)) {
                $latest_version = $lv_info[$dirname];
            }
        } 
    }
    return $latest_version;
}

function get_latestversion()
{
    static $latest_version;

    if (empty($latest_version)) {
        $latest_version = calc_loader_latest_version();
    }
    return $latest_version;
}


function runtime_loader_location()
{
    $loader_path = false;
    $ext_path = extension_dir_path();
    if ($ext_path !== false) {
        $id = $ext_path;
        $here = dirname(__FILE__);
        if (isset($id[1]) && $id[1] == ':') {
            $id = str_replace('\\','/',substr($id,2));
            $here = str_replace('\\','/',substr($here,2));
        }
        $rd=str_repeat('/..',substr_count($id,'/')).$here.'/';
        $i=strlen($rd);

        $loader_loc = DIRECTORY_SEPARATOR . basename($here) . DIRECTORY_SEPARATOR . get_loader_name();
        while($i--) {
            if($rd[$i]=='/') {
                $loader_path = runtime_location_exists($ext_path,$rd,$i,$loader_loc);
                if ($loader_path !== false) {
                    break;
                }
            }
        }

        if (!$loader_path && !empty($loader_loc) && @file_exists($loader_loc)) {
            $loader_path = basename($loader_loc);
        }
    }
    return $loader_path;
}

function runtime_location_exists($ext_dir,$path_str,$sep_pos,$loc_name)
{
    $sub_path = substr($path_str,0,$sep_pos);
    $lp = $sub_path . $loc_name;
    $fqlp = $ext_dir.$lp;

    if(@file_exists($fqlp)) {
        return $lp;
    } else {
        return false;
    }
}

function runtime_loading_is_possible() {
    return !((is_php_version_or_greater(5,2,5)) || is_restricted_server() || !ini_get('enable_dl') || !function_exists('dl') || function_is_disabled('dl') || threaded_and_not_cgi());
}

function shared_and_runtime_loading()
{
    return (find_server_type() == SERVER_SHARED && empty($_SESSION['use_ini_method']) && runtime_loading_is_possible());
}

function get_valid_runtime_loading_path($ignore_loading_check = false)
{
    if ($ignore_loading_check || runtime_loading_is_possible()) {
        return runtime_loader_location();
    } else {
        return false;
    }
}

function runtime_loading($rtl_path = null)
{
    if (empty($rtl_path)) {
        $rtl_path = get_valid_runtime_loading_path();
    }
    if (!empty($rtl_path) && @dl($rtl_path)) {
        return $rtl_path;
    } else {
        return false;
    }
}

function get_runtime_loading_path_if_applicable()
{
    $rtl = null;
    if (shared_and_runtime_loading()) {
        $rtl = get_valid_runtime_loading_path();
    }
    return $rtl;
}

function try_runtime_loading_if_applicable()
{
    $rtl_path = get_runtime_loading_path_if_applicable();
    if (!empty($rtl_path)) {
        return runtime_loading($rtl_path);
    } else {
        return $rtl_path;
    }
}

function runtime_loading_instructions()
{
    $default = get_default_address();
    echo '<h4>Runtime Loading Instructions</h4>';
    echo '<div class=panel>';
    echo '<p>On your shared server the Loader can be installed using the runtime loading method.';
    echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";

    if ('.' == extension_dir()) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        echo "Please note that on your system the Loader <em>must</em> be present in the same " . $dirphrase . " as the first encoded file accessed.";
    }
    echo '<ol>';
    loader_download_instructions(); 
    $loader_dir = loader_install_instructions(SERVER_SHARED,dirname(__FILE__));
    shared_test_instructions();
    echo '</ol>';
    echo '</div>';
}

function runtime_loading_errors()
{
    $errors = array();
    $ext_path = extension_dir_path();
    if (false === $ext_path) {
        $errors[ERROR_RUNTIME_EXT_DIR_NOT_FOUND] = "Extensions directory cannot be found.";
    } else {
        $expected_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . get_loader_name();
        if (!@file_exists($expected_file)) {
            $errors[ERROR_RUNTIME_LOADER_FILE_NOT_FOUND] = "The Loader file was expected to be at $expected_file but could not be found.";
        } else {
            $errors = loader_compatibility_test($expected_file);
        }
    }
    return $errors;
}


function windows_package_name()
{
    $sys = get_sysinfo();
	$loader = get_loaderinfo();
    return (LOADERS_PACKAGE_PREFIX . 'win' . '_' . ($sys['THREAD_SAFE']?'':'nonts_') . strtolower($sys['PHP_COMPILER']) .  '_' . $loader['arch']);
}

function unix_package_name()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($reqd_version,$exact_match) = get_reqd_version($loader['osvariants']);
        if ($reqd_version) {
            $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $reqd_version . '_' . $loader['arch'];
        } else {
            $basename = "";
        }
    } else {
        $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $loader['arch'];
    }
    return array($basename,$multiple_os_versions);
}

function loader_download_instructions()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;

    if (is_ms_windows()) {
        if (is_bool($sysinfo['THREAD_SAFE'])) {
            $download_str = '<li>Download the following archive of Windows ' . $sysinfo['PHP_COMPILER'];
            if (!$sysinfo['THREAD_SAFE']) {
                $download_str .= ' non-TS';
            }
            $download_str .= ' ' . $loader['arch'] . ' Loaders:';
            echo $download_str;
            $basename = windows_package_name();
            echo make_archive_list($basename,array('zip'));
            echo 'A Loaders archive can also be downloaded from <a href="' . LOADERS_PAGE . '" target="loaders">' . LOADERS_PAGE . '</a>.';
        } else {
            echo '<li>Download a Windows Loaders archive from <a href="' . LOADERS_PAGE  . '" target=loaders>here</a>. If PHP is built with thread safety disabled, use the Windows non-TS Loaders.';
        }
    } else {
        list($basename,$multiple_os_versions) = unix_package_name(); 
        if ($basename == "") {
            echo '<li>Download a ' . $loader['osname'] . ' ' . $loader['arch'] . ' Loaders archive from <a href="' . LOADERS_PAGE . '" target="loaders">here</a>.';
            echo "<br>Your system appears to be ${loader['osnamequal']} for ${loader['wordsize']} bit. If Loaders are not available for that exact release of ${loader['osname']}, Loaders built for an earlier release should work. Note that you may need to install back compatibility libraries for the operating system.";
            echo '<br>If you cannot find a suitable loader then please raise a ticket at <a href="'. SUPPORT_SITE . '">our support helpdesk</a>.';
        } else {
            echo '<li>Download one of the following archives of Loaders for ' . $loader['osnamequal'] . ' ' . $loader['arch'] . ':'; 
            if (SERVER_SHARED == find_server_type()) {
                $archives = array('zip','tar.gz');
            } else {
                $archives = array('tar.gz','zip');
            }
            echo make_archive_list($basename,$archives);
            echo "</p>";
            if ($multiple_os_versions && !$exact_match) {
                echo "<p>Note that you may need to install back compatibility libraries for  ${loader['osname']}.</p>";
            }
        }
    }

    echo '</li>';
}

function ini_dir()
{
    $sysinfo = get_sysinfo();
    $parent_dir = '';
    if (!empty($sysinfo['PHP_INI'])) {
        $parent_dir = dirname($sysinfo['PHP_INI']);
    } else {
        $parent_dir = $_SERVER["PHPRC"];
        if (@is_file($parent_dir)) {
            $parent_dir = dirname($parent_dir);
        }
    }
    return $parent_dir;
}

function unix_install_dir()
{
    $ext_dir = extension_dir_path();
    $cur_dir = @realpath('.');
    if (empty($ext_dir) || $ext_dir == $cur_dir) {
        $loader_dir = UNIX_SYSTEM_LOADER_DIR;
    } else {
        $loader_dir = $ext_dir;
    }
    return $loader_dir;
}

function windows_install_dir()
{
    $sysinfo = get_sysinfo();
    if ($sysinfo['SS'] == 'IIS') {
        if (false === ($ext_dir = extension_dir_path())) {
            $parent_dir = ini_dir();
            $ext_dir = $parent_dir . '\\ext';
            if (!empty($parent_dir) && @file_exists($ext_dir)) {
                $loader_dir = $ext_dir;
            } else {
                $loader_dir = $_SERVER['windir'] . '\\' . WINDOWS_IIS_LOADER_DIR;
            }
        } else {
            $loader_dir = $ext_dir;
        }
    } else {
        if (false === ($ext_dir = extension_dir_path())) {
			$parent_dir = ini_dir();
			$loader_dir = $parent_dir . '\\' . 'ioncube';
		} else {
			$loader_dir = $ext_dir;
		}
    }
    return $loader_dir;
}

function loader_install_dir($server_type)
{
    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $loader_dir = get_default_loader_dir_webspace();
    } elseif (is_ms_windows()) {
        $loader_dir = windows_install_dir();
    } else {
        $loader_dir = unix_install_dir();
    }
    return $loader_dir;
}

function writeable_directories()
{
    $root_path = @realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    $root_path_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
    $above_root_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/../cgi-bin");

    $paths = array();
    foreach (array($root_path,$above_root_path,$root_path_cgi_bin,$above_root_cgi_bin) as $p) {
        if (@is_writeable($p)) {
            $paths[] = $p;
        }
    }
    return $paths;
}

function loader_install_instructions($server_type,$loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = loader_install_dir($server_type);
    }
    if (SERVER_LOCAL == $server_type) {
        echo "<li>Put the Loader files in <code>$loader_dir</code></li>";
    } else {
        echo "<li>Transfer the Loaders to your web server and install in <code>$loader_dir</code></li>";
    }
    return $loader_dir;
}

function zend_extension_lines($loader_dir)
{
    $zend_extension_lines = array();
    $sysinfo = get_sysinfo();
    $qt = (is_ms_windows()?'"':'');
    $loader = get_loaderinfo();

    if (!is_bool($sysinfo['THREAD_SAFE']) || !$sysinfo['THREAD_SAFE']) {
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file'] . $qt;
        $zend_extension_lines[] = "zend_extension = " . $path;
    }
    if ((!is_bool($sysinfo['THREAD_SAFE']) && !is_php_version_or_greater(5,3)) || $sysinfo['THREAD_SAFE']) {
        $line_start = is_php_version_or_greater(5,3)?'zend_extension':'zend_extension_ts';
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file_ts'] . $qt;
        $zend_extension_lines[] = $line_start . " = " . $path;
    }
    return $zend_extension_lines;
}

function user_ini_base()
{
    $doc_root_path = realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    if (!empty($above_root_path) && @is_writeable($above_root_path)) {
        $start_path = $above_root_path;
    } else {
        $start_path = $doc_root_path;
    }
    return $start_path;
}

function user_ini_space_path($file)
{
    $user_base = user_ini_base();
    $fpath = @realpath($file);
    if (!empty($fpath) && (0 === strpos($fpath,$user_base))) {
        return $fpath;
    } else {
        return false;
    }
}

function default_ini_path()
{
    return (realpath($_SERVER['DOCUMENT_ROOT']));
}

function shared_ini_location()
{
    $phprc = getenv('PHPRC');
    if (!empty($phprc)) {
        $phprc_path = user_ini_space_path($phprc);
        if (false !== $phprc_path) {
            return $phprc_path;
        } else {
            return default_ini_path();
        }
    } else {
        return default_ini_path();
    }
}


function zend_extension_instructions($server_type,$loader_dir)
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();
    $editing_ini = true;

    $php_ini_name = ini_file_name();

    if (isset($sysinfo['PHP_INI']) && @file_exists($sysinfo['PHP_INI'])) {
        $php_ini_path = $sysinfo['PHP_INI'];
    } else {
        $php_ini_path = '';
    }

    if (is_bool($sysinfo['THREAD_SAFE'])) {
        $kwd = zend_extension_line_start();
    } else {
        $kwd = 'zend_extension/zend_extension_ts';
    }

    $server_type_code = server_type_code();

    $zend_extension_lines = zend_extension_lines($loader_dir);

    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $ini_dir = shared_ini_location();
        $php_ini_path = $ini_dir . DIRECTORY_SEPARATOR . $php_ini_name;
        if (@file_exists($php_ini_path)) {
            $edit_line = "<li>Edit the <code>$php_ini_name</code> in the <code>$ini_dir</code> directory";
            if (zend_extension_line_missing($php_ini_path) && @is_writeable($php_ini_path) && @is_writeable($ini_dir)) {
                if (function_exists('file_get_contents')) {
                    $ini_strs = @file_get_contents($php_ini_path);
                } else {
                    $lines = @file($php_ini_path);
                    $ini_strs = join(' ',$lines);
                }
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                        fwrite($fh,$zl . PHP_EOL);
                    }
                    fwrite($fh,$ini_strs);
                    fclose($fh);
                    $editing_ini = false;
                    echo "<li>Your php.ini file at $php_ini_path has been modified to include the necessary line for the ionCube Loader.";
                } else {
                    echo $edit_line;
                }
            } else {
               echo $edit_line;
            }
        } else {
            $download_ini_file = "<li><a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">Save this  <code>$php_ini_name</code> file</a> and upload it to <code>$ini_dir</code> (full path on your server).";
            if (@is_writeable($ini_dir)) {
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                       fwrite($fh,$zl . PHP_EOL);
                    }
                    if (!empty($sysinfo['PHP_INI']) && is_readable($sysinfo['PHP_INI'])) {
                        if (function_exists('file_get_contents')) {
                           $ini_strs = @file_get_contents($sysinfo['PHP_INI']);
                        } else {
                           $lines = @file($sysinfo['PHP_INI']);
                           $ini_strs = join(' ',$lines);
                        }
                        fwrite($fh,$ini_strs);
                    }
                    fclose($fh); 
                    echo "<li>A <code>$php_ini_name</code> file has been created for you in <code>$ini_dir</code>.";
                } else {
                    echo $download_ini_file;
                }
            } else {
                echo $download_ini_file;
            }
            $editing_ini = false;
        }
    } elseif (!empty($sysinfo['PHP_INI'])) {
        if (empty($sysinfo['PHP_INI_DIR'])) {
            echo "<li>Edit the file <code>${sysinfo['PHP_INI']}</code>";
        } else {
            $php_ini_path = find_additional_ioncube_ini();
            if (empty($php_ini_path)) {
                $php_ini_name = ADDITIONAL_INI_FILE_NAME;
                echo "<li><a href=\"$base&amp;page=phpconfig&amp;download=1&amp;newlinesonly=1&amp;ininame=$php_ini_name&amp;stype=$server_type_code\">Save this $php_ini_name file</a> and put it in your ini files directory, <code>${sysinfo['PHP_INI_DIR']}</code>";
                $editing_ini = false;
            } else {
                $php_ini_name = basename($php_ini_path);
                echo "<li>Edit the file <code>$php_ini_path</code>";
            }
        }
    } else {
        echo "<li>Edit the system <code>$php_ini_name</code> file";
    }
    if ($editing_ini) {
        echo " and <b>before</b> any other $kwd lines ensure that the following is included:<br>";
        foreach ($zend_extension_lines as $zl) {
            echo "<code>$zl</code><br>";
        }
        if (!empty($php_ini_path)) {
            if (zend_extension_line_missing($php_ini_path)) {
                echo "<a>Alternatively, replace your current <code>$php_ini_path</code> file with <a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">this new $php_ini_name file</a>."; 
            }
        }
    }
    echo '</li>';
}

function server_restart_instructions()
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();

    if ($sysinfo['SS']) {
		if ($sysinfo['SS'] == 'PHP-FPM') {
			echo "<li>Restart PHP-FPM.</li>";
		} else {
			echo "<li>Restart the ${sysinfo['SS']} server software.</li>";
		}
    } else {
        echo "<li>Restart the server software.</li>";
    }

    echo "<li>When the server software has restarted, <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the Loader</a>.</li>";

	if ($sysinfo['SS'] && $sysinfo['SS'] == 'PHP-FPM') {
		echo '<li>If the Loader installation failed, check the PHP-FPM error log file for errors.</li>';
    } elseif ($sysinfo['SS'] == 'Apache' && !is_ms_windows()) {
        echo '<li>If the Loader installation failed, check the Apache error log file for errors and see our guide to <a target="unix_errors" href="'. UNIX_ERRORS_URL . '">Unix related errors</a>.</li>';
    }
}

function shared_test_instructions()
{
    $base = get_base_address();
    echo "<li><a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">Click here to test the Loader</a>.</li>";
}

function link_to_php_ini_instructions()
{
    $default = get_default_address();
    echo "<p><a href=\"{$default}&amp;stype=s&amp;ini=1\">Please click here for instructions on using the php.ini method instead</a>.</p>";
}

function php_ini_instruction_list($server_type)
{
    echo '<h4>Installation Instructions</h4>';
    echo '<div class=panel>';
    echo '<ol>';

    loader_download_instructions(); 
    $loader_dir = loader_install_instructions($server_type);
    zend_extension_instructions($server_type,$loader_dir);
    if ($server_type != SERVER_SHARED || !own_php_ini_possible()) {
        server_restart_instructions();
    } else {
        shared_test_instructions();
    } 
    echo '</ol>';
    echo '</div>';
}

function php_ini_install_shared($give_preamble = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();
    if ($give_preamble) {
        echo "<p>On your <strong>shared</strong> server, the Loader should be installed using a <code>$php_ini_name</code> configuration file.";
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";
    }

    if (own_php_ini_possible()) {
        echo '<p>With your hosting account, you may be able to use your own PHP configuration file.</p>';
    } else {
        echo "<p>It appears that you cannot install the ionCube Loader using the <code>$php_ini_name</code> file. Your server provider or system administrator should be able to perform the installation for you. Please refer them to the following instructions.</p>";
    }

    php_ini_instruction_list(SERVER_SHARED);
}

function php_ini_install($server_type_desc = null, $server_type = SERVER_DEDICATED, $required = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();

    echo '<p>';
    if ($server_type_desc) {
        echo "For a <strong>$server_type_desc</strong> server ";
    } else {
        echo "For this server ";
    }

    if ($required) {
        echo "you should install the ionCube Loader using the <code>$php_ini_name</code> configuration file.";
    } else {
        echo "installing the ionCube Loader using the <code>$php_ini_name</code> file is recommended.";
    }
    if ($server_type_desc) {
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a $server_type_desc server</a>.)";
    }
    echo '</p>';
      
    php_ini_instruction_list($server_type);
}



function help_resources($error_list = array())
{
	$self = get_self();
    $base = get_base_address();
    $server_type_code = server_type_code();
    $server_type = find_server_type();
    $sysinfo = get_sysinfo();
    $resources = array(
            '<a target="_blank" href="' . LOADERS_FAQ_URL . '">ionCube Loaders FAQ</a>',
            '<a target="_blank" href="' . LOADER_FORUM_URL . '">ionCube Loader Forum</a>'
        );
    if (SERVER_SHARED != $server_type || own_php_ini_possible(true)) {
		$support_info = array ( 
			'department' 		=> WIZARD_SUPPORT_TICKET_DEPARTMENT,
			'subject' 			=> "ionCube Loader installation problem",
			'message' 			=> support_ticket_information()
		   );
		if (SERVER_LOCAL == $server_type && !info_should_be_disabled()) {
			$temp_files = system_info_temporary_files();
		} else {
			$temp_files = NULL;
		}
		if (!empty($temp_files)) {
			$support_info['ini'] = base64_encode(file_get_contents($temp_files['ini']));
			$support_info['phpinfo'] = base64_encode(file_get_contents($temp_files['phpinfo']));
			$support_info['additional'] = base64_encode(file_get_contents($temp_files['additional']));
			
			$loader_path = find_loader(true);
			if (is_string($loader_path)) {		
				$support_info['loader'] = base64_encode(file_get_contents($loader_path));
				$support_info['loader_name'] = basename($loader_path);
			} else {
				$support_info['loader'] = '';
				$support_info['loader_name'] = '';
			}
		} else {
			$support_info['ini'] = '';
			$support_info['phpinfo'] = '';
			$support_info['additional'] = '';
			$support_info['loader'] = '';
			$support_info['loader_name'] = '';
		}
		 
        $resources[2] = '<form action="' . SUPPORT_SITE . 'lw_index.php' .'" method="POST" id="support-ticket"><a href="" onclick="document.getElementById(\'support-ticket\').submit(); return false;">Raise a support ticket through our helpdesk</a>';
		$resources[2] .= '<input type="hidden" name="department" value="' . $support_info['department'] . '"/>';
		$resources[2] .= '<input type="hidden" name="subject" value="' . $support_info['subject'] . '"/>';
		$resources[2] .= '<input type="hidden" name="message" value="' . $support_info['message'] . '"/>';
		if (!empty($temp_files)) {
			$resources[2] .= '<input type="hidden" name="phpinfo" value="' . $support_info['phpinfo'] . '"/>';
			$resources[2] .= '<input type="hidden" name="ini" value="' . $support_info['ini'] . '"/>';
			$resources[2] .= '<input type="hidden" name="additional" value="' . $support_info['additional'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader" value="' . $support_info['loader'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader_name" value="' . $support_info['loader_name'] . '"/>';
		}
		$resources[2] .= '</form>';
    } 
	
    if (SERVER_SHARED == $server_type && own_php_ini_possible(true) && !user_ini_space_path($sysinfo['PHP_INI'])) {
        $resources[3] = '<strong>Please check with your host that you can create php.ini files that will override the system one.</strong>';
    }
    return $resources;
}

function system_info_temporary_files()
{
    $tmpfname_ini = get_tempnam("/tmp", "INI");
    $tmpfname_ini .= ".ini";
    $fh_ini = @fopen($tmpfname_ini,'wb');
    if ($fh_ini) {
        $config = all_ini_contents();
        fwrite($fh_ini,$config);
        fclose($fh_ini);
    } else {
        $tmpfname_ini = '';
    }

    $tmpfname_pinf = get_tempnam("/tmp", "PIN");
    $tmpfname_pinf .= ".html";
    $fh_pinfo = @fopen($tmpfname_pinf,'wb');
    if ($fh_pinfo) {
        ob_start();
        @phpinfo();
        $pinfo = ob_get_contents();
        ob_end_clean();
        fwrite($fh_pinfo,$pinfo);
        fclose($fh_pinfo);
    } else {
        $tmpfname_pinf = '';
    }

    $tmpfname_add = get_tempnam("/tmp", "ADD");
    $tmpfname_add .= ".html";
    $fh_add = @fopen($tmpfname_add,'wb');
    if ($fh_add) {
        ob_start();
        extra_page(false);
        $extra = ob_get_contents();
        ob_end_clean();
        fwrite($fh_add,$extra);
        fclose($fh_add);
    } else {
        $tmpfname_add = '';
    }

    if (empty($tmpfname_ini) || empty($tmpfname_pinf) || empty($tmpfname_add)) {
        return (array());
    } else {
        return (array('ini'           =>   $tmpfname_ini,
                      'phpinfo'       =>   $tmpfname_pinf,
                      'additional'    =>   $tmpfname_add));
    }
}

function get_tempnam($default_tmp_dir = '', $prefix = '')
{
	if (function_exists('sys_get_temp_dir')) {
		return tempnam(sys_get_temp_dir(),$prefix);
	} else {
		return @tempnam($default_tmp_dir, $prefix);
	}
}
function system_info_archive_page()
{
    info_disabled_check();
	$server_type = find_server_type();
	if (SERVER_LOCAL != $server_type) {
		exit;
	}
    $loader = find_loader(true);
    if (is_string($loader)) {
        $loader_file = $loader;
    } else {
        $loader_file = '';
    }
    $all_files = system_info_temporary_files();
    if (!empty($all_files)) {
        if (!empty($loader_file)) {
            $all_files['loader'] = $loader_file;
        }
        $archive_name =  get_tempnam('/tmp',"ARC");
        if (extension_loaded('zip')) {
            $archive_name .= '.zip';
            $zip = @new ZipArchive();
            $mode = @constant("ZIPARCHIVE::OVERWRITE");
            if (!$zip || $zip->open($archive_name, $mode)!==TRUE) {
                $archive_name = '';
            } else {
                foreach($all_files as $f) {
                    $zip->addFile($f,basename($f));
                }
                $zip->close();
            }
        } elseif (extension_loaded('zlib') && !is_ms_windows()) {
            $tar_name = $archive_name . ".tar";
            $all_files_str = join(' ',$all_files);
            $script = "tar -chf $tar_name $all_files_str";
            $result = @system($script,$retval);
            if ($result !== false) {
                $archive_name = $tar_name . '.gz';
                $zp = gzopen($archive_name,"w9");
                $tar_contents = get_file_contents($tar_name);
                gzwrite($zp,$tar_contents);
                gzclose($zp);
            } else {
                $archive_name = '';
            }
        } else {
            $archive_name = '';
        }
    } else {
        $archive_name = '';
    }
    if ($archive_name) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. $archive_name);
        @readfile($archive_name);
    } else {
        $self = get_self();
        $base = get_base_address();
        $server_type_code = server_type_code();
        heading();
        echo "<p>A downloadable archive of system information could not be created.<br> 
            <strong>Please save each of the following and then attach those files to the support ticket:</strong></p>"; 
        echo "<ul>";
        echo "<li><a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo()</a></li>";
        echo "<li><a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a></li>";
        echo "<li><a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional information</a></li>";
        echo "<li><a href=\"$self?page=loaderbin\">loader file</a></li>";
        echo "</ul>";
        footer(true);
    }
}

function support_ticket_information($error_list = array())
{
    $sys = get_sysinfo();
    $ld = get_loaderinfo();

    $ticket_strs = array();
    $ticket_strs[] = "PLEASE DO NOT REMOVE THE FOLLOWING INFORMATION\r\n";
    $ticket_strs[] = "==============\r\n";
    if (!empty($error_list)) {
        $ticket_strs[] = "[hr]";
        $ticket_strs[] = "ERRORS";
        $ticket_strs[] = "[table]";
        $ticket_strs[] = '[tr][td]' . join('[/td][/tr][tr][td]',$error_list) . '[/td][/tr]';
        $ticket_strs[] = "[/table]";
    }
    $ticket_strs[] = "[hr]";
    $ticket_strs[] = "SYSTEM INFORMATION";
    $info_lines = array();
    $info_lines["Wizard version"] = script_version();
    $info_lines["PHP uname"] = $ld['uname'];
    $info_lines["Machine architecture"] = $ld['arch'];
    $info_lines["Word size"] = $ld['wordsize'];
    $info_lines["Operating system"] = $ld['osname'] . ' ' . $ld['osver'];
    if (selinux_is_enabled() || possibly_selinux()) {
        $info_lines["Security enhancements"] = "SELinux";
    } elseif (grsecurity_is_enabled()) {
        $info_lines["Security enhancements"] = "Grsecurity";
    } else {
        $info_lines["Security enhancements"] = "None";
    }
    $info_lines["PHP version"] = PHP_VERSION; 
    if ($sys['DEBUG_BUILD']) {
        $info_lines["DEBUG BUILD"] = "DEBUG BUILD OF PHP";
    }
    if (!$sys['SUPPORTED_COMPILER']) {
        $info_lines["SUPPORTED PHP COMPILER"] = "FALSE";
        $info_lines["PHP COMPILER"] = $sys['PHP_COMPILER'];
    }
    $info_lines["Is CLI?"] = ($sys['IS_CLI']?"Yes":"No");
    $info_lines["Is CGI?"] = ($sys['IS_CGI']?"Yes":"No");
    $info_lines["Is thread-safe?"] = ($sys['THREAD_SAFE']?"Yes":"No");
    $info_lines["Web server"] = $sys['FULL_SS'];
    $info_lines["Server type"] = server_type_string();
    $info_lines["PHP ini file"] = $sys['PHP_INI'];
    if (!@file_exists($sys['PHP_INI'])) {
        $info_lines["Ini file found"] = "INI FILE NOT FOUND";
    } else {
        if (is_readable($sys['PHP_INI'])) {
            $info_lines["Ini file found"] = "INI FILE READABLE";
        } else {
            $fh = @fopen($sys['PHP_INI'],"rb");
            if ($fh === false) {
                $info_lines["Ini file found"] = "INI FILE FOUND BUT POSSIBLY NOT READABLE";
            } else {
                $info_lines["Ini file found"] = "INI FILE READABLE";
            }
        }
    }
    $info_lines["PHPRC"] = $sys['PHPRC'];
    $loader_path = find_loader();
    if (is_string($loader_path)) {
        $info_lines["Loader path"] =  $loader_path;
        $info_lines["Loader file size"] = filesize($loader_path) . " bytes.";
        $info_lines["Loader MD5 sum"] =  md5_file($loader_path);
    } else {
        $info_lines["Loader path"] =  "LOADER PATH NOT FOUND";
    }
    $server_type_code = server_type_code();
    if (!empty($_SESSION['hostprovider'])) {
      $info_lines['Hosting provider'] = $_SESSION['hostprovider'];
      $info_lines['Provider URL'] = $_SESSION['hosturl'];
    }
    $info_lines["Wizard script path"] = '[url]http://' . $_SERVER["HTTP_HOST"] . get_self() . '?stype='. $server_type_code . '[/url]';
    $ticket_strs[] = "[table]";
    foreach ($info_lines as $h => $i) {
        $value = (empty($i))?'EMPTY':$i;
        $ticket_strs[] = '[tr][td]' . $h . '[/td]' . '[td]' . $value . '[/td][/tr]';
    }
    $ticket_strs[] = '[/table]';
    $ticket_strs[] = '[hr]';
    $ticket_strs[] = "\r\n==============\r\n";
    $ticket_strs[] = "PLEASE ENTER ANY ADDITIONAL INFORMATION BELOW\r\n";

    $support_ticket_str = join('',$ticket_strs);
    return urlencode($support_ticket_str);
}

function wizard_stats_data($page_id)
{
    $data = array();

    try_runtime_loading_if_applicable();
    $sysinfo = get_sysinfo();
    $ldinfo = get_loaderinfo();

    $data['sessionid'] = session_id();
    $data['wizard_version'] = script_version();
    $data['server_type'] = server_type_code();
    $data['hostprovider'] = (isset($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $data['hosturl'] = (isset($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $data['page_id'] = $page_id;
    $data['loader_state'] = (extension_loaded(LOADER_EXTENSION_NAME))?'installed':'failure';
    $data['ini_location'] = $sysinfo['PHP_INI'];
    $data['is_cgi'] = ($sysinfo['IS_CGI'])?"yes":"no";
    $data['is_ts'] = ($sysinfo['THREAD_SAFE'])?"yes":"no";
    $data['arch'] = $ldinfo['arch'];
    $data['php_version'] = PHP_VERSION;
    $data['os'] = $ldinfo['osname'];
    $data['word_size'] = $ldinfo['wordsize'];
    $data['referrer'] =  $_SERVER["HTTP_HOST"] . get_self();

    return $data;
}

function send_stats($page_id = 'default')
{
    $server_type = find_server_type();
    $res = false;

    if (SERVER_LOCAL != $server_type) {
        $stats_data = wizard_stats_data($page_id);

        if (!isset($_SESSION['stats_sent'][$page_id][$stats_data['loader_state']])) {
            $url = WIZARD_STATS_URL;

            if (!empty($stats_data)) {
                if(function_exists('http_build_query')) {
                    $qparams = http_build_query($stats_data);
                } else {
                    $qparams = php4_http_build_query($stats_data);
                }
                $url .= '?' . $qparams;
                $res = remote_file_contents($url);
            }
            $_SESSION['stats_sent'][$page_id][$stats_data['loader_state']] = 1;
        } else {
            $res = true;
        }
    } else {
        $res = 'LOCAL';
    }
    return $res;
}

function os_arch_string_check($loader_str)
{
    $errors = array();
    if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_str,$os_matches)) {
        $loader_info = get_loaderinfo();
        $dirname = calc_dirname();
        $packed_osname = preg_replace('/\s/','',strtolower($loader_info['osname']));
        if (strtolower($dirname) != $os_matches[1] && $packed_osname != $os_matches[2]) {
            $errors[ERROR_LOADER_WRONG_OS] = "You have the wrong loader for your operating system, ". $loader_info['osname'] . ".";
        } else {
            $loader_wordsize = (strpos($os_matches[3],'64') === false)?32:64;
            if ($loader_info['arch'] != ($ap = required_loader_arch($os_matches[3],$loader_info['oscode'],$loader_wordsize))) {
                $err_str = "You have the wrong loader for your machine architecture.";
                $err_str .= " Your system is " . $loader_info['arch'];
                $err_str .= " but the loader you are using is for " . $ap . ".";
                $errors[ERROR_LOADER_WRONG_ARCH] = $err_str;
            }
        }
    }
    return $errors;
}

function get_loader_strings($loader_location)
{
    if (function_exists('file_get_contents')) {
        $loader_strs = @file_get_contents($loader_location);
    } else {
        $lines = @file($loader_location);
        $loader_strs = join(' ',$lines);
    }
    return $loader_strs;
}

function loader_system($loader_location)
{
    $loader_system = array();
    $loader_strs = get_loader_strings($loader_location);

    if (!empty($loader_strs)) {

        if (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
            $loader_system['oscode'] = 'win';
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '_nonts')?0:1;
			if (preg_match("/_localtime([0-9][0-9])/i",$loader_strs,$size_matches)) {
				$loader_system['wordsize'] = ($size_matches[1] == '64')?64:32;
			} else {
				$loader_system['wordsize'] = 32;
			}
            $loader_system['arch'] = ($loader_system['wordsize'] == 64)?'x86-64':'x86';
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
			if ($loader_system['php_version_major'] == 8 && $loader_system['php_version_minor'] >= 1) {
				$loader_system['compiler'] = 'VC16';
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] >= 2) {
				$loader_system['compiler'] = 'VC15'; 
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] < 2) {
				$loader_system['compiler'] = 'VC14'; 
			} elseif ($loader_system['php_version_major'] == 5 && $loader_system['php_version_minor'] >= 5) {
				$loader_system['compiler'] = 'VC11'; 
			} elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_system['compiler'] = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_system['compiler'] = 'VC6';
            }
        } elseif (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '-ts')?1:0;
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
            if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_strs,$os_matches)) {
                $loader_system['oscode'] = strtolower(substr($os_matches[2],0,3));
                $loader_system['wordsize'] = (strpos($os_matches[3],'64') === false)?32:64;
                $loader_system['arch'] = required_loader_arch($os_matches[3],$loader_system['oscode'],$loader_system['wordsize']);
                $loader_system['compiler'] = $os_matches[4];
            }
        }
        if (preg_match("/ionCube Loader Version\s+(\S+)/",$loader_strs,$loader_version)) {
            $loader_system['loader_version'] = $loader_version[1];
		} elseif (preg_match("/ioncube_loader_(\d{1,2}\.\d\.\d{1,2})\./",$loader_strs,$loader_version)){
			$loader_system['loader_version'] = $loader_version[1];
        } else {
            $loader_system['loader_version'] = 'UNKNOWN';
        }
        if (isset($loader_system['php_version_major'])) {
            $loader_system['php_version'] = $loader_system['php_version_major'] . '.' . $loader_system['php_version_minor'];
        }
    }
    return $loader_system;
}

function loader_compatibility_test($loader_location)
{
    $errors = array();

    $sysinfo = get_sysinfo();
    if (LOADER_NAME_CHECK) {
        $installed_loader_name = basename($loader_location);
        $expected_loader_name = get_loader_name();
        if ($installed_loader_name != $expected_loader_name) {
            $errors[ERROR_LOADER_UNEXPECTED_NAME] = "The installed loader (<code>$installed_loader_name</code>) does not have the name expected (<code>$expected_loader_name</code>) for your system. Please check that you have the correct loader for your system.";
        }
    }
    if (empty($errors) && !is_readable($loader_location)) {
        $execute_error = "The loader at $loader_location does not appear to be readable.";
        $execute_error .= "<br>Please check that it exists and is readable.";
        $execute_error .= "<br>Please also check the permissions of the containing ";
        $execute_error .= (is_ms_windows()?'folder':'directory') . '.';
		if ($sysinfo['SS'] == 'PHP-FPM') {
			$execute_error .= "<br>Please also check that PHP-FPM has been restarted.";
        } elseif (($sysinfo['SS'] == 'IIS') || !($sysinfo['IS_CGI'] || $sysinfo['IS_CLI'])) {
            $execute_error .= "<br>Please also check that the web server has been restarted.";
        }
        $execute_error .= ".";
        $errors[ERROR_LOADER_NOT_READABLE] = $execute_error;
    }
    $loader_strs = get_loader_strings($loader_location);
    $phpv = php_version(); 
    if (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
        if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
            $loader_php = $version_matches[1] . "." . $version_matches[2];
            $server_php =  $phpv['major'] . "." .  $phpv['minor'];
            $errors[ERROR_LOADER_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
        }
        if (is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'] && !is_ms_windows() && !(isset($version_matches[4]) && $version_matches[4] == '-ts')) {
            $errors[ERROR_LOADER_NONTS_PHP_TS] = "Your server is running a thread-safe version of PHP but the loader is not a thread-safe version.";
        } elseif (isset($version_matches[4]) && $version_matches[4] == '-ts' && !(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'])) {
            $errors[ERROR_LOADER_TS_PHP_NONTS] = "Your server is running a non-thread-safe version of PHP but the loader is a thread-safe version.";
        }
    } elseif (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
        if (!is_ms_windows()) {
            $errors[ERROR_LOADER_WIN_SERVER_NONWIN] = "You have a Windows loader but your server does not appear to be running Windows.";
        } else {
            if (isset($version_matches[4]) && $version_matches[4] == '_nonts' && is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) {
                $errors[ERROR_LOADER_WIN_NONTS_PHP_TS] = "You have the non-thread-safe version of the Windows loader but you need the thread-safe one.";
            } elseif (!(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) && !(isset($version_matches[4]) && $version_matches[4] == '_nonts')) {
                $errors[ERROR_LOADER_WIN_TS_PHP_NONTS] = "You have the thread-safe version of the Windows loader but you need the non-thread-safe one."; 
            }
            if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
                $loader_php = $version_matches[1] . "." . $version_matches[2];
                $server_php =  $phpv['major'] . "." .  $phpv['minor'];
                $errors[ERROR_LOADER_WIN_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
            }
                        
            if ($version_matches[1] == 8 && $version_matches[2] >= 1) {
                $loader_compiler = 'VC16';
            } elseif ($version_matches[1] == 7 && $version_matches[2] >= 2) {
                $loader_compiler = 'VC15'; 
            } elseif ($version_matches[1] == 7) {
                $loader_compiler = 'VC14'; 
            } elseif ($version_matches[1] == 5 && $version_matches[2] >= 5) {
                $loader_compiler = 'VC11'; 
            } elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_compiler = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_compiler = 'VC6';
            }
            if ($loader_compiler != $sysinfo['PHP_COMPILER']) {
                $errors[ERROR_LOADER_WIN_COMPILER_MISMATCH] = "Your loader was built using $loader_compiler but you need the loader built using ${sysinfo['PHP_COMPILER']}.";
            }
        }
    } else {
            $errors[ERROR_LOADER_PHP_VERSION_UNKNOWN] = "The PHP version for the loader cannot be determined - please check that you have a valid ionCube Loader.";
    } 
    $errors += os_arch_string_check($loader_strs);

    return $errors;
}


function shared_server()
{
    if (!$rtl_path = runtime_loading()) {
        if (empty($_SESSION['use_ini_method']) && runtime_loading_is_possible()) {
            runtime_loading_instructions();
        } else {
            php_ini_install_shared();
        }
    } else {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        echo "<p>The ionCube Loader $lv for PHP $phpv has been successfully installed.</p>";
        $is_legacy_loader = loader_major_version_instructions($mv);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,$newer_version);
        }
        successful_install_end_instructions($rtl_path);
    }
}

function dedicated_server()
{
    php_ini_install('dedicated or VPS', SERVER_DEDICATED, true);
}

function local_install()
{
    php_ini_install('local',SERVER_LOCAL, true);
}


function unregister_globals()
{
    if (!ini_get('register_globals')) {
        return;
    }

    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

function clear_session($persist = array())
{
    $persist['not_go_daddy'] = empty($_SESSION['not_go_daddy'])?0:1;
    $persist['use_ini_method'] = empty($_SESSION['use_ini_method'])?0:1;
    $persist['server_type'] = empty($_SESSION['server_type'])?SERVER_UNKNOWN:$_SESSION['server_type'];
    @session_destroy();
    $_SESSION = array();
    $_SESSION['CREATED'] = time();
    $_SESSION = $persist;
}

function can_archive()
{
	return (extension_loaded('zip') || (extension_loaded('zlib') && !is_ms_windows()));
}

function is_ioncube()
{
        return (($_SERVER["REMOTE_ADDR"] == IONCUBE_IP_ADDRESS) || ($_SERVER["REMOTE_ADDR"] == gethostbyname(IONCUBE_ACCESS_ADDRESS)));
}

function can_reach_ioncube()
{
	return (isset($_SESSION['remote_access_successful']));
}

function info_should_be_disabled($only_allow_ioncube = false)
{
    $elapsed = time() - max(filemtime(__FILE__),filectime(__FILE__));
	
	if (is_ioncube()) {
		$cutoff_time = IONCUBE_WIZARD_EXPIRY_MINUTES * 60;
	} else {
		if (!$only_allow_ioncube && !extension_loaded(LOADER_EXTENSION_NAME)) {
			$cutoff_time = WIZARD_EXPIRY_MINUTES * 60;
		} else {
			return true;
		}
	}
	
    return ($elapsed > $cutoff_time);
}

function info_disabled_text()
{
    return "The information you have tried to access has been disabled for security reasons. Please re-install this Loader Wizard script and try again.";
}

function info_disabled_check()
{
    if (info_should_be_disabled()) {
        heading();
        echo info_disabled_text();
        footer(true);
        exit;
    }
}

function run()
{

	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (preg_match('/googlebot/i',$user_agent)) {
		exit;
	}
    unregister_globals();
    if (is_php_version_or_greater(4,3,0)) {
        ini_set('session.use_only_cookies',1);
    }
    $session_ok = @session_start();

    if (!defined('PHP_EOL')) {
        if (is_ms_windows()) {
            define('PHP_EOL',"\r\n");
        } else {
            define('PHP_EOL',"\n");
        }
    }

    if (!isset($_SESSION['CREATED'])) {
        $_SESSION['CREATED'] = time();
    } elseif (time() - $_SESSION['CREATED'] > SESSION_LIFETIME_MINUTES * 60 ) {
        clear_session(); 
    }
    if (!isset($_SERVER)) $_SERVER =& $HTTP_SERVER_VARS;

    (php_sapi_name() == 'cli') && die("This script should only be run by a web server.\n");

    $page = get_request_parameter('page');
    $host = get_request_parameter('host');
    $clear = get_request_parameter('clear');
    $ini = get_request_parameter('ini');
    $timeout = get_request_parameter('timeout');

    if ($timeout) {
        $_SESSION['timing_out'] = 1;
        $_SESSION['initial_run'] = 0;
    }

    if (!empty($host)) {
        if ($host == 'ngd') {
            $_SESSION['not_go_daddy'] = 1;
        }
    }
    if (!empty($ini)) {
        $_SESSION['use_ini_method'] = 1;
    }

    if (!empty($clear)) {
        clear_session();
        unset($_SESSION['not_go_daddy']);
        unset($_SESSION['use_ini_method']);
        unset($_SESSION['server_type']);
    } else {
        $stype = get_request_parameter('stype');
        $hostprovider = get_request_parameter('hostprovider');
        $hosturl = get_request_parameter('hosturl');
        if (!empty($hostprovider)) {
            $_SESSION['hostprovider'] = $hostprovider;
            $_SESSION['hosturl'] = $hosturl;
        }
        $server_type = find_server_type($stype,false,true);
    }
    if ($session_ok && !$timeout && !isset($_SESSION['initial_run']) && empty($page)) {
        $_SESSION['initial_run'] = 1;
        initial_page();
        @session_write_close();
        exit;
    } else {
        $_SESSION['initial_run'] = 0;
    }

    if (empty($_SESSION['server_type'])) {
        $_SESSION['server_type'] = SERVER_UNKNOWN;
    }

    if (empty($page) || !function_exists($page . "_page")) {
        $page = get_default_page();
    } 

    $fn = "{$page}_page";
    $fn();

    @session_write_close();
    exit(0);
}

function wizardversion_page()
{
    $start_time = time();
    $wizard_version_only = get_request_parameter('wizard_only');
    $clear_session_info = get_request_parameter('clear_info');
    if ($clear_session_info) {
        unset($_SESSION['timing_out']);
        unset($_SESSION['latest_wizard_version']);
    }
    $wizard_version = latest_wizard_version();
    $message = '';
    if (false === $wizard_version) {
        $message = "0";
    } elseif (update_is_available($wizard_version)) {
        $message = "$wizard_version";
    } else {
        $message = "1";
    }
    echo $message;
    @session_write_close();
    exit(0);
}

function platforminfo_page()
{
    $message = '';
    $platforms = get_loader_platforms();
    $message = empty($platforms)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function loaderversion_page()
{
    $message = '';
    $loader_versions = get_loader_version_info();
    $message = empty($loader_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function compilerversion_page()
{
    $message = '';
    $compiler_versions = find_win_compilers();
    $message = empty($compiler_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function initial_page()
{
    $self = get_self();
    $start_page = get_default_address(false);
    $stage_timeout = 7000;
    $step_lag = 500;

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <style type="text/css">
        body {
            height: 100%;
            width: 100%;
        }
        </style>
        <script type="text/javascript">
        var timingOut = 0;
        var xmlHttpTimeout;
        var ajax;
        var statusPar;
        var stage_timeout = $stage_timeout;
        var step_lag = $step_lag;

        function checkNextStep(ajax,expected,continuation) {
            if (ajax.readyState==4 && ajax.status==200)
            {
                clearTimeout(xmlHttpTimeout);
                if (ajax.responseText == expected) {
                   setTimeout('',step_lag);
                   continuation();
                } else {
                   statusPar.innerHTML = 'Unable to check for update<br>script continuing';
                   setTimeout("window.location.href = '$start_page&timeout=1'",1000);
                }
            }
        }

        function getXmlHttp() {
            if (window.XMLHttpRequest) {
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xmlhttp;
        }
        var startMainLoaderWizard = function() {
            window.location.href = '$start_page';
        }
        var loaderVersionCheck = function() {
            statusPar.innerHTML = 'Stage 4/4: Getting latest loader versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",startMainLoaderWizard);
            }
            xmlHttp.open("GET","$self?page=loaderversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var platformCheck = function() {
            statusPar.innerHTML = 'Stage 3/4: Getting platform information';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",loaderVersionCheck);
            }
            xmlHttp.open("GET","$self?page=platforminfo",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var compilerVersionCheck = function() {
            statusPar.innerHTML = 'Stage 2/4: Getting compiler versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",platformCheck);
            }
            xmlHttp.open("GET","$self?page=compilerversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var startChecks = function() {
            statusPar = document.getElementById('status');
            statusPar.innerHTML = 'Stage 1/4: Getting Loader Wizard version';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",compilerVersionCheck);
            }
            xmlHttp.open("GET","$self?page=wizardversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        function ajaxTimeout(){
           ajax.abort();
           statusPar.innerHTML = 'Cannot reach server<br>script continuing';
           setTimeout("window.location.href = '$start_page&timeout=1'",1000);
        }
        </script>
    </head>
    <body>

    <div id="loading"><script type="text/javascript">document.write('<p>Initialising<br>ionCube Loader Wizard<br><span id="status"></span></p>');</script><p id="noscript">Your browser does not support JavaScript so the ionCube Loader Wizard initialisation cannot be made now. This script can get the latest loader version information from the ionCube server when you go to the next page.<br>Please choose one of the following. <br>If the script appears to hang please restart the script and choose the "NO" option.<br><br><br><a href="$start_page">YES - my server DOES have internet access</a><br><br><a href="$start_page&timeout=1">NO - my server does NOT have internet access</a></p></div>
    <script type="text/javascript">
        document.getElementById('noscript').style.display = 'none';
        window.onload = startChecks;
    </script>
    </body>
    </html>
EOT;
}

function default_page($loader_extension = LOADER_EXTENSION_NAME)
{
    $self = get_self();
    foreach (array('self') as $vn) {
        if (empty($$vn)) {
			$server_data = print_r($_SERVER,true);
            error("Unable to initialise ($vn)". ' $_SERVER is: ' . $server_data);
        }
    }

    heading();

    $wizard_update = check_for_wizard_update(true);

    $rtl = try_runtime_loading_if_applicable();

    $server_type = find_server_type();

    if (extension_loaded($loader_extension) && $server_type != SERVER_UNKNOWN) {
        loader_already_installed($rtl);
    } else {
        loader_not_installed();
    }
    send_stats('default');

    footer($wizard_update);
}

function uninstall_wizard_instructions()
{
    echo '<p><strong>For security reasons we advise that you remove this Wizard script from your server now that the ionCube Loader is installed.</strong></p>';
}

function contact_script_provider_instructions()
{
    echo '<p>Please contact the script provider if you do experience any problems running encoded files.</p>';
}

function may_need_to_copy_ini()
{
    $sys = get_sysinfo();
    if (ini_same_dir_as_wizard() && $sys['IS_CGI']) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        $ini = ini_file_name();
        echo "<p>Please note that if encoded files in a different $dirphrase from the Wizard fail then you should attempt to copy the $ini file to each $dirphrase in which you have encoded files.</p>";
    }
}

function ioncube_24_is_available()
{
	$loaderinfo = get_loaderinfo();
	$php_ver = php_version();
   
	return ($loaderinfo['oscode'] == 'lin' && (($php_ver['major'] == 5 && $php_ver['minor'] >= 3) || $php_ver['major'] > 5) );
}

function ioncube_24_is_enabled()
{
	$ic24_enabled = ini_get(IC24_ENABLED_INI_PROPERTY);
	return $ic24_enabled;
}

function ioncube_24_information()
{
    if (ioncube_24_is_available() && !ioncube_24_is_enabled()) {
        $self = get_self();
        echo '<div class="ic24">';
        echo '<div class="ic24graphic">';
        echo '<a target="_blank" href="' . IONCUBE24_URL . '"><img id="ic24logo" src="' . $self . '?page=ic24logo" alt="ionCube24 logo"></a>';
        echo '</div>';
        echo '<div id="ic24info">';
        echo '<p><strong>Bonus Features!</strong> The ionCube Loader can also give ';
        echo '<strong>real-time intrusion protection</strong> to protect against malware and <strong>PHP error reporting</strong> ';
        echo 'to alert when things go wrong on your website.</p>';
        echo '<p>These features are disabled by default but easily activated. ';
        echo '<strong><a target="_blank" href="' . IONCUBE24_URL . '">visit ioncube24.com</a></strong> to find out more.</p>';
        echo '</div>';
        echo '</div>';
    }
}

function cli_install_instructions()
{

	if (is_php_version_or_greater(5,3)) {
		$cli_loader_installed = shell_exec('php -r "echo extension_loaded(\"' . LOADER_EXTENSION_NAME . '\");"');
		
		if (!$cli_loader_installed) {
			$cli_php_ini_output = shell_exec("php --ini");
			
			$ini_loader_loc = scan_inis_for_loader();
		
			if (!is_null($cli_php_ini_output)) {
				echo '<div class="panel">';
				echo '<h4>Loader Installation for Command-Line (CLI) PHP</h4>';
				echo "<p>At present it does not look like the ionCube Loader is installed for command-line (CLI) PHP.</p>";
				echo "<p>Please note that if you need to run the CLI PHP, such as for <strong>cron jobs</strong>, then please ensure the zend_extension line for the ionCube Loader is included in your CLI PHP configuration.</p>";
				
				if (!empty($ini_loader_loc['location'])) {
					echo "<p>The zend_extension line that needs to be copied is:</p>";
					echo "<p><kbd>zend_extension = " . $ini_loader_loc['location'] . "</kbd></p>";
				}
				
				echo "<p>Your CLI PHP Configuration is:</p>";
				echo '<div class="terminal">';
				echo "<pre>";
				echo $cli_php_ini_output;
				echo "</pre>";
				echo '</div>';
				echo '</div>';
			}
		}
	}
}

function successful_install_end_instructions($rtl_path = null)
{
    if (empty($rtl_path)) {
        may_need_to_copy_ini();
    } elseif (is_string($rtl_path)) {
        echo "<p>The runtime loading method of installation was used with path <code>$rtl_path</code></p>";
    }
    contact_script_provider_instructions();
    if (is_legacy_platform()) {
        legacy_platform_instructions();
    }
	
	if (!is_ms_windows() && is_php_version_or_greater(5,3)) {
		cli_install_instructions();
	}
	
    uninstall_wizard_instructions();
	
	ioncube_24_information();
}

function loader_major_version_instructions($mv)
{
    if ($mv < LATEST_LOADER_MAJOR_VERSION) {
        echo "<p><strong>The installed version of the Loader cannot run files produced by the most recent ionCube Encoder.</strong>";
        echo " You will need a version " . LATEST_LOADER_MAJOR_VERSION . " ionCube Loader to run such files.</p>";
    }
    return ($mv < LATEST_LOADER_MAJOR_VERSION);
}

function loader_already_installed($rtl = null)
{
    list($lv,$mv,$newer_version) = ioncube_loader_version_information();
    $phpv = php_version_maj_min();
    $php_str = ' for PHP ' . $phpv;
    echo '<div class="success">';
    echo '<h4>Loader Installed</h4>';
    if ($newer_version) {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is <strong>already installed</strong> but it is an old version.';
        echo ' It is recommended that the Loader be upgraded to the latest version if possible.</p>';
        $know_latest_version = is_string($newer_version);
        $is_legacy_loader = loader_major_version_instructions($mv);
        echo '</div>';
        loader_upgrade_instructions($lv,$newer_version);
    } else {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is already installed and encoded files should run without problems.</p>'; 
        echo '</div>';
        $is_legacy_loader = loader_major_version_instructions($mv,true);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,true);
        }
    }

    successful_install_end_instructions($rtl);
}

function loader_upgrade_instructions($installed_version,$newer_version)
{
    if ($newer_version) {
        echo '<div class="panel">';
        echo '<h4>Loader Upgrade Instructions</h4>';
        $restart_needed = true;
        $server_type = find_server_type();
        if ($server_type == SERVER_SHARED || $server_type == SERVER_UNKNOWN) {
            $loader_path = find_loader(true);
            if (!is_string($loader_path) || false === user_ini_space_path($loader_path)) {
                $verb_case = ($server_type == SERVER_UNKNOWN)?"may":"will";
                echo "<p>Please note that you $verb_case need your system administrator to do the following to upgrade. The web server will need to be restarted after the loader file is changed.</p>";
            }
            $restart_needed = false;
        }
        if (is_string($newer_version)) {
            $version_str = "version $newer_version";
        } else {
            $version_str = "a newer version";
        }
        $loader_name =  get_loader_name();
        echo "<p>To upgrade from version $installed_version to $version_str of the ionCube Loader, please replace your existing loader file, $loader_name, with
            the file of the same name from one of the following packages:</p>";
        if (is_ms_windows()) {
            $basename = windows_package_name();
        } else {
            list($basename,$multiple_os_versions) = unix_package_name();
        }
        echo make_archive_list($basename,array('zip','tar.gz'));
        if ($restart_needed) {
            echo "<p>Once you have replaced the loader file please restart your web server.</p>";
        }
        echo '</div>';
    }
}

function legacy_platform_warning()
{
    $leg_warn = '<p><strong>You are on a platform on which ionCube Loaders are no longer being developed. ';
    $leg_warn .= 'Loaders on your platform may not be able to run files produced by the latest ionCube Encoder. ';
    $leg_warn .= 'Please switch, if possible, to a platform on which loaders are currently supported. ';
    $leg_warn .= 'A list of currently supported platforms is shown on our <a href="' . LOADERS_PAGE . '" target="loaders">loaders page</a>.</strong></p>';

    return $leg_warn;
}

function legacy_platform_instructions()
{
    echo legacy_platform_warning();
}

function loader_not_installed()
{
    $loader = get_loaderinfo();
    $sysinfo = get_sysinfo();

    $stype = get_request_parameter('stype');
    $manual_select = get_request_parameter('manual');
    $host_type = find_server_type($stype,$manual_select,true);

    if ($host_type != SERVER_UNKNOWN && is_array($loader) && !$sysinfo['DEBUG_BUILD']) {
        $warnings = server_restriction_warnings();
        if (is_legacy_platform()) {
            $warnings[] = legacy_platform_warning();
        }
        if (empty($_SESSION['use_ini_method']) && $host_type == SERVER_SHARED && runtime_loading_is_possible()) {
            $errors = runtime_loading_errors();
        } else {
            $errors = ini_loader_errors();
            $warnings = array_merge($warnings,ini_loader_warnings());
        }
        if (!empty($errors)) {
            if (count($errors) > 1) {
                $problem_str = "Please note that the following problems currently exist";
            } else {
                $problem_str = "Please note that the following problem currently exists";
            }
            echo '<div class="alert">' .$problem_str . ' with the ionCube Loader installation:';
            echo make_list($errors,"ul"); 
            echo '</div>';
        }
        if (!empty($warnings)) {
            $addword = empty($errors)?'':'also';
            $plural = (count($warnings)>1)?'s':'';
            echo '<div class="warning">';
            echo "Please note $addword the following issue$plural:";
            echo make_list($warnings,"ul"); 
            echo '</div>';
        }
    }
    if (!isset($stype)) {
        echo '<p>To use files that have been protected by the <a href="' . ENCODER_URL . '" target=encoder>ionCube PHP Encoder</a>, a component called the ionCube Loader must be installed.</p>';
    }

    if (!is_supported_php_version()) {
        echo '<p>Your server is running PHP version ' . PHP_VERSION . ' and is
                unsupported by ionCube Loaders.  Recommended PHP 4 versions are PHP 4.2 or higher, 
                PHP 5.1 or higher for PHP 5, PHP 7.1 or higher for PHP 7 and PHP 8.1 or higher for PHP 8. Please note that there is not an ionCube Loader for PHP 8.0.</p>';
	} elseif ($latest_supported_php_version = is_after_max_php_version_supported()) {
		echo '<strong>Your server is running PHP version ' . PHP_VERSION . ' and is
                currently unsupported by any ionCube Loaders. <br/>This may change in the future if a Loader is produced for your PHP platform.<br/>In the meantime please downgrade PHP to version ' . $latest_supported_php_version . '.</strong>';
    } elseif ($sysinfo['DEBUG_BUILD']) {
         echo '<p>Your server is currently running a debug build of PHP. The Loader cannot be installed with a debug build of PHP. Please ensure that PHP is reconfigured with debug disabled. Note that debug builds of PHP cannot help in debugging PHP scripts.</p>'; 
    } elseif (!is_array($loader)) {
        if ($loader == ERROR_WINDOWS_64_BIT) {
            echo '<p>Loaders for 64-bit PHP on Windows are not currently available. However, if you <b>install and run 32-bit PHP</b> the corresponding 32-bit loader for Windows should work.</p>';
            if ($sysinfo['THREAD_SAFE']) {
                echo '<li>Download one of the following archives of 32-bit Windows x86 loaders:';
            } else {
                echo '<li>Download one of the following archives of 32-bit Windows non-TS x86 loaders:';
            }
            echo make_archive_list(windows_package_name());
        } else {
            echo '<p>There may not be an ionCube Loader available for your type of system at the moment. However, if you create a <a href="'  . SUPPORT_SITE . '">support ticket</a> more advice and information may be available to assist. Please include the URL for this Wizard in your ticket.</p>';
        }
    } elseif (!$sysinfo['SUPPORTED_COMPILER']) {
        $supported_compilers = supported_win_compilers();
        $supported_compiler_string = join('/',$supported_compilers);
        echo '<p>At the current time the ionCube Loader requires PHP to be built with ' . $supported_compiler_string . '. Your PHP software has been built using ' . $sysinfo['PHP_COMPILER'] . '. Supported builds of PHP are available from <a href="https://windows.php.net/download/">PHP.net</a>.';
    } else {
        switch ($host_type) {
            case SERVER_SHARED:
                shared_server();
                break;
            case SERVER_DEDICATED:
                dedicated_server();
                break;
            case SERVER_LOCAL:
                local_install();
                break;
            default:
                echo server_selection_form();
                break;
        }
    }
}

function server_selection_form()
{
    $self = get_self();
    $timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?1:0;
    $hostprovider = (!empty($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $hostprovider = htmlspecialchars($hostprovider, ENT_QUOTES, 'UTF-8');
    $hosturl = (!empty($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $hosturl =  htmlspecialchars($hosturl, ENT_QUOTES, 'UTF-8');
    $form = <<<EOT
    <p>This Wizard will give you information on how to install the ionCube Loader.</p>
    <p>Please select the type of web server that you have and then click Next.</p>
    <script type=text/javascript>
        function trim(s) {
            return s.replace(/^\s+|\s+$/g,"");
        }
        function input_ok() {
            var l = document.getElementById('local');
            if (l.checked) {
                return true;
            } 

            var s = document.getElementById('shared');
            var d = document.getElementById('dedi');

            if (!s.checked && !d.checked) {
                alert("Please select one of the server types.");
                return false;
            } else {
                var hn = document.getElementById('hostprovider');
                var hu = document.getElementById('hosturl');
                var hostprovider = trim(hn.value);
                var hosturl = trim(hu.value);

                if (!hostprovider || !hosturl) {
                    alert("Please enter both a hosting provider name and their URL.");
                    return false;
                }
                if (hostprovider.length < 1) {
                    alert("The hosting provider name should be at least 1 character in length.");
                    return false;
                }
                if (!hosturl.match(/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+/)) {
                    alert("The hosting provider URL is invalid.");
                    return false;
                }
                if (hosturl.length < 4) {
                    alert("The hosting provider URL should be at least 4 characters in length.");
                    return false;
                }
            }
            return true;
        }
    </script>
    <form method=GET action=$self>
        <input type="hidden" name="page" value="default">
        <input type="hidden" name="timeout" value="$timeout">
        <input type=radio id=shared name=stype value=s onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=shared>Shared <small>(for example, server with FTP access only and no access to php.ini)</small></label><br>
        <input type=radio id=dedi name=stype value=d onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=dedi>Dedicated or VPS <small>(server with full root ssh access)</small></label><br>
        <div id="hostinginfo" style="display: none">If you are on a shared or dedicated server, please give your hosting provider and their URL:
            <table>
                <tr><td><label for=hostprovider>Name of your hosting provider</label></td><td><input type=text id="hostprovider" name=hostprovider value="$hostprovider"></td></tr>
                <tr><td><label for=hosturl>URL of your hosting provider</label></td><td><input type=text id="hosturl" name=hosturl value="$hosturl"></td></tr>
            </table>
        </div>
        <input type=radio id=local name=stype value=l onclick="document.getElementById('hostinginfo').style.display = 'none';"><label for=local>Local install</label>
        <p><input type=submit value=Next onclick="return (input_ok(this) && showOverlay());"></p>
    </form>
EOT;
    return $form;
}

function phpinfo_page()
{
    info_disabled_check();
    if (function_is_disabled('phpinfo')) {
        echo "phpinfo is disabled on this server";
    } else {
        @phpinfo();
    }
}

function loader_check_page($ext_name = LOADER_EXTENSION_NAME)
{
    heading();

    $rtl_path = try_runtime_loading_if_applicable();
	
    if (extension_loaded($ext_name)) {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        $php_str = ' for PHP ' . $phpv;
        echo '<div class="success">';
        echo '<h4>Loader Installed Successfully</h4>';
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' <strong>is installed</strong> and encoded files should run successfully.';
        if ($newer_version) {
            echo ' Please note though that you have an old version of the ionCube Loader.</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            loader_upgrade_instructions($lv,$newer_version);
        } else {
            echo '</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            if ($is_legacy_loader) {
                loader_upgrade_instructions($lv,true);
            }
        }
        successful_install_end_instructions($rtl_path);
    } else {
        echo '<div class="failure">';
        echo '<h4>Loader Not Installed</h4>';
        echo '<p>The ionCube Loader is <b>not</b> currently installed successfully.</p>';
	
        if (!is_null($rtl_path)) {
            echo '<p>Runtime loading was attempted but has failed.</p>';
            echo '</div>';
            $rt_errors = runtime_loading_errors();
            if (!empty($rt_errors)) {
                list_loader_errors($rt_errors);
            } 
            link_to_php_ini_instructions();
        } else {
            echo '</div>';
            list_loader_errors();
        }
    }
	
    send_stats('check');
    footer(true);
}

function ini_loader_errors()
{
    $errors = array();
    if (SERVER_SHARED == find_server_type() && !own_php_ini_possible(true)) {
        $errors[ERROR_INI_USER_CANNOT_CREATE] = "It appears that you are not be able to create your own ini files on your shared server. <br><strong>You will need to ask your server administrator to install the ionCube Loader for you.</strong>";
    }
    $loader_loc = find_loader(false);
    if (is_string($loader_loc)) {
        if (!shared_and_runtime_loading()) {
            $sys = get_sysinfo();
            if (empty($sys['PHP_INI'])) {
                $errors[ERROR_INI_NO_PATH] = 'No file path found for the PHP configuration file (php.ini).';
            } elseif (!@file_exists($sys['PHP_INI'])) {
                $errors[ERROR_INI_NOT_FOUND] = 'The PHP configuration file (' . $sys['PHP_INI'] .') cannot be found.';
            }
        }
        $errors = $errors + loader_compatibility_test($loader_loc);
    } else {
        $errors = $errors + $loader_loc;
        $fs_location = find_loader_filesystem();
        if (!empty($fs_location)) {
            $fs_loader_errors = loader_compatibility_test($fs_location);
            if (!empty($fs_loader_errors)) {
                $errors[ERROR_LOADER_WRONG_GENERAL] = "The loader file found at $fs_location is not the correct one for your system.";
            }
            $errors = $errors + $fs_loader_errors;
        }
    } 
    return $errors;
}

function unix_path_dir($dir = '')
{
    if (empty($dir)) {
        $dir = dirname(__FILE__);
    }
    if (is_ms_windows()) {
        $dir = str_replace('\\','/',substr($dir,2));
    }
    return $dir;
}

function unrecognised_inis_webspace($startdir)
{
    $ini_list = array();

    $ini_name = ini_file_name();
    $sys = get_sysinfo();
    $depth = substr_count($startdir,'/');

    $rel_path = '';
    $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
    for ($seps = 0; $seps < $depth; $seps++) {
        $full_ini_loc = @realpath($startdir . '/' . $rel_path) . DIRECTORY_SEPARATOR . $ini_name;
        if (@file_exists($full_ini_loc) && $sys['PHP_INI'] != $full_ini_loc) {
            $ini_list[] = @realpath($full_ini_loc);
        }

        if (dirname($full_ini_loc) == $rootpath) {
            break;
        }
        $rel_path .= '../';
    }
    return $ini_list;
}

function correct_loader_wrong_location()
{
    $loader_location_pair = array();
    $loader_location = find_loader_filesystem();
    if (is_string($loader_location) && !empty($loader_location)) {
        $loader_errors = loader_compatibility_test($loader_location);
        if (empty($loader_errors)) {
            $ini_loader = scan_inis_for_loader();
            if (!empty($ini_loader['location'])) {
                $ini_loader_errors = loader_compatibility_test($ini_loader['location']);
                if (!empty($ini_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = dirname($ini_loader['location']);
                }
            } else {
                $std_dir = loader_install_dir(find_server_type());
                $std_ld_path = $std_dir . DIRECTORY_SEPARATOR . get_loader_name();
                if (@file_exists($std_ld_path)) {
                    $stdloc_loader_errors = loader_compatibility_test($std_ld_path);
                } else {
                    $stdloc_loader_errors = array("Loader file does not exist.");
                }
                if (!empty($stdloc_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = $std_dir;
                }
            }
        }
    }
    return $loader_location_pair;
}

function ini_loader_warnings()
{
    $warnings = array();
    if (find_server_type() == SERVER_SHARED)
    {
        if (own_php_ini_possible()) {
            $sys = get_sysinfo();
            $ini_name = ini_file_name();
            $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
            $root_ini_file = $rootpath . DIRECTORY_SEPARATOR . $ini_name;
            $cgibinpath = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
            $cgibin_ini_file = (empty($cgibinpath))?'':$cgibinpath . DIRECTORY_SEPARATOR . $ini_name;
            $here = unix_path_dir();
            $ini_files = unrecognised_inis_webspace($here);
            $shared_ini_loc = shared_ini_location();
            $shared_ini_file = $shared_ini_loc . DIRECTORY_SEPARATOR . $ini_name;
            $ini_dir = dirname($sys['PHP_INI']);
            $all_ini_locations_used = !empty($ini_files);
            foreach ($ini_files as $full_ini_loc) {
                $advice = "The file $full_ini_loc is not being recognised by PHP.";
                $advice .= " Please check that the name and location of the file are correct.";
                if (!ini_same_dir_as_wizard()) {
                    $ini_loc_dir = dirname($full_ini_loc);
                    if (!@file_exists($shared_ini_file) && !empty($shared_ini_loc) && $ini_loc_dir != $shared_ini_loc && $ini_dir != $shared_ini_loc) {
                        $all_ini_locations_used = false;
                        $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $shared_ini_loc . "</code>.";
                    } else {
                        if (!@file_exists($root_ini_file) && $rootpath != $shared_ini_loc && $full_ini_loc != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $rootpath . "</code>.";
                        } 
                        if (!empty($cgibin_ini_file) && !@file_exists($cgibin_ini_file) && $cgibinpath != $shared_ini_loc && $full_ini_loc != $cgibinpath && $cgibinpath != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= "  Please try copying the <code>$full_ini_loc</code> file to <code>" . $cgibinpath . "</code>.";
                        }
                        $herepath = realpath($here);
                        $here_ini_file = $herepath . DIRECTORY_SEPARATOR . $ini_name;
                        if (!@file_exists($here_ini_file) && $herepath != $rootpath && $herepath != $cgibinpath) {
                            $all_ini_locations_used = false;
                            $advice .= " It may be necessary to copy the <code>$full_ini_loc</code> file to <code>$herepath</code> and to all " . (is_ms_windows()?'folders':'directories') . ' in which you have encoded files';
                        }
                    }
                } else {
                    $all_ini_locations_used = false;
                }
                $warnings[] = $advice;
            }
            if ($all_ini_locations_used) {
                $warnings[] = "<strong>It looks as if ini files are not being recognised in any of the standard locations in your webspace. Please contact your hosting provider to check whether you can create your own PHP ini file and where it should go.</strong>";
            }
        } else {
            if (own_php_ini_possible(true)) {
                $warnings[] = "You may not be able to create your own ini files on your shared server. <br><strong>You might need to ask your server administrator to install the ionCube Loader for you.</strong>";
            }
        }
    } else {
        $loader_dir_pair = correct_loader_wrong_location();
        if (!empty($loader_dir_pair)) {
            $advice = "The correct loader for your system has been found at <code>${loader_dir_pair['loader']}</code>."; 
            if ($loader_dir_pair['loader'] != $loader_dir_pair['newloc']) {
                $advice .= " Please copy the loader from <code>${loader_dir_pair['loader']}</code> to <code>${loader_dir_pair['newloc']}</code>.";
            }
            $warnings[] = $advice;
        }
    }
    return $warnings;
}

function list_loader_errors($errors = array(),$warnings = array(),$suggest_restart = true)
{
    $default = get_default_address();
    $retry_message = '';

    
    if (empty($errors)) {
        $errors = ini_loader_errors();
        if (empty($warnings)) {
            $warnings = ini_loader_warnings();
        }
    }
	
    if (!empty($errors)) {
        $try_again = '<a href="#" onClick="window.location.href=window.location.href">try again</a>';
	
        echo '<div class="alert">';
        if (count($errors) > 1) {
            echo 'The following problems have been found with the ionCube Loader installation:';
            $retry_message = "Please correct those errors and $try_again.";
        } else {
            echo 'The following problem has been found with the ionCube Loader installation:';
            $retry_message = "Please correct that error and $try_again.";
        }
        if (array_key_exists(ERROR_INI_USER_CANNOT_CREATE,$errors)) {
            $retry_message = '';
        }
        echo make_list($errors,"ul");
        echo '</div>';
        if (!empty($warnings)) {
            echo '<div class="warning">';
            echo 'Please also note the following:';
            echo make_list($warnings,"ul");
            echo '</div>';
        }
    } elseif (!empty($warnings)) {
        echo '<div class="warning">';
        echo 'There are the following potential problems:';
        echo make_list($warnings,"ul");
        echo '</div>';
    } elseif ($suggest_restart) {
        if (SERVER_SHARED == find_server_type()) {
            echo "<p>Please contact your server administrator about installing the ionCube Loader.</p>";
        } else {
            if (selinux_is_enabled()) {
                echo "<p>It appears that SELinux is enabled on your server. This might be solved by running the command <code>restorecon [full path to loader file]</code> as root.</p>";
            } elseif (grsecurity_is_enabled()) {
                echo "<p>It appears that grsecurity is enabled on your server. Please run the command, <code>execstack -c [full path to loader file]</code> and then restart your web server.</p>";
            } else {
                $sysinfo = get_sysinfo();
                $ss = $sysinfo['SS'];
				if ($ss == 'PHP-FPM') {
					echo "<p>Please check that PHP-FPM has been restarted.</p>";
                } elseif (!$sysinfo['CGI_CLI'] || is_ms_windows()) {
                    echo "<p>Please check that the $ss web server software has been restarted.</p>";
                } 
            }
        }
    }
    echo '<div>';
    echo $retry_message;
    echo " You may wish to view the following for further help:";
    echo make_list(help_resources($errors),"ul");
    echo '<a href="' . $default . '">Click here to go back to the start of the Loader Wizard</a>.</div>';
}

function phpconfig_page()
{
    info_disabled_check();
    $sys = get_sysinfo();
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        } else {
			if (!preg_match('`^.*\.ini$`',$ini_file_name) || preg_match('`/`',$ini_file_name) || preg_match('`\\\`',$ini_file_name)) {
				die("Illegal file name $ini_file_name");
			}
		}
        header('Content-Type: text/plain');
        header('Content-Disposition: attachment; filename=' . $ini_file_name);
    } else {
        header('Content-Type: text/plain');
    }
    $exclude_original = get_request_parameter('newlinesonly');
    $prepend = get_request_parameter('prepend');
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    if (!empty($exclude_original) || !empty($prepend)) {
        $loader_dir = loader_install_dir($server_type);
        $zend_lines = zend_extension_lines($loader_dir);
        echo join(PHP_EOL,$zend_lines);
        echo PHP_EOL;
    }
    if (empty($ini_file_name) || empty($sys['PHP_INI_DIR']) || ($sys['PHP_INI_BASENAME'] == $ini_file_name)) {
        $original_ini_file = isset($sys['PHP_INI'])?$sys['PHP_INI']:'';
    } else {
        $original_ini_file = $sys['PHP_INI_DIR'] . DIRECTORY_SEPARATOR . $ini_file_name;
    }
    if (empty($exclude_original) && !empty($original_ini_file) && @file_exists($original_ini_file)) {
        if (!empty($download)) {
            @readfile($original_ini_file);
        } else {
            echo all_ini_contents();
        } 
    }
}

function extra_page($check_access_to_info = true)
{
    if ($check_access_to_info) {
		info_disabled_check();
	}
    heading();
    $sys = get_sysinfo();
    $ini_loader = scan_inis_for_loader();
    $ini_loader_path = $ini_loader['location'];
    $loader_path = find_loader(true);
    $ldinf = get_loaderinfo();
    $self = get_self();
    echo "<h4>Additional Information</h4>";
    echo "<table>";
    $lines = array();
    if (is_string($loader_path)) {
        $lines['Loader is at'] = $loader_path;
        $loader_system = loader_system($loader_path);
        if (!empty($loader_system)) {
            $lines['Loader OS code'] = $loader_system['oscode'];
            $lines['Loader architecture'] = $loader_system['arch'];
            $lines['Loader word size'] = $loader_system['wordsize'];
            $lines['Loader PHP version'] = $loader_system['php_version'];
            $lines['Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Loader compiler'] = $loader_system['compiler'];
            $lines['Loader version'] = $loader_system['loader_version'];
            $lines['File size is'] = filesize($loader_path) . " bytes.";
            $lines['MD5 sum is'] = md5_file($loader_path);
        }
        $lines['Loader file'] = "<a href=\"$self?page=loaderbin\">Download loader file</a>";
    } else {
        $lines['Loader file'] = "Loader cannot be found.";
    }
    $lines['Loader found in ini file'] = empty($ini_loader_path)?"No":"Yes";
    if (!empty($ini_loader_path) && (!is_string($loader_path) || $ini_loader_path != $loader_path)) {
        $lines['Loader location found in ini file'] =  $ini_loader_path;
        $loader_system = loader_system($ini_loader_path);
        if (!empty($loader_system)) {
            $lines['Ini Loader OS code'] = $loader_system['oscode'];
            $lines['Ini Loader architecture'] = $loader_system['arch'];
            $lines['Ini Loader word size'] = $loader_system['wordsize'];
            $lines['Ini Loader PHP version'] = $loader_system['php_version'];
            $lines['Ini Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Ini Loader compiler'] = $loader_system['compiler'];
            $lines['Ini Loader version'] = $loader_system['loader_version'];
        }
    }
    $lines["OS extra security"] = (selinux_is_enabled() || possibly_selinux())?"SELinux":(grsecurity_is_enabled()?"Grsecurity":"None");
    $lines['PHPRC is'] = $sys['PHPRC'];
    $lines['INI DIR is'] = $sys['PHP_INI_DIR'];
    $lines['Additional INI files'] = $sys['PHP_INI_ADDITIONAL'];
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    $lines['Server type is'] = server_type_string();
    $lines["PHP uname"] = $ldinf['uname'];
    $lines['Server word size is'] = $ldinf['wordsize'];
    $lines['Disabled functions'] = ini_get('disable_functions');
    $writeable_dirs = writeable_directories();
    $lines['Writeable loader locations'] = (empty($writeable_dirs))?"<em>None</em>":join(", ",$writeable_dirs);
    if (!empty($_SESSION['hostprovider'])) {
        $lines['Hosting provider'] = $_SESSION['hostprovider'];
        $lines['Provider URL'] = $_SESSION['hosturl'];
    }
    foreach ($lines as $h => $i) {
        $v = (empty($i))?'<em>EMPTY</em>':$i;
        echo '<tr><th>'. $h . ':</th>' . '<td>' . $v . '</td></tr>';
    }
    echo "</table>";
    footer(true);
}

function loaderbin_page()
{
    info_disabled_check();
    $loader_path = find_loader(true);
    if (is_string($loader_path)) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. basename($loader_path));
        @readfile($loader_path);
    }
}



function GoDaddy_root($html_root = '')
{
    if (empty($_SESSION['not_go_daddy']) && empty($_SESSION['godaddy_root'])) {
        $godaddy_pattern = "[\\/]home[\\/]content[\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z]+[\\/]html";

        if (empty($html_root)) {
            $html_root =  $_SERVER['DOCUMENT_ROOT'];
        }
        if (preg_match("@$godaddy_pattern@i",$html_root,$matches)) {
            $_SESSION['godaddy_root'] = $matches[0];
        } else {
            $_SESSION['not_go_daddy'] = 1;
            $_SESSION['godaddy_root'] = '';
        } 
    } elseif (!empty($_SESSION['not_go_daddy'])) {
        $_SESSION['godaddy_root'] = '';
    }
    if (!empty($_SESSION['godaddy_root'])) {
        $_SESSION['hostprovider'] = 'GoDaddy';
        $_SESSION['hosturl'] = 'www.godaddy.com';
    }
    return $_SESSION['godaddy_root'];
}

function GoDaddy_windows_instructions()
{
    $instr = "It appears that you are hosted on a Windows server at GoDaddy.<br/>";
    $instr .= "Please change to a Linux hosting plan at GoDaddy.<br />";
    $instr .=  "If you <a href=\"https://help.godaddy.com/\">contact their support team</a> they should be able to switch you to a Linux server.";

    echo $instr;
}

function GoDaddy_linux_instructions($html_dir)
{
    $base = get_base_address();
    $loader_name = get_loader_name();
    $zend_extension_line="<code>zend_extension = $html_dir/ioncube/$loader_name</code>";
    $php_ini_name = is_php_version_or_greater(5,0)?'php5.ini':'php.ini';
    $ini_path = $html_dir . '/' . $php_ini_name;

    $instr = array();
    $instr[] = 'In your html directory, ' . $html_dir . ', create a sub-directory called <b>ioncube</b>.';
    if (@file_exists($ini_path)) {
       $instr[] = "Edit the $php_ini_name in your  $html_dir and add the following line to the <b>top</b> of the file:<br>" . $zend_extension_line ;
    } else {
        $instr[] = "<a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=s&amp;download=1&amp;prepend=1\">Save this $php_ini_name file</a> and upload it to your html directory, $html_dir";
    }
    $instr[] = 'Download the <a target="_blank" href="' . IONCUBE_DOWNLOADS_SERVER . '"/ioncube_loaders_lin_x86.zip">Linux ionCube Loaders</a>.';
    $instr[] = 'Unzip the loaders and upload them into the ioncube directory you created previously.';
    $instr[] = 'The encoded files should now be working.';

    echo '<div class=panel>';
    echo (make_list($instr));
    echo '</div>';
}

function GoDaddy_page()
{
    $base = get_base_address();

    heading();

        $inst_str = '<h4>GoDaddy Installation Instructions</h4>';
        $inst_str .= '<p>It appears that you are hosted with GoDaddy (<a target="_blank" href="https://www.godaddy.com/">www.godaddy.com</a>). ';
        $inst_str .= "If that is <b>not</b> the case then please <a href=\"$base&amp;page=default&amp;host=ngd\">click here to go to the main page of this installation wizard</a>.</p>";
        $inst_str .= "<p>If you have already installed the loader then please <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the loader</a>.</p>";

        echo $inst_str;

        if (is_ms_windows()) {
            GoDaddy_windows_instructions();
        } else {
            GoDaddy_linux_instructions($_SESSION['godaddy_root']);
        }

    send_stats('gd_default');

    footer(true);
}



function get_request_parameter($param_name)
{
    static $request_array;

    if (!isset($request_array)) {
        if (isset($_GET)) {
            $request_array = $_GET;
        } elseif (isset($HTTP_GET_VARS)) {
            $request_array = $HTTP_GET_VARS;
        }
    }

    if (isset($request_array[$param_name])) {
        $return_value = strip_tags($request_array[$param_name]);
    } else {
        $return_value = null;
    }
    return $return_value;
}

function make_list($list_items,$list_type='ol')
{
    $html = '';
    if (!empty($list_items)) {
        $html .= "<$list_type>";
        $html .= '<li>';
        $html .= join('</li><li>',$list_items);
        $html .= '</li>';
        $html .= "</$list_type>";
    }
    return $html;
} 

function make_archive_list($basename,$archives_list = array(),$download_server = IONCUBE_DOWNLOADS_SERVER)
{
    if (empty($archives_list)) {
        $archives_list = array('tar.gz','zip');
    }

    foreach ($archives_list as $a) {
        $link_text = $a;
        $ext_sep = '.';
        $archive_list[] = "<a href=\"$download_server/$basename$ext_sep$a\">$link_text</a>";
    }

    return make_list($archive_list,"ul");
}

function error($m)
{
    die("<b>ERROR:</b> <span class=\"error\">$m</span><p>Please help us improve this script by <a href=\"". SUPPORT_SITE . "\">reporting this error</a> and including the URL to the script so that we can test it.");
}


function filter_server_input($server_var)
{
	$res = htmlspecialchars($_SERVER[$server_var], ENT_QUOTES, "UTF-8");
	return $res;
}

function failsafe_get_self()
{
    $result = '';
    $sfn = filter_server_input('SCRIPT_FILENAME');
    $dr = $_SERVER['DOCUMENT_ROOT'];
    if (!empty($sfn) && !empty($dr)) {
        if ($dr == '/' || $dr == '\\') {
            $result = $sfn;
        } else {
            $drpos = strpos($sfn,$dr);
            if ($drpos === 0) {
                $drlen = strlen($dr);
                $result = substr($sfn,$drlen);
            }
        }
        $result = str_replace('\\','/',$result);
    }
    if (empty($result)) {
        $result = DEFAULT_SELF;
    }
    return $result;
}

function get_self()
{ 
	$page = '';
    if (empty($_SERVER['PHP_SELF'])) {
        if (empty($_SERVER['SCRIPT_NAME'])) {
            if (empty($_SERVER['REQUEST_URI'])) {
                $page = failsafe_get_self();
            } else {
                $page = filter_server_input('REQUEST_URI');
            }
        } else {
            $page = filter_server_input('SCRIPT_NAME');
        }
    } else {
        $page = filter_server_input('PHP_SELF');
    }
	return $page;
}

function get_default_page()
{
    $godaddy_root = GoDaddy_root();
    if (empty($godaddy_root)) {
         $page = 'default';
    } else {
         $page = 'GoDaddy';
    }
    return $page;
}

function get_base_address()
{
    $self = get_self();
    $remote_timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?'timeout=1':'timeout=0';
    $using_ini = (isset($_SESSION['use_ini_method']) && $_SESSION['use_ini_method'])?'ini=1':'ini=0';
    return $self . '?' . $remote_timeout . '&' . $using_ini;
}

function get_default_address($include_timeout = true)
{
    if ($include_timeout) {
        $base =  get_base_address();
        $base .= "&amp;";
    } else {
        $base = get_self();
        $base .= "?";
    }
    $page = get_default_page();

    return $base . 'page=' . $page;
}

function heading()
{
    $self = get_self();

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <meta name="robots" content="noindex, nofollow">
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <script type="text/javascript">
            function showOverlay()
            {
                document.getElementById('overlay').style.display = 'block';
                return true;
            }

            function hideOverlay()
            {
                document.getElementById('overlay').style.display = 'none';
                return true;
            }
        </script>
    </head>
    <body onload="hideOverlay()">
    <div id="overlay">
        <div id="inner_overlay">Checking server configuration<br>Please wait</div>
    </div>
    <div id="header">
        <img src="?page=logo" alt="ionCube logo">
    </div>
	<div id="important">
	<h3 class="important">IMPORTANT: Ensure that This Script Is Removed When No Longer Required</h3>
	</div>
    <div id="main">
    <h2>ionCube Loader Wizard</h2>
EOT;
}

function footer($update_info = null)
{
    $self = get_self();
    $base = get_base_address();
    $default = get_default_address(false);
    $year = gmdate("Y");

    echo "</div>";
    echo "<div id=\"footer\">" .
    "Copyright ionCube Ltd. 2002-$year | " .
    "Loader Wizard version " . script_version() . " ";

    if ($update_info === true) {
        $update_info = check_for_wizard_update(false);  
    }
    $loader_wizard_loc = LOADER_WIZARD_URL;
    $wizard_version_string =<<<EOT
    <script type="text/javascript">
    var xmlhttp;
    function version_check()
    { 
        var body = document.getElementsByTagName('body')[0];
        var ldel = document.getElementById('loading');
        if (!ldel) {
            body.innerHTML += '<div id="loading"></div>';
            ldel = document.getElementById('loading');
        }
        ldel.innerHTML = '<p>Retrieving Wizard version information<br>Please wait</p>';
        ldel.style.display = 'block';
        ldel.style.height = '300px';
        ldel.style.left = '200px';
        ldel.style.border = '4px #660000 solid';
        if (window.XMLHttpRequest) {
            xmlhttp=new XMLHttpRequest();
        } else {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            var loadedOkay = 0;
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                var wizardversion = xmlhttp.responseText;
                var msg;
                clearTimeout(xmlHttpTimeout);
                buttons = '';
                if (wizardversion == '1') {
                    msg = 'You have the current version of the<br>ionCube Loader Wizard'; 
                } else if (wizardversion != '0') {
                    msg = 'A new version, ' + wizardversion + ', of the loader wizard is available';
                    buttons = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; window.open(\'$loader_wizard_loc\'); return false">Get new version</button> &nbsp;'; 
                } else {
                    msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
                }
                buttons += '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>'; 
                ldel.innerHTML = '<p>' + msg +  '<br>' + buttons + '</p>';
            }
        }
        xmlhttp.open("GET",'$self?page=wizardversion&wizard_only=1&clear_info=1',true);
        xmlhttp.send();
        var xmlHttpTimeout=setTimeout(ajaxTimeout,7000);
    }
    function ajaxTimeout(){
       xmlhttp.abort();
       msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
       button = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>';
       var ldel = document.getElementById('loading');
       ldel.innerHTML = '<p>' + msg +  '<br>' + button + '</p>';
    }
    </script>
EOT;

    $wizard_version_string .= '('; 
    if ($update_info === null) {
        $wizard_version_string .= '<a target="_blank" href="' . $loader_wizard_loc . '" onclick="version_check();return false;">check for new version</a>';
    } else if ($update_info !== false) {
        $wizard_version_string .= '<a href="' . LOADERS_PAGE .'" target="_blank">download version ' . $update_info . '</a>';
    } else {
        $wizard_version_string .=  "current";
    }
    $wizard_version_string .= ')'; 
    echo $wizard_version_string;

    $server_type_code = server_type_code();
	
	if (!info_should_be_disabled(true)) {
		echo " | <a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo</a>";
		echo " | <a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a>";
		echo " | <a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional</a>";
	}

    echo " | <a href=\"$default\" onclick=\"showOverlay();\">wizard start</a>";
    echo " | <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">loader test</a>";
    echo ' | <a href="' . LOADERS_PAGE . '" target="loaders">loaders</a>';

    echo "</div>\n";
    echo "\n</body></html>\n";
}

function css_page()
{
    header('Content-Type: text/css');
    echo <<<EOT
    body {
        font-family: verdana, helvetica, arial, sans-serif;
        font-size: 10pt;
        line-height: 150%;
        margin: 0px;
        min-height: 400px;
        position: relative;
    }

    code {
        color: #c00080;
    }

    li {
        margin-top: 10px;
    }
    #overlay {
        display: block;
        z-index: 100;
        position: absolute;
        top: 0;
        left: 0;
        padding: 0;
        margin: 0;
        width: 100%;
        height: 100%;
        background-color: white;
    }
    #inner_overlay {
        display: block;
        z-index: 100;
        position: absolute;
        font-size: 200%;
        color: #660000;
        top: 50%;
        left: 25%;
        width: 460px;
        height: 460px;
        line-height: 200%;
        text-align: center;
        vertical-align: middle;
    }

    #loading {
        display: block;
        position: absolute;
        top: 33%;
        left: 25%;
        margin: auto;
        height: 320px;
        width: 460px;
        padding: 4px;
        color: #660000;
        background-color: white;
        z-index: 100;
    }

    #loading p {
        position: absolute;
        margin-top: 10px;
        text-align: center;
        vertical-align: middle;
        padding-left: 40px;
        padding-right: 30px;
        font-size: 200%;
        line-height: 200%;
    }

    #loading p span#status{
        font-size: 60%;
        line-height: 120%;
    }
    #loading p#noscript {
        font-size: 120%;
        line-height: 120%;
        position: absolute;
        text-align: left;
        padding-top: 10px;
        bottom: 0;
    }
    #loading p#noscript a {
        text-align: center;
    }

    #loading button {
        margin-top: 20px;
        line-height: 100%;
        padding-top: 4px;
        padding-bottom: 4px;
    }


    h4 {
        margin-bottom: 0;
        padding-bottom: 4px;
    }

    p,#main div {
        max-width: 1000px;
        width: 75%;
    }

    #hostinginfo {
        margin-top: 10px;
        margin-left: 20px;
    }
    #hostinginfo table {
        font-size: 1.00em;
    }
    #hostinginfo table td {
        padding-right: 4px;
    }
    #hostinginfo input {
        margin-top: 6px;
    }

    #hostinginfo label {
        margin-left: 6px;
    }

    th {
        text-align: left;
    }
	
	#important {
		margin-top: 12px;
	} 
	h3.important {
		margin: 0;
		border: 0;
        border-top: 1px solid #660000;
		border-bottom: 1px solid #660000;
        padding: 1ex 0 1ex 0;
        background-color: #CB2430;
		text-align: center;
        color: #ffffff; 
        width: 100%;
	}

    .alert {
        margin: 2ex 0;
        border: 1px solid #660000;
        padding: 1ex 1em;
        background-color: #ffeeee;
        color: #660000; 
        width: 75%;
    }

    .warning {
        margin: 2ex 0;
        border: 1px solid #FFBF00;
        padding: 1ex 1em;
        background-color: #FDF5E6;
        color: #000000; 
        width: 75%;
    }

    .success {
        margin: 2ex 0;
        border: 1px solid #006600;
        padding: 1ex 1em;
        background-color: #EEFFEE;
        color: #000000; 
        width: 75%;
    }

    .error {
        color: #FF0000;
    }

    .panel {
        border: 1px solid #c0c0c0;
        background-color: #f0f0f0;
        width: 75%;
        padding: 1ex 1em;
    }
	
	.terminal {
		border: none;
		background-color: #000000;
		color: #ffffff;
		width: 50%;
		padding: 1ex 1em;
	}

    #header {
        background: #fff;
    }

    #footer {
        border-top: 1px solid #404040;
        margin-top: 20px;
        padding-top: 10px;
        padding-left: 20px;
        font-size: 75%;
        text-align: left;
    }

    #main {
        margin: 20px;
    }
	
	
	#main .ic24 {
		position: relative;
		width: 75%;
		height: auto;
		border-width: 1px 1px 1px 1px;
		border-style: solid;
		border-color: #4B8DF8;   
		background-color: #EFEFFF;
		padding: 12px;
		padding-top: 16px;
		padding-bottom: 8px;
		margin-top: 20px;
		overflow: hidden;
	}
	
	#main .ic24 p {
		width: 100%;
	}
	
	
	#main .ic24graphic {
		position: relative;
		width: auto;
		height: auto;
		border: none;
		padding: 0px;
		padding-right: 16px;
		margin: 0px;
		float: left;
		
	}
	
	#main #ic24info {
		position: relative;
		width: auto;
		height: auto;
		float: left;
	}
	
	#main #ic24info a {
		color: #0B4DB8;
		text-decoration: none;
	}
	
	#main #ic24logo {
		max-width: 132px;
		max-height: 132px;
	}
	
EOT;
}

function logo_page()
{
$img_encoded = 'iVBORw0KGgoAAAANSUhEUgAAAakAAACABAMAAABD1osiAAAAKlBMVEUAAAAAAADnHCwAAAAAAAAAAAAAAAAAAABMCQ4AAADnHCznHCznHCwAAAAjcBE1AAAADHRSTlMAeDRHwSqg4BJl/PLTJLuIAAAF1UlEQVR42u2by4vTQBzHp3TTzR6EBtfXYS/+BZW6Pg6FFavgoRDBBx4KFd+HQgWFvQQqiuJhoeL7sP+LR0EPlj6yPfz+F5NMZ77TmmJjM3ZT5nNpOzvNzGcev5lMusxgMBgMBoPBYDAYDAaDwWDQwel5YRnC/jkvbZYdjFV2MFbZwVhlB2OVIVZyb2HIED/n5AfLEj/nhWUJY5UdjFV2MFbZwVgdMqzNZydXz2qrf59Kq2a1NmTsRnfVrLZOfj3VrrkrZuVb/dpBvZEJqzOOc5TNQ75rjXKDtV+ZsNoi6rJ52OhZwxONwiGwsi46zqnt1Kx8r7N8q/wmRfhP3BSsrK7VW/u13krDysGwT8o5kvilxa2YZ/U2eulEC0KhCTlLCo0UrPYff7Tfe+2lWt0glTT6qjB02e0eW6ZVjiZYaF4hq+eXlmll1yik75TL5eMeDVOxsj89hNQyrN5QyDFRm9GCVmCZVrYXBr4OE9w8ZFbBCNr+x646ycAhs/o3moFUj62Y1UY4/txVs9oLrAZs1azCAVhaNSsLgXNpVt/+dlNXZAplx4mLiXecU5hHhcBqN6lV/p3znk1xEYUltfr+t0J/4dN1jwKGWIg+VKuBdL5JAQ9EYj34ILOAjWq12lG+eE2xsk9EF/7CFN7WKOCpq9kK2/CTyp93mFUbpyKRZmwNi2oX4Y0dfgULd8QL4vRdvVavJ+6XYLVPIQjmHq9xAqvbJBTa8paTBCOtVpZHY1DrSmCF7flABotBIiuLJM+RQdJJO1qoVnUKqfLh1pBWrX10YVu0ciuRVXjlfpUiXGSmp85xdFaaT7thZUV95I5DRldaDYJPT8oXmyQqnYP0nFZetL23tgjtsT/e8uc9mKa3XsFqL3Rpy3YsCSufhwmrJgbeGmo/jxUCjd2UzWWFg1EuEzv6rJoY4ftyQapghBRElda5cxKrEfaPvGPWw+Esyx1ps8pHhaP0LqxK8p7KZwFHklt1kEqNcbsNcFfT12a1zgtEv7WFVZehB93xUGVJrPg7MXgPxotDUWlCV5dVhYtgjhV5KuLd+jixktjqYHoHmVcLw9fSt2ry8lDBlrAqKomN5FZI5aX0+Rztqmk7uqywtGKhRQ+KmbeT3AoDDN89gsJQBQ1WWFrFpmgkIruq2kpuhWCASFNBYXxN1GGFKk1XqqLWiXjeOvpv3n2gpBDm4dtL1aqnyaqAcA2bGCu0d3Ir5GkSPasKsFlO3WpNGf68P3wdVhs84tRIRZ/VEUwWfIyxwo4puRUiDh0+q2jntnJWOf6aplVv+VZ5VGMBq3tlhQuarNYnw3V9Zgzkr8PFYiByAi0xcM7ILva+7kJWNeyktVoV5l2FeSI1kluh8UKrlnar6dv2qNhejBVG6yDeaifOajg5X9tR4sH/sLIIBeFTjJV4JMImmd5KNmGFvHxfyV9Guq2mDvnQc9NWyIuOBWrD2BSzZ4fsHi6rzUq26cRdY2e2VSU+ChJ6IDdh1Zi+wylAVa9VfWqu+2y2VYFiO6uGzHsTVj01WOxgsOq3KqB0nMbMsLK96fNxKVASgrDCSogcHjpbq5WNg1WcVsRY4Zi3i1Xblqm7OLFXrHbRWn2GxUG/FduX0yIHwRlWFomD3ojrT+Vxje+KE3tYiQ6ym3JJKKidnW9rscJkuSwOiUdsphXO5P2724y9PPOI+njMMSyxOzWiTViF7/0v4kS6gzEcZA0545X0WbFmVClnk1B4vJXsDYArcPzXitUxCnhW5f070SyXHGfTw1jUYVUgMGKzrTBKQQk/LonYzSlWxToyFuOapaXRim2hqd2/WbFbJEBlLTx8k1a1QNmaai0eUMBAp5XVFFIdNtMqVqs/nhmvpGQuSJRWUmHoMsl5klzRacWsE4Sn3TOswMtH9Mfvbj+L36JNWrFzUgqcE6ofdf8X9PXN6qWjbF5eOverV51ye/ICd+NCWv549er0ha3o69vMYDAYDAaDwWAwGAwGg8FgSJffF2mwYDNbStYAAAAASUVORK5CYII=';

    header('Content-Type: image/png');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}

function ic24logo_page()
{
	$img_encoded = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6b3NiPSJodHRwOi8vd3d3Lm9wZW5zd2F0Y2hib29rLm9yZy91cmkvMjAwOS9vc2IiCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB2ZXJzaW9uPSIxLjAiCiAgIHdpZHRoPSI2OTAiCiAgIGhlaWdodD0iNjkxLjI1IgogICB2aWV3Qm94PSIwIDAgNTUyIDU1MyIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgaWQ9InN2ZzMwMzUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImlvbkN1YmUyNF9jdWJlLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwODMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzQ5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTM1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzMzkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzMxIgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTMzMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzMjUiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzI3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NSIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4ODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NzMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODc1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDEiCiAgICAgICB4MT0iNDQzNS40NDI0IgogICAgICAgeTE9IjI5NDkuMDQyIgogICAgICAgeDI9IjQ4MzQuMzkyMSIKICAgICAgIHkyPSIyOTQ5LjA0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTgiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjAiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxOCIKICAgICBpZD0ibmFtZWR2aWV3MzA4MSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC45NjUzODc0IgogICAgIGlua3NjYXBlOmN4PSI3MjQuNTI3MjIiCiAgICAgaW5rc2NhcGU6Y3k9IjMzMy4xMTQ1MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMzAzNSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMCIKICAgICBmaXQtbWFyZ2luLWxlZnQ9IjAiCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIKICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDM3Ij4KQ3JlYXRlZCBieSBwb3RyYWNlIDEuMTEsIHdyaXR0ZW4gYnkgUGV0ZXIgU2VsaW5nZXIgMjAwMS0yMDEzCjxyZGY6UkRGPgogIDxjYzpXb3JrCiAgICAgcmRmOmFib3V0PSIiPgogICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICA8ZGM6dHlwZQogICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICA8L2NjOldvcms+CjwvcmRmOlJERj4KPC9tZXRhZGF0YT4KICA8ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMSwwLDAsLTAuMSwtNCw1NTcpIgogICAgIGlkPSJnMzAzOSIKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO3N0cm9rZTpub25lIj4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIC0yLDg2OCAtMyw4NjcgLTg2NywzIC04NjgsMiAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA0MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDMiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDM4MjcsNTU2MyBjIC00LC0zIC03LC0zOTUgLTcsLTg3MCBsIDAsLTg2MyA4NzAsMCA4NzAsMCAwLDg3MCAwLDg3MCAtODYzLDAgYyAtNDc1LDAgLTg2NywtMyAtODcwLC03IHoiCiAgICAgICBpZD0icGF0aDMwNDUiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDI4MDAgMCwtODcwIDg2OCwyIDg2NywzIDMsODY4IDIsODY3IC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDciCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDE5MzAsMjgwMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiBtIDEwMzUsNjMwIGMgODAsLTMxIDE1NCwtMTAyIDE5MSwtMTgzIDI1LC01NCAyOCwtNzQgMjksLTE1NyAwLC0xOTAgLTc0LC0zMTggLTM0NCwtNTkyIGwgLTE3NCwtMTc4IDI3NiwwIDI3NywwIDAsLTgwIDAsLTgwIC00MDcsMiAtNDA4LDMgLTMsNTYgLTMsNTUgMTgxLDE3NCBjIDM1NSwzMzkgNDUyLDQ5MyA0MjMsNjY3IC0xOSwxMDYgLTcxLDE2MiAtMTcyLDE4NCAtOTIsMjAgLTIwMiwtNiAtMjkzLC02OSBsIC00NiwtMzEgLTI2LDU4IGMgLTE0LDMyIC0yNiw2MiAtMjYsNjYgMCwyMiAxNDcsOTkgMjI4LDEyMCA4MiwyMSAyMjEsMTQgMjk3LC0xNSB6IgogICAgICAgaWQ9InBhdGgzMDQ5IgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAzODIyLDI4MDMgMywtODY4IDg2OCwtMyA4NjcsLTIgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAyLC04NjcgeiBtIDExNzgsMjQyIDAsLTM5NSA5MCwwIDkwLDAgMCwtNzAgMCwtNzAgLTkwLDAgLTkwLDAgMCwtMTcwIDAsLTE3MCAtODUsMCAtODUsMCAwLDE3MCAwLDE3MCAtMjkwLDAgLTI5MCwwIDAsNjMgMCw2NCAyODEsNDAxIDI4MSw0MDIgOTQsMCA5NCwwIDAsLTM5NSB6IgogICAgICAgaWQ9InBhdGgzMDUxIgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA0NzkwLDMxNzMgYyAtMjQsLTQzIC0xMTEsLTE3MiAtMTk1LC0yODggLTgzLC0xMTUgLTE1NSwtMjE2IC0xNTksLTIyMiAtNiwtMTAgMzUsLTEzIDE5MywtMTMgbCAxOTksMCA0LDI5OCBjIDIsMTYzIDMsMjk4IDIsMzAwIC0xLDIgLTIxLC0zMiAtNDQsLTc1IHoiCiAgICAgICBpZD0icGF0aDMwNTMiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NTM0MSk7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTg1MTYsMTc0MyBjIC0zLC04MzUgLTksLTE1NTMgLTEyLC0xNTk1IGwgLTYsLTc4IDE3MCwwIDE3MCwwIDcsODggYyAzLDQ4IDksMTI3IDEzLDE3NiBsIDcsODkgNDAsLTU5IGMgNTMsLTc3IDE2MCwtMTgxIDIyOSwtMjIzIDEyOCwtNzcgMjQ4LC0xMTEgNDIxLC0xMTggMjEwLC05IDM4NywzOCA1NTIsMTQ3IDI3NiwxODEgNDM4LDQ4MiA0NzQsODc5IDM5LDQzMyAtMTA1LDgzOSAtMzc1LDEwNTYgLTE1NSwxMjUgLTMzMCwxODUgLTU0MSwxODUgLTE5OSwwIC0zNTcsLTQwIC00OTMsLTEyNiAtNzEsLTQ1IC0xODMsLTE1MyAtMjI1LC0yMTkgbCAtMzIsLTUwIC0zLDY4MyAtMiw2ODIgLTE5NCwwIC0xOTQsMCAtNiwtMTUxNyB6IG0gMTE1NSwyMjMgYyAxNDksLTMyIDMwNSwtMTQ4IDM4OCwtMjg5IDc5LC0xMzUgMTIxLC0zMTMgMTIxLC01MTIgMCwtMTk2IC0zNSwtMzU2IC0xMDgsLTUwMCAtNDMsLTg0IC0xNzEsLTIxNyAtMjQ5LC0yNTggLTc3LC00MSAtMTkyLC02NyAtMjk0LC02NyAtMTE2LDAgLTE3NywxMyAtMjc4LDYyIC0xNDYsNjkgLTI1OCwyMDMgLTMxNywzNzggLTE3LDQ5IC0xOSw4OCAtMTksMzYwIDAsMzA1IDAsMzA1IDI3LDM4NSAzNywxMDkgOTEsMTk2IDE2OSwyNzUgNzQsNzQgMTkwLDE0MSAyODYsMTY0IDc2LDE5IDE5MSwxOSAyNzQsMiB6IgogICAgICAgaWQ9InBhdGgzMDU1IgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE3NCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTQ2MTAsMzEzOSBjIC01MTgsLTY1IC05NDQsLTM1NyAtMTE2NCwtNzk3IC0xNDEsLTI4MCAtMjAxLC02MzYgLTE2NiwtOTgzIDcyLC03MTEgNDgwLC0xMTc3IDExNDcsLTEzMTAgMjExLC00MiA1NTcsLTM2IDgxMywxMiAxMTksMjMgMzIwLDg2IDMyNiwxMDMgNiwxNyAtNzIsMzExIC04MiwzMDkgLTUsLTEgLTQ5LC0xNiAtOTcsLTMzIC0xNDcsLTUyIC0yNjIsLTcxIC00NzAsLTc3IC0yMTAsLTYgLTMyMCw0IC00NTcsNDQgLTQzNywxMjYgLTcwNSw0NzIgLTc2MSw5NzkgLTE1LDE0MCAtNSwzODggMjAsNTE0IDYwLDI5OSAxOTgsNTM2IDQwMyw2OTAgMjIzLDE2OSA0NzIsMjM4IDgwOCwyMjcgMTg0LC02IDMwNywtMjggNDQyLC03OCA0NiwtMTYgODksLTMxIDk2LC0zMiA5LC0xIDMwLDQ5IDYyLDE1MyAyNyw4NSA0OCwxNTUgNDcsMTU2IC01Miw0MCAtMjc2LDEwMSAtNDU3LDEyMyAtOTcsMTMgLTQxNCwxMiAtNTEwLDAgeiIKICAgICAgIGlkPSJwYXRoMzA1NyIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNzApIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczNzAsMjg1NSAwLC0xOTUgMjEwLDAgMjEwLDAgMCwxOTUgMCwxOTUgLTIxMCwwIC0yMTAsMCAwLC0xOTUgeiIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNjYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIzODg2LDMwMjQgYyAtOTksLTE4IC0yNjQsLTczIC0zNDgsLTExNSAtNzEsLTM1IC0yMTgsLTEzMCAtMjM3LC0xNTMgLTEwLC0xMiAwLC00MCA1MCwtMTUwIDM0LC03NSA2MywtMTM2IDY1LC0xMzYgMSwwIDM2LDI0IDc3LDUzIDE2NiwxMTkgMzI0LDE3NiA1MTMsMTg0IDMwOCwxNCA1MDMsLTEwOCA1ODAsLTM2MiAxNCwtNDYgMTksLTkzIDE5LC0yMDAgLTEsLTE3MSAtMTksLTI0NyAtMTAwLC00MTAgLTEzMCwtMjYxIC0zODAsLTU0MyAtMTA0NCwtMTE4MCBsIC0yNTAsLTI0MCAtMSwtMTIyIDAsLTEyMyA5MzUsMCA5MzUsMCAwLDE2NSAwLDE2NSAtNjU3LDAgLTY1NywwIDEwOSwxMDEgYyA2MSw1NiAyMTgsMjEwIDM1MCwzNDMgMzQyLDM0NSA1MTgsNTYzIDYzNCw3ODYgMTc5LDM0NSAxOTgsNjc4IDU3LDk2NSAtODEsMTYzIC0xODgsMjcwIC0zNTEsMzUxIC0xNDEsNzAgLTIxOSw4NiAtNDI1LDkwIC0xMjUsMiAtMTk4LC0xIC0yNTQsLTEyIHoiCiAgICAgICBpZD0icGF0aDMwNjEiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE2MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMjY2ODEsMjk3NyBjIC02LC04IC0yOTksLTQyNSAtNjUxLC05MjggbCAtNjQwLC05MTQgMCwtMTMyIDAsLTEzMyA2ODAsMCA2ODAsMCAwLC00MDAgMCwtNDAwIDE4NSwwIDE4NSwwIDAsNDAwIDAsNDAwIDIwNSwwIDIwNSwwIDAsMTU1IDAsMTU1IC0yMDUsMCAtMjA1LDAgMCw5MDUgMCw5MDUgLTIxNCwwIGMgLTE2NiwwIC0yMTYsLTMgLTIyNSwtMTMgeiBtIDcxLC0xMDg0IC0zLC03MTMgLTQ4MCwwIGMgLTM4MiwwIC00NzksMyAtNDczLDEzIDUsNiAxNjYsMjMwIDM1OCw0OTcgMzQ3LDQ4MSAzOTksNTYwIDUzMCw3OTggMzgsNjggNjksMTIyIDcwLDEyMCAwLC0yIDAsLTMyNCAtMiwtNzE1IHoiCiAgICAgICBpZD0icGF0aDMwNjMiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE1OCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTE5MjcsMjI4OCBjIC0xMDgsLTEwIC0yNDgsLTU1IC0zNDEsLTExMCAtODIsLTQ4IC0yMDMsLTE2MCAtMjQ3LC0yMjkgLTE3LC0yNyAtMzQsLTQ3IC0zOCwtNDQgLTMsNCAtMTAsODIgLTE2LDE3MyBsIC0xMCwxNjcgLTE3OSwzIC0xNzgsMiA2LC00NyBjIDQsLTI3IDksLTUxNyAxMiwtMTA5MCBsIDYsLTEwNDMgMTk5LDAgMTk4LDAgMyw3MjcgMyw3MjggMzEsNzIgYyAxMTMsMjYwIDM0MSwzOTggNTk4LDM2MiAxNjQsLTIyIDI3NiwtMTAzIDM0NiwtMjUxIDczLC0xNTQgNzIsLTE0OCA3NywtOTM1IGwgNSwtNzAzIDE5NCwwIDE5NCwwIDAsNzIzIGMgMCw3OTYgLTIsODI0IC02Miw5OTcgLTEyMSwzNDcgLTQyMCw1MzMgLTgwMSw0OTggeiIKICAgICAgIGlkPSJwYXRoMzA2NSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNTQpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczOTAsMTE4MCAwLC0xMTEwIDE5MCwwIDE5MCwwIDAsMTExMCAwLDExMTAgLTE5MCwwIC0xOTAsMCAwLC0xMTEwIHoiCiAgICAgICBpZD0icGF0aDMwNjciCiAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMTUwKSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA5MTk5LDIyODAgYyAtMjIwLC0zNyAtNDE4LC0xMzggLTU3MCwtMjg5IC0xNTAsLTE1MSAtMjQyLC0zMjkgLTI5NSwtNTcxIC0yNiwtMTE5IC0yNywtNDI5IC0xLC01NDcgNTIsLTI0NCAxNDksLTQyNiAzMDUsLTU3NSAxODcsLTE3OCAzOTYsLTI2NCA2NjgsLTI3NSA1MDAsLTIxIDkxMiwyNTEgMTA2NSw3MDQgNTQsMTYxIDY0LDIzMCA2Myw0NDggMCwxNjcgLTMsMjE1IC0yMSwyOTEgLTEwMyw0NDEgLTM5MCw3MzAgLTgwMyw4MDggLTg3LDE3IC0zMjYsMjAgLTQxMSw2IHogbSAzMzQsLTMwNSBjIDI1NSwtNjYgNDM4LC0zMDggNDg3LC02NDQgMTcsLTExNiA4LC0zNDMgLTE4LC00NDIgLTY0LC0yNDMgLTE5NywtNDIzIC0zNzQsLTUwOCAtMTA1LC01MCAtMTg0LC02NiAtMjk2LC01OCAtMjIxLDE1IC0zOTMsMTM2IC01MDgsMzU5IC02NiwxMjkgLTk1LDI1MCAtMTAxLDQyNSAtMTEsMzA4IDY3LDU0NSAyMzYsNzE0IDgxLDgxIDE1OCwxMjYgMjYxLDE1MyA3MywxOSAyNDEsMjAgMzEzLDEgeiIKICAgICAgIGlkPSJwYXRoMzA2OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNDYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIxNzUwLDIyNzUgYyAtMzUyLC03MCAtNjExLC0zMDUgLTczOSwtNjY4IC01OCwtMTY1IC03NSwtMjcxIC03NSwtNDc3IC0xLC0yMDQgMTAsLTI3OSA2NiwtNDQ3IDExOSwtMzYwIDQyMCwtNTk4IDgyNiwtNjUzIDEyNywtMTggMzkyLC04IDU0MiwyMCAxMjIsMjIgMzYwLDk2IDM2MCwxMTEgMCwxOCAtNjMsMjY0IC02OSwyNzEgLTMsNCAtNTEsLTggLTEwNiwtMjcgLTE1NCwtNTEgLTI3MiwtNjggLTQ3NSwtNjggLTIwMywwIC0yNzgsMTUgLTQwOSw4MyAtMjE0LDExMSAtMzI4LDMwMiAtMzU2LDU5OCBsIC03LDcyIDc2NSwwIGMgNjg4LDAgNzY1LDIgNzcxLDE2IDEyLDMyIDYsMzAzIC05LDM5MCAtNDMsMjQ0IC0xMzQsNDMzIC0yNzcsNTcwIC0xMTUsMTEyIC0yMzUsMTc0IC00MDAsMjA4IC05NCwxOSAtMzE0LDIwIC00MDgsMSB6IG0gMzUzLC0yOTUgYyAyMDcsLTY0IDMzOCwtMjU3IDM2MywtNTM1IGwgNywtNzUgLTU3NywwIC01NzYsMCAwLDIzIGMgMCw1MiA0MiwxODcgODYsMjc1IDgyLDE2OCAyMjcsMjkyIDM3NCwzMjEgMzAsNiA2NCwxMyA3NSwxNSA0MSwxMCAxODUsLTUgMjQ4LC0yNCB6IgogICAgICAgaWQ9InBhdGgzMDcxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE0MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gNDAsOTEwIDAsLTg3MCA4NjgsMiA4NjcsMyAzLDg2OCAyLDg2NyAtODcwLDAgLTg3MCwwIDAsLTg3MCB6IgogICAgICAgaWQ9InBhdGgzMDc1IgogICAgICAgc3R5bGU9ImZpbGw6I2MwMWQyZTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDkxMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA3NyIKICAgICAgIHN0eWxlPSJmaWxsOiNjMDFkMmU7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMzgyMCw5MTAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNzkiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICA8L2c+Cjwvc3ZnPgo=';
	header('Content-Type: image/svg+xml');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}
alt-php82-ioncube-loader/README.txt000064400000007751150413447530012667 0ustar00                            The ionCube Loader 
                            ------------------

This package contains:

* ionCube Loaders

* a Loader Wizard script to assist with Loader installation (loader-wizard.php)

* the License document for use of the Loader and encoded files (LICENSE.txt)

* User Guide describing options that can be configured through a php.ini file.  
  There are options that may improve performance, particularly with files on
  a network drive. Options for the ionCube24 intrusion protection and PHP error
  reporting service (ioncube24.com) are also described.


INSTALLATION
============

Quick Guide for experienced system admins
-----------------------------------------

The Loader is a PHP engine extension, so should be referenced with 
a zend_extension line in a php.ini file. It must be the first engine
extension to be installed. 

The Loader must be for the correct operating system, match the 
PHP version, and for whether PHP is built as thread-safe (TS) or not. 
All information required for installing is available on a phpinfo page. 

For example, if your web server is 64 bit Linux, thread safety is disabled,
PHP is version 8.1.8, the main php.ini file is /etc/php.ini and you
have unpacked Loaders to /usr/local/ioncube, you would:

1) edit /etc/php.ini
2) at the top of the php.ini file add

zend_extension = /usr/local/ioncube/ioncube_loader_lin_8.1.so

3) restart the PHP environment (i.e. Apache, php-fpm, etc.)

4) Check a phpinfo page and the Loader should show up in the Zend Engine box.


Assisted Installation with the Loader Wizard
--------------------------------------------

1. Upload the contents of this package to a directory/folder called ioncube
   within the top level of your web scripts area. This is sometimes called the
   "web root" or "document root". Common names for this location are "www",
   "public_html", and "htdocs", but it may be different on your server.

2. Launch the Loader Wizard script in your browser. For example:
     https://yourdomain/ioncube/loader-wizard.php

   If the wizard is not found, check carefully the location on your server
   where you uploaded the Loaders and the wizard script. 

3. Follow the steps given by the Loader Wizard. If you have full access to the 
   server then installation should be easy. If your hosting plan is more limited, 
   you may need to ask your hosting provider for assistance. 

4. The Loader Wizard can automatically create a ticket in our support system
   if installation is unsuccessful, and we are happy to assist in that case.

   YouTube with a search for "ioncube loader wizard" also gives some helpful 
   examples of installation.


WHERE TO INSTALL THE LOADERS
============================

The Loader Wizard should be used to guide the installation process but the
following are the standard locations for the Loader files. Loader file
packages can be obtained from https://www.ioncube.com/loaders.php

Please check that you have the correct package of Loaders for your system.

Installing to a remote SHARED server
------------------------------------

* Upload the Loader files to a directory/folder called ioncube within your
  main web scripts area.  (This will probably be where you placed the
  loader-wizard.php script.)


Installing to a remote UNIX/LINUX DEDICATED or VPS server
---------------------------------------------------------

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, /usr/local/ioncube


** Installing to a remote WINDOWS DEDICATED or VPS server

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, C:\windows\system32


64-BIT LOADERS FOR WINDOWS
--------------------------

64-bit Loaders for Windows are available for PHP 5.5 upwards.
The Loader Wizard will not give directions for installing 64-bit Loaders for
any earlier version of PHP 5.

Copyright (c) 2002-2025 ionCube Ltd.           Last revised January 2025
alt-php82-snuffleupagus/README.md000064400000014667150413447530012453 0ustar00<h1 align="center">
  <br>
  <a href="https://snuffleupagus.readthedocs.io/">
    <img src="https://github.com/jvoisin/snuffleupagus/raw/master/doc/source/_static/sp.png" alt="Snuffleupagus' logo" width="200"></a>
  <br>
  Snuffleupagus
  <br>
</h1>

<h4 align="center">Security module for php7 and php8 - Killing bugclasses and virtual-patching the rest!</h4>

<p align="center">
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml/badge.svg"
         alt="Testing PHP7 on various Linux distributions" />
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml/badge.svg"
         alt="Testing PHP8 on various Linux distributions" />
  </a>
  <a href="https://scan.coverity.com/projects/jvoisin-snuffleupagus">
    <img src="https://scan.coverity.com/projects/13821/badge.svg?flat=1"
         alt="Coverity">
  </a>
  <a href="https://bestpractices.coreinfrastructure.org/projects/1267">
      <img src="https://bestpractices.coreinfrastructure.org/projects/1267/badge"
           alt="CII Best Practises">
  </a>
  <a href="http://snuffleupagus.readthedocs.io/?badge=latest">
    <img src="https://readthedocs.org/projects/snuffleupagus/badge/?version=latest"
         alt="readthedocs.org">
  </a>
  <a href="https://coveralls.io/github/jvoisin/snuffleupagus?branch=master">
    <img src="https://coveralls.io/repos/github/jvoisin/snuffleupagus/badge.svg?branch=master"
         alt="coveralls">
  </a>
  <a href="https://twitter.com/dustriorg">
    <img src="https://img.shields.io/badge/twitter-follow-blue.svg"
         alt="twitter">
  </a>
  <a href="https://repology.org/project/php:snuffleupagus/versions">
    <img src="https://repology.org/badge/tiny-repos/php:snuffleupagus.svg"
         alt="Packaging status">
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/codeql-analysis.yml/badge.svg"
         alt="CodeQL">
  </a>
</p>

<p align="center">
  <a href="#key-features">Key Features</a> •
  <a href="#download">Download</a> •
  <a href="#examples">Examples</a> •
  <a href="https://snuffleupagus.readthedocs.io/">Documentation</a> •
  <a href="https://github.com/jvoisin/snuffleupagus/blob/master/LICENSE">License</a> •
  <a href="#thanks">Thanks</a>
</p>

Snuffleupagus is a [PHP 7+ and 8+](https://secure.php.net/) module designed to
drastically raise the cost of attacks against websites, by killing entire bug
classes. It also provides a powerful virtual-patching system, allowing
administrator to fix specific vulnerabilities and audit suspicious behaviours
without having to touch the PHP code.

## Key Features

* No [noticeable performance impact](https://dustri.org/b/snuffleupagus-030-dentalium-elephantinum.html)
* Powerful yet simple to write virtual-patching rules
* Killing several classes of vulnerabilities
  * [Unserialize-based](https://www.owasp.org/images/9/9e/Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits.pdf) code execution
  * [`mail`-based]( https://blog.ripstech.com/2016/roundcube-command-execution-via-email/ ) code execution
  * Cookie-stealing [XSS]( https://en.wikipedia.org/wiki/Cross-site_scripting )
  * File-upload based code execution
  * Weak PRNG
  * [XXE]( https://en.wikipedia.org/wiki/XML_external_entity_attack )
  * Filter based remote code execution and assorted shenanigans
* Several hardening features
  * Automatic `secure` and `samesite` flag for cookies
  * Bundled set of rules to detect post-compromissions behaviours
  * Global [strict mode]( https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations) and type-juggling prevention
  * Whitelisting of [stream wrappers](https://secure.php.net/manual/en/intro.stream.php)
  * Preventing writeable files execution
  * Whitelist/blacklist for `eval`
  * Enforcing TLS certificate validation when using [curl](https://secure.php.net/manual/en/book.curl.php)
  * Request dumping capability
* A relatively sane code base:
  * A [comprehensive](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master) test suite close to 100% coverage
  * Every commit is tested on [several distributions](https://gitlab.com/jvoisin/snuffleupagus/pipelines)
  * An `clang-format`-enforced code style
  * A [comprehensive documentation](https://snuffleupagus.rtfd.io)
  * Usage of [coverity](https://scan.coverity.com/projects/jvoisin-snuffleupagus), codeql, [scan-build](https://clang-analyzer.llvm.org/scan-build.html), …

## Download

We've got a [download
page](https://snuffleupagus.readthedocs.io/download.html), where you can find
packages for your distribution, but you can of course just `git clone` this
repo, or check the releases on [github](https://github.com/jvoisin/snuffleupagus/releases).

## Examples

We're providing [various example rules](https://github.com/jvoisin/snuffleupagus/tree/master/config),
that are looking like this:

```python
# Harden the `chmod` function
sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop();

# Mitigate command injection in `system`
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n]").drop();
```

Upon violation of a rule, you should see lines like this in your logs:

```python
[snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in /var/www/index.php:2, because the return value (0) of the function 'strpos' matched a rule.
```

## Documentation

We've got a [comprehensive website](https://snuffleupagus.readthedocs.io/) with
all the documentation that you could possibly wish for. You can of course
[build it yourself](https://github.com/jvoisin/snuffleupagus/tree/master/doc).

## Thanks

Many thanks to:

- The [Suhosin project](https://suhosin.org) for being a __huge__ source of inspiration
- [NBS System](https://www.nbs-system.com) for initially sponsoring the development
- [Suhosin-ng](https://github.com/sektioneins/suhosin-ng) for their
  [experimentations](https://github.com/sektioneins/suhosin-ng/wiki/News)
  and [contributions](https://github.com/jvoisin/snuffleupagus/commits?author=bef),
  as well as [NLNet](https://nlnet.nl/project/Suhosin-NG/) for sponsoring it
- All [our contributors](https://github.com/jvoisin/snuffleupagus/graphs/contributors)

alt-php82-snuffleupagus/CONTRIBUTING.md000064400000013046150413447540013414 0ustar00## Contributing

First off, thank you for considering contributing to snuffleupagus.

### 1. Where do I go from here?

If you've noticed a bug or have a question,
look at the [faq](https://snuffleupagus.readthedocs.io/faq.html) and
[search the issue tracker](https://github.com/jvoisin/snuffleupagus/issues)
to see if someone else has already created a ticket. If not, go ahead and
[make one](https://github.com/jvoisin/snuffleupagus/issues/new)!

### 2. Fork & create a branch

If this is something you think you can fix,
then [fork snuffleupagus](https://help.github.com/articles/fork-a-repo) and
create a branch with a descriptive name.

A good branch name would be (where issue #325 is the ticket you're working on):

```sh
git checkout -b 325-kill-sql-injections
```

### 3. Get the test suite running

Just type `make coverage` or `make debug`, the testsuite should be run
automatically.

Please add tests if you're fixing a bug or adding a new feature: we do have a
[high coverage](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master)
(functions, lines and branches), and intend to keep it that way.

#### 3.3 Debugging failures in the test suite

If your changes have introduced run-time failures in the test-suite, you can
easily troubleshoot them by inspecting the files that
[php has generated](https://qa.php.net/write-test.php#analyzing-failing-tests)
for this purpose.

A nice trick is to edit the `.sh` file to prepend `gdb --args` to it before
launching it, in order to run the failing test inside GDB.


### 4. Did you find a bug?

* **Ensure the bug was not already reported** by
  [searching all issues](https://github.com/jvoisin/snuffleupagus/issues?q=).
* If you're unable to find an open issue addressing the problem,
  [open a new one](https://github.com/jvoisin/snuffleupagus/issues/new).
  Be sure to include a **title and clear description**,
  as much relevant information as possible, and a **code sample**
  or an **executable test case** demonstrating the expected behavior that is not
  occurring.


### 5. Get the style right

Your patch should follow the same conventions & pass the same code quality
checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to
ensure a consistent code-style. Please run it with `clang-format --style="{BasedOnStyle: google, SortIncludes: false}"`
before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format).

### 6. Make a Pull Request

At this point, you should switch back to your master branch and make sure it's
up to date with our upstream master branch:

```sh
git remote add upstream git@github.com:jvoisin/snuffleupagus.git
git checkout master
git pull upstream master
```

Then update your feature branch from your local copy of master, and push it!

```sh
git checkout 325-kill-sql-injections
git rebase master
git push --set-upstream origin 325-kill-sql-injections
```

Finally, go to GitHub and [make a Pull Request](https://help.github.com/articles/creating-a-pull-request) :D

Travis CI will [run our test suite](https://travis-ci.org/jvoisin/snuffleupagus)
against all supported PHP versions. We care about quality, so your PR won't be
merged until all tests pass. It's unlikely, but it's possible that your changes
pass tests in one PHP version but fail in another. In that case, you'll have to
setup your development environment to use the problematic PHP version, and
investigate what's going on!

### 7. Keeping your Pull Request updated

If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
has changed, and that you need to update your branch so it's easier to merge.

To learn more about rebasing in Git, there are a lot of [good](http://git-scm.com/book/en/Git-Branching-Rebasing)
[resources](https://help.github.com/articles/interactive-rebase) but here's the suggested workflow:

```sh
git checkout 325-kill-sql-injections
git pull --rebase upstream master
git push --force-with-lease 325-kill-sql-injections
```

### 8. Merging a PR (maintainers only)

A PR can only be merged into master by a maintainer if:

1. It is passing CI.
2. It has been approved by at least one maintainer. If it was a maintainer who
   opened the PR, only one extra approval is needed.
3. It has no requested changes.
4. It is up to date with current master.

Any maintainer is allowed to merge a PR if all of these conditions are met.

### 9. Shipping a release (maintainers only)

Maintainers need to do the following to push out a release:

1. Make sure that all pending and mergeable pull requests are in
2. Close the corresponding
	 [milestone](https://github.com/jvoisin/snuffleupagus/milestones)
2. Run `valgrind` (by adding a `-m` after the `-q` in the Makefile) and check that everything is ok.
   Don't mind the python-related issues.
2. Run `cd src; phpize; ./configure --enable-snuffleupagus --enable-debug; scan-build make`
   and fix the possible issues.
3. Update the `src/php_snuffleupagus.h` according to [semantic versioning](https://semver.org/)
4. Update the changelog page in the documentation
5. Update the Debian changelog in `./debian/changelog` with `cd debian; dch`
6. Commit the result
7. Clean up the folder `make clean; git clean -xdf`
8. Create a tag for the release:

  ```sh
  git tag -s v$MAJOR.$MINOR.$PATCH -m "v$MAJOR.$MINOR.$PATCH"
  git push --tags
	git push origin master
  ```

9. Wait for the CI on the new tag branch to finish
10. Create the [release on github](https://github.com/jvoisin/snuffleupagus/releases)
11. Add the freshly built Debian packages from the CI to the release
12. Do the *secret release dance*
alt-php72-snuffleupagus/README.md000064400000014667150413456360012453 0ustar00<h1 align="center">
  <br>
  <a href="https://snuffleupagus.readthedocs.io/">
    <img src="https://github.com/jvoisin/snuffleupagus/raw/master/doc/source/_static/sp.png" alt="Snuffleupagus' logo" width="200"></a>
  <br>
  Snuffleupagus
  <br>
</h1>

<h4 align="center">Security module for php7 and php8 - Killing bugclasses and virtual-patching the rest!</h4>

<p align="center">
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml/badge.svg"
         alt="Testing PHP7 on various Linux distributions" />
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml/badge.svg"
         alt="Testing PHP8 on various Linux distributions" />
  </a>
  <a href="https://scan.coverity.com/projects/jvoisin-snuffleupagus">
    <img src="https://scan.coverity.com/projects/13821/badge.svg?flat=1"
         alt="Coverity">
  </a>
  <a href="https://bestpractices.coreinfrastructure.org/projects/1267">
      <img src="https://bestpractices.coreinfrastructure.org/projects/1267/badge"
           alt="CII Best Practises">
  </a>
  <a href="http://snuffleupagus.readthedocs.io/?badge=latest">
    <img src="https://readthedocs.org/projects/snuffleupagus/badge/?version=latest"
         alt="readthedocs.org">
  </a>
  <a href="https://coveralls.io/github/jvoisin/snuffleupagus?branch=master">
    <img src="https://coveralls.io/repos/github/jvoisin/snuffleupagus/badge.svg?branch=master"
         alt="coveralls">
  </a>
  <a href="https://twitter.com/dustriorg">
    <img src="https://img.shields.io/badge/twitter-follow-blue.svg"
         alt="twitter">
  </a>
  <a href="https://repology.org/project/php:snuffleupagus/versions">
    <img src="https://repology.org/badge/tiny-repos/php:snuffleupagus.svg"
         alt="Packaging status">
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/codeql-analysis.yml/badge.svg"
         alt="CodeQL">
  </a>
</p>

<p align="center">
  <a href="#key-features">Key Features</a> •
  <a href="#download">Download</a> •
  <a href="#examples">Examples</a> •
  <a href="https://snuffleupagus.readthedocs.io/">Documentation</a> •
  <a href="https://github.com/jvoisin/snuffleupagus/blob/master/LICENSE">License</a> •
  <a href="#thanks">Thanks</a>
</p>

Snuffleupagus is a [PHP 7+ and 8+](https://secure.php.net/) module designed to
drastically raise the cost of attacks against websites, by killing entire bug
classes. It also provides a powerful virtual-patching system, allowing
administrator to fix specific vulnerabilities and audit suspicious behaviours
without having to touch the PHP code.

## Key Features

* No [noticeable performance impact](https://dustri.org/b/snuffleupagus-030-dentalium-elephantinum.html)
* Powerful yet simple to write virtual-patching rules
* Killing several classes of vulnerabilities
  * [Unserialize-based](https://www.owasp.org/images/9/9e/Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits.pdf) code execution
  * [`mail`-based]( https://blog.ripstech.com/2016/roundcube-command-execution-via-email/ ) code execution
  * Cookie-stealing [XSS]( https://en.wikipedia.org/wiki/Cross-site_scripting )
  * File-upload based code execution
  * Weak PRNG
  * [XXE]( https://en.wikipedia.org/wiki/XML_external_entity_attack )
  * Filter based remote code execution and assorted shenanigans
* Several hardening features
  * Automatic `secure` and `samesite` flag for cookies
  * Bundled set of rules to detect post-compromissions behaviours
  * Global [strict mode]( https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations) and type-juggling prevention
  * Whitelisting of [stream wrappers](https://secure.php.net/manual/en/intro.stream.php)
  * Preventing writeable files execution
  * Whitelist/blacklist for `eval`
  * Enforcing TLS certificate validation when using [curl](https://secure.php.net/manual/en/book.curl.php)
  * Request dumping capability
* A relatively sane code base:
  * A [comprehensive](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master) test suite close to 100% coverage
  * Every commit is tested on [several distributions](https://gitlab.com/jvoisin/snuffleupagus/pipelines)
  * An `clang-format`-enforced code style
  * A [comprehensive documentation](https://snuffleupagus.rtfd.io)
  * Usage of [coverity](https://scan.coverity.com/projects/jvoisin-snuffleupagus), codeql, [scan-build](https://clang-analyzer.llvm.org/scan-build.html), …

## Download

We've got a [download
page](https://snuffleupagus.readthedocs.io/download.html), where you can find
packages for your distribution, but you can of course just `git clone` this
repo, or check the releases on [github](https://github.com/jvoisin/snuffleupagus/releases).

## Examples

We're providing [various example rules](https://github.com/jvoisin/snuffleupagus/tree/master/config),
that are looking like this:

```python
# Harden the `chmod` function
sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop();

# Mitigate command injection in `system`
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n]").drop();
```

Upon violation of a rule, you should see lines like this in your logs:

```python
[snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in /var/www/index.php:2, because the return value (0) of the function 'strpos' matched a rule.
```

## Documentation

We've got a [comprehensive website](https://snuffleupagus.readthedocs.io/) with
all the documentation that you could possibly wish for. You can of course
[build it yourself](https://github.com/jvoisin/snuffleupagus/tree/master/doc).

## Thanks

Many thanks to:

- The [Suhosin project](https://suhosin.org) for being a __huge__ source of inspiration
- [NBS System](https://www.nbs-system.com) for initially sponsoring the development
- [Suhosin-ng](https://github.com/sektioneins/suhosin-ng) for their
  [experimentations](https://github.com/sektioneins/suhosin-ng/wiki/News)
  and [contributions](https://github.com/jvoisin/snuffleupagus/commits?author=bef),
  as well as [NLNet](https://nlnet.nl/project/Suhosin-NG/) for sponsoring it
- All [our contributors](https://github.com/jvoisin/snuffleupagus/graphs/contributors)

alt-php72-snuffleupagus/CONTRIBUTING.md000064400000013046150413456370013414 0ustar00## Contributing

First off, thank you for considering contributing to snuffleupagus.

### 1. Where do I go from here?

If you've noticed a bug or have a question,
look at the [faq](https://snuffleupagus.readthedocs.io/faq.html) and
[search the issue tracker](https://github.com/jvoisin/snuffleupagus/issues)
to see if someone else has already created a ticket. If not, go ahead and
[make one](https://github.com/jvoisin/snuffleupagus/issues/new)!

### 2. Fork & create a branch

If this is something you think you can fix,
then [fork snuffleupagus](https://help.github.com/articles/fork-a-repo) and
create a branch with a descriptive name.

A good branch name would be (where issue #325 is the ticket you're working on):

```sh
git checkout -b 325-kill-sql-injections
```

### 3. Get the test suite running

Just type `make coverage` or `make debug`, the testsuite should be run
automatically.

Please add tests if you're fixing a bug or adding a new feature: we do have a
[high coverage](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master)
(functions, lines and branches), and intend to keep it that way.

#### 3.3 Debugging failures in the test suite

If your changes have introduced run-time failures in the test-suite, you can
easily troubleshoot them by inspecting the files that
[php has generated](https://qa.php.net/write-test.php#analyzing-failing-tests)
for this purpose.

A nice trick is to edit the `.sh` file to prepend `gdb --args` to it before
launching it, in order to run the failing test inside GDB.


### 4. Did you find a bug?

* **Ensure the bug was not already reported** by
  [searching all issues](https://github.com/jvoisin/snuffleupagus/issues?q=).
* If you're unable to find an open issue addressing the problem,
  [open a new one](https://github.com/jvoisin/snuffleupagus/issues/new).
  Be sure to include a **title and clear description**,
  as much relevant information as possible, and a **code sample**
  or an **executable test case** demonstrating the expected behavior that is not
  occurring.


### 5. Get the style right

Your patch should follow the same conventions & pass the same code quality
checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to
ensure a consistent code-style. Please run it with `clang-format --style="{BasedOnStyle: google, SortIncludes: false}"`
before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format).

### 6. Make a Pull Request

At this point, you should switch back to your master branch and make sure it's
up to date with our upstream master branch:

```sh
git remote add upstream git@github.com:jvoisin/snuffleupagus.git
git checkout master
git pull upstream master
```

Then update your feature branch from your local copy of master, and push it!

```sh
git checkout 325-kill-sql-injections
git rebase master
git push --set-upstream origin 325-kill-sql-injections
```

Finally, go to GitHub and [make a Pull Request](https://help.github.com/articles/creating-a-pull-request) :D

Travis CI will [run our test suite](https://travis-ci.org/jvoisin/snuffleupagus)
against all supported PHP versions. We care about quality, so your PR won't be
merged until all tests pass. It's unlikely, but it's possible that your changes
pass tests in one PHP version but fail in another. In that case, you'll have to
setup your development environment to use the problematic PHP version, and
investigate what's going on!

### 7. Keeping your Pull Request updated

If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
has changed, and that you need to update your branch so it's easier to merge.

To learn more about rebasing in Git, there are a lot of [good](http://git-scm.com/book/en/Git-Branching-Rebasing)
[resources](https://help.github.com/articles/interactive-rebase) but here's the suggested workflow:

```sh
git checkout 325-kill-sql-injections
git pull --rebase upstream master
git push --force-with-lease 325-kill-sql-injections
```

### 8. Merging a PR (maintainers only)

A PR can only be merged into master by a maintainer if:

1. It is passing CI.
2. It has been approved by at least one maintainer. If it was a maintainer who
   opened the PR, only one extra approval is needed.
3. It has no requested changes.
4. It is up to date with current master.

Any maintainer is allowed to merge a PR if all of these conditions are met.

### 9. Shipping a release (maintainers only)

Maintainers need to do the following to push out a release:

1. Make sure that all pending and mergeable pull requests are in
2. Close the corresponding
	 [milestone](https://github.com/jvoisin/snuffleupagus/milestones)
2. Run `valgrind` (by adding a `-m` after the `-q` in the Makefile) and check that everything is ok.
   Don't mind the python-related issues.
2. Run `cd src; phpize; ./configure --enable-snuffleupagus --enable-debug; scan-build make`
   and fix the possible issues.
3. Update the `src/php_snuffleupagus.h` according to [semantic versioning](https://semver.org/)
4. Update the changelog page in the documentation
5. Update the Debian changelog in `./debian/changelog` with `cd debian; dch`
6. Commit the result
7. Clean up the folder `make clean; git clean -xdf`
8. Create a tag for the release:

  ```sh
  git tag -s v$MAJOR.$MINOR.$PATCH -m "v$MAJOR.$MINOR.$PATCH"
  git push --tags
	git push origin master
  ```

9. Wait for the CI on the new tag branch to finish
10. Create the [release on github](https://github.com/jvoisin/snuffleupagus/releases)
11. Add the freshly built Debian packages from the CI to the release
12. Do the *secret release dance*
alt-php72-ioncube-loader/USER-GUIDE.txt000064400000026060150413456440013334 0ustar00ionCube Loader 14.4 User Guide
=====================================

This document describes the available php.ini configuration options of the
ionCube Loader that relate to processing of PHP encoded files, and also the
ionCube24 service. It also describes which encoded files can be run by each
ionCube Loader.

PERFORMANCE OF ENCODED FILES
----------------------------

We recommend that the encoded paths feature (see below) is used 
with encoded files in order to maximise performance.

ENCODED FILES  
-------------

INI entry: ioncube.loader.encoded_paths

Purpose:   Specify the locations of encoded files

  The ionCube Loader will normally examine a PHP file before processing
  to test whether it is encoded, and will run the file itself if necessary.
  Although this checking is very efficient, restricting which files the
  Loader tests for being encoded may give extra performance. If set to 
  a series of paths or files, only files in those locations are tested.

  Entries should be separated by a : on Unix and ; on Windows. 
  A path may be prefixed with + or - to add or remove that path from
  the possible locations. + is assumed if no character is given.


Examples: (... means ioncube.loader.encoded_paths)

  * Site with a single encoded module in /var/www/html/modules/RSS

... = "/var/www/html/modules/RSS"


  * As above, with a site configuration file encoded too.

... = "/var/www/html/modules/RSS:/var/www/html/config/config.php"


  * Encoded files may be anywhere except for /var/www/html/framework

... = "/:-/var/www/html/framework"


  * Site with most modules encoded except for one

... = "/var/www/html/modules:-/var/www/html/modules/plain"


  * As above, with an encoded config file in the plain directory

... = "/site/modules:-/site/modules/plain:/site/modules/plain/config.php"


Locations:

  The ioncube.loader.encoded_paths property can be set in a php.ini
  file, in a .htaccess file (when using Apache), in a .user.ini file
  (when using CGI PHP 5.3+) or using ini_set within a PHP script. In ini
  files only the last value will be used for the encoded_paths property. If
  you wish to build up the value in several lines then, for PHP 5.1+, you
  can use the following syntax:

ioncube.loader.encoded_paths = "/path1"  
ioncube.loader.encoded_paths = ${ioncube.loader.encoded_paths}":/path2"  
; etc...

LIMITATIONS OF LOADERS AND ENCODED FILES
----------------------------------------

Encoded files can, in general, run on versions of PHP equal to
or greater than the source language of the Encoder used to
produce them. So a file produced by the Encoder for PHP 7.2
can be run by the Loaders for PHP 7.2, 7.3 and 7.4, but 7.1. This 
means that the Loaders offer good backwards compatibility, 
however there are the following limitations:

  * The Loader for PHP 8.3 can run files produced by the PHP 8.2 and
    8.3 Encoders.

  * The Loader for PHP 8.2 can only run files produced for
    PHP 8.2. Updates for files produced for PHP 8.1 should
    be obtained to use them with PHP 8.2.

  * The Loader for PHP 8.1 can only run files produced for
    PHP 8.1.

  * The Loaders for PHP 7.1 through 7.4 can only run files 
    produced by the Encoders for PHP 7. 

  * The Loader for PHP 7.0 can only run files produced by the
    Encoder for PHP 5.6.

  * The Loaders for PHP 5.5 and PHP 5.6 cannot run files 
    produced by the PHP 4 Encoder.


IONCUBE24 : real-time intrusion protection and PHP error reporting
---------
### (Available for Linux 32 and 64 bit x86 servers using PHP 7)

ionCube24 (https://ioncube24.com) is an ionCube service that uses the
ionCube Loader to provide both real-time protection against the exploit of
website vulnerabilities and alerting of website errors.

Vulnerabilities in PHP applications are common, particularly in sites using 
Wordpress and other plugin based systems. Exploits result in website
defacement or customer data being compromised, and ionCube24 provides a 
uniquely powerful defense. 

PHP errors can cause intermittent or even persistent blank pages or errors for
visitors until discovered, and without active monitoring this could go
undetected indefinitely. ionCube24 active monitoring ensures you are always
aware of problems in your website code.

ionCube24 is free to try, with the server side support built into the Linux
Loaders as standard. With the Loader installed, ionCube24 can be activated
at any time to give active intrusion protection and error reporting.

## php.ini settings

ionCube24 has a powerful real-time web interface to configure, monitor and
manage things, and there are also settings that can be used in a php.ini
file as summarised below.

The setup process at https://ioncube24.com automatically gives the settings
that you need to get started, but you may wish to make changes yourself
once setup. The default values are given with each example.

### Global settings

INI entry: ic24.enable ; default 0

Purpose: Enable or disable all ionCube24 features. 

This defaults to 0 (off), and in this case no ionCube24 behaviour is
activated.

Example:

  ic24.enable = 1

----------

INI entry: ic24.api_access_key ; provided during setup

Purpose: An authentication key for adminstration requests. 

  This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.api_check_ip ; default 1

Purpose: Specify whether the IP for admin requests should be validated

  If set, ionCube24 refuses access to API functions unless the calling IP
  is a known ionCube IP address. This option should be left with the
  default setting unless web requests pass through a proxy and your site
  appears to be accessed from the IP of the proxy instead of ionCube. Note
  that access to API functions will still be authenticated by access key.

----------

INI entry: ic24.api_max_timeout ; default 7

Purpose: Maximum timeout period when sending notifications to ionCube24.

  The actual period is adaptive so that a brief increase in typical latency
  will favour a timeout followed by a retry rather than a longer than usual
  timeout.

----------

INI entry: ic24.home_dir ; no default

Purpose: The home directory for ionCube24 related system files. 

  A location outside of the web root is recommended.  It should be writable
  by the web server during startup.

Example:

ic24.home_dir = /var/www/ic24_home

----------

INI entry: ic24.update_domains_retry_interval ; default 30

Purpose: The number of seconds to wait before retrying a fetch of the set
of domains being managed.


### Security related settings

INI entry: ic24.sec.enable ; default "auto"

Purpose: Enable the intrusion protection feature of ionCube24.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

INI entry: ic24.sec.initial_state ; default 1

Purpose: The default for whether security should be enabled or
disabled. The default is to enable protection. Any files on a protected
domain will become blocked if they are changed, so setting this to 0 will
avoid accidental blocking when using ionCube24 for the first time.
Protection may be enabled and disabled using the ionCube24 control panel and
also via the User API.

Accepted values:

   * 1 : protection will be active when ionCube24 initialises.
   * 0 : protection will be disabled.

----------

INI entry: ic24.sec.initial_action ; default "block"

Purpose: The initial setting for how new and modified files should be
treated when about to execute. The default is to block. The action is taken
only if protection is enabled, and the setting may be changed via the
ionCube24 control panel.

Accepted values:

   * "block" : prevent execution of new or modified files
   * "allow" : allow execution of new or modified files

Note that depending on the notification settings, a notification may still
be generated when a new or modified file is about to execute even if it is
not blocked.

----------

INI entry: ic24.sec.initial_notify ; default "always"

Purpose: The initial setting for whether a notification is generated the 
first time an unacknowledged new or modified file is attempted to be
executed. This setting can be changed via the ionCube24 control panel.

Accepted values:

   * "always" : always notify of a new modification 
   * "once"   : only the first detected modification is reported
   * "never"  : never notify of new and modified files

----------

INI entry: ic24.sec.exclusion_key ; provided during setup

Purpose: A key that if present at the start of a file, will identify the
file as trusted. This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.sec.trusted_include_paths ; no default

Purpose: List paths from where files can be included and automatically
trusted.

Example:

ic24.sec.trusted_include_paths = "/var/cache:/var/cache2"

Directories can be excluded from the list by prefixing with a minus
character -. e.g.

"/var/cache:-/var/cache/subdir"

This is useful if your site creates and/or modifies files by itself from
time to time, e.g. in a cache directory. Requests that *directly* access
files on a trusted include path will be blocked but the file itself will
not be blocked, so requests that use the file as intended will still work.
See ioncube24.com for more details once signed up.  As an alternative, if
possible we recommend producing files that include the exclusion key.

----------

INI entry: ic24.sec.block_uploaded_files ; default 1

Purpose: If set, block any uploaded files in ionCube24 that are processed
using the standard PHP mechanism for uploaded files. This applies even if
the file is subsequently included and where included files being
automatically approved with the previous setting.

----------

INI entry: ic24.sec.block_stdin ; default 1

Purpose: Refuse code that PHP sees via stdin.  If disabled, code via
stdin will run without security checking as there is no filepath. This
setting should be left on as PHP would normally never receive a script via
stdin.

### PHP Error reporting settings

INI entry: ic24.phperr.enable ; default "auto"

Purpose: Enable reporting of PHP errors to ionCube24.  When enabled, any
non-ignored errors are reported to ionCube24 in realtime, triggering
alerting so errors can be investigated as necessary.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

### Deprecated settings

Deprecated settings are subject to removal in a future
release.

INI entry: ic24.phperr.ignore ; default 0

Purpose: Specify default error levels to always ignore for all domains.

Note that default and per-domain errors to ignore can also be set via the
web interface, and are combined with this setting. Leaving this unset and
using the web interface is recommended for maximum flexibility.

Example: 

ic24.phperr.ignore = E_NOTICE | E_DEPRECATED

(c) ionCube Ltd. 2025
alt-php72-ioncube-loader/USER-GUIDE.pdf000064400000115466150413456440013277 0ustar00%PDF-1.4
1 0 obj
<<
/Title (��Markdown To PDF)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20250130155421Z)
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 33  
813.500000  0]
endobj
9 0 obj
[0 /XYZ 33  
749.750000  0]
endobj
10 0 obj
[0 /XYZ 33  
700.250000  0]
endobj
11 0 obj
[0 /XYZ 33  
131.750000  0]
endobj
12 0 obj
[0 /XYZ 33  
296  0]
endobj
13 0 obj
[0 /XYZ 33  
97.2500000  0]
endobj
14 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [71.2500000  66.5000000  144.750000  75.5000000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 15 0 R
/Resources 17 0 R
/Annots 18 0 R
/MediaBox [0 0 595 842]
>>
endobj
17 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
18 0 obj
[ 14 0 R ]
endobj
15 0 obj
<<
/Length 16 0 R
/Filter /FlateDecode
>>
stream
x��][��8v~�_��FI���@w� �0l A�l���8;��Ϗ.TU�򱪾�(���H�\lR���_�ۗo��#y����|�r�RSd�I���ej�'�P�{��Ï�����s�����~�n�|���{ޡ������/�ɿ��{�_�]��.���#L�,/������Sd�Nu%���=������O�o�>���2)�T������魞�eZ	�s�e�]y��J7ߕ�5X��}�I.����/�ߟ���ㄪ�>Oʰ�WVEXx
=��12����E��?�fy���C���}�5eH��5�^���k���N��%y����׿tjJ!����َ�"�t��ӈ�Gre�s�n�L��)�s��ӈ�GL��=�FL7���,�#��u5yNկ�������|�[�k��ҎTi�=�]<>g<�
G>�#&UE���w ���D�o*D����
aϧ�����Ont)�}���o��ɻ�����/_���ɇ��Ǘ���xy��y�������sf}��6��&-��.#�wV�-�Ϡ��7��t�w�i5����Av
u٣�N5����}�i9>wQ�9�z�v-�-�Ң{��y�TM�K�պ9j
�M�0D0�p?O�|Lg��Y�����a`�9�
�����SL�I7�H˞]��
B�a�X���x�ρ��s,�WSJ�*xs�`����q���-��}���;�ۈqS7���i/ƪ@���~��S1���[^o&�'�^�/8ާ�s�B�+y�����q��6s�1��1w&8�co�����&��:���b�"��eBѷ��R�)g#�fW���x�c׌��H��s0�������ɮ�EVv�:�a�Y
�|��>2��ءӜ�ַ֊��El��|�_w�{�N��A<����v�V)a��-�ë��lr
�E
��Z��-e�`�->S��Y��xݵT�^k�;�
�1M�{�v��w��:I#�(@�(Yw\-t�9]�����4b�Tr:��9cG�<:�&� ^�CQ�j�t�U��	S|�3A�8g��M�^���c�@8Vðf���c��5;�s��@�9�>!�ٽ�5{�����%)�&ěpW7aMW�g7c�R��<����&M��o�ףO��{�Y��Ms���|�tFs�Z-��`�b|����~��z�?��^���{��G~�����o���bN�ҝ[�V���5t��8�q�f5*؈p�:H��a��K�u���–n_��99��F���] p�9��\rSݟ�LfG��Օ�6��` 1|���=ę0 <dz���#��ص�.�#��1J���*K�|�ɔU��T}���=��(��DT��?6��3��)Z���1��xG69Qp$�#�p���T�<��gbo/Į�j��2��|�#��?����������8*I�d�.6��u4r��Y&iRqC�
c���
��PF\Ƥń�<N"H�����,�U�щ�d�>L��N���L����4�шy��w�!�5a<t��k���2���g?�W�g��e�-镫��� @'-��~�7�?�$�h0W�.��-��m@$
�XL�^�3�
��ǁ��L�T(A����e�n����v�W��7����U��\KL�q,����j�^Y!��D���a�M����`p	n��$N&$0�J5��?",�~}�����3��d츮�M���rb�#�($fR��>m��~��E�ofw(n�K�ox,��ŰƄ�H�Z�)&�X�c�n�
3L]0�|�5���x� �b�X�Zڈ��׏��r�_��TK�WL$�W��p���,�9�&F�Q6ܾ����*u��կ9���?���{Z�ߙ���5� �u�_�9��L�O�!h��IH�˴{UN=K�$���ue��B&Bm?ץ��9���b$k�<Я��l���t�!:98"�D�Ah��� ���i㣗4J�r
�v�<b�x�U���9ۊ����E*��__�_ߚ�Y�a�T��[�b{h�l	������"���/MV
��L�/Y����1��1�s~�1�
��Ռ"�׿�Pu�ٰQΫ�p5ח/0oe2J�.�)�^��i�9�TM�&��cE�JkY�?��~��2/Êaeq��r4n).c<C��fD�P�L���ע��φʋc<8�½0�p��Y�k���7�х�k �Ţ7s֍�ni��;�%�҉���vF�c���ե����t��Y��oZ�Se�f��L'r18�X�.��s��K�)Y
8�\�`��v+�i+�$�RɯݗZ���BW��[^��(i���RiY�ʺ��T�V�W�a�2��Z����gԿ��$c���OA����cp�TG�_ ����7N�k����I�a��ğ�-�v)� P�H��\�0;�d��"h�2�W�� �x1��Ȓl�fpıF�âO�s�
(T;�⁀��#�L�I^�l��֯�hT�߮K��J(;�@A9ҒHKV�%Gߪ�T��<���y*��)��<��j0I�ku:OY��<eծUu��w3�d�ZK�<U�k�<��|�5�ɡ{�˯�JiCX�b��dži����~�,�җ��6<rf� �"Kr�7R#��,�(�F�7����aq4�R�.�7p��*�j��vPL��jx�ձ�M�:y9�:��Q��������T�V�:y1�:m|d�1P���`��k-�:���L���
2�g�C�w��߮T�6��5��cr3����-gtR4�7�r�J�4�9ጲZ8Y�!��(,�3Z�m���&E�KV&�n�������)�;����L�2o�2�iP�Vm~��
Jg��z������T�V�A�L�hP�M�o?T��L2v��5�ZH��i��¶8�8
��n�q)p����e!R�<i�B��*�iE�����Y���U��
;�p���� ��U~�m#���ԺS4�(b��]
&�v�Ni)�"�_۵�Q�`��L2v���#O#�MT�ՇQ6���r��֧r@��0p`/~Sj���B(��pձ��0�}�����9b��`�8/�M(��j�S�?Մ��xpx�6���|�v�E3R���.��,�Bԇ4y_�ƶ�03��؝yqY��f�Njj��豤��XǒZ^RK6U�Ϯ�ߖ�a�m�Y	�ӓ`f�ud��s�k߳�hޚ*�
�k�qo�����z�5$�����W��3�k���L*m��|�75/:QT��QS�i����T��bANx��(,~��VLW	'�;�l%�Z8��fn1WGe*^�v�3�s��ֶ�l�Uc�1�cKR��vC�u9��ܤ�;��~��M
[&��g��%_Y8P������IM5V�;��Sk�pT�3]��ϱxw6�j�SL��F��
|� S=`�=��k��T*GsT��b��i�V2T7��j&��G�	#�ln2�R�s�@�i<z����ʉ~����d�0�bB�O��m��"pC0�bN���K=���$���"m���F�{�|��C�P�	�8*��W6
����u��C�����W�2��gn����׳B�
��2_��a�*B\칺 k�@Fv�2FpL���g̼��L�C�1ta��3�Y�H���-�Ӊ��"!�*O>�9�.�[�J��c�p@���K��:u�%�ʑ]�E.j�4�WaY�W�R(�j����׃O�q)��1WF:����i*��=�ƛ��X�-��g1f޽����ύ��J
'V�%����ȓ��UO)���"�0R�s$<�O!ެx���fI3����A0	�?��^뵽�f��i��'�}���a�&lM�42,��
]ji��2�>t���ˠ��`�j�S�c)����;���&U�ݑ�2U���c�慜T���B����֡��ӉM��Y��ϱ���Y�XA�st�bނ6����s ��s?b]Gc�^?����)zLF���S��v<�|�����ݦ0��2�qc�w��왎(û/��-y�>y��~�����#y�!��!y��r0in-���D
)H� ��?�\_�سtY�b����1@ԭ_��)����($����Y3�`���D29K^˕1p�5�b����Mo����7��I~����`�ôue
�1��op��0�`�!�n3QA�V
���P!%��fxp(:�6-Æ��+E{��~���{~�W�v4 d�'pSI�o3ɳ��"�)�1I0�"pN�ΰ*�WRw!�}4�
!����9wV�4�a+d�6�u���S�x�w�1�1;���(��F�}3�s��Q&#�)�@�)LUbc���e�oQ��D���y����lQ�7"�
fQw0<�B3�yaX3�>C6�Ҭ��[fF%`�lw0D�z�fb܁��o]�G
�c� 
�a�"_��gS���`��d^����7#m^z��f��X|1}�sa�HP���,㛹W�욹W��i�^�YӀ��4soW�I�]�m�^=�̽��]��4so7�IƮ�p3��T�`��l;��~s��������n:�0��6m����f�.�,��h�>��J1�vw�x$���G�7+���G���j�ρ�ԍ��<խ��H�7���p��멡�ԍ��<ӯ���T?�/�((�'���ի}GQ�D�H��q^fv�f��
c>9����� ҃M�G0�-��gxැ�ߐ9�>�9�e�o��c�YX���*|��T��;�7�
��M�F?c*Py��ן#SA3��T��5�l�T�2�^66t>��y�_oqS��+'FSA�� �
�j�h��.��E�l�Ekѱ�sĢ�5����,�.��.�w�0c݌��<ӯ�8��}٭Ȣ7n��pBżm�!��84F����z\UjD�F��g��݅`D��Mp-u/��fNp-�N�,˱�ڌ��<խg�2�\Kk�*��ڌ��<ӯ���Z)
��z9�,��D1��Ĭ��-Eq(�8�@T�h��^.�y��$�������$D�
6��PPjG�`�������A��Ϯ'F�R;b�L��҂�&
Joc�欞�i�a"J��#8{��)�pb��:=��Q<ݴx�6:�/ة�|���jѲ��~[�&26N���ĝ>�#CnԒ�#�<;�F��&�rA1���d}5����w0���~$���
�t5�ڟ�$����r�PI��(�2U5�f��9�V7
{̰�c���q�1�v ����r�M�j��p��	�~�t�X:)�v��f1�:��=�#�3ŧp�!R�`�h��x|K�ix��"9����o�R���_ds��E6�\ds��m��{N��0
�Fy,�!{J�O��������I���ޜr�gK�Z�p���jڎ��~s�;g�;UZ���0XLM-Y�g�s�i5D��s�9ֽQ���s��Kp&����gT��nE�k�f���=���33#�7�g�����z�x�w���J�����	JR����zB�v�)�ka���
Ʒⵃ0�����X��Y����Ǟ�NL�G���9ܩ�O��e!�E�Fd�aD��X��\0�$�����S�kk�qo�"��Ҋ��q��|�5�������Yϭ��T59(j�p仼��W���=��A;�Nw<.=�A5�]�<���kF<�j��+��y�*�GT�'e���w�����7bo[&�L�.*���SN[����k#/���53c����.l9H:T96�a�=����#Bm�"T&L�`ج��T��M�p�f����)�
�L�VA���h��@����[Y�9֬SLu
�VC4ᢚVy��{��$�5.U��!�������Sl�)����ɫ��t��k��$��RzQ����x��{ʤ���3΂��������'��H�@����EaJ�%0F6c�JnJ�H�]~=���z$�K��o�=	�R�4�yp`<�k��i�R�@�u�[�ނ�@���< ��p�g��XL���Nل��ݴ>���׮�pc���_j�1�g|`LQ�L�)�Ѷ�>rS0��e�E)��*F�,�^���Y�ê����2X��j��wai�EU]�!�1~T�4^�E"�n���4��ӳ���W�1��r"�Fg&��2��oh�>#.<kU˗��ŀwP�ptk��]�s0l�Zk�����	�F��+����S�>��K~8�|z;�*�~N>�I�˙
endstream
endobj
16 0 obj
6379
endobj
20 0 obj
[1 /XYZ 33  
760.250000  0]
endobj
21 0 obj
[1 /XYZ 33  
672.500000  0]
endobj
22 0 obj
[1 /XYZ 33  
158.750000  0]
endobj
23 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [102  696.500000  175.500000  705.500000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
19 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 24 0 R
/Resources 26 0 R
/Annots 27 0 R
/MediaBox [0 0 595 842]
>>
endobj
26 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
27 0 obj
[ 23 0 R ]
endobj
24 0 obj
<<
/Length 25 0 R
/Filter /FlateDecode
>>
stream
x��][k�H~�_��Ȫ*�.`�maaL���C�dv���d��+�JmK꯺��QIrk㶫���:��\��o>F��#����-zr?o>l�8�I�_T�{������P�}���l�G�7����7���x���h��4�p���"�����_��~�����e��<�_�l��痿�$��TeQ�=�Z���?��V�H�"I�6ڨf,��߽x��=��K�gi�آ��mZ&����&o~���JuE5�迟6�V�?w]�X]���\�؎��:)�Ĕ��]�&�vm�w]X=Q�:Iҩ�V:��k3ݬm�w�~� ���c[׏���,R:z�5j���X��2���KtYq�۫��M�L[�C]�ݶ�b�iV�5:�LRl[t\6��hɷ-YlR�k�ٶ�q���Ӣ�ۊ�ߦ�{F5C;f�ʺgt�t����Ūf�[�kɒ�tG-ۏE�xf�w�j[��768S��c�<CЁʶ-*iሱ�Pccf�W��^�d��;�z�L=���h�N��z�n�gf��ZU“Ep�RU�7�����#P7��6�{C��Y˟k�6�	c���Sg��ʡVKM���ⳍ�vݞ���·u
�֔�􆟁3U�n��h(�.�����u+�d����pl�,`���L��Cڡ�CU�Wam���@��Ң��ū����[��k�G��YQ<6QY�5֞�:�������aLT��W�je�~Ō��%xl��q�4sd���{��p>�}��ӆ��q^�9 >-�B«������lY%�IBʾ��S/��2r�s�	�Jiӌ�Ϝ9��߆׍�q?�؄W�uX�1���0(>?��Q{��P�@s<���
�,���9Ƣ �A�=���fzռ��!Y����2��68��#��`��,����5�ش,�ʌs�72#���-<Z�!��y�(���&��H��1)�3�5�H�㑍p�L��i�׎
�(���(�Ö#�_�������LM߶�I�&��X��Ԝ�Y棢t��=,�O]�`��Lg�c��~��||�Dc<c��]����+F�y����L���M���*y,+S��<�V'T���і��1��P���o������"�yZK𹓃r���;u�Z+ĩS�wwF����윪�o��g܊�=�C�������i^w�3-������-o���
��ma�s�=-�|��[k7��V]|���kty]�����Ϗ���]^EWW��Me��Ԭ[:�-�����@z�x
Yj��$�S����x%�Q��Pnj,T��	.U��9%A�itzSQ6�`֩���qf9J�ך�����!v�Ѐ���=Ϻ1#M=�*�h�ŒӠ�]K��J�^��b''�U���@/Lo�N��:�dD00�h`��]�i�c��P�t!*��IE��|1�I���a*Ɣ���Hr	v�^�ƊNmՎ�9i��lL(�:D�d0�a�ztZ�дCr��H��uW}N�_]��.f�"�=���i�zi]iӥv,�-�#'���̽��AP%n�Ex=�;=���dG���lt��ӬC���Ɣ�8�'Iq
O%,&�
%#�F(�u���u�Y���%Ťp�"_�!r�* �	k	�L��̙�i�H*�S�h�u��u�OMYf�2�5��L��Z0e����u
_�ܨ�I �F�Dcӈ��Ri���U����х���"!���S�J�T#F�I��c��>ƶ��ƒ�k���-�u��Ze7}խ���q�Ͳ
eh��E�'��QO?E{
�	����`7�8z����6`�;���f\?.�w����:�昬7��M m�z���k�۽�た��'Z��^:~z�5����6*���06{�-0��S6/+ΚD�[�vL�'SJZM��RԢ3ؒ÷�?c`�{�Ƕ+Yp�v���
?��CN�=��X���~q��cv��Q�������>;�={C{����-����kf�:�EA�2\�c�(�py� �\}E^G���̉�t\&f'��e| ��Ӣ�ZZhDiaܢ�( %Q�2XQ�h�Y_��2��s�*︨_&N���.����?ӗ
UR+�n���Ƕ͜��"�! �TD*+�H%��0&UcLy�bLnj��1ݞ���0�|��б�ɔtn�H�zI�a@?��>�w��ZO?p���P��p���h��u�?�
����׀���3�����mx>pv�){J�vDxfzD�;��8"J7Ӂ�\8��Ԧ�eo{f��ɫ�2!�TBR�[̙��P�P5��LgL;�[ô���
=�`� �G��n�w�L<
�N�g�O�^��ee�,f��w�2�eW��:���F>���QO�u<gY.N+��
N��Q��xu���g�����5�s�5�iM�2E�y�!���!ѬvFV�t��)X���9'���5�i����j%VPa����%�.����z•���4��D&
��у��PQ��WӔ�K�	D��S�%�S��7f�Dtc(z���c(8���R��#�C�YSl"��S���)�CY��n"���N�}��1o����A�pd���%IJp���T���N�(:ĈR�2��Rr���o���[Ӭ_q��8N�_!��zb��I��b.\�\W5gj��AK�� 2��P9���R�����:5]~��2֣	�)U{}r4P��9㫢!�]�	N���Q:a��H2��ZF�Jx`8c��R�B�<�������L֑��ߕ3k���
ߜߐ��D�R"��rԱ��|��	��Ռ�]�����хSC$�褲�I�59f��]�*�jq�1/�|�cN��#�xl8����*4D�,\�œ�B����6�R���I�3��'զiQI||�OQD��a8���"56,v���f`{�1f�"��)Мq��
 ������E��dZ&\;��:)�:��.�-����I�zc�#X(7��&�J�Ya�sm������5)���r���6�U
�	˘v0T��|�:Õ�3�p4AUA�QSz��l����}���PWN0�o�f&
=P��$p-ҁ$�N-꘠�F��YWa�zeyqJ(�䭭5S@`r�D$�w�eʛ ��ں��k�K��]�ʚH��s-?��eO�C|����`�ū�]��NZ|�^�%�|�f�e{���oCA�L�;%���b\p�q�@�D��Y__q>.+Y�6��dwA��REsj�p�-�Fvi�+���75���g2���t"C��@������iA/L]&&�;ZTa4/J'c¢�u(Cp��"�ra�!,Z��|*Hyx���g�|�!�K��Ҥ���Ɋe^��9��[8P0*e0�D� :ZF�O�+Yu{�4�	�Ǻ7��8,��k�

��֙���%!�F�u�"�{8�؈;N4����\���p��sL�'%�]�G��f��n`竩�ʗ$
��W3���CwӟƼ1�NDY�
<j�?ؕKd=c!�Y��8C�s% vM3��%#v�L�j�|4n��
�3̮���!Z&����C���'�u�>��a`��_E�d��dM�*Ü���C��'�)ܽHת��J�b�	#8��%g��3�e���C�ݭ��$���t��s�;���?����i��fH�MUv�4�2N�~�Y�bE[dg���y�[��u�dE
�pL\���x��5p��_����G�gZ��%-��'�~�q?��i:p>�G{�;<86Ϩ�Z�)E{�Z����Ňo�F�����~������Utu]�����I�Ļ���{��MO(l���>H"=�������.��gڿ�tJ�/~�ǯ�߆Qc�~b&�^`�`�36<S쩹{f1#��<k�;�1��(���*�mN�]*�?�5���P	@�_\!�dR�2LX��%g�$H�&�@#|��
L�B�DR�T-���e��1��r�<Ӄ�#mu}q��O*��d͇2��ZD��S�|ژʒ.mj�c:ϙ�}���Oi��T�ޗ����T����}�m����-q�vY�b0�e�e3!��*u�2bh,�m}ߎ��s�ަ,�)���Z ���w���]�g�z�
S��p"e�0.L��>w$!�S�
�T�����Ϟ�ߊ��s�y����'�Mټ����uK�y.o�7��Ow	0��7�v0����bJcȂ��0��<��Q�;���Ս�Ӎ�@7�N7����tc�W7�N7���:��vtcD7�vd�u�<�=+r��E߽;2��d�=l��S
endstream
endobj
25 0 obj
4362
endobj
29 0 obj
[2 /XYZ 33  
122.750000  0]
endobj
28 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 30 0 R
/Resources 32 0 R
/Annots 33 0 R
/MediaBox [0 0 595 842]
>>
endobj
32 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
33 0 obj
[ ]
endobj
30 0 obj
<<
/Length 31 0 R
/Filter /FlateDecode
>>
stream
x��]߯۶~�_��QDR% ����A�a�C��+��h�
۟?ɢl�G��=�$�-��k]Q$ux~~����}��?��O�>��O7E�l��u��:�B׹�������/����͇͇�߯�a��?>��y�?k�����f:�s��/����������S.�V�����_UQVyը�n�/����߾�~k�Q�uQhm�Q�\F���EcrS��u�'}�޼����)U����\U��sS4ua�F�8�:Ӯ6Y]����������L�6j�U�v��z�-˹]٣G��4�i
�w�6���L���OY?�W��Oݤ_�J�٧�7�����/�k�cd�ʷ�+-+��ck�+��^�y��rp�m�T�)���T����NSTz|��J�'s�G�y���Q��NF�g���}{�iZb)lKC�g�m���>��c��P�mYE�������.�~��J��P����Ŗ芮�G���g�G�s��	���<�|�4��wľ���{�[PO�
�Q|O��RK�����liBQ`�0��R\n{�xf�',3b5����h�>;��\#>.��3��S�˕=�G�p�X�a�7P���]1�z�w�dn{�Tǣ����;�
�
�SL!�9��8^)�~�J��M���k5�S]���&NcO	��J1+
�5���g��A9�U̩'T�نs���;�g;0L���̿o�����$��E!�-�`�_��{��4|����w��s�Ѱ·�~�	֍?����ϡ�)>��,œj��h�,���Jg|^i�]T1l�5o�9�mc
���ŋ�|���kF�3r�
����R/~�hS{?��x^������#�1��+�s���O�!��7�K5Bã�xLU�v��5���`���ю
�C�d���L��L;w�s�<�Hfn�aC�Q
"�,��)d���u�=��D�ak��Q���X�c�/���r����X�a_�����a�8�!4�
a<�8��d�\���!�nʒH�����̬3ұJ��1��v���q4·&�!�:����坨�)�	{K�g�mh|�HD,����vCx�(l�|a�/~��i�*/Ϟ�h�S	O��P��/�DL�c��o���:M&1.Ӯ��T�(m����ДݷMfl���Ƙ�nli
��1��L?^�w�'�q6���l�w�'�W��>7�����7�v�%�R
�b��� v)��:î�����e�?�	̸(0�"f��eR�9�Ue����b�sZs���DZ=�AkΉA[�b��y$�+ft����b��Ġ-�xű쮸�}nor1��ދ4"��`�F�7o^˫��&%��f=G�i��.'~u��{J��$��D�hxw�Y��-����=
����'�m?����+)=Vڙ�R��q��@=Djh����F�ר�D
��$��0f��
f,8
*�<��v�̕#��=&U�EgM�W��:�D���R�wJ���hIK��H�C�T�X�w�J�dV�@� ]SPeF�L!�i�zj_JU���g�0)��l�X�{�q�2%c�)܏�M؟�%���?NȾ1=$��Uy�X���X��-���9F�m���}��G�5�<�k���G(��7��
�M�k��-9��5�I��6L���a��t%�2�0%u���l@1Ʀ	��X5!��	�V�l�F��HuW��>ӏ煐n�	!�gu?��Pwō�s�x��vJ=�:I�'|Xc	��W�J(I��'P�a�[N[���d.��=1Hٸ06>q&��u���O�sc�W���C��J1�2����Ʀ%ƣ�H(��*S�����4Ʉ`��.�:x � 6+�l��`� R"r��k�uJdu�%ci��Ho�Ա�t�3$қ���\۵%�PJ�? �u%��Y��jb�8%]�Y�D���Dz�B�x8Z��͛bo�ԁ��JJ��;��)���Q;����N�Kn�i��o�$x�#��G�:�DG�K��D��z�R�R�BZ���C(=�x�B�����l`bс�K����K��f'�����ޛ]��\OJqN)�aJL)α��M3�CJq��g��o��~:���v����9�.믘�}�o�]�~:���֏w����F��a����ڧUvd��F+�S�İ伳X{�d'6U�F6�l���%;Vdx1�����4�k�mz�|���bF��~<���5����cF�7�;��
�M��w��,��C	��"ӞR���͠d��u��o[p���Od\�L�FYe<I�E����7�(p�xJ|�t�;3�\?��[oF�쯘�}��K�s��o�x'f��f��Q1�	e�0�����dV�;�&J�ξ��Ғ~?�c�#�����0:���=r��VE��\]��~�6�p4�4d�0�"�R|�h�3fp������q�9!��;
��"��Ce��<�յ����N�s�s��J�d��ld����P���'[l��+D�8Z-aѽ��=ӆ�rO-8�("�q��XE�0�%��i��$Yr�E{����ej����A0ώ׊��'۴���2��ފ���_��������HA�̖�hG�
5�&7t1��wZ�zO@��.1��c\�9�33P��)*%�V�ܶx=Li"\	;Zq�!Y�:Q$kՅ��z��x��n�Kkԕ*�p�
"�qkPvk0�d�2���N���iķ���)����1���$�� *���s�E��f�p��:�W�4�Z�p�^��>q��f�w�/!x�a�jD����ڬ�V�\W�Q�Np�&zΚ)6��	�������%�X���v'�a��.��4G�]^۫�Ԉ�d�����i���D���ɋ�i���d!���(`E
�S05��d���0�	�<Z�;���l>�%�Clk�T63�j��U�˥�C�-M��z�D8�8Z�=�B1uK/e�i�*�A�_�C��d��=/i�B{��B؏�W�=<�9�<"Sۮ��
���a�����|�sD�����@t����x���M�E���h��D��<�=8��R�i���X
Y�e=3�G������b5�����Z��8�mw�u�xkd=I҄��0>t&Qg��%hG[��{�|�J��?M�-�N���rs�Ө�M��ȾZ2�_D�Mh�VM1�'&1X����{�e뙊�~Y4���p�q1���l���7�
Y�-07l�0�3eO��=?z`�����pNe+�&~jsK��e�zu��H���$|?�Q7�\S�e�R6��e�D�[`w?X@b0~��9.W7�`٬M٦DK)>s�M4�� ���yͮ���,���5b�p¨�!:FP�.ք������I�{Sp��)pS{��u��|kY�1�@ٜs�$u�U��������&�Z@c�h�jA�{�h��0o�;)�e���'�-b�2�#��E#���/���~I*:gAP�T�]��t�mA�==P9��K��Pxw�zp)�K]z�f��uD{2��T�}�+�	C��~.�P�M������R�C�q�{b�K�L�����`���h�
�>A��ݡ�'�*2�*���K6�R��H&�(T9VP�1�e_� !LX_�l.C�'��OW?�2hiLЖI|`����Zp�<�!��U�uHgL!�DJ��FHe�Dʞ{��%�����e�#tsʏ 
Hf\�E�W�[p˄%�y����C6%���~��@���jx�=p�O`�5�ҿ��0>O�r����lS�/
ܣj��d�s�=�Ze�rmp�=%�G���K��LJ"��Aհ����y��~�`рl����d�쌚|�nRluE�23N�Y����sƸ�rB��+3ZٜY��jFs���Q5�9�'K6�K������qn�\��ŝr�RUc.��JL�A&�ɸ�M�q�1u2���x=Tg5�
��y�@L���ك�Tp��)��0�?��*�P+
50�UYY�)Q�n(��2��F
��s��3����>T�X��H�e�
�@D%*�π�ek��j�8��L�,�Ra,�{�Ehk���u+�Eh[����"t�G+;c�iBUu�]�qY�y��������*+(�w��dmelj�륱RyY�x�?I�Y�fl��r��'�ɟ��<�]d�?�W����y��@��m7���@���u��'�M�gpZy�	�
�?�P�8�X��>&������͛�����������y��}����S#��t�Q����/OGKX-yu'qzO��9q�uQfz]j�W�'��q��PR��8.��g�Qp�
�5~���q�#�F0��v���BLj���ui���#��u� �<Ǫ<L�Lj�x���B��$eG�}S~R��1~s�Q`����]��g�F��A\����2�|&�Ō�JL`��tL�
�c�f��I���!�Ʌ���*��h�B6�?�5�r������9S�N1�_89�-�G;2Z���ឪ���LQ��\�S{b�Q�]�u���T�T�I5,�T�J����N�z(��_�����2�'Y-�WF����6�kO��C����T�}�T���V���M�}�3c���7��ucKS�o��g��k?u���订��k�w������~޼�f�l���U�m-w�c�UG+0�,?�
�i*v�2{@(��y���.���DTIej��Տ�"����s�T��T1,���i{̘ژv���D:����y��נ�;���C�a��l��
endstream
endobj
31 0 obj
4897
endobj
35 0 obj
[3 /XYZ 33  
765.500000  0]
endobj
36 0 obj
<<
/__WKANCHOR_2 8 0 R
/__WKANCHOR_4 9 0 R
/__WKANCHOR_6 10 0 R
/__WKANCHOR_a 11 0 R
/__WKANCHOR_8 12 0 R
/__WKANCHOR_c 13 0 R
/__WKANCHOR_e 20 0 R
/__WKANCHOR_g 21 0 R
/__WKANCHOR_i 22 0 R
/__WKANCHOR_k 29 0 R
/__WKANCHOR_m 35 0 R
>>
endobj
39 0 obj
<</Title (��PERFORMANCE OF ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_4
  /Count 0
  /Next 40 0 R
>>
endobj
40 0 obj
<</Title (��ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_6
  /Count 0
  /Next 41 0 R
  /Prev 39 0 R
>>
endobj
41 0 obj
<</Title (��LIMITATIONS OF LOADERS AND ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_8
  /Count 0
  /Next 42 0 R
  /Prev 40 0 R
>>
endobj
44 0 obj
<</Title (��\(Available for Linux 32 and 64 bit x86 servers using PHP 7\))
  /Parent 42 0 R
  /Dest /__WKANCHOR_c
  /Count 0
>>
endobj
42 0 obj
<</Title (��IONCUBE24 : real-time intrusion protection and PHP error reporting)
  /Parent 38 0 R
  /Dest /__WKANCHOR_a
  /Count 0
  /Next 43 0 R
  /Prev 41 0 R
  /First 44 0 R
  /Last 44 0 R
>>
endobj
45 0 obj
<</Title (��Global settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_g
  /Count 0
  /Next 46 0 R
>>
endobj
46 0 obj
<</Title (��Security related settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_i
  /Count 0
  /Next 47 0 R
  /Prev 45 0 R
>>
endobj
47 0 obj
<</Title (��PHP Error reporting settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_k
  /Count 0
  /Next 48 0 R
  /Prev 46 0 R
>>
endobj
48 0 obj
<</Title (��Deprecated settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_m
  /Count 0
  /Prev 47 0 R
>>
endobj
43 0 obj
<</Title (��php.ini settings)
  /Parent 38 0 R
  /Dest /__WKANCHOR_e
  /Count 0
  /Prev 42 0 R
  /First 45 0 R
  /Last 48 0 R
>>
endobj
38 0 obj
<</Title (��ionCube Loader 14.4 User Guide)
  /Parent 37 0 R
  /Dest /__WKANCHOR_2
  /Count 0
  /First 39 0 R
  /Last 43 0 R
>>
endobj
37 0 obj
<</Type /Outlines /First 38 0 R
/Last 38 0 R>>
endobj
49 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/Outlines 37 0 R
/PageMode /UseOutlines
/Dests 36 0 R
>>
endobj
34 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 50 0 R
/Resources 52 0 R
/Annots 53 0 R
/MediaBox [0 0 595 842]
>>
endobj
52 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
53 0 obj
[ ]
endobj
50 0 obj
<<
/Length 51 0 R
/Filter /FlateDecode
>>
stream
x��[mk�8��_��u�jIP
M��AI�>��d�X�e�����?9gc'��L��^wj'�F�g4�������MLf�/bI�ټ��w��'�g�_�Pҽ�нX��ⱸ-n��Ǣm���|(&M_E��|�{��Gh�k��I��W��%�����+_�M+�>~�����*�����~�c����e�Rk��jl�|>3��Rz]=���-C���hU}�.�W֧�(c�&j�ixO�0��F|}W��=v�a��a�:7:�Lsg��xW	S57��ߦ?��.��H��I���3M{�s��l]-I���NOI�;z�m�c1}�c���:]��J(-�E�γ沸/lHތ����<���B,>U�5u��O5����2Va;k�Q�DV�#�:�qʭ��QkZ�$��}ܚ6+�++�Bg<J�N�0�=�s6$�$��=�A�d�Z���>�X0m[���ܬ$׋Y�	��*6�
h�k/Tj��虦=
�v��uԞ�J-�=߶w�Pq����H��'���i±TU���N�X<�����i�j86���e����
+��=J۟guI�m�h����Zs$1Dt��Op�.����}�~h�w-�
�M]�E��w
�-c�"–�t��6C�@V�'~2�r� ����r���ϋw�~���BL�f�o���	�����f�s�i�9�E�/��3�h�69l�B�-%9~Hk�$��A�Ϸ�%���I�x<ж��8�C�Hە�9�'|Ɯ�<��H1尚���o����:��	ýÊ���4u,P��:r��������kF�Lɣ�2o�9�5JX8��o<ی�o��0w�5;j��V��-7q}�a�q�����U�'7�+�wr��^�t}ﵳ1A��o�qi{����"�� �LSZ�����T� ق��dž[-��
J<l-@�5�(�����l5��V(���H�Q���&��Xpu.��AI����X.�D+[K�h{A�y�4��T���8�7=����T���l�p5R�XX�Dl5&[��a	
��g�8&[X��=�$�A�2�A9[Ƒ�>/�U�F�=�l}8��l�q���kΜ���x��yo��Z�)�`Te���/m�(�%N���b(c�S|=Y
[�WN!��a�a�i�:��x‘|�����̄���.Y��3?��>r��b$�f�8�9ebNfb�-�Xqkx�F-��r=^�Y3�U74�}��GʚG{����ɚo��9��L��É�qW
�	���Ki�������i�G?X��8��3��N������돶*��)#�<��������aX�*N�{<��-2��sh�Q�aU?�T/�T2���F��a���F����g�.����13�ގS������ [�'�Y�����B֬�^:�� ��F�_�U�o��u��|˾V���-W��h�#�D���D��~3���
[�Gj�8�18��<���Lk�o�6��L?��K��]bT[^����'_0��ls��K��[��Y{XE�얞�]�^u�����H��Ȍ��d��}����jz�
endstream
endobj
51 0 obj
1581
endobj
54 0 obj
<< /Type /FontDescriptor
/FontName /QCCAAA+Roboto-Regular
/Flags 4 
/FontBBox [-736.816406 -270.996093 1148.43750 1056.15234 ]
/ItalicAngle 0 
/Ascent 927.734375 
/Descent -244.140625 
/CapHeight 927.734375 
/StemV 48.8281250 
/FontFile2 55 0 R
>>
endobj
55 0 obj
<<
/Length1 6976 
/Length 58 0 R
/Filter /FlateDecode
>>
stream
x�}X	\G����{�F�1+Ȍ�`�P`&�7�)ry" �9ܠ� ry+(*�&��&Fr�I0�$���[s=�xd�M6	0��g0׾���ꪯ���5B�
�L8B����j�=���bI��_�y=�����Н����q!l!���';Ư������삲*���`�B`l�1-���#d~&��UE$�,�v#�U����7�	Bh;��`:Rp����$��V,�-BGb�j���!K�������eD$$S�A�e�x?�4�C��Hm�9"'���B�j��S{5�A�M3ϥ����a����F9QG�5��S��rs���R�*Z9�%M1�_��$���Wq
{��Q�87���K��0Q.�LպA��t�'�蝝���>��y?p��rqQ�r����j���G�J�����J��˴HF���t4x�o��v�\�j��b��͍s�Kv�����}{\,�'�4��Sm��MAA;��Vo���m�����3�((D���'�.�J��^�Q�Y�˱
���˰�3Q�޸* ���5k�z�f����6�~�R��]�}��ȲF�uS��F7�� U
R�)u��Ͽ�c�}��q�C�O}��2��_b��LY9ik�=��W���h:�ցCq�[�x::��ip���V=��m���@��Z��)&���p�
�>�r���ө�͐��O��A����.I�C��dg����i�D���Q�Т�5(	�c^UR�w�h�m*�����x~I™��aT�s��=52b~������Y�%���,\'	���y2�� C.���
(����*����z�����<����zy�Yï\ޒ�]�$~X��Sl�&ž]�O=�ych0���b���4�>m���Ҹ=�GG2u�_8������
��g��_<r�9%���7ȝ+�Dv��4ȡ���	�P���*�����R�t�)lk�9��
[6}s�Ͽ(- z��7-��7/GpZ��->	����W��HNJH�O]pLTĬ�����8~�r�������Ӌq�9��~�-���e�B��ՙ�%�J�ʊ/Mݶ�K/TT� *��'6�(�ˁ�Z�=Hʚu�,7eew�wsr�^@�q��!�-@�,����<��t�[�w�3�Of�05�a���Y�L�{A画�-t�3���kȽ��"C�#e��	����B�5�shk�y�;�����[�}7�K�1�v���*�-�ta@#Q�$u�����;�	�i����s����E�1g�
@5E��c7��
N���7��7�aD�w�M[n�ݱ^Z��c�@85<��k���͟s���:���e�:���d���(%���z�r栱
�o�me�Ĝɀ�Q0��l���N�b�se%��f���[�fN(-?_��a�5�!A%ً�KČi.SfL���ٺz���}zf��5ST3f��Oܓ�`��ؔ$�Gf�`��C	���e�����S��7����h�Qy��j�Fx}CϳM�Qh&����fU�A���P\t!�R��C�.����:���g�C�����R��=0i�/�f�7��96Ԓ��|�8���g
�:Gc0���:���l�ε�!��j�C����_�!Ӻ���@lx�e�@L秅���榦ܬ�C�,���*���М��Q�us�L�O��{�ȎTo��q2_�}��3��-�Ȫpu��Ip)�y�f4��xk-i�O�x�8�e	��&7��Ouv@И��g0�T���� 6�gҁR�y��^��@��7�lc;r�&
��Y7s��R p���Wh�:l�<y��ox`����Bqp�9u��zl�Ĉ�fzt'HrS��{�,6\�75X���/���Ū��C�,k2�&� Β�Y^�I9DL���-9Ē�-�	�Aa�O��⋗�L]�E���	ډ�ا�c�-Y����!�`�^q�?����C�򲑃��܀́�Z���8�\��ҁ��O&%u/\0��{%��m�ɝƧ��ص�z����N@����{�y
�i��J����t��K�4L�Yf�)�e/_2�vU�\+/*�K�8�a�PV�|DĶ����Eb�5��h��um�z��\n܋Ѹ9i�:��s�w�^*e�>�M��8Z���U�8`XG
9}�M���-v���q��q;����|I8�ֿ���28����6:���;��>$i�y��:��yj_��"=nNN�w��,~��#b���bRӱ�r���<�ďCk[��;�b㫑[F'�#��caP�5��%�����f�6GF��n���}q=�h+���X�r��:7��{�{�
������*��l��H��F8-ԞY(3R{{��I�o!m�����.q��o�~��r3p����¹vH�R�V�W��`@;�?|I�ʸ�	�Z��i���an搋�=7��ws�,�g[�C�E����
w��Do�q{��e:�x�S��zE�Ͽ�3��Xc��Ajd�a��^�/�g?6ԇE�B�s!hw$�Ò�v�Ce~V8UT�NSz���m,�&<�f[h��4W��/q�H�`��i��\ø�ܔ��lQo�0I��ѰȲ����AK����	�	����[{N�7�F��5ԟ�i�z���?���A^��73��]�u���ĸ��Wr�?�,!>���w(������w삦ъ�d��9���
{�'��pn��_�&�S��{T��j��j��C��Q��Ć(8K�e�?������2w6]��NP�~s|�3T��x����]��[fa ��_h.^��\��u��,�o��!����Z��r"�s
ӡ��.8�Ҟ�K�钘��_�>p�fK�©���C�'�w���x&�47�$����1)� �.A�X�eV5<@�Q$!��H��$ǣ�?��o�,_��b|����1q�Lv��gs��ں���kSo�]I��s�<U\�矑��.*�-0��7_��7?6��tn�?����>2j���ܹR̟����2�����Ar@�\��;M�_�i.�]����P*��{�c}�F�I��a�S�r_��F��GLs@��t�,�L��Y	��e��Ξr-�
��VUmqۓ�l������%�^}��+d}�#~� ֈ_v���@<��
HqҨm�1����-M������_��N{09���Y�1����y~4��W�:V\��Oࡺz���K�û�z�
R���nc�C��

���?�;������@�|��@��k�M�/�Q
U2m@�Z����������{<�?����v�ֱ��1F���L]���2�)
�~*��w?�׉�22�\	��\s3�ف���ѠF�1�p���a4�bW�IH~%�~c~vVn�k���6|��
v=va!�[�Ö�ԯ��w�K@��O>�Ry�/�,X�b���+���4\��k~A�b��G�$���߁|T>SG���z��@CKmd�Ⱥ�Pl��[����V-^�i�[W6m鍈ظ����{[8/(�EO��^LY�r����1k�g�� $�nS`���d�͟��z+jU�h'����b.��r�zDox�XD�Gr8�'8�;0���koG��y5A��G`�_-�A�5�^�K�������~I��\���a`���Po�,���}F�nS�����1Q
O,[q�aIuٿoK�����mz1�v@n�,
-�킁D\����x���˽/��&`�6���G]��W
��5 �Y�ꖳ�{�5�ؑ�A�kX���.޴��k7â�%k
�Be��}�����O'�au��a ~S�8�ޅ�s���+^,*����k��$&���k����H���P\�
*-


(*	F���yi�C�<�,'&Noga[±Z]��1����3��19��;.������-{�t�)�'Xt�p��qw�s�����]�0/�\��uN���c�s��J���l����G���d���ؗ\~	q4��~�*`��w-eI��Ҙ��a�.�>"l��U[�]�t۶�G����u����/!��ի�ڒV�&�FF�F)�;�S�NB��Q_d���;W���4�.�q�����*��o�����K"A�L샩5Q�!;�/����ˌ��1u՚M��b�]� $h=Ƞc����G}��R:��eŌ��'�Wԥ�}�0R��Y���4��F�_�f��ZO1��]3�m���z0Ƃ�	T��x	9q{���0��0�=�*��7��� F�
��qęat;�T��b�?�����s�ϛ���<Y?��s2�7&^���4�8�yp����P��m��'?<�G�����1CvO�<S�����E����8�PvO���+�k%�����"��\�*�I%��r�!��<�C(�h�ů$|I��a�FҍEO'�]��U$Y(%�Kē�ƶY-�H=Bl�[D��3z�52�)�X�%�!]��8#�$�N��82�{�8��=r���1�I�lߏ'6^X��.��#d}�l������$
�x��Fҁe
�D��Ä��d:�Kƾ(,EXJ���C���+I&J�Dw�F�z��Ë$���,��x�O�D:�.��t#�;�rq\%w�����Z^�g�����`/L��B���p_��"d�&�Q��Z./���$����M�M��36l�ٺ��l�m���4f՘�1c��<6�IKd�#i�/;r�A��b�3�wZ���s�:��oX�<�oY�����u����d�
g�^@�HX?��)�z�Z�Ek��5k] n䶵.#N���Ǔx��IYGJH�"٤��P��o	��F��'�
#�$����"���w�Y�R+�H���8��֕�de���<<=U!FcV~�*�0m�jQ~�*�}*U�f�f�Td��X\o-�2,$ָ�X��H.��㒩H��fd�秖����Cg��V)�k�M�-��
��?�0���c��k�����x6�����x�p��EJ�-b����8�K~��'f��|d'
{
%��bO$�8�!‰ç�Ħ-++�3���rvjQjZv�lcI֜�����Ҍ�9�aA�qA�^�q��G+�
endstream
endobj
58 0 obj
5244
endobj
56 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Roboto-Regular
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 54 0 R
/CIDToGIDMap /Identity
/W [0 [440 241 566 547 646 547 557 526 246 534 540 559 336 557 557 261 643 512 676 592 546 519 869 324 481 241 557 344 557 626 707 195 557 270 745 469 564 611 548 682 866 647 707 651 589 880 339 345 492 240 503 557 557 562 448 210 564 557 557 557 557 618 274 409 631 317 237 ]
]
>>
endobj
57 0 obj
<< /Length 826 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0042> [<0069> <006F> <006E> <0043> <0075> <0062> <0065> <0020> <004C> <0061> <0064> <0072> <0031> <0034> <002E> <0055> <0073> <0047> <0054> <0068> <0063> <006D> <0074> <0076> <006C> <0070> <0066> <0067> <0050> <0048> <002C> <0032> <0049> <0077> <0079> <0045> <0052> <0046> <004F> <004D> <0041> <004E> <0044> <0053> <0057> <0028> <0029> <0078> <003A> <006B> <0035> <0033> <002B> <005F> <003B> <0071> <0037> <0038> <0030> <0036> <0042> <002D> <002F> <0056> <0022> <006A> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
6 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Roboto-Regular
/Encoding /Identity-H
/DescendantFonts [56 0 R]
/ToUnicode 57 0 R>>
endobj
59 0 obj
<< /Type /FontDescriptor
/FontName /QHCAAA+Consolas
/Flags 4 
/FontBBox [-432.128906 -302.246093 677.246093 1011.23046 ]
/ItalicAngle 0 
/Ascent 742.675781 
/Descent -257.324218 
/CapHeight 742.675781 
/StemV 70.3125000 
/FontFile2 60 0 R
>>
endobj
60 0 obj
<<
/Length1 11900 
/Length 63 0 R
/Filter /FlateDecode
>>
stream
x��yytǙgW7�� �H$��M���/�%ID @�hZ�%��x��-;vd[����$���x2Il����;M6;���y��y����Yٱw=~�l�W�
�e�X�+tuu�W���jR����8�P�������`����%Vf�Ux�o������c�hde��e��X�<�L�=<�����}���u<�<�6�����ߚ(ʌ�/.��[�ڨ'(ʢ�g6^��ێ��\MQ�a�͢�(1E��(
�;�kj��

i����E-�J�7��՛@��c�R]TwS���'hZ:E�)�o���bލ2S"j��D��̀�
8EJ�7;��J��:\��`��_G0P���K���f�$��Pe�_���!frMD��*U��@p@���h����.�;�c{��~Ra�K
d�R���D)SH*�*d����5��n��g���x�mv����5FCqQ�`�r����`tnZZ�T�*�R��^�����A6{��*'CN�r��`�>��{�#�3j7��2�L&/S�f���T��j��L=���S�ĔL�R���Xƿ,3�-f�N���(�c��"�Q6����*�uא����w���4j~<��+���wN�[L�M���X���}�d:1>��b���TZgecS��PsyE�R�r9C�};�B�e��[
��8]�a��
<��90��r"�����L
���Zde���[�o��k���}��:u4�&��Rt��k�e�R��ܳR����rW�<32|y�'X+˖;]����
�r��P���ڽ���!T(��ܭk�x��n~¼���sb�
`}h�?�(��üпep���@�}�����������7���V�3�N������4*�щ��	��W:�Ln�hW��~�ď�M!�,e1���NY(��pI6,R��I�y󌤦ʍ�yvx�|��Zv����ݡ�J�ԾW���x��Z���~|�������LTӆo`i]���.~!U�9s�,�o�޽���s�`���XOW�W�}�c���^�pT�ܾ@������Se������� n�x�;�j�[�*�]�������g6�r�F���3hd
�V�x�
b�΂f>O��:���
~B���yv�I�(�IN�cD����oyk�g\Nvpr���[������D|d�)d1��⨫�i�Ֆ;�Z��5ώ�AbF")�>��:��g��Ӄ[����clr����]��ju.w�	�3����_�V��h*l5�kg�:MqQQ�Fge��U�+*F��H��ZQkQ�����q��Vi���7�xt��壍�G�P�:���1?'�F�<�`����(�
�+ǝ��q����o�t+����;���yi|dϤB����~���@����;=�Z�����P���j�vn�xh���.g0������PR�˟S(d�B�!�����1��])*�����`Vi
T�؅�I���9�n�(U>恟���p�Q=�*�#�b�Q��9�/�ռxF24:>3������!�3�u�r��;w���b��^g9�H���G~z�>PQ�ӵ��/�xr_k��*�0[�
d?)hؐ�2�+RG�-(v�y�����3#���*�pEy������\�Ku~������(6Z<�mkG�.�͊f��p
��,���x�}k�7�܀=�T0/�hw(y@�k���PwV�������.?+���X��5L|5���Ţ"nJ����y����~:���k�6X��6�W)��\i���z}�~�}d��~���֦{����%�4>�Z�8R�p?{��$�L��bdU6���|fh�7/{�G�=�.W��eI���$�'��OdZ��3��$7w��Cj)������5�Ȇ��6���F���]��Lks�ɿ����ll��W[W��=911��BPf xO_s�ۣ׫U���ᕖ��;�5�xkL�B.���{&;�+���˂��\�+)�R"��Qc�F�F��hL*��Q�u{�몽����Y��P&/Ui�&�V�Ҫ4P�X�+�5���������OT<�"�V�Y�.V(����ʚ,j�m�B���ػ�c���Xs��-���%��������Kp��r��q��Ľ��V:tZTTR�**)���A��6�����֎�S˨�.r����t���
:�����j�]Q��ZSӾg�Ζ�r�x�"j�j��hJ���W@i�q�/p��k/����p���i�$wg��w�4�ɡ3�v�Gw�T榛�~��ysm�E����]���ij@5S�O�����ןC���;�7�����o���\'�큹e�8�~�5�G��[�,��u��h����Ք�d���х�7��O�(�=��"���)��]�ʆM�_���Fy�-�^j*�L�K
eE��R�J�5؞��EQiY��t�����Qo4����G�Ӛ
v��u��>���N	
����Z;B���aW�H�4��lY;�\�Y��e�C�@
�T��e1�Kp�9�/�&8/9�z�ZL0�r�|N��rhR�ĥ���/tZ��dc]�/��{����2UyECco��t�D]����Xg��Y�Q��~֊�Ck��McuMg���`��g���}�aZ2l�v�Y͞*����5��1xȫV�E�N�$T�	�6�h�p�
�!����`&X�=�����:�\NU)Bf���������3[����2}�	(��.��|��OZ�u���v��jF3�1C��"\��^��(�x2\���jƶd�������:�ƈDi���hktVZ�0�hc��M�`����\e	�\��ru�3���'8���4�%#��
�k�`�g�҉��v��)J3A7:
΂$d���^'2}-r��p�?�^G�}k��wf��K��B�S�cHI���M��Խ�zh3P�]�U'�t�[Q���v��5(WF��)�Ѩ$<�ug�}LƤ,1[�C㝡&���@Ն
��;jk�d��uLM�l<Ԥ7�45`T��
��u���D�I,�`���
G�%֘��'w��)�����q7���H$���bv���X+U�-.wm��6Y�J�i���qgW��Vo,.R��Zi0"SZf����}�m5�F�Z��c�`S(�(S�4z��+�^�5�f����Z0n�W��6{I�Q����Huj�F��i���
6-V��R�����b���#��k	�x�G?"u

 ��\�e�|��ܴq�=���3�\�LJ����v�{���xg�������B�A�W/}㟿8�}#uS�\�M5C����`d6e9��ʅ�NU�q6 ��ñ�R5�8�SƆ`CMS������'�`��r������G�5vn�:����YWoc���ͪ�6�"��@@�PG{Q���t5���DZ({�H.s�F+[�in�ꮩ1�D}$Q�J.�JD�
���q55�h�h���6�S
_��-�'Z^5���&*,f�s�4v��1'�ߥ� =�^G��;��z@�@TK�ԣ�Co�?���5Y�k���Alt�
���P��߼��͢�����:��l�{X!7�+��G�z�>���W?�W�f����6�5��9R�rt�X�w獡S�sTB��ǵ��:0
�������
F�NKꚚ�C�Cm�͵6�w�M���zg��\T��B�7:+��>X�hߧV�ڵk��'�M>���BB^懰+�4��x�v���o�ݻ�
�\VTl4y�[G{��n�9x|bp~�U���!}�ڵ��
�
�j8��U�ʖ��ZBc]����m]�ݽ}#��J��Q�QF�.ɈAP����}y�a��ƻ\�kFo";�.�?̈́W��_Y�~?q�CQ1He�s�P�wɝ�9!A�u�pb�G��M�b��깕/��ї�#���:���XG��B��v�N[n�V5�6�\.�f�d�]����U�@_�	�ҏ<u���^=B��=#Ǐ]~��N�]�=ǎ���ag�X�[
ٹ�n��9p\�ZY3z:�q�Ve)��w���vl��Zf�%U�D
!�ڲp�Cͽ}û"F�ƀ1�頻he��_s���
��_�D:�-Vi�1�Ev[}� .�Μ��{n�aO9�/��0����>�>��Nr��&�6�:Ɲ@��O�Пq�v	���W�ז8�~���7��&+Z��!��y,�8�
�ܕW��o+�{�vÁ��3��T��x�j�@��ׇ�;۷�����P(��궎�'��R��%]W���-��.g��嬘�5l0��[#�z��ҨG��o�j�����\")+-��ڂ�*����Q�,���=�q���\^P {<mm��ݶ��@�wV���K��S�E�o�Kk���_Ҷ��tPlz�;���I��p��
%�"H�T���=��x
z�"S�$kܴش����K��k��%1�y{uwˑ��t�[�ET��<[������juW
���=�������J�\����Ѷ�J�J���\Ύ��=m�J��~��N��r�ښ�G��|���nO��vt�ȑ�dNo��U��S旦ý[�pb��O�!����ƩGT��!w�yU��GE�����k��&������b�-T��P���SO��N�S7���N�\�{�C�Tn>Ư+c�����~���'�tW�؞H|���;��ػ붆�ɂ��ߌ��>X׍��m�w���~���|����g��
w�W�Y��d������������������� �z ~�q��"**������‘/s�G#���S�!���qxW���u�́���Cm�j�^lz�,������
hU���}���~��2��"mX?�0�[��]�p�e��;���ze��o���sc�ûv�j�t�8�ؤ�������]{�����F4E�H*"\<`1�h�{���+��O��yY�߁#�'���~��)ķط�ׅ%m����v��ȳ�K��F��5���D�Ǐ�YB)�/c��^��s��
wܖD�����]�F	�;���`�3p�m�p�@�愶�%h)a-�B�П��S	��C��	h^��Vh[x~��К��o�
<bd�����D����>A���oL#s��>�D�!J�>��.�'��şK�%A�i���NH�)}��t�
�>Q�O�JY�짲��Z�G~^���mE�bX1���⇊�ElQ+�n�z��۟%��멜=�B���B���ӧB_D ��S
�.�%0>%�TzW�PzP�R��q�/��'�&��W���WPy��/Bۋ� �ƒK�	�F	W���R�i�Oì
}������Q��@�)=r}	�	})u�	��C��~!���B_&�M��rj\���WP�J�ѧ�cB��J��Q߃J�j�:*�T��Pi*Ee��RY�^|��a$�$ԉ,�M%�b��06G�ûy��=��oW��c�uvG<�NeR�Y�7�^L���x*�c�	vw|n>�aw�2���X��m0	�6�d&�C�0�~�����R"�۹o����:-�ͻl7N����PJ�@YxKg@6��Ja�+h��0�,Qk�X ��1�<~3�w6�y^��fG��a�)NL��`��g�0�M����p���e��<�̥SK�x8�ZX'㱌�N��c�@�Ѵ�X�PUDh7�������/E��7���T*{7]�A>�P,���g�x���,�s��������~�҄�y�
4��^J�u��ό���%s"D�,Y���`�B��=��]�(�������2�[�'4Ä���=�%c��>9/��b��8���𔀧Cdk,JV����V|�f5�7ssz��ě�9�7)b�X��X�0�:��bLk(#�a��(C�����=*�'ފmrX�����eBiC�Q��E�+dw�;<�_\+C�()�k(����ܕ�3A,�[=}��2M�� c1�>���#���uZ�ܻ{B�;���M_H��$��9�2y�_ ��z��
҄A�	���狷-�	<�1�՘�9�x,ː��9��ab�$p��!F}I�)mX{KB8���;-ț\K�x��%�J+ٛ��y�[5�!���Uy��*�*)�Fn~�{zR���B�`��s��s4#؟�WΧp��lI�ov=��=8A�&�s���2#D���躟�OY�_�̟!=LPae]�9��3dn>�-�q{�/Ģ�l*�.ebl<�.�Ss���B<9�ƒ���Tr!��\NF�d�4��#K�l8�e�e�A6YH%S��p��Kf1��b,��C�&I=2N�#YȒ�|�p���Lx!�.ǣ�j6?cS�(�]Y�-��xf5�>�y�ga��T*
dR�H��3R�p�07���'c��t:�YL%��C;
��@0�$؉x2�Z��<F��Dx�
'�ex�ē��%���<V�.���f"��M��Tzv���˂�$I�q<F7)!��ԛZJ�ci�	V9�,C�_H�� �B?�I����i!��X2
��NPVd"�X���Xr4�����%��I,A�n���4�Ľ��B,NdZ�|>�f��l�
D�?�������$dk0Of>��cB3 ?�5����[�,6��D*�����e����6�
g�1vf�=N�`�lО	�yG[��%�<��E(�j�Z&����[����B���E���8�n�/5��.���.//�r���P���q~�6�%��C��,A�4A���9�x�lx&?��R�^��|�]ɫS��8����G��Wr���@.�1(���P,���pQRje׫�e�W��;���o ���ǕE����r<-���ȸYn���OU��M2�]�?�U�6�~mP�Ȅ|���#�T��r�f��3
���%K�˕˜>/+_�$I~�QIy=�o�i�ߍ�k{�P
�H=|*Erp�[�����_W�g16T���'8��c�l{7���]�dq�X��G�����ш�:�BL/��0!� ����ީ$�^U���������w�L'`	�M�#<P����i��V�]��|I�aWH�D*��)��9ň�2^j)���"vg�3K,n�XmU-1.��%R���/BY��0`���lx)���3���;�	
endstream
endobj
63 0 obj
7274
endobj
61 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Consolas
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 59 0 R
/CIDToGIDMap /Identity
/DW 545 >>
endobj
62 0 obj
<< /Length 742 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0036> [<0069> <006F> <006E> <0063> <0075> <0062> <0065> <002E> <006C> <0061> <0064> <0072> <005F> <0070> <0074> <0068> <0073> <003A> <003B> <002B> <002D> <002F> <0076> <0077> <006D> <0052> <0053> <0020> <003D> <0022> <0066> <0067> <006B> <0031> <0024> <007B> <007D> <0032> <0034> <0030> <0079> <0078> <0037> <0033> <0045> <004E> <004F> <0054> <0049> <0043> <007C> <0044> <0050> <0041> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Consolas
/Encoding /Identity-H
/DescendantFonts [61 0 R]
/ToUnicode 62 0 R>>
endobj
2 0 obj
<<
/Type /Pages
/Kids 
[
5 0 R
19 0 R
28 0 R
34 0 R
]
/Count 4
/ProcSet [/PDF /Text /ImageB /ImageC]
>>
endobj
xref
0 64
0000000000 65535 f 
0000000009 00000 n 
0000038255 00000 n 
0000000187 00000 n 
0000000282 00000 n 
0000000756 00000 n 
0000029337 00000 n 
0000038121 00000 n 
0000000319 00000 n 
0000000362 00000 n 
0000000405 00000 n 
0000000449 00000 n 
0000000493 00000 n 
0000000530 00000 n 
0000000574 00000 n 
0000001080 00000 n 
0000007535 00000 n 
0000000877 00000 n 
0000001053 00000 n 
0000007863 00000 n 
0000007556 00000 n 
0000007600 00000 n 
0000007644 00000 n 
0000007688 00000 n 
0000008188 00000 n 
0000012626 00000 n 
0000007985 00000 n 
0000008161 00000 n 
0000012691 00000 n 
0000012647 00000 n 
0000013009 00000 n 
0000017982 00000 n 
0000012813 00000 n 
0000012989 00000 n 
0000020361 00000 n 
0000018003 00000 n 
0000018047 00000 n 
0000020194 00000 n 
0000020020 00000 n 
0000018298 00000 n 
0000018452 00000 n 
0000018591 00000 n 
0000018987 00000 n 
0000019859 00000 n 
0000018784 00000 n 
0000019263 00000 n 
0000019391 00000 n 
0000019554 00000 n 
0000019723 00000 n 
0000020257 00000 n 
0000020679 00000 n 
0000022336 00000 n 
0000020483 00000 n 
0000020659 00000 n 
0000022357 00000 n 
0000022621 00000 n 
0000027977 00000 n 
0000028459 00000 n 
0000027956 00000 n 
0000029477 00000 n 
0000029735 00000 n 
0000037122 00000 n 
0000037327 00000 n 
0000037101 00000 n 
trailer
<<
/Size 64
/Info 1 0 R
/Root 49 0 R
>>
startxref
38374
%%EOF
alt-php72-ioncube-loader/LICENSE.txt000064400000025020150413456440013000 0ustar00LICENCE AGREEMENT FOR THE IONCUBE PHP LOADER, PROVIDED TO ENABLE THE USE
OF IONCUBE ENCODED FILES AND AS PART OF THE IONCUBE24 SERVICE (ioncube24.com)

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING THE
LOADER SOFTWARE. THE INSTALLATION AND/OR USE OR COPYING OF THE IONCUBE PHP
LOADER SOFTWARE INDICATES YOUR ACCEPTANCE OF THIS LICENCE AGREEMENT.  IF YOU
DO NOT ACCEPT THE TERMS OF THIS LICENCE AGREEMENT, DO NOT INSTALL, COPY
AND/OR USE THE LOADER SOFTWARE.

DEFINITIONS

The following definitions shall apply in this document:

LOADER shall mean the ionCube PHP Loader software package or collection 
of Loaders, including any modifications or upgrades to the software, used for
executing PHP scripts previously encoded with the ionCube PHP Encoder
software to render them non-humanly readable, and any associated
documentation or electronic or online materials relating to the software.

ENCODER shall mean any ionCube PHP Encoder software or service used for the
purpose of producing non-humanly readable encoded files from PHP scripts.

ENCODED FILE shall mean a non-humanly readable file produced by the 
Encoder and being derived from humanly readable PHP script source.

PROVIDER shall mean ionCube Ltd.

USER/YOU shall mean any entity who has downloaded or obtained through any
other means a version of the Loader software.


1 LICENSE ENTITLEMENT 

1.1 The Loader is provided without charge.  Title to the Loader does not pass
to the user in any circumstances.  The Loader is supplied as object code.

1.2 The provider grants a personal, non-transferable, non-exclusive licence to
use the Loader in accordance with the terms and conditions of this Licence
Agreement.

1.3 The installation or downloading and use of the Loader entitles the user
to install and use the Loader for its own internal lawful purposes.


2 DISTRIBUTION 

2.1 The Loader may be freely distributed to third parties alone or as 
part of a distribution containing other items provided that this license
is also included. 

2.2 The Loader may under no circumstances be branded as another product, 
whether distributed or not. 

2.3 Distribution as part of a commercial product is permitted provided such
distribution is in accordance with clauses 2.1 and 2.2 with respect to the 
Loader.


3 ANALYSIS / REVERSE ENGINEERING / MODIFICATION 

Except insofar as the user is permitted to do so in accordance with applicable
law:

3.1 Any analysis of the Loader and embedded data by any means and by
any entity whether human or otherwise and including but without limitation to
discover details of internal operation, to reverse engineer, to de-compile
object code, or to modify for the purposes of modifying behaviour is
forbidden.

3.2 Any analysis of encoded files by any means and by any entity whether human
or otherwise and including but without limitation to discover details of file
format or for the purposes of modifying behaviour or scope of their usage is
forbidden.


4 WARRANTY

THE LOADER SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
WARRANTIES INCLUDING BUT WITHOUT LIMITATION THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE ARE
DISCLAIMED. THE PROVIDER DOES NOT WARRANT THAT THE LOADER IS UNINTERRUPTED
OR ERROR FREE, NOR THAT THE OPERATION OF THE LOADER WILL FUNCTION IN
CONJUNCTION WITH ANY OTHER PRODUCT.  


5 LIMITATION OF LIABILITY 

5.1 IN NO EVENT WILL THE PROVIDER OF THE LOADER BE LIABLE TO THE USER OR ANY
PARTY FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR OTHER
CONSEQUENTIAL DAMAGES ARISING DIRECTLY OR INDIRECTLY FROM THIS LICENCE
AGREEMENT OR ANY USE OF THE LOADER OR ENCODED FILES, EVEN IF THE PROVIDER IS
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

5.2 THE LOADER IS PROVIDED ON AN "AS IS" BASIS.  THE PROVIDER EXCLUDES ALL
WARRANTIES, CONDITIONS, TERMS, UNDERTAKINGS AND REPRESENTATIONS (EXCLUDING
FRAUDULENT MISREPRESENTATION) OF ANY KIND, EXPRESS OR IMPLIED, STATUTORY OR
OTHERWISE IN CONNECTION WITH THE LOADER TO THE FULLEST EXTENT PERMITTED BY
LAW.

5.3 DOWNLOADING THE LOADER IS AT YOUR OWN RISK AND THE PROVIDER DOES NOT
ACCEPT LIABILITY FOR ANY DIRECT OR INDIRECT LOSS OR DAMAGE HOWSOEVER CAUSED AS
A RESULT OF ANY COMPUTER VIRUSES, BUGS, TROJAN HORSES, WORMS, SOFTWARE BOMBS
OR OTHER SIMILAR PROGRAMS ARISING FROM YOUR USE OF THE LOADER.  WHILST THE
PROVIDER WILL DO ITS BEST TO ENSURE THAT THE LOADER IS FREE FROM SUCH
DESTRUCTIVE PROGRAMS, IT IS YOUR RESPONSIBILITY TO TAKE REASONABLE PRECAUTIONS
TO SCAN FOR SUCH DESTRUCTIVE PROGRAMS DOWNLOADED FROM THE INTERNET.

5.4 THE PROVIDER'S MAXIMUM LIABILITY FOR ANY LOSS OR DAMAGE ARISING FROM THIS
LICENCE AGREEMENT SHALL IN ANY EVENT BE LIMITED IN THE SOLE DISCRETION OF THE
PROVIDER TO THE REPLACEMENT OF THE LOADER PRODUCT.

5.5 DUE TO THE NATURE OF THE INTERNET, THE PROVIDER CANNOT GUARANTEE THAT ANY
E-MAILS OR OTHER ELECTRONIC TRANSMISSIONS WILL BE SENT TO YOU OR RECEIVED BY
THE PROVIDER OR THAT THE CONTENT OF SUCH TRANSMISSIONS WILL BE SECURE DURING
TRANSMISSION.


6 BUG FIXING AND PRODUCT SUPPORT 

6.1 The provider will use reasonable endeavours to provide support to users.
The provider will at their discretion only provide support for the latest
release.

6.2 Support comprises of fault reporting via tickets and fault diagnosis,
recommendations on workarounds, and where reasonably possible a timely
resolution.

6.3 The user accepts that on occasion the ability of the provider to meet
anticipated or published support schedules may be impaired due to, but without
limitation, Internet service provider failures or software failures that
affect the ability to communicate for an indeterminate period.

6.4 The provider reserves the right to refuse to provide support at any time.

6.5 The provider wishes to maintain and offer a product of the highest
possible quality, and accordingly may from time to time and at its discretion
make product changes for the purpose of correcting behaviour in variance to
the published specification or the user's reasonable expectations. 

6.6 The provider reserves the right to charge for support where the user does
not have a valid support plan in place, or where the support offered exceeds
the scope of the active support plan.


7 PRODUCT UPGRADES

7.1 The provider may from time to time release product upgrades. These will
be provided free of charge and attempts made to provide a timely notification
to customers of the existence of any new release.


8 ERRORS AND OMISSIONS

Whilst reasonable endeavours are made to ensure the accuracy of documentation
concerning the details of the Loader, the user accepts the possibility of
inaccuracies in information presented in any format, including email
communications and online services. The provider shall under no circumstances
be liable for any events that arise as a result of unintentional inaccuracies
or omissions.


9 USER INDEMNITY

You agree to fully indemnify, defend and hold the provider harmless
immediately upon demand from and against all actions, liability, claims,
losses, damages, costs and expenses (including legal/attorney fees) incurred
by the provider arising directly or indirectly as a result of your breach of
this Licence Agreement.


10 INTELLECTUAL PROPERTY RIGHTS

10.1 The user acknowledges that the Loader and associated documentation and
materials contain proprietary information of the provider and are and shall
remain the exclusive property of the provider and/or its licensors and all
title, copyright, trade marks, trade names, patents and other intellectual
property rights therein of whatever nature shall remain the sole property of
the provider and/or its licensors.

10.2 No title to or rights of ownership, copyright or other intellectual
property in the Loader is transferred to the user (other than the licence
rights expressly granted in this Licence Agreement).


11 TERMINATION

11.1 The provider reserves the right to terminate this Licence Agreement
immediately by notice in writing against the user if the user is in breach of
any terms and conditions of this Licence Agreement.

11.2 Termination of this Licence Agreement for any reason shall be without
prejudice to any other rights or remedies of the provider which may have
arisen on or before the date of termination under this Licence Agreement or in
law.

11.3 The provisions of the following clauses shall survive any termination of
this agreement; clause 3, 5, 10 and 13.


12 GENERAL

12.1 The provider reserves the right to transfer or assign all or any of its
rights and duties and responsibilities set out in this Licence Agreement to
another party.

12.2 Headings have been included for convenience only and will not be used in
construing any provision of this Licence Agreement.

12.3 No delay or failure by the provider to exercise any powers, rights or
remedies under this Licence Agreement will operate as a waiver of them nor
will any single or partial exercise of any such powers, rights or remedies
include any other or further exercise of them.

12.4 If any part of this Licence Agreement is found by a court of competent
jurisdiction or other competent authority to be invalid, unlawful or
unenforceable then such part shall be severed from the remainder of this
Licence Agreement which will continue to be valid and enforceable to the
fullest extent permitted by applicable law.

12.5 This Licence Agreement including the documents or other sources referred
to herein supersede all prior representations, understandings and agreements
between the user and the provider relating to the Loader and sets forth the
entire agreement and understanding between the user and the provider relating
to the Loader.

12.6 Nothing in this Licence Agreement shall be deemed to constitute a
partnership between you and the provider nor constitute either party being an
agent of the other party.

12.7 This Agreement does not create any rights or benefits enforceable by any
person not a party to it (within the meaning of the U.K.Contracts (Rights of
Third Parties) Act 1999) except that a person who under clause 12.1 is a
permitted successor or assignee of the rights or benefits of the provider may
enforce such rights or benefits.


13 GOVERNING LAW AND JURISDICTION

This License Agreement and any issues relating thereto shall be construed and
interpreted in accordance with the laws of England and subject to the
exclusive jurisdiction of the English courts.

Copyright (c) 2002-2024 ionCube Ltd.          Last revised 23-April-2015
alt-php72-ioncube-loader/loader-wizard.php000064400000541746150413456440014454 0ustar00<?php // -*- c++ -*-

/** 
 * ionCube Loader install Wizard
 *
 * ionCube is a registered trademark of ionCube Ltd. 
 *
 * Copyright (c) ionCube Ltd. 2002-2022
 */


 

define ('ERROR_UNKNOWN_OS',1);
define ('ERROR_UNSUPPORTED_OS',2);
define ('ERROR_UNKNOWN_ARCH',3);
define ('ERROR_UNSUPPORTED_ARCH',4);
define ('ERROR_UNSUPPORTED_ARCH_OS',5);
define ('ERROR_WINDOWS_64_BIT',6);
define ('ERROR_PHP_UNSUPPORTED',7);
define ('ERROR_PHP_DEBUG_BUILD',8);
define ('ERROR_RUNTIME_EXT_DIR_NOT_FOUND',101);
define ('ERROR_RUNTIME_LOADER_FILE_NOT_FOUND',102);
define ('ERROR_INI_NOT_FIRST_ZE',201);
define ('ERROR_INI_WRONG_ZE_START',202);
define ('ERROR_INI_ZE_LINE_NOT_FOUND',203);
define ('ERROR_INI_LOADER_FILE_NOT_FOUND',204);
define ('ERROR_INI_NOT_FULL_PATH',205);
define ('ERROR_INI_NO_PATH',206);
define ('ERROR_INI_NOT_FOUND',207);
define ('ERROR_INI_NOT_READABLE',208);
define ('ERROR_INI_MULTIPLE_IC_LOADER_LINES',209);
define ('ERROR_INI_USER_INI_NOT_FOUND',210);
define ('ERROR_INI_USER_CANNOT_CREATE',211);
define ('ERROR_LOADER_UNEXPECTED_NAME',301);
define ('ERROR_LOADER_NOT_READABLE',302);
define ('ERROR_LOADER_PHP_MISMATCH',303);
define ('ERROR_LOADER_NONTS_PHP_TS',304);
define ('ERROR_LOADER_TS_PHP_NONTS',305);
define ('ERROR_LOADER_WRONG_OS',306);
define ('ERROR_LOADER_WRONG_ARCH',307);
define ('ERROR_LOADER_WRONG_GENERAL',308);
define ('ERROR_LOADER_WIN_SERVER_NONWIN',321);
define ('ERROR_LOADER_WIN_NONTS_PHP_TS',322);
define ('ERROR_LOADER_WIN_TS_PHP_NONTS',323);
define ('ERROR_LOADER_WIN_PHP_MISMATCH',324);
define ('ERROR_LOADER_WIN_COMPILER_MISMATCH',325);
define ('ERROR_LOADER_NOT_FOUND',380);
define ('ERROR_LOADER_PHP_VERSION_UNKNOWN',390);


define ('SERVER_UNKNOWN',0);
define ('HAS_PHP_INI',1);
define ('SERVER_SHARED',2); 
define ('SERVER_VPS',5); 
define ('SERVER_DEDICATED',7); 
define ('SERVER_LOCAL',9);

define ('IONCUBE_IP_ADDRESS',
			'94.101.154.134');
define  ('IONCUBE_ACCESS_ADDRESS',
			'lwaccess.ioncube.com');
define ('LOADERS_PAGE',
            'https://loaders.ioncube.com/'); 
define ('SUPPORT_SITE',
            'https://support.ioncube.com/');                                 
define ('WIZARD_SUPPORT_TICKET_DEPARTMENT',
			'3');
define ('LOADER_FORUM_URL',
            'https://forum.ioncube.com/viewforum.php?f=4');                  
define ('LOADERS_FAQ_URL',
            'https://www.ioncube.com/faqs/loaders.php');                     
define ('UNIX_ERRORS_URL',
            'https://www.ioncube.com/loaders/unix_startup_errors.php');      
define ('LOADER_WIZARD_URL',
            LOADERS_PAGE);                                                  
define ('ENCODER_URL',
            'https://www.ioncube.com/sa_encoder.php');                       
define ('LOADER_VERSION_URL',
            'https://www.ioncube.com/feeds/product_info/versions.php');    
define ('WIZARD_LATEST_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-wizard'); 
define ('PHP_COMPILERS_URL',
            LOADER_VERSION_URL . '?item=php-compilers');
define ('LOADER_PLATFORM_URL',
            LOADER_VERSION_URL . '?item=loader-platforms-all');   
define ('LOADER_LATEST_VERSIONS_URL',
            LOADER_VERSION_URL . '?item=loader-versions'); 
define ('LOADER_PHP_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-php-support'); 
define ('WIZARD_STATS_URL',
            'https://www.ioncube.com/feeds/stats/wizard.php');    
define ('IONCUBE_DOWNLOADS_SERVER',
            'https://downloads.ioncube.com/loader_downloads');          
define ('IONCUBE24_URL',
			'https://ioncube24.com');
define ('IONCUBE_CONNECT_TIMEOUT',4);

define ('DEFAULT_SELF','/ioncube/loader-wizard.php');
define ('LOADER_NAME_CHECK',true);
define ('LOADER_EXTENSION_NAME','ionCube Loader');
define ('LOADER_SUBDIR','ioncube');
define ('WINDOWS_IIS_LOADER_DIR', 'system32');
define ('ADDITIONAL_INI_FILE_NAME','00-ioncube.ini');
define ('UNIX_SYSTEM_LOADER_DIR','/usr/local/ioncube');
define ('RECENT_LOADER_VERSION','4.0.7');
define ('LATEST_LOADER_MAJOR_VERSION',12);
define ('LOADERS_PACKAGE_PREFIX','ioncube_loaders_');
define ('SESSION_LIFETIME_MINUTES',360);
define ('WIZARD_EXPIRY_MINUTES',2880);
define ('IONCUBE_WIZARD_EXPIRY_MINUTES',10080);
define ('MIN_INITIALISE_TIME',4);
define ('IC24_ENABLED_INI_PROPERTY',"ic24.enable");

    run();


function php4_http_build_query($formdata, $numeric_prefix = null, $key = null ) {
    $res = array();
    foreach ((array)$formdata as $k=>$v) {
        $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
        if ($key) $tmp_key = $key.'['.$tmp_key.']';
        if ( is_array($v) || is_object($v) ) {
            $res[] = php4_http_build_query($v, null , $tmp_key);
        } else {
            $res[] = $tmp_key."=".urlencode($v);
        }
   }
   $separator = ini_get('arg_separator.output');
   return implode($separator, $res);
}


function script_version()
{
    return "2.73";
}

function retrieve_latest_wizard_version()
{
    $v = false;

    $s = trim(remote_file_contents(WIZARD_LATEST_VERSION_URL));
    if (preg_match('/^\d+([.]\d+)*$/', $s)) {
        $v = $s;
    }

    return $v;
}

function latest_wizard_version()
{
    if (!isset($_SESSION['latest_wizard_version'])) {
        $_SESSION['latest_wizard_version'] = retrieve_latest_wizard_version();
    } 
    return $_SESSION['latest_wizard_version'];
}

function update_is_available($lv)
{
    if (is_numeric($lv)) {
        $lv_parts = explode('.',$lv);
        $script_parts = explode('.',script_version());
        return ($lv_parts[0] > $script_parts[0] || ($lv_parts[0] == $script_parts[0] && $lv_parts[1] > $script_parts[1]));
    } else {
        return null;
    }
}

function check_for_wizard_update($echo_message = false)
{
    $latest_version = latest_wizard_version();
    $update_available = update_is_available($latest_version);

    if ($update_available) {
        if ($echo_message) {
            echo '<p class="alert">An updated version of this Wizard script is available <a href="' . LOADER_WIZARD_URL . '">here</a>.</p>';
        }
        return $latest_version;
    } else {
        return $update_available;
    }
}


function remote_file_contents($url)
{
    $remote_file_opening = ini_get('allow_url_fopen');
    $contents = false;
    if (isset($_SESSION['timing_out']) && $_SESSION['timing_out']) {
        return false;
    }
    @session_write_close();
    $timing_out = 0;
    if ($remote_file_opening) {
        $fh = @fopen($url,'rb');
        if ($fh) {
            stream_set_blocking($fh,0);
            stream_set_timeout($fh,IONCUBE_CONNECT_TIMEOUT);
            while (!feof($fh)) {
                $result = fread($fh, 8192);
                $info = stream_get_meta_data($fh);
                $timing_out = $info['timed_out']?1:0;
                if ($timing_out) {
                    break;
                }
                if ($result !== false) {
                    $contents .= $result;
                } else {
                    break;
                }
            }
            fclose($fh);
        } else {
            $timing_out = 1;
        }
    } elseif (extension_loaded('curl')) {
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,IONCUBE_CONNECT_TIMEOUT);
            $output = curl_exec($ch);
            $info = curl_getinfo($ch);
            $timing_out = ($info['http_code'] >= 400)?1:0;
            curl_close($ch);

            if (is_string($output)) {
                $contents = $output;
            }
    } else {
        $timing_out = 1;
    }
    @session_start();
    $_SESSION['timing_out'] = $timing_out;
    return $contents;
}

function php_version()
{
    $v = explode('.',PHP_VERSION);

    return array(
           'major'      =>  $v[0],
           'minor'      =>  $v[1],
           'release'    =>  $v[2]);
}

function php_version_maj_min()
{
    $vprts = php_version();
    return ($vprts['major'] . '.' . $vprts['minor']);
}

function is_supported_php_version()
{
    $v = php_version(); 

    return ((($v['major'] == 4) && ($v['minor'] >= 1)) ||
      (($v['major'] == 5) && (($v['minor'] >= 1) || ($v['release'] >= 3))) ||
	  $v['major'] == 7 || ($v['major'] == 8 && $v['minor'] >= 1));
}

function is_php_version_or_greater($major,$minor,$release = 0)
{
    $version = php_version();
    return ($version['major'] > $major || 
            ($version['major'] == $major && $version['minor'] > $minor) ||
            ($version['major'] == $major && $version['minor'] == $minor && $version['release'] >= $release));
}

function ini_file_name()
{
    $sysinfo = get_sysinfo();
    return (!empty($sysinfo['PHP_INI'])?$sysinfo['PHP_INI_BASENAME']:'php.ini');
}

function get_remote_session_value($session_var,$remote_url,$default_function)
{
    if (!isset($_SESSION[$session_var])) {
        $serialised_res = remote_file_contents($remote_url);
        $unserialised_res = @unserialize($serialised_res);
        if (empty($unserialised_res)) {
            $unserialised_res = call_user_func($default_function);
        } else {
			$_SESSION['remote_access_successful'] = 1;
		}
        if (false === $unserialised_res) {
            $unserialised_res = '';
        }
        $_SESSION[$session_var] = $unserialised_res;
    }
    return $_SESSION[$session_var];
}

function get_file_contents($file)
{
    if (function_exists('file_get_contents')) {
        $strs = @file_get_contents($file);
    } else {
        $lines = @file($file);
        $strs = join(' ',$lines);
    }
    return $strs;
}

function default_platform_list()
{
    $platforms = array();


    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6', 'is_legacy' => 1,       'os_mod' => '_vc6',     'arch'=>'x86',  'dirname'=>'win32', 'us1-dir'=>'windows_vc6/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6 (Non-TS)',   'is_legacy' => 1,  'os_mod' => '_nonts_vc6',   'arch'=>'x86',  'dirname'=>'win32-nonts', 'us1-dir'=>'windows_vc6/x86-nonts' );

    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9',        'os_mod' => '_vc9',     'arch'=>'x86',  'dirname'=>'win32_vc9', 'us1-dir'=>'windows_vc9/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9 (Non-TS)',   'os_mod' => '_nonts_vc9',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc9', 'us1-dir'=>'windows_vc9/x86-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86',  'dirname'=>'win32_vc11', 'us1-dir'=>'windows_vc11/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc11', 'us1-dir'=>'windows_vc11/x86-nonts' );
	
	$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86-64',  'dirname'=>'win64_vc11', 'us1-dir'=>'windows_vc11/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc11', 'us1-dir'=>'windows_vc11/amd64-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86',  'dirname'=>'win32_vc14', 'us1-dir'=>'windows_vc14/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc14', 'us1-dir'=>'windows_vc14/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86-64',  'dirname'=>'win64_vc14', 'us1-dir'=>'windows_vc14/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc14', 'us1-dir'=>'windows_vc14/amd64-nonts' );
	
		 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86',  'dirname'=>'win32_vc15', 'us1-dir'=>'windows_vc15/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc15', 'us1-dir'=>'windows_vc15/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86-64',  'dirname'=>'win64_vc15', 'us1-dir'=>'windows_vc15/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc15', 'us1-dir'=>'windows_vc15/amd64-nonts' );

    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86',      'dirname'=>'linux_i686-glibc2.3.4', 'us1-dir'=>'linux/x86');
    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86-64',   'dirname'=>'linux_x86_64-glibc2.3.4', 'us1-dir'=>'linux/x86_64');
$platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc',      'dirname'=>'linux_ppc-glibc2.3.4','us1-dir'=>'linux/ppc');
            $platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc64',    'dirname'=>'linux_ppc64-glibc2.5','us1-dir'=>'linux/ppc64');
    

$platforms[] = array('os'=>'dra', 'os_human'=>'DragonFly', 'arch'=>'x86',      'dirname'=>'dragonfly_i386-1.7', 'us1-dir'=>'Dragonfly/x86');

$platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 4', 'os_mod'=>'_4',  'arch'=>'x86',      'dirname'=>'freebsd_i386-4.8', 'us1-dir'=>'FreeBSD/v4');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86',      'dirname'=>'freebsd_i386-6.2', 'us1-dir'=>'FreeBSD/v6/x86');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-6.2', 'us1-dir'=>'FreeBSD/v6/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86',      'dirname'=>'freebsd_i386-7.3', 'us1-dir'=>'FreeBSD/v7/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-7.3', 'us1-dir'=>'FreeBSD/v7/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86',      'dirname'=>'freebsd_i386-8.0', 'us1-dir'=>'FreeBSD/v8/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-8.0', 'us1-dir'=>'FreeBSD/v8/AMD64');
    
    $platforms[] = array('os'=>'bsd', 'os_human'=>'BSDi',     'is_legacy' => 1,           'arch'=>'x86',      'dirname'=>'bsdi_i386-4.3.1');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86',      'dirname'=>'netbsd_i386-2.1','us1-dir'=>'NetBSD/x86');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86-64',   'dirname'=>'netbsd_amd64-2.0','us1-dir'=>'NetBSD/x86_64');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.2', 'os_mod'=>'_4.2',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.2', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.5', 'os_mod'=>'_4.5',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.5', 'us1-dir'=>'OpenBSD/x86');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.6', 'os_mod'=>'_4.6',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.6', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.7', 'os_mod'=>'_4.7',  'arch'=>'x86-64', 'dirname'=>'openbsd_amd64-4.7', 'us1-dir' => 'OpenBSD/x86_64');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',    'is_legacy' => 1, 'arch'=>'ppc',      'dirname'=>'osx_powerpc-8.5','us1-dir'=>'OSX/ppc');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86',      'dirname'=>'osx_i386-8.11','us1-dir'=>'OSX/x86');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86-64',       'dirname'=>'osx_x86-64-10.2','us1-dir'=>'OSX/x86_64');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',  'is_legacy' => 1,          'arch'=>'sparc',    'dirname'=>'solaris_sparc-5.9', 'us1-dir'=>'Solaris/sparc');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',            'arch'=>'x86',      'dirname'=>'solaris_i386-5.10','us1-dir'=>'Solaris/x86');

    return $platforms;
}

function get_loader_platforms()
{
    return get_remote_session_value('loader_platform_info',LOADER_PLATFORM_URL,'default_platform_list');
}

function get_platforminfo()
{
    static $platforminfo;

    if (empty($platforminfo)) {
        $platforminfo = get_loader_platforms();
    }
    return $platforminfo;
}

function default_php_versions()
{
	return array();
}

function get_php_versions()
{
	return get_remote_session_value('php_version_info',LOADER_PHP_VERSION_URL,'default_php_versions');
}


function get_max_php_version_supported()
{
	static $max_php_version;
	
	if (empty($max_php_version)) {
		$php_versions = get_php_versions();
		
		$dirname = calc_dirname();
		
		if (array_key_exists($dirname,$php_versions)) {
			$max_php_version = $php_versions[$dirname];
		} else {
			$max_php_version = NULL;
		}
	}
	
	return $max_php_version;
}

function is_after_max_php_version_supported()
{
	$is_too_recent_php = false;
	
	$supported_php_version = get_max_php_version_supported();
	
	if (!is_null($supported_php_version)) {
		$pversion = php_version();
		
		$supported_parts = explode('.',$supported_php_version);
		$is_too_recent_php = ($supported_parts[0] < $pversion['major'] || ($supported_parts[0] == $pversion['major'] && $supported_parts[1] < $pversion['minor']));
	}
	
	if ($is_too_recent_php) {
		return $supported_php_version;
	} else {
		return false;
	}
}

function supported_os_variants($os_code,$arch_code)
{
    if (empty($os_code)) {
        return ERROR_UNKNOWN_OS;
    }
    if (empty($arch_code)) {
        return ERROR_UNKNOWN_ARCH;
    }

    $os_found = false;
    $arch_found = false;
    $os_arch_matches = array();
    $pinfo = get_platforminfo();

    foreach ($pinfo as $p) {
        if ($p['os'] == $os_code && $p['arch'] == $arch_code) {
            $os_arch_matches[$p['os_human']] = (isset($p['os_mod']))?(0 + (int) str_replace('_','',$p['os_mod'])):'';
        } 
        if ($p['os'] == $os_code) {
            $os_found = true;
        } elseif ($p['arch'] == $arch_code) {
            $arch_found = true;
        }
    }
    if (!empty($os_arch_matches)) {
        asort($os_arch_matches);
        return $os_arch_matches;
    } elseif (!$os_found) {
        return ERROR_UNSUPPORTED_OS;
    } elseif (!$arch_found) {
        return ERROR_UNSUPPORTED_ARCH;
    } else {
        return ERROR_UNSUPPORTED_ARCH_OS;
    }
}

function default_win_compilers()
{
    return array('VC6','VC9','VC11','VC14','VC15', 'VC16');
}

function supported_win_compilers()
{
    static $win_compilers;

    if (empty($win_compilers)) {
        $win_compilers = find_win_compilers();
    }
    return $win_compilers;
}

function find_win_compilers()
{
    return get_remote_session_value('php_compilers_info',PHP_COMPILERS_URL,'default_win_compilers');
}

function server_software_info()
{
    $ss = array('full' => '','short' => '');
    $ss['full'] = $_SERVER['SERVER_SOFTWARE'];

    if (preg_match('/apache/i', $ss['full'])) {
        $ss['short'] = 'Apache';
    } else if (preg_match('/IIS/',$ss['full'])) {
        $ss['short'] = 'IIS';
    } else {
        $ss['short'] = '';
    }
    return $ss;
}

function match_arch_pattern($str)
{
    $arch = null;
    $arch_patterns = array(
             'i.?86'        => 'x86',
             'x86[-_]64'    => 'x86',
             'x86'          => 'x86',
             'amd64'        => 'x86',
             'SMP Tue Jan 01 00:00:00 CEST 2000 all GNU\/Linux' => 'x86',
             'ppc64'        => 'ppc',
             'ppc'          => 'ppc',
             'powerpc'      => 'ppc',
             'sparc'        => 'sparc',
             'sun'          => 'sparc',
			 'armv7l'       => 'armv7l',
             'aarch64'      => 'aarch64'
         );

    foreach ($arch_patterns as $token => $a) {
        if (preg_match("/$token/i", $str)) {
          $arch = $a;
          break;
        }
    }
    return $arch;
}

function required_loader_arch($mach_info,$os_code,$wordsize)
{
    if ($os_code == 'win') {
        $arch = ($wordsize == 32)?'x86':'x86-64';
    } elseif (!empty($os_code)) {
        $arch = match_arch_pattern($mach_info);
        if ($wordsize == 64) {
            if ($arch == 'x86') {
                $arch = 'x86-64';
            } elseif ($arch == 'ppc') {
                $arch = 'ppc64';
            }
        }
    } else {
        $arch = ERROR_UNKNOWN_ARCH;
    }
    return $arch;
}

function uname($part = 'a')
{
    $result = '';
    if (!function_is_disabled('php_uname')) {
        $result = @php_uname($part);
    } elseif (function_exists('posix_uname') && !function_is_disabled('posix_uname')) {
        $posix_equivs = array(
                     'm' => 'machine',
                     'n' => 'nodename',
                     'r' => 'release',
                     's' => 'sysname'
                 );
        $puname = @posix_uname();
        if ($part == 'a' || !array_key_exists($part,$posix_equivs)) {
           $result = join(' ',$puname);
        } else {
           $result = $puname[$posix_equivs[$part]];
        }
    } else {
        if (!function_is_disabled('phpinfo')) {
            ob_start();
            phpinfo(INFO_GENERAL);
            $pinfo = ob_get_contents();
            ob_end_clean();
            if (preg_match('~System.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$match)) {
                $uname = $match[2];
                if ($part == 'r') {
                    if (!empty($uname) && preg_match('/\S+\s+\S+\s+([0-9.]+)/',$uname,$matchver)) {
                        $result = $matchver[1];
                    } else {
                        $result = '';
                    }
                } else {
                    $result = $uname;
                }
            }
        } else {
            $result = '';
        }
    }
    return $result;
}

function calc_word_size($os_code)
{
    $wordsize = null;
    if ('win' === $os_code) {
        ob_start();
        phpinfo(INFO_GENERAL);
        $pinfo = ob_get_contents();
        ob_end_clean();
        if (preg_match('~Compiler.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$compmatch)) {
            if (preg_match("/(VC[0-9]+)/i",$compmatch[2],$vcmatch)) {
                $compiler = strtoupper($vcmatch[1]);
            } elseif (stripos(trim($compmatch[2]),"Visual C++ 2019") === 0) {
                $compiler = 'VC16';
            } else {
                $compiler = 'VC6';
            }
        } else {
            $compiler = 'VC6';
        }
        if ($compiler === 'VC9' || $compiler === 'VC11' || $compiler === 'VC14' 
                || $compiler === 'VC15' || $compiler === 'VC16') {
			if (preg_match('~Architecture.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$archmatch)) {
				if (preg_match("/x64/i",$archmatch[2])) {
					$wordsize = 64;
				} else {
					$wordsize = 32;
				}
            } elseif (isset($_ENV['PROCESSOR_ARCHITECTURE']) && preg_match('~(amd64|x86-64|x86_64)~i',$_ENV['PROCESSOR_ARCHITECTURE'])) {
                if (preg_match('~Configure Command.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$confmatch)) {
                    if (preg_match('~(x64|lib64|system64)~i',$confmatch[2])) {
                        $wordsize = 64;
                    }
                }
            } else {
				$wordsize = 32;
			}
        }
    }
    if (empty($wordsize)) {
        $wordsize = ((-1^0xffffffff)?64:32);
    }
    return $wordsize;
}

function required_loader($unamestr = '')
{
    $un = empty($unamestr)?uname():$unamestr;

    $php_major_version = substr(PHP_VERSION,0,3);

    $os_name = substr($un,0,strpos($un,' '));
    $os_code = empty($os_name)?'':strtolower(substr($os_name,0,3));

    $wordsize = calc_word_size($os_code);

	if ($os_code == 'win' && $wordsize == 64 && $php_major_version < '5.5') {
        $arch = ERROR_WINDOWS_64_BIT;
	} else {
		$arch = required_loader_arch($un,$os_code,$wordsize);
	}
    if (!is_string($arch)) {
        return $arch;
    }
    $os_variants = supported_os_variants($os_code,$arch);
    if (!is_array($os_variants)) {
        return $os_variants;
    }

    $os_ver = '';
    if (preg_match('/([0-9.]+)/',uname('r'),$match)) {
        $os_ver = $match[1];
    }
    $os_ver_parts = preg_split('@\.@',$os_ver);

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $loader_sfix = (($os_code == 'win') ? 'dll' : 'so');
    $file = "ioncube_loader_{$os_code_h}_{$php_major_version}.{$loader_sfix}";

    if ($os_code == 'win') {
        $os_name = 'Windows';
        $file_ts = $file;
        $os_name_qual = 'Windows';
    } else {
        $os_names = array_keys($os_variants);
        if (count($os_variants) > 1) {
            $parts = explode(" ",$os_names[0]); 
            $os_name = $parts[0];
            $os_name_qual = $os_name . ' ' . $os_ver_parts[0] . '.' . $os_ver_parts[1];
        } else {
            $os_name = $os_names[0];
            $os_name_qual = $os_name;
        }
        $file_ts = "ioncube_loader_{$os_code_h}_{$php_major_version}_ts.{$loader_sfix}";
    }

    return array(
           'uname'      =>  $un,
           'arch'       =>  $arch,
           'oscode'     =>  $os_code,
           'oscode_h'   =>  $os_code_h,
           'osname'     =>  $os_name,
           'osnamequal' =>  $os_name_qual,
           'osvariants' =>  $os_variants,
           'osver'      =>  $os_ver,
           'osver2'     =>  $os_ver_parts,
           'file'       =>  $file,
           'file_ts'    =>  $file_ts,
           'wordsize'   =>  $wordsize
       );
}

function ic_system_info()
{
    $thread_safe = null;
    $debug_build = null;
    $cgi_cli = false;
	$is_fpm = false;
    $is_cgi = false;
    $is_cli = false;
    $php_ini_path = '';
    $php_ini_dir = '';
    $php_ini_add = '';
    $is_supported_compiler = true;
    $php_compiler = is_ms_windows()?'VC6':'';

    ob_start();
    phpinfo(INFO_GENERAL);
    $php_info = ob_get_contents();
    ob_end_clean();

    $breaker = (php_sapi_name() == 'cli')?"\n":'</tr>';
    $lines = explode($breaker,$php_info);
    foreach ($lines as $line) {
        if (preg_match('/command/i',$line)) {
          continue;
        }

        if (preg_match('/thread safety/i', $line)) {
          $thread_safe = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('/debug build/i', $line)) {
          $debug_build = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('~configuration file.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
          $php_ini_path = $match[2];

          if (!@file_exists($php_ini_path)) {
                $php_ini_path = '';
          }
        }
        if (preg_match('~dir for additional \.ini files.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_dir = $match[2];
            if (!@file_exists($php_ini_dir)) {
                $php_ini_dir = '';
            }
        }
        if (preg_match('~additional \.ini files parsed.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_add = $match[2];
        }
        if (preg_match('/compiler/i',$line)) {
            $supported_match = join('|',supported_win_compilers());
            $is_supported_compiler = preg_match("/($supported_match)/i",$line);
            if (preg_match("/(VC[0-9]+)/i",$line,$match)) {
                $php_compiler = strtoupper($match[1]);
            } elseif (preg_match("/Visual C\+\+ 2017/i",$line)) {
				$php_compiler = "VC15";
				$is_supported_compiler = true;
            } elseif (preg_match("/Visual C\+\+ 2019/i",$line)) {
				$php_compiler = "VC16";
				$is_supported_compiler = true;
			} else {
                $php_compiler = '';
            }
        }
    }
    $is_cgi = strpos(php_sapi_name(),'cgi') !== false;
    $is_cli = strpos(php_sapi_name(),'cli') !== false;
	$is_fpm = strpos(php_sapi_name(),'fpm-fcgi') !== false;
    $cgi_cli = $is_cgi || $is_cli;

    $ss = server_software_info();
	
	if ($is_fpm) {
		$ss['short'] = 'PHP-FPM';
		$ss['full'] = 'PHP-FPM ' . $ss['full'];
	}

    if (!$php_ini_path && function_exists('php_ini_loaded_file')) {
        $php_ini_path = php_ini_loaded_file();
        if ($php_ini_path === false) {
            $php_ini_path = '';
        }
    }
    if (!empty($php_ini_path)) {
        $real_path = @realpath($php_ini_path);
        if (false !== $real_path) {
            $php_ini_path = $real_path;
        }
    }

    $php_ini_basename = basename($php_ini_path);

    return array(
           'THREAD_SAFE'        => $thread_safe,
           'DEBUG_BUILD'        => $debug_build,
           'PHP_INI'            => $php_ini_path,
           'PHP_INI_BASENAME'   => $php_ini_basename,
           'PHP_INI_DIR'        => $php_ini_dir,
           'PHP_INI_ADDITIONAL' => $php_ini_add,
           'PHPRC'              => getenv('PHPRC'),
           'CGI_CLI'            => $cgi_cli,
           'IS_CGI'             => $is_cgi,
           'IS_CLI'             => $is_cli,
		   'IS_FPM'				=> $is_fpm,
           'PHP_COMPILER'       => $php_compiler,
           'SUPPORTED_COMPILER' => $is_supported_compiler,
           'FULL_SS'            => $ss['full'],
           'SS'                 => $ss['short']);
}

function is_possibly_dedicated_or_local()
{
    $sys = get_sysinfo();

    return (empty($sys['PHP_INI']) || !@file_exists($sys['PHP_INI']) || (is_readable($sys['PHP_INI']) && (0 !== strpos($sys['PHP_INI'],$_SERVER['DOCUMENT_ROOT']))));
}

function is_local()
{
    $ret = false;
    if ($_SERVER["SERVER_NAME"] == 'localhost') {
        $ret = true;
    } else {
        $ip_address = strtolower($_SERVER["REMOTE_ADDR"]);
        if (strpos(':',$ip_address) === false) {
            $ip_parts = explode('.',$ip_address);
            $ret = (($ip_parts[0] == 10) || 
                    ($ip_parts[0] == 172 && $ip_parts[1] >= 16 &&  $ip_parts[1] <= 31) ||
                    ($ip_parts[0] == 192 && $ip_parts[1] == 168));
        } else {
            $ret = ($ip_address == '::1') || (($ip_address[0] == 'f') && ($ip_address[1] >= 'c' && $ip_address[1] <= 'f'));
        }
    }
    return $ret;
}

function is_shared()
{
    return !is_local() && !is_possibly_dedicated_or_local();
}

function find_server_type($chosen_type = '',$type_must_be_chosen = false,$set_session = false)
{
    $server_type = SERVER_UNKNOWN;
    if (empty($chosen_type)) {
        if ($type_must_be_chosen) {
            $server_type = SERVER_UNKNOWN;
        } else {
            if (isset($_SESSION['server_type']) && $_SESSION['server_type'] != SERVER_UNKNOWN) {
                $server_type = $_SESSION['server_type'];
            } elseif (is_local()) {
                $server_type = SERVER_LOCAL;
            } elseif (!is_possibly_dedicated_or_local()) {
                $server_type = SERVER_SHARED;
            } else {
                $server_type = SERVER_UNKNOWN;
            } 
        }
    } else {
        switch ($chosen_type)  {
            case 's':
                $server_type = SERVER_SHARED;
                break;
            case 'd':
                $server_type = SERVER_DEDICATED;
                break;
            case 'l':
                $server_type = SERVER_LOCAL;
                break;
            default:
                $server_type = SERVER_UNKNOWN;
                break;
        }
    }
    if ($set_session) {
        $_SESSION['server_type'] = $server_type;
    }
    return $server_type;
}

function server_type_string()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_string = 'SHARED';
            break;
        case SERVER_LOCAL:
            $server_string = 'LOCAL';
            break;
        case SERVER_DEDICATED:
            $server_string = 'DEDICATED';
            break;
        default:
            $server_string = 'UNKNOWN';
            break;
    }
    return $server_string;
}

function server_type_code()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_char = 's';
            break;
        case SERVER_LOCAL:
            $server_char = 'l';
            break;
        case SERVER_DEDICATED:
            $server_char = 'd';
            break;
        default:
            $server_char = '';
            break;
    }
    return $server_char;
}

function get_sysinfo()
{
    static $sysinfo;

    if (empty($sysinfo)) {
        $sysinfo = ic_system_info();
    }
    return $sysinfo;
}

function get_loaderinfo()
{
    static $loader;

    if (empty($loader)) {
        $loader = required_loader();
    }
    return $loader;
}

function is_ms_windows()
{
    $loader_info = get_loaderinfo();
    return ($loader_info['oscode'] == 'win');
}

function function_is_disabled($fn_name)
{
    $disabled_functions=explode(',',ini_get('disable_functions'));
    return in_array($fn_name, $disabled_functions);
}

function selinux_is_enabled()
{
    $se_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('sestatus');
        $se_enabled = preg_match('/enabled/i',$cmd);
    }

    return $se_enabled;
}

function grsecurity_is_enabled()
{
    $gr_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('gradm -S');
        $gr_enabled = preg_match('/enabled/i',$cmd);
    }

    return $gr_enabled;
}

function threaded_and_not_cgi()
{
    $sys = get_sysinfo();
    return($sys['THREAD_SAFE'] && !$sys['IS_CGI']);
}

function is_restricted_server($only_safe_mode = false)
{
    $disable_functions = ini_get('disable_functions');
    $open_basedir = ini_get('open_basedir');
    $php_restrictions = !empty($disable_functions) || !empty($open_basedir);
    $system_restrictions = selinux_is_enabled() || grsecurity_is_enabled();
    $non_safe_mode_restrictions = $php_restrictions || $system_restrictions;
    return (ini_get('safe_mode') || (!$only_safe_mode && $non_safe_mode_restrictions));
}

function server_restriction_warnings()
{
    $warnings = array();

    if (find_server_type() == SERVER_SHARED) {
        if (is_restricted_server()) {
            $warnings[] = "Server restrictions are in place which might affect the operation of this Loader Wizard or prevent the installation of the Loader.";
        }
    } else {
        $warning_suffix = "This may affect the operation of this Loader Wizard.";
        if (ini_get('safe_mode')) {
            $warnings[] = "Safe mode is in effect on the server. " . $warning_suffix;
        } 
        $disabled_functions = ini_get('disable_functions');
        if (!empty($disabled_functions)) {
            $warnings[] = "Some functions are disabled through disable_functions. " . $warning_suffix;
        }
        $open_basedir = ini_get('open_basedir');
        if (!empty($open_basedir)) {
            $warnings[] = "Open basedir restrictions are in effect. " . $warning_suffix;
        }
    }
    return $warnings;
}

function own_php_ini_possible($only_safe_mode = false)
{
    $sysinfo = get_sysinfo();
    return ($sysinfo['CGI_CLI'] && !is_ms_windows() && !is_restricted_server($only_safe_mode));
}

function extension_dir()
{
    $extdir = ini_get('extension_dir');
    if ($extdir == './' || ($extdir == '.\\' && is_ms_windows())) {
        $extdir = '.';
    }
    return $extdir;
}

function possibly_selinux()
{
    $loaderinfo = get_loaderinfo();
    $se_env = (getenv("SELINUX_INIT"));
    return (strtolower($loaderinfo['osname']) == 'linux' && $se_env && ($se_env == 'Yes' || $se_env == '1'));
}

function ini_same_dir_as_wizard()
{
    $sys = get_sysinfo();
    return dirname($sys['PHP_INI']) == dirname(__FILE__); 
}

function extension_dir_path()
{
    $ext_dir = extension_dir();
    if ($ext_dir == '.' || (dirname($ext_dir) == '.')) {
        $ext_dir_path = @realpath($ext_dir);
    } else {
        $ext_dir_path = $ext_dir;
    }
    return $ext_dir_path;
}

function get_loader_name()
{
    $u = uname();
    $sys = get_sysinfo();
    $os = substr($u,0,strpos($u,' '));
    $os_code = strtolower(substr($u,0,3));

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $php_version = phpversion();
    $php_family = substr($php_version,0,3);

    $loader_sfix = (($os_code == 'win') ? '.dll' : (($sys['THREAD_SAFE'])?'_ts.so':'.so'));
    $loader_name="ioncube_loader_{$os_code_h}_{$php_family}{$loader_sfix}";

    return $loader_name;
}

function get_reqd_version($variants)
{
    $exact_match = false;
    $nearest_version = 0;
    $loader_info = get_loaderinfo();
    $os_version = $loader_info['osver2'][0] . '.' . $loader_info['osver2'][1];
    $os_version_major = $loader_info['osver2'][0];
    foreach ($variants as $v) {
        if ($v == $os_version || (is_int($v) && $v == $os_version_major)) {
            $exact_match = true;
            $nearest_version = $v;
            break;
        } elseif ($v > $os_version) {
            break;
        } else {
            $nearest_version = $v;
        }
    }
    return (array($nearest_version,$exact_match));
}

function get_default_loader_dir_webspace()
{
    return ($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . LOADER_SUBDIR);
}

function get_loader_location($loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = get_default_loader_dir_webspace();
    }
    $loader_name = get_loader_name(); 
    return ($loader_dir . DIRECTORY_SEPARATOR . $loader_name);
}

function get_loader_location_from_ini($php_ini = '')
{
    $errors = array();
    if (empty($php_ini)) {
        $sysinfo = get_sysinfo();
        $php_ini = $sysinfo['PHP_INI'];
    }
    if (!@file_exists($php_ini)) {
        if (empty($php_ini)) {
            $errors[ERROR_INI_NOT_FOUND] = "The configuration file could not be found.";
        } else {
            $errors[ERROR_INI_NOT_FOUND] = "The $php_ini file could not be found.";
        }
    } elseif (!is_readable($php_ini)) {
        $errors[ERROR_INI_NOT_READABLE] = "The $php_ini file could not be read.";
    }
    if (!empty($errors)) {
        return array('location' => '', 'errors' => $errors);
    } 
    $lines = file($php_ini);
    $ext_start = zend_extension_line_start();
    $wrong_ext_start = ($ext_start == 'zend_extension')?'zend_extension_ts':'zend_extension';
    $loader_path = '';
    $loader_name_match = "ioncube_loader";
    foreach ($lines as $l) {
        if (preg_match("/^\s*$ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$corr_matches)) {
            if (preg_match("/$loader_name_match/i",$corr_matches[1])) {
                if (!empty($loader_path)) {
                    $errors[ERROR_INI_MULTIPLE_IC_LOADER_LINES] = "It appears that multiple $ext_start lines for the ionCube Loader have been included in the configuration file, $php_ini.";
                }
                $loader_path = $corr_matches[1];
            } else {
                if (empty($loader_path)) {
                    $errors[ERROR_INI_NOT_FIRST_ZE] = "The ionCube Loader must be the first Zend extension listed in the configuration file, $php_ini.";
                }
            }
        }
        if (empty($loader_path)) {
            if (preg_match("/^\s*$wrong_ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$bad_start_matches)) {
                if (preg_match("/$loader_name_match/i",$bad_start_matches[1])) {
                    $bad_zend_ext_msg = "The line for the ionCube Loader in the configuration file, $php_ini, should start with $ext_start and <b>not</b> $wrong_ext_start.";
                    $errors[ERROR_INI_WRONG_ZE_START] = $bad_zend_ext_msg;
                    $loader_path = $bad_start_matches[1];
                }
            }
        }
    }
    $loader_path = trim($loader_path);
    if ($loader_path === '') {
        $errors[ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration file, $php_ini.";
    } elseif (!@file_exists($loader_path)) {
        $errors[ERROR_INI_LOADER_FILE_NOT_FOUND] = "The loader file  $loader_path, listed in the configuration file, $php_ini, does not exist or is not accessible.";
    } elseif (basename($loader_path) == $loader_path) {
        $errors[ERROR_INI_NOT_FULL_PATH] = "A full path must be specified for the loader file in the configuration file, $php_ini.";
    }
    return array('location' => $loader_path, 'errors' => $errors);
}

function zend_extension_line_missing($ini_path)
{
    $loader_loc = get_loader_location_from_ini($ini_path);
    return (!empty($loader_loc['errors']) && array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$loader_loc['errors']));
}

function find_additional_ioncube_ini()
{
    $sys = get_sysinfo();
    $ioncube_ini = '';

    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
        foreach ($ini_files as $f) {
            $fn = trim($f);
            $bfn = basename($fn);
            if (preg_match('/ioncube/i',$bfn)) {
                $ioncube_ini = $fn;
                break;
            }
        }
    }
    return $ioncube_ini;
}

function get_additional_ini_files()
{
    $sys = get_sysinfo();
    $ini_files = array();
    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
    }
    return (array_map('trim',$ini_files));
}

function all_ini_contents()
{
    $sys = get_sysinfo();
    $output = '';

    $output .= ";;; *MAIN INI FILE AT ${sys['PHP_INI']}* ;;;" . PHP_EOL;
    $output .= get_file_contents($sys['PHP_INI']);
    $other_inis = get_additional_ini_files();
    foreach ($other_inis as $inif) {
        $output .= ";;; *Additional ini file at $inif* ;;;" . PHP_EOL;
        $output .= get_file_contents($inif);
    }
    $here = unix_path_dir();
    $unrec_ini_files = unrecognised_inis_webspace($here);
    foreach ($unrec_ini_files as $urinif) {
        $output .= ";;; *UNRECOGNISED INI FILE at $urinif* ;;;" . PHP_EOL;
        $output .= get_file_contents($urinif);
    }
    return $output;
}

function scan_inis_for_loader()
{
    $ldloc = array('location' => '', 'errors' => array());
    $sysinfo = get_sysinfo();
    if (empty($sysinfo['PHP_INI'])) {
        $ini_files_not_found = array("Main ini file");
        $ini_file_list = get_additional_ini_files();
    } else {
        $ini_files_not_found = array();
        $ini_file_list = array_merge(array($sysinfo['PHP_INI']),get_additional_ini_files());
    }
    $server_type = find_server_type();
    $shared_server = SERVER_SHARED == $server_type;
    foreach ($ini_file_list as $f) {
        $ldloc = get_loader_location_from_ini($f);
        if (array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$ldloc['errors'])) {
            unset($ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND]);
        } 
        if ($shared_server && array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            if (false == user_ini_space_path($f)) {
                $ldloc['errors'][ERROR_INI_NOT_FOUND] = "A system ini file cannot be found or read by the Wizard - you cannot do anything about this on your shared server.";
            } else {
                $ldloc['errors'][ERROR_INI_USER_INI_NOT_FOUND] = $ldloc['errors'][ERROR_INI_NOT_FOUND];
            }
        } elseif (array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            $ini_files_not_found[] = $f;
        }
        if (!empty($ldloc['location'])) {
            break;
        }
    }
    if (!empty($ini_files_not_found)) {
        $plural = (count($ini_files_not_found) > 1)?"s":"";
        $ldloc['errors'][ERROR_INI_NOT_FOUND] = "The following ini file$plural could not be found by the Wizard: " . join(',',$ini_files_not_found);
        if (is_restricted_server()) {
            $ldloc['errors'][ERROR_INI_NOT_FOUND] .= "<br> This may be due to server restrictions in place.";
        }
    }
    if (empty($ldloc['location'])) {
        $ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration.";
    }
    return $ldloc;
}

function find_loader_filesystem()
{
    $ld_inst_dir = loader_install_dir(find_server_type());
    $loader_name = get_loader_name();
    $suggested_loader_path = $ld_inst_dir . DIRECTORY_SEPARATOR . $loader_name;
    if (@file_exists($suggested_loader_path)) {
        $location = $suggested_loader_path;
    } elseif (@file_exists($loader_name)) {
        $location = @realpath($loader_name);
    } else {
        $ld_loc = get_loader_location();
        if (@file_exists($ld_loc)) {
            $location = $ld_loc;
        } else {
            $location = '';
        }
    }
    return $location;
}

function find_loader($search_directories_if_not_ini = false)
{
    $sysinfo = get_sysinfo();
    $php_ini = $sysinfo['PHP_INI'];
    $rtl_path = get_runtime_loading_path_if_applicable();
    $location = '';
    $errors = array();

    if (!empty($rtl_path)) {
        $location = $rtl_path;
    } else {
        $loader_ini = scan_inis_for_loader();
        $location = $loader_ini['location'];
        $errors = $loader_ini['errors'];
    }
    if (empty($location) && (empty($errors) || $search_directories_if_not_ini)) {
        $errors = array(); 
        $location = find_loader_filesystem();
        if (empty($location)) {
            $errors[ERROR_LOADER_NOT_FOUND] = 'The loader file could not be found in standard locations.';
        }
    }
    if (!empty($errors)) {
        return $errors;
    } else {
        return $location;
    }
}

function zend_extension_line_start()
{
    $sysinfo = get_sysinfo();
    $is_53_or_later = is_php_version_or_greater(5,3);
    return (is_bool($sysinfo['THREAD_SAFE']) && $sysinfo['THREAD_SAFE'] && !$is_53_or_later ? 'zend_extension_ts' : 'zend_extension');
}

function ioncube_loader_version_information()
{
    $old_version = true;
    $liv = "";
    $lv = "";
    $mv = 0;
    if (function_exists('ioncube_loader_iversion')) {
        $liv = ioncube_loader_iversion();
        $lv = sprintf("%d.%d.%d", $liv / 10000, ($liv / 100) % 100, $liv % 100);

        $latest_version =  get_latestversion();

        $lat_parts = explode('.',$latest_version);
        $cur_parts = explode('.',$lv);

        if (($cur_parts[0] > $lat_parts[0]) || 
            ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] > $lat_parts[1]) ||
             ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] == $lat_parts[1] && $cur_parts[2] >= $lat_parts[2])) {
            $old_version = false;
        } else {
            $old_version = $latest_version;
        }
        $mv = $cur_parts[0];
    }
    return array($lv,$mv,$old_version);
}

function default_loader_version_info()
{
    return array();
}

function get_loader_version_info()
{
    return get_remote_session_value('loader_version_info',LOADER_LATEST_VERSIONS_URL,'default_loader_version_info');
}

function calc_platform()
{
    $platform = array();
    $platform_info = get_platforminfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($osvar,$exact_match) = get_reqd_version($loader['osvariants']);
    } else {
        $osvar = null;
        if (is_ms_windows()) {
            $sys = get_sysinfo();
            $phpc = (empty($sys['PHP_COMPILER']))?'vc6':strtolower($sys['PHP_COMPILER']); 
            $osvar = ($sys['THREAD_SAFE']?'':'nonts_') . $phpc;
        }
    }
    foreach ($platform_info as $p) {
        if ($p['os'] == $loader['oscode'] && $p['arch'] == $loader['arch'] && (empty($osvar) || $p['os_mod'] == "_" . $osvar)) {
            $platform = $p;
            break;
        }
    }
    return $platform;
}

function get_platform()
{
    static $this_platform;

    if (!isset($this_platform)) {
        $this_platform = calc_platform();
    }

    return $this_platform;
}

function is_legacy_platform()
{
    $platform = get_platform();
    return array_key_exists('is_legacy',$platform);
}

function calc_dirname()
{
    $dirname = '';
    $platform = get_platform();
    if (!empty($platform)) {
        $dirname = $platform['dirname'];
    }
    return $dirname;
}

function calc_loader_latest_version()
{
    $lv_info = get_loader_version_info();
    $latest_version = RECENT_LOADER_VERSION;
    if (!empty($lv_info)) {
        $dirname = calc_dirname();
      
        if (!empty($dirname)) {
            $compiler_specific_version = false;
            if (is_ms_windows()) {
                $sys = get_sysinfo();
                $phpc = strtolower($sys['PHP_COMPILER']);
                if (!empty($phpc)) {
                    $dirname_comp = $dirname . "_" . $phpc;
                    if (array_key_exists($dirname_comp,$lv_info)) {
                        $latest_version = $lv_info[$dirname_comp];
                        $compiler_specific_version = true;
                    }
                }
            }
            if (!$compiler_specific_version && array_key_exists($dirname,$lv_info)) {
                $latest_version = $lv_info[$dirname];
            }
        } 
    }
    return $latest_version;
}

function get_latestversion()
{
    static $latest_version;

    if (empty($latest_version)) {
        $latest_version = calc_loader_latest_version();
    }
    return $latest_version;
}


function runtime_loader_location()
{
    $loader_path = false;
    $ext_path = extension_dir_path();
    if ($ext_path !== false) {
        $id = $ext_path;
        $here = dirname(__FILE__);
        if (isset($id[1]) && $id[1] == ':') {
            $id = str_replace('\\','/',substr($id,2));
            $here = str_replace('\\','/',substr($here,2));
        }
        $rd=str_repeat('/..',substr_count($id,'/')).$here.'/';
        $i=strlen($rd);

        $loader_loc = DIRECTORY_SEPARATOR . basename($here) . DIRECTORY_SEPARATOR . get_loader_name();
        while($i--) {
            if($rd[$i]=='/') {
                $loader_path = runtime_location_exists($ext_path,$rd,$i,$loader_loc);
                if ($loader_path !== false) {
                    break;
                }
            }
        }

        if (!$loader_path && !empty($loader_loc) && @file_exists($loader_loc)) {
            $loader_path = basename($loader_loc);
        }
    }
    return $loader_path;
}

function runtime_location_exists($ext_dir,$path_str,$sep_pos,$loc_name)
{
    $sub_path = substr($path_str,0,$sep_pos);
    $lp = $sub_path . $loc_name;
    $fqlp = $ext_dir.$lp;

    if(@file_exists($fqlp)) {
        return $lp;
    } else {
        return false;
    }
}

function runtime_loading_is_possible() {
    return !((is_php_version_or_greater(5,2,5)) || is_restricted_server() || !ini_get('enable_dl') || !function_exists('dl') || function_is_disabled('dl') || threaded_and_not_cgi());
}

function shared_and_runtime_loading()
{
    return (find_server_type() == SERVER_SHARED && empty($_SESSION['use_ini_method']) && runtime_loading_is_possible());
}

function get_valid_runtime_loading_path($ignore_loading_check = false)
{
    if ($ignore_loading_check || runtime_loading_is_possible()) {
        return runtime_loader_location();
    } else {
        return false;
    }
}

function runtime_loading($rtl_path = null)
{
    if (empty($rtl_path)) {
        $rtl_path = get_valid_runtime_loading_path();
    }
    if (!empty($rtl_path) && @dl($rtl_path)) {
        return $rtl_path;
    } else {
        return false;
    }
}

function get_runtime_loading_path_if_applicable()
{
    $rtl = null;
    if (shared_and_runtime_loading()) {
        $rtl = get_valid_runtime_loading_path();
    }
    return $rtl;
}

function try_runtime_loading_if_applicable()
{
    $rtl_path = get_runtime_loading_path_if_applicable();
    if (!empty($rtl_path)) {
        return runtime_loading($rtl_path);
    } else {
        return $rtl_path;
    }
}

function runtime_loading_instructions()
{
    $default = get_default_address();
    echo '<h4>Runtime Loading Instructions</h4>';
    echo '<div class=panel>';
    echo '<p>On your shared server the Loader can be installed using the runtime loading method.';
    echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";

    if ('.' == extension_dir()) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        echo "Please note that on your system the Loader <em>must</em> be present in the same " . $dirphrase . " as the first encoded file accessed.";
    }
    echo '<ol>';
    loader_download_instructions(); 
    $loader_dir = loader_install_instructions(SERVER_SHARED,dirname(__FILE__));
    shared_test_instructions();
    echo '</ol>';
    echo '</div>';
}

function runtime_loading_errors()
{
    $errors = array();
    $ext_path = extension_dir_path();
    if (false === $ext_path) {
        $errors[ERROR_RUNTIME_EXT_DIR_NOT_FOUND] = "Extensions directory cannot be found.";
    } else {
        $expected_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . get_loader_name();
        if (!@file_exists($expected_file)) {
            $errors[ERROR_RUNTIME_LOADER_FILE_NOT_FOUND] = "The Loader file was expected to be at $expected_file but could not be found.";
        } else {
            $errors = loader_compatibility_test($expected_file);
        }
    }
    return $errors;
}


function windows_package_name()
{
    $sys = get_sysinfo();
	$loader = get_loaderinfo();
    return (LOADERS_PACKAGE_PREFIX . 'win' . '_' . ($sys['THREAD_SAFE']?'':'nonts_') . strtolower($sys['PHP_COMPILER']) .  '_' . $loader['arch']);
}

function unix_package_name()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($reqd_version,$exact_match) = get_reqd_version($loader['osvariants']);
        if ($reqd_version) {
            $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $reqd_version . '_' . $loader['arch'];
        } else {
            $basename = "";
        }
    } else {
        $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $loader['arch'];
    }
    return array($basename,$multiple_os_versions);
}

function loader_download_instructions()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;

    if (is_ms_windows()) {
        if (is_bool($sysinfo['THREAD_SAFE'])) {
            $download_str = '<li>Download the following archive of Windows ' . $sysinfo['PHP_COMPILER'];
            if (!$sysinfo['THREAD_SAFE']) {
                $download_str .= ' non-TS';
            }
            $download_str .= ' ' . $loader['arch'] . ' Loaders:';
            echo $download_str;
            $basename = windows_package_name();
            echo make_archive_list($basename,array('zip'));
            echo 'A Loaders archive can also be downloaded from <a href="' . LOADERS_PAGE . '" target="loaders">' . LOADERS_PAGE . '</a>.';
        } else {
            echo '<li>Download a Windows Loaders archive from <a href="' . LOADERS_PAGE  . '" target=loaders>here</a>. If PHP is built with thread safety disabled, use the Windows non-TS Loaders.';
        }
    } else {
        list($basename,$multiple_os_versions) = unix_package_name(); 
        if ($basename == "") {
            echo '<li>Download a ' . $loader['osname'] . ' ' . $loader['arch'] . ' Loaders archive from <a href="' . LOADERS_PAGE . '" target="loaders">here</a>.';
            echo "<br>Your system appears to be ${loader['osnamequal']} for ${loader['wordsize']} bit. If Loaders are not available for that exact release of ${loader['osname']}, Loaders built for an earlier release should work. Note that you may need to install back compatibility libraries for the operating system.";
            echo '<br>If you cannot find a suitable loader then please raise a ticket at <a href="'. SUPPORT_SITE . '">our support helpdesk</a>.';
        } else {
            echo '<li>Download one of the following archives of Loaders for ' . $loader['osnamequal'] . ' ' . $loader['arch'] . ':'; 
            if (SERVER_SHARED == find_server_type()) {
                $archives = array('zip','tar.gz');
            } else {
                $archives = array('tar.gz','zip');
            }
            echo make_archive_list($basename,$archives);
            echo "</p>";
            if ($multiple_os_versions && !$exact_match) {
                echo "<p>Note that you may need to install back compatibility libraries for  ${loader['osname']}.</p>";
            }
        }
    }

    echo '</li>';
}

function ini_dir()
{
    $sysinfo = get_sysinfo();
    $parent_dir = '';
    if (!empty($sysinfo['PHP_INI'])) {
        $parent_dir = dirname($sysinfo['PHP_INI']);
    } else {
        $parent_dir = $_SERVER["PHPRC"];
        if (@is_file($parent_dir)) {
            $parent_dir = dirname($parent_dir);
        }
    }
    return $parent_dir;
}

function unix_install_dir()
{
    $ext_dir = extension_dir_path();
    $cur_dir = @realpath('.');
    if (empty($ext_dir) || $ext_dir == $cur_dir) {
        $loader_dir = UNIX_SYSTEM_LOADER_DIR;
    } else {
        $loader_dir = $ext_dir;
    }
    return $loader_dir;
}

function windows_install_dir()
{
    $sysinfo = get_sysinfo();
    if ($sysinfo['SS'] == 'IIS') {
        if (false === ($ext_dir = extension_dir_path())) {
            $parent_dir = ini_dir();
            $ext_dir = $parent_dir . '\\ext';
            if (!empty($parent_dir) && @file_exists($ext_dir)) {
                $loader_dir = $ext_dir;
            } else {
                $loader_dir = $_SERVER['windir'] . '\\' . WINDOWS_IIS_LOADER_DIR;
            }
        } else {
            $loader_dir = $ext_dir;
        }
    } else {
        if (false === ($ext_dir = extension_dir_path())) {
			$parent_dir = ini_dir();
			$loader_dir = $parent_dir . '\\' . 'ioncube';
		} else {
			$loader_dir = $ext_dir;
		}
    }
    return $loader_dir;
}

function loader_install_dir($server_type)
{
    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $loader_dir = get_default_loader_dir_webspace();
    } elseif (is_ms_windows()) {
        $loader_dir = windows_install_dir();
    } else {
        $loader_dir = unix_install_dir();
    }
    return $loader_dir;
}

function writeable_directories()
{
    $root_path = @realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    $root_path_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
    $above_root_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/../cgi-bin");

    $paths = array();
    foreach (array($root_path,$above_root_path,$root_path_cgi_bin,$above_root_cgi_bin) as $p) {
        if (@is_writeable($p)) {
            $paths[] = $p;
        }
    }
    return $paths;
}

function loader_install_instructions($server_type,$loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = loader_install_dir($server_type);
    }
    if (SERVER_LOCAL == $server_type) {
        echo "<li>Put the Loader files in <code>$loader_dir</code></li>";
    } else {
        echo "<li>Transfer the Loaders to your web server and install in <code>$loader_dir</code></li>";
    }
    return $loader_dir;
}

function zend_extension_lines($loader_dir)
{
    $zend_extension_lines = array();
    $sysinfo = get_sysinfo();
    $qt = (is_ms_windows()?'"':'');
    $loader = get_loaderinfo();

    if (!is_bool($sysinfo['THREAD_SAFE']) || !$sysinfo['THREAD_SAFE']) {
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file'] . $qt;
        $zend_extension_lines[] = "zend_extension = " . $path;
    }
    if ((!is_bool($sysinfo['THREAD_SAFE']) && !is_php_version_or_greater(5,3)) || $sysinfo['THREAD_SAFE']) {
        $line_start = is_php_version_or_greater(5,3)?'zend_extension':'zend_extension_ts';
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file_ts'] . $qt;
        $zend_extension_lines[] = $line_start . " = " . $path;
    }
    return $zend_extension_lines;
}

function user_ini_base()
{
    $doc_root_path = realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    if (!empty($above_root_path) && @is_writeable($above_root_path)) {
        $start_path = $above_root_path;
    } else {
        $start_path = $doc_root_path;
    }
    return $start_path;
}

function user_ini_space_path($file)
{
    $user_base = user_ini_base();
    $fpath = @realpath($file);
    if (!empty($fpath) && (0 === strpos($fpath,$user_base))) {
        return $fpath;
    } else {
        return false;
    }
}

function default_ini_path()
{
    return (realpath($_SERVER['DOCUMENT_ROOT']));
}

function shared_ini_location()
{
    $phprc = getenv('PHPRC');
    if (!empty($phprc)) {
        $phprc_path = user_ini_space_path($phprc);
        if (false !== $phprc_path) {
            return $phprc_path;
        } else {
            return default_ini_path();
        }
    } else {
        return default_ini_path();
    }
}


function zend_extension_instructions($server_type,$loader_dir)
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();
    $editing_ini = true;

    $php_ini_name = ini_file_name();

    if (isset($sysinfo['PHP_INI']) && @file_exists($sysinfo['PHP_INI'])) {
        $php_ini_path = $sysinfo['PHP_INI'];
    } else {
        $php_ini_path = '';
    }

    if (is_bool($sysinfo['THREAD_SAFE'])) {
        $kwd = zend_extension_line_start();
    } else {
        $kwd = 'zend_extension/zend_extension_ts';
    }

    $server_type_code = server_type_code();

    $zend_extension_lines = zend_extension_lines($loader_dir);

    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $ini_dir = shared_ini_location();
        $php_ini_path = $ini_dir . DIRECTORY_SEPARATOR . $php_ini_name;
        if (@file_exists($php_ini_path)) {
            $edit_line = "<li>Edit the <code>$php_ini_name</code> in the <code>$ini_dir</code> directory";
            if (zend_extension_line_missing($php_ini_path) && @is_writeable($php_ini_path) && @is_writeable($ini_dir)) {
                if (function_exists('file_get_contents')) {
                    $ini_strs = @file_get_contents($php_ini_path);
                } else {
                    $lines = @file($php_ini_path);
                    $ini_strs = join(' ',$lines);
                }
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                        fwrite($fh,$zl . PHP_EOL);
                    }
                    fwrite($fh,$ini_strs);
                    fclose($fh);
                    $editing_ini = false;
                    echo "<li>Your php.ini file at $php_ini_path has been modified to include the necessary line for the ionCube Loader.";
                } else {
                    echo $edit_line;
                }
            } else {
               echo $edit_line;
            }
        } else {
            $download_ini_file = "<li><a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">Save this  <code>$php_ini_name</code> file</a> and upload it to <code>$ini_dir</code> (full path on your server).";
            if (@is_writeable($ini_dir)) {
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                       fwrite($fh,$zl . PHP_EOL);
                    }
                    if (!empty($sysinfo['PHP_INI']) && is_readable($sysinfo['PHP_INI'])) {
                        if (function_exists('file_get_contents')) {
                           $ini_strs = @file_get_contents($sysinfo['PHP_INI']);
                        } else {
                           $lines = @file($sysinfo['PHP_INI']);
                           $ini_strs = join(' ',$lines);
                        }
                        fwrite($fh,$ini_strs);
                    }
                    fclose($fh); 
                    echo "<li>A <code>$php_ini_name</code> file has been created for you in <code>$ini_dir</code>.";
                } else {
                    echo $download_ini_file;
                }
            } else {
                echo $download_ini_file;
            }
            $editing_ini = false;
        }
    } elseif (!empty($sysinfo['PHP_INI'])) {
        if (empty($sysinfo['PHP_INI_DIR'])) {
            echo "<li>Edit the file <code>${sysinfo['PHP_INI']}</code>";
        } else {
            $php_ini_path = find_additional_ioncube_ini();
            if (empty($php_ini_path)) {
                $php_ini_name = ADDITIONAL_INI_FILE_NAME;
                echo "<li><a href=\"$base&amp;page=phpconfig&amp;download=1&amp;newlinesonly=1&amp;ininame=$php_ini_name&amp;stype=$server_type_code\">Save this $php_ini_name file</a> and put it in your ini files directory, <code>${sysinfo['PHP_INI_DIR']}</code>";
                $editing_ini = false;
            } else {
                $php_ini_name = basename($php_ini_path);
                echo "<li>Edit the file <code>$php_ini_path</code>";
            }
        }
    } else {
        echo "<li>Edit the system <code>$php_ini_name</code> file";
    }
    if ($editing_ini) {
        echo " and <b>before</b> any other $kwd lines ensure that the following is included:<br>";
        foreach ($zend_extension_lines as $zl) {
            echo "<code>$zl</code><br>";
        }
        if (!empty($php_ini_path)) {
            if (zend_extension_line_missing($php_ini_path)) {
                echo "<a>Alternatively, replace your current <code>$php_ini_path</code> file with <a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">this new $php_ini_name file</a>."; 
            }
        }
    }
    echo '</li>';
}

function server_restart_instructions()
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();

    if ($sysinfo['SS']) {
		if ($sysinfo['SS'] == 'PHP-FPM') {
			echo "<li>Restart PHP-FPM.</li>";
		} else {
			echo "<li>Restart the ${sysinfo['SS']} server software.</li>";
		}
    } else {
        echo "<li>Restart the server software.</li>";
    }

    echo "<li>When the server software has restarted, <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the Loader</a>.</li>";

	if ($sysinfo['SS'] && $sysinfo['SS'] == 'PHP-FPM') {
		echo '<li>If the Loader installation failed, check the PHP-FPM error log file for errors.</li>';
    } elseif ($sysinfo['SS'] == 'Apache' && !is_ms_windows()) {
        echo '<li>If the Loader installation failed, check the Apache error log file for errors and see our guide to <a target="unix_errors" href="'. UNIX_ERRORS_URL . '">Unix related errors</a>.</li>';
    }
}

function shared_test_instructions()
{
    $base = get_base_address();
    echo "<li><a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">Click here to test the Loader</a>.</li>";
}

function link_to_php_ini_instructions()
{
    $default = get_default_address();
    echo "<p><a href=\"{$default}&amp;stype=s&amp;ini=1\">Please click here for instructions on using the php.ini method instead</a>.</p>";
}

function php_ini_instruction_list($server_type)
{
    echo '<h4>Installation Instructions</h4>';
    echo '<div class=panel>';
    echo '<ol>';

    loader_download_instructions(); 
    $loader_dir = loader_install_instructions($server_type);
    zend_extension_instructions($server_type,$loader_dir);
    if ($server_type != SERVER_SHARED || !own_php_ini_possible()) {
        server_restart_instructions();
    } else {
        shared_test_instructions();
    } 
    echo '</ol>';
    echo '</div>';
}

function php_ini_install_shared($give_preamble = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();
    if ($give_preamble) {
        echo "<p>On your <strong>shared</strong> server, the Loader should be installed using a <code>$php_ini_name</code> configuration file.";
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";
    }

    if (own_php_ini_possible()) {
        echo '<p>With your hosting account, you may be able to use your own PHP configuration file.</p>';
    } else {
        echo "<p>It appears that you cannot install the ionCube Loader using the <code>$php_ini_name</code> file. Your server provider or system administrator should be able to perform the installation for you. Please refer them to the following instructions.</p>";
    }

    php_ini_instruction_list(SERVER_SHARED);
}

function php_ini_install($server_type_desc = null, $server_type = SERVER_DEDICATED, $required = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();

    echo '<p>';
    if ($server_type_desc) {
        echo "For a <strong>$server_type_desc</strong> server ";
    } else {
        echo "For this server ";
    }

    if ($required) {
        echo "you should install the ionCube Loader using the <code>$php_ini_name</code> configuration file.";
    } else {
        echo "installing the ionCube Loader using the <code>$php_ini_name</code> file is recommended.";
    }
    if ($server_type_desc) {
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a $server_type_desc server</a>.)";
    }
    echo '</p>';
      
    php_ini_instruction_list($server_type);
}



function help_resources($error_list = array())
{
	$self = get_self();
    $base = get_base_address();
    $server_type_code = server_type_code();
    $server_type = find_server_type();
    $sysinfo = get_sysinfo();
    $resources = array(
            '<a target="_blank" href="' . LOADERS_FAQ_URL . '">ionCube Loaders FAQ</a>',
            '<a target="_blank" href="' . LOADER_FORUM_URL . '">ionCube Loader Forum</a>'
        );
    if (SERVER_SHARED != $server_type || own_php_ini_possible(true)) {
		$support_info = array ( 
			'department' 		=> WIZARD_SUPPORT_TICKET_DEPARTMENT,
			'subject' 			=> "ionCube Loader installation problem",
			'message' 			=> support_ticket_information()
		   );
		if (SERVER_LOCAL == $server_type && !info_should_be_disabled()) {
			$temp_files = system_info_temporary_files();
		} else {
			$temp_files = NULL;
		}
		if (!empty($temp_files)) {
			$support_info['ini'] = base64_encode(file_get_contents($temp_files['ini']));
			$support_info['phpinfo'] = base64_encode(file_get_contents($temp_files['phpinfo']));
			$support_info['additional'] = base64_encode(file_get_contents($temp_files['additional']));
			
			$loader_path = find_loader(true);
			if (is_string($loader_path)) {		
				$support_info['loader'] = base64_encode(file_get_contents($loader_path));
				$support_info['loader_name'] = basename($loader_path);
			} else {
				$support_info['loader'] = '';
				$support_info['loader_name'] = '';
			}
		} else {
			$support_info['ini'] = '';
			$support_info['phpinfo'] = '';
			$support_info['additional'] = '';
			$support_info['loader'] = '';
			$support_info['loader_name'] = '';
		}
		 
        $resources[2] = '<form action="' . SUPPORT_SITE . 'lw_index.php' .'" method="POST" id="support-ticket"><a href="" onclick="document.getElementById(\'support-ticket\').submit(); return false;">Raise a support ticket through our helpdesk</a>';
		$resources[2] .= '<input type="hidden" name="department" value="' . $support_info['department'] . '"/>';
		$resources[2] .= '<input type="hidden" name="subject" value="' . $support_info['subject'] . '"/>';
		$resources[2] .= '<input type="hidden" name="message" value="' . $support_info['message'] . '"/>';
		if (!empty($temp_files)) {
			$resources[2] .= '<input type="hidden" name="phpinfo" value="' . $support_info['phpinfo'] . '"/>';
			$resources[2] .= '<input type="hidden" name="ini" value="' . $support_info['ini'] . '"/>';
			$resources[2] .= '<input type="hidden" name="additional" value="' . $support_info['additional'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader" value="' . $support_info['loader'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader_name" value="' . $support_info['loader_name'] . '"/>';
		}
		$resources[2] .= '</form>';
    } 
	
    if (SERVER_SHARED == $server_type && own_php_ini_possible(true) && !user_ini_space_path($sysinfo['PHP_INI'])) {
        $resources[3] = '<strong>Please check with your host that you can create php.ini files that will override the system one.</strong>';
    }
    return $resources;
}

function system_info_temporary_files()
{
    $tmpfname_ini = get_tempnam("/tmp", "INI");
    $tmpfname_ini .= ".ini";
    $fh_ini = @fopen($tmpfname_ini,'wb');
    if ($fh_ini) {
        $config = all_ini_contents();
        fwrite($fh_ini,$config);
        fclose($fh_ini);
    } else {
        $tmpfname_ini = '';
    }

    $tmpfname_pinf = get_tempnam("/tmp", "PIN");
    $tmpfname_pinf .= ".html";
    $fh_pinfo = @fopen($tmpfname_pinf,'wb');
    if ($fh_pinfo) {
        ob_start();
        @phpinfo();
        $pinfo = ob_get_contents();
        ob_end_clean();
        fwrite($fh_pinfo,$pinfo);
        fclose($fh_pinfo);
    } else {
        $tmpfname_pinf = '';
    }

    $tmpfname_add = get_tempnam("/tmp", "ADD");
    $tmpfname_add .= ".html";
    $fh_add = @fopen($tmpfname_add,'wb');
    if ($fh_add) {
        ob_start();
        extra_page(false);
        $extra = ob_get_contents();
        ob_end_clean();
        fwrite($fh_add,$extra);
        fclose($fh_add);
    } else {
        $tmpfname_add = '';
    }

    if (empty($tmpfname_ini) || empty($tmpfname_pinf) || empty($tmpfname_add)) {
        return (array());
    } else {
        return (array('ini'           =>   $tmpfname_ini,
                      'phpinfo'       =>   $tmpfname_pinf,
                      'additional'    =>   $tmpfname_add));
    }
}

function get_tempnam($default_tmp_dir = '', $prefix = '')
{
	if (function_exists('sys_get_temp_dir')) {
		return tempnam(sys_get_temp_dir(),$prefix);
	} else {
		return @tempnam($default_tmp_dir, $prefix);
	}
}
function system_info_archive_page()
{
    info_disabled_check();
	$server_type = find_server_type();
	if (SERVER_LOCAL != $server_type) {
		exit;
	}
    $loader = find_loader(true);
    if (is_string($loader)) {
        $loader_file = $loader;
    } else {
        $loader_file = '';
    }
    $all_files = system_info_temporary_files();
    if (!empty($all_files)) {
        if (!empty($loader_file)) {
            $all_files['loader'] = $loader_file;
        }
        $archive_name =  get_tempnam('/tmp',"ARC");
        if (extension_loaded('zip')) {
            $archive_name .= '.zip';
            $zip = @new ZipArchive();
            $mode = @constant("ZIPARCHIVE::OVERWRITE");
            if (!$zip || $zip->open($archive_name, $mode)!==TRUE) {
                $archive_name = '';
            } else {
                foreach($all_files as $f) {
                    $zip->addFile($f,basename($f));
                }
                $zip->close();
            }
        } elseif (extension_loaded('zlib') && !is_ms_windows()) {
            $tar_name = $archive_name . ".tar";
            $all_files_str = join(' ',$all_files);
            $script = "tar -chf $tar_name $all_files_str";
            $result = @system($script,$retval);
            if ($result !== false) {
                $archive_name = $tar_name . '.gz';
                $zp = gzopen($archive_name,"w9");
                $tar_contents = get_file_contents($tar_name);
                gzwrite($zp,$tar_contents);
                gzclose($zp);
            } else {
                $archive_name = '';
            }
        } else {
            $archive_name = '';
        }
    } else {
        $archive_name = '';
    }
    if ($archive_name) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. $archive_name);
        @readfile($archive_name);
    } else {
        $self = get_self();
        $base = get_base_address();
        $server_type_code = server_type_code();
        heading();
        echo "<p>A downloadable archive of system information could not be created.<br> 
            <strong>Please save each of the following and then attach those files to the support ticket:</strong></p>"; 
        echo "<ul>";
        echo "<li><a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo()</a></li>";
        echo "<li><a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a></li>";
        echo "<li><a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional information</a></li>";
        echo "<li><a href=\"$self?page=loaderbin\">loader file</a></li>";
        echo "</ul>";
        footer(true);
    }
}

function support_ticket_information($error_list = array())
{
    $sys = get_sysinfo();
    $ld = get_loaderinfo();

    $ticket_strs = array();
    $ticket_strs[] = "PLEASE DO NOT REMOVE THE FOLLOWING INFORMATION\r\n";
    $ticket_strs[] = "==============\r\n";
    if (!empty($error_list)) {
        $ticket_strs[] = "[hr]";
        $ticket_strs[] = "ERRORS";
        $ticket_strs[] = "[table]";
        $ticket_strs[] = '[tr][td]' . join('[/td][/tr][tr][td]',$error_list) . '[/td][/tr]';
        $ticket_strs[] = "[/table]";
    }
    $ticket_strs[] = "[hr]";
    $ticket_strs[] = "SYSTEM INFORMATION";
    $info_lines = array();
    $info_lines["Wizard version"] = script_version();
    $info_lines["PHP uname"] = $ld['uname'];
    $info_lines["Machine architecture"] = $ld['arch'];
    $info_lines["Word size"] = $ld['wordsize'];
    $info_lines["Operating system"] = $ld['osname'] . ' ' . $ld['osver'];
    if (selinux_is_enabled() || possibly_selinux()) {
        $info_lines["Security enhancements"] = "SELinux";
    } elseif (grsecurity_is_enabled()) {
        $info_lines["Security enhancements"] = "Grsecurity";
    } else {
        $info_lines["Security enhancements"] = "None";
    }
    $info_lines["PHP version"] = PHP_VERSION; 
    if ($sys['DEBUG_BUILD']) {
        $info_lines["DEBUG BUILD"] = "DEBUG BUILD OF PHP";
    }
    if (!$sys['SUPPORTED_COMPILER']) {
        $info_lines["SUPPORTED PHP COMPILER"] = "FALSE";
        $info_lines["PHP COMPILER"] = $sys['PHP_COMPILER'];
    }
    $info_lines["Is CLI?"] = ($sys['IS_CLI']?"Yes":"No");
    $info_lines["Is CGI?"] = ($sys['IS_CGI']?"Yes":"No");
    $info_lines["Is thread-safe?"] = ($sys['THREAD_SAFE']?"Yes":"No");
    $info_lines["Web server"] = $sys['FULL_SS'];
    $info_lines["Server type"] = server_type_string();
    $info_lines["PHP ini file"] = $sys['PHP_INI'];
    if (!@file_exists($sys['PHP_INI'])) {
        $info_lines["Ini file found"] = "INI FILE NOT FOUND";
    } else {
        if (is_readable($sys['PHP_INI'])) {
            $info_lines["Ini file found"] = "INI FILE READABLE";
        } else {
            $fh = @fopen($sys['PHP_INI'],"rb");
            if ($fh === false) {
                $info_lines["Ini file found"] = "INI FILE FOUND BUT POSSIBLY NOT READABLE";
            } else {
                $info_lines["Ini file found"] = "INI FILE READABLE";
            }
        }
    }
    $info_lines["PHPRC"] = $sys['PHPRC'];
    $loader_path = find_loader();
    if (is_string($loader_path)) {
        $info_lines["Loader path"] =  $loader_path;
        $info_lines["Loader file size"] = filesize($loader_path) . " bytes.";
        $info_lines["Loader MD5 sum"] =  md5_file($loader_path);
    } else {
        $info_lines["Loader path"] =  "LOADER PATH NOT FOUND";
    }
    $server_type_code = server_type_code();
    if (!empty($_SESSION['hostprovider'])) {
      $info_lines['Hosting provider'] = $_SESSION['hostprovider'];
      $info_lines['Provider URL'] = $_SESSION['hosturl'];
    }
    $info_lines["Wizard script path"] = '[url]http://' . $_SERVER["HTTP_HOST"] . get_self() . '?stype='. $server_type_code . '[/url]';
    $ticket_strs[] = "[table]";
    foreach ($info_lines as $h => $i) {
        $value = (empty($i))?'EMPTY':$i;
        $ticket_strs[] = '[tr][td]' . $h . '[/td]' . '[td]' . $value . '[/td][/tr]';
    }
    $ticket_strs[] = '[/table]';
    $ticket_strs[] = '[hr]';
    $ticket_strs[] = "\r\n==============\r\n";
    $ticket_strs[] = "PLEASE ENTER ANY ADDITIONAL INFORMATION BELOW\r\n";

    $support_ticket_str = join('',$ticket_strs);
    return urlencode($support_ticket_str);
}

function wizard_stats_data($page_id)
{
    $data = array();

    try_runtime_loading_if_applicable();
    $sysinfo = get_sysinfo();
    $ldinfo = get_loaderinfo();

    $data['sessionid'] = session_id();
    $data['wizard_version'] = script_version();
    $data['server_type'] = server_type_code();
    $data['hostprovider'] = (isset($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $data['hosturl'] = (isset($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $data['page_id'] = $page_id;
    $data['loader_state'] = (extension_loaded(LOADER_EXTENSION_NAME))?'installed':'failure';
    $data['ini_location'] = $sysinfo['PHP_INI'];
    $data['is_cgi'] = ($sysinfo['IS_CGI'])?"yes":"no";
    $data['is_ts'] = ($sysinfo['THREAD_SAFE'])?"yes":"no";
    $data['arch'] = $ldinfo['arch'];
    $data['php_version'] = PHP_VERSION;
    $data['os'] = $ldinfo['osname'];
    $data['word_size'] = $ldinfo['wordsize'];
    $data['referrer'] =  $_SERVER["HTTP_HOST"] . get_self();

    return $data;
}

function send_stats($page_id = 'default')
{
    $server_type = find_server_type();
    $res = false;

    if (SERVER_LOCAL != $server_type) {
        $stats_data = wizard_stats_data($page_id);

        if (!isset($_SESSION['stats_sent'][$page_id][$stats_data['loader_state']])) {
            $url = WIZARD_STATS_URL;

            if (!empty($stats_data)) {
                if(function_exists('http_build_query')) {
                    $qparams = http_build_query($stats_data);
                } else {
                    $qparams = php4_http_build_query($stats_data);
                }
                $url .= '?' . $qparams;
                $res = remote_file_contents($url);
            }
            $_SESSION['stats_sent'][$page_id][$stats_data['loader_state']] = 1;
        } else {
            $res = true;
        }
    } else {
        $res = 'LOCAL';
    }
    return $res;
}

function os_arch_string_check($loader_str)
{
    $errors = array();
    if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_str,$os_matches)) {
        $loader_info = get_loaderinfo();
        $dirname = calc_dirname();
        $packed_osname = preg_replace('/\s/','',strtolower($loader_info['osname']));
        if (strtolower($dirname) != $os_matches[1] && $packed_osname != $os_matches[2]) {
            $errors[ERROR_LOADER_WRONG_OS] = "You have the wrong loader for your operating system, ". $loader_info['osname'] . ".";
        } else {
            $loader_wordsize = (strpos($os_matches[3],'64') === false)?32:64;
            if ($loader_info['arch'] != ($ap = required_loader_arch($os_matches[3],$loader_info['oscode'],$loader_wordsize))) {
                $err_str = "You have the wrong loader for your machine architecture.";
                $err_str .= " Your system is " . $loader_info['arch'];
                $err_str .= " but the loader you are using is for " . $ap . ".";
                $errors[ERROR_LOADER_WRONG_ARCH] = $err_str;
            }
        }
    }
    return $errors;
}

function get_loader_strings($loader_location)
{
    if (function_exists('file_get_contents')) {
        $loader_strs = @file_get_contents($loader_location);
    } else {
        $lines = @file($loader_location);
        $loader_strs = join(' ',$lines);
    }
    return $loader_strs;
}

function loader_system($loader_location)
{
    $loader_system = array();
    $loader_strs = get_loader_strings($loader_location);

    if (!empty($loader_strs)) {

        if (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
            $loader_system['oscode'] = 'win';
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '_nonts')?0:1;
			if (preg_match("/_localtime([0-9][0-9])/i",$loader_strs,$size_matches)) {
				$loader_system['wordsize'] = ($size_matches[1] == '64')?64:32;
			} else {
				$loader_system['wordsize'] = 32;
			}
            $loader_system['arch'] = ($loader_system['wordsize'] == 64)?'x86-64':'x86';
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
			if ($loader_system['php_version_major'] == 8 && $loader_system['php_version_minor'] >= 1) {
				$loader_system['compiler'] = 'VC16';
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] >= 2) {
				$loader_system['compiler'] = 'VC15'; 
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] < 2) {
				$loader_system['compiler'] = 'VC14'; 
			} elseif ($loader_system['php_version_major'] == 5 && $loader_system['php_version_minor'] >= 5) {
				$loader_system['compiler'] = 'VC11'; 
			} elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_system['compiler'] = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_system['compiler'] = 'VC6';
            }
        } elseif (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '-ts')?1:0;
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
            if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_strs,$os_matches)) {
                $loader_system['oscode'] = strtolower(substr($os_matches[2],0,3));
                $loader_system['wordsize'] = (strpos($os_matches[3],'64') === false)?32:64;
                $loader_system['arch'] = required_loader_arch($os_matches[3],$loader_system['oscode'],$loader_system['wordsize']);
                $loader_system['compiler'] = $os_matches[4];
            }
        }
        if (preg_match("/ionCube Loader Version\s+(\S+)/",$loader_strs,$loader_version)) {
            $loader_system['loader_version'] = $loader_version[1];
		} elseif (preg_match("/ioncube_loader_(\d{1,2}\.\d\.\d{1,2})\./",$loader_strs,$loader_version)){
			$loader_system['loader_version'] = $loader_version[1];
        } else {
            $loader_system['loader_version'] = 'UNKNOWN';
        }
        if (isset($loader_system['php_version_major'])) {
            $loader_system['php_version'] = $loader_system['php_version_major'] . '.' . $loader_system['php_version_minor'];
        }
    }
    return $loader_system;
}

function loader_compatibility_test($loader_location)
{
    $errors = array();

    $sysinfo = get_sysinfo();
    if (LOADER_NAME_CHECK) {
        $installed_loader_name = basename($loader_location);
        $expected_loader_name = get_loader_name();
        if ($installed_loader_name != $expected_loader_name) {
            $errors[ERROR_LOADER_UNEXPECTED_NAME] = "The installed loader (<code>$installed_loader_name</code>) does not have the name expected (<code>$expected_loader_name</code>) for your system. Please check that you have the correct loader for your system.";
        }
    }
    if (empty($errors) && !is_readable($loader_location)) {
        $execute_error = "The loader at $loader_location does not appear to be readable.";
        $execute_error .= "<br>Please check that it exists and is readable.";
        $execute_error .= "<br>Please also check the permissions of the containing ";
        $execute_error .= (is_ms_windows()?'folder':'directory') . '.';
		if ($sysinfo['SS'] == 'PHP-FPM') {
			$execute_error .= "<br>Please also check that PHP-FPM has been restarted.";
        } elseif (($sysinfo['SS'] == 'IIS') || !($sysinfo['IS_CGI'] || $sysinfo['IS_CLI'])) {
            $execute_error .= "<br>Please also check that the web server has been restarted.";
        }
        $execute_error .= ".";
        $errors[ERROR_LOADER_NOT_READABLE] = $execute_error;
    }
    $loader_strs = get_loader_strings($loader_location);
    $phpv = php_version(); 
    if (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
        if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
            $loader_php = $version_matches[1] . "." . $version_matches[2];
            $server_php =  $phpv['major'] . "." .  $phpv['minor'];
            $errors[ERROR_LOADER_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
        }
        if (is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'] && !is_ms_windows() && !(isset($version_matches[4]) && $version_matches[4] == '-ts')) {
            $errors[ERROR_LOADER_NONTS_PHP_TS] = "Your server is running a thread-safe version of PHP but the loader is not a thread-safe version.";
        } elseif (isset($version_matches[4]) && $version_matches[4] == '-ts' && !(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'])) {
            $errors[ERROR_LOADER_TS_PHP_NONTS] = "Your server is running a non-thread-safe version of PHP but the loader is a thread-safe version.";
        }
    } elseif (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
        if (!is_ms_windows()) {
            $errors[ERROR_LOADER_WIN_SERVER_NONWIN] = "You have a Windows loader but your server does not appear to be running Windows.";
        } else {
            if (isset($version_matches[4]) && $version_matches[4] == '_nonts' && is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) {
                $errors[ERROR_LOADER_WIN_NONTS_PHP_TS] = "You have the non-thread-safe version of the Windows loader but you need the thread-safe one.";
            } elseif (!(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) && !(isset($version_matches[4]) && $version_matches[4] == '_nonts')) {
                $errors[ERROR_LOADER_WIN_TS_PHP_NONTS] = "You have the thread-safe version of the Windows loader but you need the non-thread-safe one."; 
            }
            if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
                $loader_php = $version_matches[1] . "." . $version_matches[2];
                $server_php =  $phpv['major'] . "." .  $phpv['minor'];
                $errors[ERROR_LOADER_WIN_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
            }
                        
            if ($version_matches[1] == 8 && $version_matches[2] >= 1) {
                $loader_compiler = 'VC16';
            } elseif ($version_matches[1] == 7 && $version_matches[2] >= 2) {
                $loader_compiler = 'VC15'; 
            } elseif ($version_matches[1] == 7) {
                $loader_compiler = 'VC14'; 
            } elseif ($version_matches[1] == 5 && $version_matches[2] >= 5) {
                $loader_compiler = 'VC11'; 
            } elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_compiler = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_compiler = 'VC6';
            }
            if ($loader_compiler != $sysinfo['PHP_COMPILER']) {
                $errors[ERROR_LOADER_WIN_COMPILER_MISMATCH] = "Your loader was built using $loader_compiler but you need the loader built using ${sysinfo['PHP_COMPILER']}.";
            }
        }
    } else {
            $errors[ERROR_LOADER_PHP_VERSION_UNKNOWN] = "The PHP version for the loader cannot be determined - please check that you have a valid ionCube Loader.";
    } 
    $errors += os_arch_string_check($loader_strs);

    return $errors;
}


function shared_server()
{
    if (!$rtl_path = runtime_loading()) {
        if (empty($_SESSION['use_ini_method']) && runtime_loading_is_possible()) {
            runtime_loading_instructions();
        } else {
            php_ini_install_shared();
        }
    } else {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        echo "<p>The ionCube Loader $lv for PHP $phpv has been successfully installed.</p>";
        $is_legacy_loader = loader_major_version_instructions($mv);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,$newer_version);
        }
        successful_install_end_instructions($rtl_path);
    }
}

function dedicated_server()
{
    php_ini_install('dedicated or VPS', SERVER_DEDICATED, true);
}

function local_install()
{
    php_ini_install('local',SERVER_LOCAL, true);
}


function unregister_globals()
{
    if (!ini_get('register_globals')) {
        return;
    }

    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

function clear_session($persist = array())
{
    $persist['not_go_daddy'] = empty($_SESSION['not_go_daddy'])?0:1;
    $persist['use_ini_method'] = empty($_SESSION['use_ini_method'])?0:1;
    $persist['server_type'] = empty($_SESSION['server_type'])?SERVER_UNKNOWN:$_SESSION['server_type'];
    @session_destroy();
    $_SESSION = array();
    $_SESSION['CREATED'] = time();
    $_SESSION = $persist;
}

function can_archive()
{
	return (extension_loaded('zip') || (extension_loaded('zlib') && !is_ms_windows()));
}

function is_ioncube()
{
        return (($_SERVER["REMOTE_ADDR"] == IONCUBE_IP_ADDRESS) || ($_SERVER["REMOTE_ADDR"] == gethostbyname(IONCUBE_ACCESS_ADDRESS)));
}

function can_reach_ioncube()
{
	return (isset($_SESSION['remote_access_successful']));
}

function info_should_be_disabled($only_allow_ioncube = false)
{
    $elapsed = time() - max(filemtime(__FILE__),filectime(__FILE__));
	
	if (is_ioncube()) {
		$cutoff_time = IONCUBE_WIZARD_EXPIRY_MINUTES * 60;
	} else {
		if (!$only_allow_ioncube && !extension_loaded(LOADER_EXTENSION_NAME)) {
			$cutoff_time = WIZARD_EXPIRY_MINUTES * 60;
		} else {
			return true;
		}
	}
	
    return ($elapsed > $cutoff_time);
}

function info_disabled_text()
{
    return "The information you have tried to access has been disabled for security reasons. Please re-install this Loader Wizard script and try again.";
}

function info_disabled_check()
{
    if (info_should_be_disabled()) {
        heading();
        echo info_disabled_text();
        footer(true);
        exit;
    }
}

function run()
{

	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (preg_match('/googlebot/i',$user_agent)) {
		exit;
	}
    unregister_globals();
    if (is_php_version_or_greater(4,3,0)) {
        ini_set('session.use_only_cookies',1);
    }
    $session_ok = @session_start();

    if (!defined('PHP_EOL')) {
        if (is_ms_windows()) {
            define('PHP_EOL',"\r\n");
        } else {
            define('PHP_EOL',"\n");
        }
    }

    if (!isset($_SESSION['CREATED'])) {
        $_SESSION['CREATED'] = time();
    } elseif (time() - $_SESSION['CREATED'] > SESSION_LIFETIME_MINUTES * 60 ) {
        clear_session(); 
    }
    if (!isset($_SERVER)) $_SERVER =& $HTTP_SERVER_VARS;

    (php_sapi_name() == 'cli') && die("This script should only be run by a web server.\n");

    $page = get_request_parameter('page');
    $host = get_request_parameter('host');
    $clear = get_request_parameter('clear');
    $ini = get_request_parameter('ini');
    $timeout = get_request_parameter('timeout');

    if ($timeout) {
        $_SESSION['timing_out'] = 1;
        $_SESSION['initial_run'] = 0;
    }

    if (!empty($host)) {
        if ($host == 'ngd') {
            $_SESSION['not_go_daddy'] = 1;
        }
    }
    if (!empty($ini)) {
        $_SESSION['use_ini_method'] = 1;
    }

    if (!empty($clear)) {
        clear_session();
        unset($_SESSION['not_go_daddy']);
        unset($_SESSION['use_ini_method']);
        unset($_SESSION['server_type']);
    } else {
        $stype = get_request_parameter('stype');
        $hostprovider = get_request_parameter('hostprovider');
        $hosturl = get_request_parameter('hosturl');
        if (!empty($hostprovider)) {
            $_SESSION['hostprovider'] = $hostprovider;
            $_SESSION['hosturl'] = $hosturl;
        }
        $server_type = find_server_type($stype,false,true);
    }
    if ($session_ok && !$timeout && !isset($_SESSION['initial_run']) && empty($page)) {
        $_SESSION['initial_run'] = 1;
        initial_page();
        @session_write_close();
        exit;
    } else {
        $_SESSION['initial_run'] = 0;
    }

    if (empty($_SESSION['server_type'])) {
        $_SESSION['server_type'] = SERVER_UNKNOWN;
    }

    if (empty($page) || !function_exists($page . "_page")) {
        $page = get_default_page();
    } 

    $fn = "{$page}_page";
    $fn();

    @session_write_close();
    exit(0);
}

function wizardversion_page()
{
    $start_time = time();
    $wizard_version_only = get_request_parameter('wizard_only');
    $clear_session_info = get_request_parameter('clear_info');
    if ($clear_session_info) {
        unset($_SESSION['timing_out']);
        unset($_SESSION['latest_wizard_version']);
    }
    $wizard_version = latest_wizard_version();
    $message = '';
    if (false === $wizard_version) {
        $message = "0";
    } elseif (update_is_available($wizard_version)) {
        $message = "$wizard_version";
    } else {
        $message = "1";
    }
    echo $message;
    @session_write_close();
    exit(0);
}

function platforminfo_page()
{
    $message = '';
    $platforms = get_loader_platforms();
    $message = empty($platforms)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function loaderversion_page()
{
    $message = '';
    $loader_versions = get_loader_version_info();
    $message = empty($loader_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function compilerversion_page()
{
    $message = '';
    $compiler_versions = find_win_compilers();
    $message = empty($compiler_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function initial_page()
{
    $self = get_self();
    $start_page = get_default_address(false);
    $stage_timeout = 7000;
    $step_lag = 500;

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <style type="text/css">
        body {
            height: 100%;
            width: 100%;
        }
        </style>
        <script type="text/javascript">
        var timingOut = 0;
        var xmlHttpTimeout;
        var ajax;
        var statusPar;
        var stage_timeout = $stage_timeout;
        var step_lag = $step_lag;

        function checkNextStep(ajax,expected,continuation) {
            if (ajax.readyState==4 && ajax.status==200)
            {
                clearTimeout(xmlHttpTimeout);
                if (ajax.responseText == expected) {
                   setTimeout('',step_lag);
                   continuation();
                } else {
                   statusPar.innerHTML = 'Unable to check for update<br>script continuing';
                   setTimeout("window.location.href = '$start_page&timeout=1'",1000);
                }
            }
        }

        function getXmlHttp() {
            if (window.XMLHttpRequest) {
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xmlhttp;
        }
        var startMainLoaderWizard = function() {
            window.location.href = '$start_page';
        }
        var loaderVersionCheck = function() {
            statusPar.innerHTML = 'Stage 4/4: Getting latest loader versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",startMainLoaderWizard);
            }
            xmlHttp.open("GET","$self?page=loaderversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var platformCheck = function() {
            statusPar.innerHTML = 'Stage 3/4: Getting platform information';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",loaderVersionCheck);
            }
            xmlHttp.open("GET","$self?page=platforminfo",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var compilerVersionCheck = function() {
            statusPar.innerHTML = 'Stage 2/4: Getting compiler versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",platformCheck);
            }
            xmlHttp.open("GET","$self?page=compilerversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var startChecks = function() {
            statusPar = document.getElementById('status');
            statusPar.innerHTML = 'Stage 1/4: Getting Loader Wizard version';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",compilerVersionCheck);
            }
            xmlHttp.open("GET","$self?page=wizardversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        function ajaxTimeout(){
           ajax.abort();
           statusPar.innerHTML = 'Cannot reach server<br>script continuing';
           setTimeout("window.location.href = '$start_page&timeout=1'",1000);
        }
        </script>
    </head>
    <body>

    <div id="loading"><script type="text/javascript">document.write('<p>Initialising<br>ionCube Loader Wizard<br><span id="status"></span></p>');</script><p id="noscript">Your browser does not support JavaScript so the ionCube Loader Wizard initialisation cannot be made now. This script can get the latest loader version information from the ionCube server when you go to the next page.<br>Please choose one of the following. <br>If the script appears to hang please restart the script and choose the "NO" option.<br><br><br><a href="$start_page">YES - my server DOES have internet access</a><br><br><a href="$start_page&timeout=1">NO - my server does NOT have internet access</a></p></div>
    <script type="text/javascript">
        document.getElementById('noscript').style.display = 'none';
        window.onload = startChecks;
    </script>
    </body>
    </html>
EOT;
}

function default_page($loader_extension = LOADER_EXTENSION_NAME)
{
    $self = get_self();
    foreach (array('self') as $vn) {
        if (empty($$vn)) {
			$server_data = print_r($_SERVER,true);
            error("Unable to initialise ($vn)". ' $_SERVER is: ' . $server_data);
        }
    }

    heading();

    $wizard_update = check_for_wizard_update(true);

    $rtl = try_runtime_loading_if_applicable();

    $server_type = find_server_type();

    if (extension_loaded($loader_extension) && $server_type != SERVER_UNKNOWN) {
        loader_already_installed($rtl);
    } else {
        loader_not_installed();
    }
    send_stats('default');

    footer($wizard_update);
}

function uninstall_wizard_instructions()
{
    echo '<p><strong>For security reasons we advise that you remove this Wizard script from your server now that the ionCube Loader is installed.</strong></p>';
}

function contact_script_provider_instructions()
{
    echo '<p>Please contact the script provider if you do experience any problems running encoded files.</p>';
}

function may_need_to_copy_ini()
{
    $sys = get_sysinfo();
    if (ini_same_dir_as_wizard() && $sys['IS_CGI']) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        $ini = ini_file_name();
        echo "<p>Please note that if encoded files in a different $dirphrase from the Wizard fail then you should attempt to copy the $ini file to each $dirphrase in which you have encoded files.</p>";
    }
}

function ioncube_24_is_available()
{
	$loaderinfo = get_loaderinfo();
	$php_ver = php_version();
   
	return ($loaderinfo['oscode'] == 'lin' && (($php_ver['major'] == 5 && $php_ver['minor'] >= 3) || $php_ver['major'] > 5) );
}

function ioncube_24_is_enabled()
{
	$ic24_enabled = ini_get(IC24_ENABLED_INI_PROPERTY);
	return $ic24_enabled;
}

function ioncube_24_information()
{
    if (ioncube_24_is_available() && !ioncube_24_is_enabled()) {
        $self = get_self();
        echo '<div class="ic24">';
        echo '<div class="ic24graphic">';
        echo '<a target="_blank" href="' . IONCUBE24_URL . '"><img id="ic24logo" src="' . $self . '?page=ic24logo" alt="ionCube24 logo"></a>';
        echo '</div>';
        echo '<div id="ic24info">';
        echo '<p><strong>Bonus Features!</strong> The ionCube Loader can also give ';
        echo '<strong>real-time intrusion protection</strong> to protect against malware and <strong>PHP error reporting</strong> ';
        echo 'to alert when things go wrong on your website.</p>';
        echo '<p>These features are disabled by default but easily activated. ';
        echo '<strong><a target="_blank" href="' . IONCUBE24_URL . '">visit ioncube24.com</a></strong> to find out more.</p>';
        echo '</div>';
        echo '</div>';
    }
}

function cli_install_instructions()
{

	if (is_php_version_or_greater(5,3)) {
		$cli_loader_installed = shell_exec('php -r "echo extension_loaded(\"' . LOADER_EXTENSION_NAME . '\");"');
		
		if (!$cli_loader_installed) {
			$cli_php_ini_output = shell_exec("php --ini");
			
			$ini_loader_loc = scan_inis_for_loader();
		
			if (!is_null($cli_php_ini_output)) {
				echo '<div class="panel">';
				echo '<h4>Loader Installation for Command-Line (CLI) PHP</h4>';
				echo "<p>At present it does not look like the ionCube Loader is installed for command-line (CLI) PHP.</p>";
				echo "<p>Please note that if you need to run the CLI PHP, such as for <strong>cron jobs</strong>, then please ensure the zend_extension line for the ionCube Loader is included in your CLI PHP configuration.</p>";
				
				if (!empty($ini_loader_loc['location'])) {
					echo "<p>The zend_extension line that needs to be copied is:</p>";
					echo "<p><kbd>zend_extension = " . $ini_loader_loc['location'] . "</kbd></p>";
				}
				
				echo "<p>Your CLI PHP Configuration is:</p>";
				echo '<div class="terminal">';
				echo "<pre>";
				echo $cli_php_ini_output;
				echo "</pre>";
				echo '</div>';
				echo '</div>';
			}
		}
	}
}

function successful_install_end_instructions($rtl_path = null)
{
    if (empty($rtl_path)) {
        may_need_to_copy_ini();
    } elseif (is_string($rtl_path)) {
        echo "<p>The runtime loading method of installation was used with path <code>$rtl_path</code></p>";
    }
    contact_script_provider_instructions();
    if (is_legacy_platform()) {
        legacy_platform_instructions();
    }
	
	if (!is_ms_windows() && is_php_version_or_greater(5,3)) {
		cli_install_instructions();
	}
	
    uninstall_wizard_instructions();
	
	ioncube_24_information();
}

function loader_major_version_instructions($mv)
{
    if ($mv < LATEST_LOADER_MAJOR_VERSION) {
        echo "<p><strong>The installed version of the Loader cannot run files produced by the most recent ionCube Encoder.</strong>";
        echo " You will need a version " . LATEST_LOADER_MAJOR_VERSION . " ionCube Loader to run such files.</p>";
    }
    return ($mv < LATEST_LOADER_MAJOR_VERSION);
}

function loader_already_installed($rtl = null)
{
    list($lv,$mv,$newer_version) = ioncube_loader_version_information();
    $phpv = php_version_maj_min();
    $php_str = ' for PHP ' . $phpv;
    echo '<div class="success">';
    echo '<h4>Loader Installed</h4>';
    if ($newer_version) {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is <strong>already installed</strong> but it is an old version.';
        echo ' It is recommended that the Loader be upgraded to the latest version if possible.</p>';
        $know_latest_version = is_string($newer_version);
        $is_legacy_loader = loader_major_version_instructions($mv);
        echo '</div>';
        loader_upgrade_instructions($lv,$newer_version);
    } else {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is already installed and encoded files should run without problems.</p>'; 
        echo '</div>';
        $is_legacy_loader = loader_major_version_instructions($mv,true);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,true);
        }
    }

    successful_install_end_instructions($rtl);
}

function loader_upgrade_instructions($installed_version,$newer_version)
{
    if ($newer_version) {
        echo '<div class="panel">';
        echo '<h4>Loader Upgrade Instructions</h4>';
        $restart_needed = true;
        $server_type = find_server_type();
        if ($server_type == SERVER_SHARED || $server_type == SERVER_UNKNOWN) {
            $loader_path = find_loader(true);
            if (!is_string($loader_path) || false === user_ini_space_path($loader_path)) {
                $verb_case = ($server_type == SERVER_UNKNOWN)?"may":"will";
                echo "<p>Please note that you $verb_case need your system administrator to do the following to upgrade. The web server will need to be restarted after the loader file is changed.</p>";
            }
            $restart_needed = false;
        }
        if (is_string($newer_version)) {
            $version_str = "version $newer_version";
        } else {
            $version_str = "a newer version";
        }
        $loader_name =  get_loader_name();
        echo "<p>To upgrade from version $installed_version to $version_str of the ionCube Loader, please replace your existing loader file, $loader_name, with
            the file of the same name from one of the following packages:</p>";
        if (is_ms_windows()) {
            $basename = windows_package_name();
        } else {
            list($basename,$multiple_os_versions) = unix_package_name();
        }
        echo make_archive_list($basename,array('zip','tar.gz'));
        if ($restart_needed) {
            echo "<p>Once you have replaced the loader file please restart your web server.</p>";
        }
        echo '</div>';
    }
}

function legacy_platform_warning()
{
    $leg_warn = '<p><strong>You are on a platform on which ionCube Loaders are no longer being developed. ';
    $leg_warn .= 'Loaders on your platform may not be able to run files produced by the latest ionCube Encoder. ';
    $leg_warn .= 'Please switch, if possible, to a platform on which loaders are currently supported. ';
    $leg_warn .= 'A list of currently supported platforms is shown on our <a href="' . LOADERS_PAGE . '" target="loaders">loaders page</a>.</strong></p>';

    return $leg_warn;
}

function legacy_platform_instructions()
{
    echo legacy_platform_warning();
}

function loader_not_installed()
{
    $loader = get_loaderinfo();
    $sysinfo = get_sysinfo();

    $stype = get_request_parameter('stype');
    $manual_select = get_request_parameter('manual');
    $host_type = find_server_type($stype,$manual_select,true);

    if ($host_type != SERVER_UNKNOWN && is_array($loader) && !$sysinfo['DEBUG_BUILD']) {
        $warnings = server_restriction_warnings();
        if (is_legacy_platform()) {
            $warnings[] = legacy_platform_warning();
        }
        if (empty($_SESSION['use_ini_method']) && $host_type == SERVER_SHARED && runtime_loading_is_possible()) {
            $errors = runtime_loading_errors();
        } else {
            $errors = ini_loader_errors();
            $warnings = array_merge($warnings,ini_loader_warnings());
        }
        if (!empty($errors)) {
            if (count($errors) > 1) {
                $problem_str = "Please note that the following problems currently exist";
            } else {
                $problem_str = "Please note that the following problem currently exists";
            }
            echo '<div class="alert">' .$problem_str . ' with the ionCube Loader installation:';
            echo make_list($errors,"ul"); 
            echo '</div>';
        }
        if (!empty($warnings)) {
            $addword = empty($errors)?'':'also';
            $plural = (count($warnings)>1)?'s':'';
            echo '<div class="warning">';
            echo "Please note $addword the following issue$plural:";
            echo make_list($warnings,"ul"); 
            echo '</div>';
        }
    }
    if (!isset($stype)) {
        echo '<p>To use files that have been protected by the <a href="' . ENCODER_URL . '" target=encoder>ionCube PHP Encoder</a>, a component called the ionCube Loader must be installed.</p>';
    }

    if (!is_supported_php_version()) {
        echo '<p>Your server is running PHP version ' . PHP_VERSION . ' and is
                unsupported by ionCube Loaders.  Recommended PHP 4 versions are PHP 4.2 or higher, 
                PHP 5.1 or higher for PHP 5, PHP 7.1 or higher for PHP 7 and PHP 8.1 or higher for PHP 8. Please note that there is not an ionCube Loader for PHP 8.0.</p>';
	} elseif ($latest_supported_php_version = is_after_max_php_version_supported()) {
		echo '<strong>Your server is running PHP version ' . PHP_VERSION . ' and is
                currently unsupported by any ionCube Loaders. <br/>This may change in the future if a Loader is produced for your PHP platform.<br/>In the meantime please downgrade PHP to version ' . $latest_supported_php_version . '.</strong>';
    } elseif ($sysinfo['DEBUG_BUILD']) {
         echo '<p>Your server is currently running a debug build of PHP. The Loader cannot be installed with a debug build of PHP. Please ensure that PHP is reconfigured with debug disabled. Note that debug builds of PHP cannot help in debugging PHP scripts.</p>'; 
    } elseif (!is_array($loader)) {
        if ($loader == ERROR_WINDOWS_64_BIT) {
            echo '<p>Loaders for 64-bit PHP on Windows are not currently available. However, if you <b>install and run 32-bit PHP</b> the corresponding 32-bit loader for Windows should work.</p>';
            if ($sysinfo['THREAD_SAFE']) {
                echo '<li>Download one of the following archives of 32-bit Windows x86 loaders:';
            } else {
                echo '<li>Download one of the following archives of 32-bit Windows non-TS x86 loaders:';
            }
            echo make_archive_list(windows_package_name());
        } else {
            echo '<p>There may not be an ionCube Loader available for your type of system at the moment. However, if you create a <a href="'  . SUPPORT_SITE . '">support ticket</a> more advice and information may be available to assist. Please include the URL for this Wizard in your ticket.</p>';
        }
    } elseif (!$sysinfo['SUPPORTED_COMPILER']) {
        $supported_compilers = supported_win_compilers();
        $supported_compiler_string = join('/',$supported_compilers);
        echo '<p>At the current time the ionCube Loader requires PHP to be built with ' . $supported_compiler_string . '. Your PHP software has been built using ' . $sysinfo['PHP_COMPILER'] . '. Supported builds of PHP are available from <a href="https://windows.php.net/download/">PHP.net</a>.';
    } else {
        switch ($host_type) {
            case SERVER_SHARED:
                shared_server();
                break;
            case SERVER_DEDICATED:
                dedicated_server();
                break;
            case SERVER_LOCAL:
                local_install();
                break;
            default:
                echo server_selection_form();
                break;
        }
    }
}

function server_selection_form()
{
    $self = get_self();
    $timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?1:0;
    $hostprovider = (!empty($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $hostprovider = htmlspecialchars($hostprovider, ENT_QUOTES, 'UTF-8');
    $hosturl = (!empty($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $hosturl =  htmlspecialchars($hosturl, ENT_QUOTES, 'UTF-8');
    $form = <<<EOT
    <p>This Wizard will give you information on how to install the ionCube Loader.</p>
    <p>Please select the type of web server that you have and then click Next.</p>
    <script type=text/javascript>
        function trim(s) {
            return s.replace(/^\s+|\s+$/g,"");
        }
        function input_ok() {
            var l = document.getElementById('local');
            if (l.checked) {
                return true;
            } 

            var s = document.getElementById('shared');
            var d = document.getElementById('dedi');

            if (!s.checked && !d.checked) {
                alert("Please select one of the server types.");
                return false;
            } else {
                var hn = document.getElementById('hostprovider');
                var hu = document.getElementById('hosturl');
                var hostprovider = trim(hn.value);
                var hosturl = trim(hu.value);

                if (!hostprovider || !hosturl) {
                    alert("Please enter both a hosting provider name and their URL.");
                    return false;
                }
                if (hostprovider.length < 1) {
                    alert("The hosting provider name should be at least 1 character in length.");
                    return false;
                }
                if (!hosturl.match(/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+/)) {
                    alert("The hosting provider URL is invalid.");
                    return false;
                }
                if (hosturl.length < 4) {
                    alert("The hosting provider URL should be at least 4 characters in length.");
                    return false;
                }
            }
            return true;
        }
    </script>
    <form method=GET action=$self>
        <input type="hidden" name="page" value="default">
        <input type="hidden" name="timeout" value="$timeout">
        <input type=radio id=shared name=stype value=s onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=shared>Shared <small>(for example, server with FTP access only and no access to php.ini)</small></label><br>
        <input type=radio id=dedi name=stype value=d onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=dedi>Dedicated or VPS <small>(server with full root ssh access)</small></label><br>
        <div id="hostinginfo" style="display: none">If you are on a shared or dedicated server, please give your hosting provider and their URL:
            <table>
                <tr><td><label for=hostprovider>Name of your hosting provider</label></td><td><input type=text id="hostprovider" name=hostprovider value="$hostprovider"></td></tr>
                <tr><td><label for=hosturl>URL of your hosting provider</label></td><td><input type=text id="hosturl" name=hosturl value="$hosturl"></td></tr>
            </table>
        </div>
        <input type=radio id=local name=stype value=l onclick="document.getElementById('hostinginfo').style.display = 'none';"><label for=local>Local install</label>
        <p><input type=submit value=Next onclick="return (input_ok(this) && showOverlay());"></p>
    </form>
EOT;
    return $form;
}

function phpinfo_page()
{
    info_disabled_check();
    if (function_is_disabled('phpinfo')) {
        echo "phpinfo is disabled on this server";
    } else {
        @phpinfo();
    }
}

function loader_check_page($ext_name = LOADER_EXTENSION_NAME)
{
    heading();

    $rtl_path = try_runtime_loading_if_applicable();
	
    if (extension_loaded($ext_name)) {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        $php_str = ' for PHP ' . $phpv;
        echo '<div class="success">';
        echo '<h4>Loader Installed Successfully</h4>';
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' <strong>is installed</strong> and encoded files should run successfully.';
        if ($newer_version) {
            echo ' Please note though that you have an old version of the ionCube Loader.</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            loader_upgrade_instructions($lv,$newer_version);
        } else {
            echo '</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            if ($is_legacy_loader) {
                loader_upgrade_instructions($lv,true);
            }
        }
        successful_install_end_instructions($rtl_path);
    } else {
        echo '<div class="failure">';
        echo '<h4>Loader Not Installed</h4>';
        echo '<p>The ionCube Loader is <b>not</b> currently installed successfully.</p>';
	
        if (!is_null($rtl_path)) {
            echo '<p>Runtime loading was attempted but has failed.</p>';
            echo '</div>';
            $rt_errors = runtime_loading_errors();
            if (!empty($rt_errors)) {
                list_loader_errors($rt_errors);
            } 
            link_to_php_ini_instructions();
        } else {
            echo '</div>';
            list_loader_errors();
        }
    }
	
    send_stats('check');
    footer(true);
}

function ini_loader_errors()
{
    $errors = array();
    if (SERVER_SHARED == find_server_type() && !own_php_ini_possible(true)) {
        $errors[ERROR_INI_USER_CANNOT_CREATE] = "It appears that you are not be able to create your own ini files on your shared server. <br><strong>You will need to ask your server administrator to install the ionCube Loader for you.</strong>";
    }
    $loader_loc = find_loader(false);
    if (is_string($loader_loc)) {
        if (!shared_and_runtime_loading()) {
            $sys = get_sysinfo();
            if (empty($sys['PHP_INI'])) {
                $errors[ERROR_INI_NO_PATH] = 'No file path found for the PHP configuration file (php.ini).';
            } elseif (!@file_exists($sys['PHP_INI'])) {
                $errors[ERROR_INI_NOT_FOUND] = 'The PHP configuration file (' . $sys['PHP_INI'] .') cannot be found.';
            }
        }
        $errors = $errors + loader_compatibility_test($loader_loc);
    } else {
        $errors = $errors + $loader_loc;
        $fs_location = find_loader_filesystem();
        if (!empty($fs_location)) {
            $fs_loader_errors = loader_compatibility_test($fs_location);
            if (!empty($fs_loader_errors)) {
                $errors[ERROR_LOADER_WRONG_GENERAL] = "The loader file found at $fs_location is not the correct one for your system.";
            }
            $errors = $errors + $fs_loader_errors;
        }
    } 
    return $errors;
}

function unix_path_dir($dir = '')
{
    if (empty($dir)) {
        $dir = dirname(__FILE__);
    }
    if (is_ms_windows()) {
        $dir = str_replace('\\','/',substr($dir,2));
    }
    return $dir;
}

function unrecognised_inis_webspace($startdir)
{
    $ini_list = array();

    $ini_name = ini_file_name();
    $sys = get_sysinfo();
    $depth = substr_count($startdir,'/');

    $rel_path = '';
    $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
    for ($seps = 0; $seps < $depth; $seps++) {
        $full_ini_loc = @realpath($startdir . '/' . $rel_path) . DIRECTORY_SEPARATOR . $ini_name;
        if (@file_exists($full_ini_loc) && $sys['PHP_INI'] != $full_ini_loc) {
            $ini_list[] = @realpath($full_ini_loc);
        }

        if (dirname($full_ini_loc) == $rootpath) {
            break;
        }
        $rel_path .= '../';
    }
    return $ini_list;
}

function correct_loader_wrong_location()
{
    $loader_location_pair = array();
    $loader_location = find_loader_filesystem();
    if (is_string($loader_location) && !empty($loader_location)) {
        $loader_errors = loader_compatibility_test($loader_location);
        if (empty($loader_errors)) {
            $ini_loader = scan_inis_for_loader();
            if (!empty($ini_loader['location'])) {
                $ini_loader_errors = loader_compatibility_test($ini_loader['location']);
                if (!empty($ini_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = dirname($ini_loader['location']);
                }
            } else {
                $std_dir = loader_install_dir(find_server_type());
                $std_ld_path = $std_dir . DIRECTORY_SEPARATOR . get_loader_name();
                if (@file_exists($std_ld_path)) {
                    $stdloc_loader_errors = loader_compatibility_test($std_ld_path);
                } else {
                    $stdloc_loader_errors = array("Loader file does not exist.");
                }
                if (!empty($stdloc_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = $std_dir;
                }
            }
        }
    }
    return $loader_location_pair;
}

function ini_loader_warnings()
{
    $warnings = array();
    if (find_server_type() == SERVER_SHARED)
    {
        if (own_php_ini_possible()) {
            $sys = get_sysinfo();
            $ini_name = ini_file_name();
            $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
            $root_ini_file = $rootpath . DIRECTORY_SEPARATOR . $ini_name;
            $cgibinpath = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
            $cgibin_ini_file = (empty($cgibinpath))?'':$cgibinpath . DIRECTORY_SEPARATOR . $ini_name;
            $here = unix_path_dir();
            $ini_files = unrecognised_inis_webspace($here);
            $shared_ini_loc = shared_ini_location();
            $shared_ini_file = $shared_ini_loc . DIRECTORY_SEPARATOR . $ini_name;
            $ini_dir = dirname($sys['PHP_INI']);
            $all_ini_locations_used = !empty($ini_files);
            foreach ($ini_files as $full_ini_loc) {
                $advice = "The file $full_ini_loc is not being recognised by PHP.";
                $advice .= " Please check that the name and location of the file are correct.";
                if (!ini_same_dir_as_wizard()) {
                    $ini_loc_dir = dirname($full_ini_loc);
                    if (!@file_exists($shared_ini_file) && !empty($shared_ini_loc) && $ini_loc_dir != $shared_ini_loc && $ini_dir != $shared_ini_loc) {
                        $all_ini_locations_used = false;
                        $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $shared_ini_loc . "</code>.";
                    } else {
                        if (!@file_exists($root_ini_file) && $rootpath != $shared_ini_loc && $full_ini_loc != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $rootpath . "</code>.";
                        } 
                        if (!empty($cgibin_ini_file) && !@file_exists($cgibin_ini_file) && $cgibinpath != $shared_ini_loc && $full_ini_loc != $cgibinpath && $cgibinpath != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= "  Please try copying the <code>$full_ini_loc</code> file to <code>" . $cgibinpath . "</code>.";
                        }
                        $herepath = realpath($here);
                        $here_ini_file = $herepath . DIRECTORY_SEPARATOR . $ini_name;
                        if (!@file_exists($here_ini_file) && $herepath != $rootpath && $herepath != $cgibinpath) {
                            $all_ini_locations_used = false;
                            $advice .= " It may be necessary to copy the <code>$full_ini_loc</code> file to <code>$herepath</code> and to all " . (is_ms_windows()?'folders':'directories') . ' in which you have encoded files';
                        }
                    }
                } else {
                    $all_ini_locations_used = false;
                }
                $warnings[] = $advice;
            }
            if ($all_ini_locations_used) {
                $warnings[] = "<strong>It looks as if ini files are not being recognised in any of the standard locations in your webspace. Please contact your hosting provider to check whether you can create your own PHP ini file and where it should go.</strong>";
            }
        } else {
            if (own_php_ini_possible(true)) {
                $warnings[] = "You may not be able to create your own ini files on your shared server. <br><strong>You might need to ask your server administrator to install the ionCube Loader for you.</strong>";
            }
        }
    } else {
        $loader_dir_pair = correct_loader_wrong_location();
        if (!empty($loader_dir_pair)) {
            $advice = "The correct loader for your system has been found at <code>${loader_dir_pair['loader']}</code>."; 
            if ($loader_dir_pair['loader'] != $loader_dir_pair['newloc']) {
                $advice .= " Please copy the loader from <code>${loader_dir_pair['loader']}</code> to <code>${loader_dir_pair['newloc']}</code>.";
            }
            $warnings[] = $advice;
        }
    }
    return $warnings;
}

function list_loader_errors($errors = array(),$warnings = array(),$suggest_restart = true)
{
    $default = get_default_address();
    $retry_message = '';

    
    if (empty($errors)) {
        $errors = ini_loader_errors();
        if (empty($warnings)) {
            $warnings = ini_loader_warnings();
        }
    }
	
    if (!empty($errors)) {
        $try_again = '<a href="#" onClick="window.location.href=window.location.href">try again</a>';
	
        echo '<div class="alert">';
        if (count($errors) > 1) {
            echo 'The following problems have been found with the ionCube Loader installation:';
            $retry_message = "Please correct those errors and $try_again.";
        } else {
            echo 'The following problem has been found with the ionCube Loader installation:';
            $retry_message = "Please correct that error and $try_again.";
        }
        if (array_key_exists(ERROR_INI_USER_CANNOT_CREATE,$errors)) {
            $retry_message = '';
        }
        echo make_list($errors,"ul");
        echo '</div>';
        if (!empty($warnings)) {
            echo '<div class="warning">';
            echo 'Please also note the following:';
            echo make_list($warnings,"ul");
            echo '</div>';
        }
    } elseif (!empty($warnings)) {
        echo '<div class="warning">';
        echo 'There are the following potential problems:';
        echo make_list($warnings,"ul");
        echo '</div>';
    } elseif ($suggest_restart) {
        if (SERVER_SHARED == find_server_type()) {
            echo "<p>Please contact your server administrator about installing the ionCube Loader.</p>";
        } else {
            if (selinux_is_enabled()) {
                echo "<p>It appears that SELinux is enabled on your server. This might be solved by running the command <code>restorecon [full path to loader file]</code> as root.</p>";
            } elseif (grsecurity_is_enabled()) {
                echo "<p>It appears that grsecurity is enabled on your server. Please run the command, <code>execstack -c [full path to loader file]</code> and then restart your web server.</p>";
            } else {
                $sysinfo = get_sysinfo();
                $ss = $sysinfo['SS'];
				if ($ss == 'PHP-FPM') {
					echo "<p>Please check that PHP-FPM has been restarted.</p>";
                } elseif (!$sysinfo['CGI_CLI'] || is_ms_windows()) {
                    echo "<p>Please check that the $ss web server software has been restarted.</p>";
                } 
            }
        }
    }
    echo '<div>';
    echo $retry_message;
    echo " You may wish to view the following for further help:";
    echo make_list(help_resources($errors),"ul");
    echo '<a href="' . $default . '">Click here to go back to the start of the Loader Wizard</a>.</div>';
}

function phpconfig_page()
{
    info_disabled_check();
    $sys = get_sysinfo();
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        } else {
			if (!preg_match('`^.*\.ini$`',$ini_file_name) || preg_match('`/`',$ini_file_name) || preg_match('`\\\`',$ini_file_name)) {
				die("Illegal file name $ini_file_name");
			}
		}
        header('Content-Type: text/plain');
        header('Content-Disposition: attachment; filename=' . $ini_file_name);
    } else {
        header('Content-Type: text/plain');
    }
    $exclude_original = get_request_parameter('newlinesonly');
    $prepend = get_request_parameter('prepend');
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    if (!empty($exclude_original) || !empty($prepend)) {
        $loader_dir = loader_install_dir($server_type);
        $zend_lines = zend_extension_lines($loader_dir);
        echo join(PHP_EOL,$zend_lines);
        echo PHP_EOL;
    }
    if (empty($ini_file_name) || empty($sys['PHP_INI_DIR']) || ($sys['PHP_INI_BASENAME'] == $ini_file_name)) {
        $original_ini_file = isset($sys['PHP_INI'])?$sys['PHP_INI']:'';
    } else {
        $original_ini_file = $sys['PHP_INI_DIR'] . DIRECTORY_SEPARATOR . $ini_file_name;
    }
    if (empty($exclude_original) && !empty($original_ini_file) && @file_exists($original_ini_file)) {
        if (!empty($download)) {
            @readfile($original_ini_file);
        } else {
            echo all_ini_contents();
        } 
    }
}

function extra_page($check_access_to_info = true)
{
    if ($check_access_to_info) {
		info_disabled_check();
	}
    heading();
    $sys = get_sysinfo();
    $ini_loader = scan_inis_for_loader();
    $ini_loader_path = $ini_loader['location'];
    $loader_path = find_loader(true);
    $ldinf = get_loaderinfo();
    $self = get_self();
    echo "<h4>Additional Information</h4>";
    echo "<table>";
    $lines = array();
    if (is_string($loader_path)) {
        $lines['Loader is at'] = $loader_path;
        $loader_system = loader_system($loader_path);
        if (!empty($loader_system)) {
            $lines['Loader OS code'] = $loader_system['oscode'];
            $lines['Loader architecture'] = $loader_system['arch'];
            $lines['Loader word size'] = $loader_system['wordsize'];
            $lines['Loader PHP version'] = $loader_system['php_version'];
            $lines['Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Loader compiler'] = $loader_system['compiler'];
            $lines['Loader version'] = $loader_system['loader_version'];
            $lines['File size is'] = filesize($loader_path) . " bytes.";
            $lines['MD5 sum is'] = md5_file($loader_path);
        }
        $lines['Loader file'] = "<a href=\"$self?page=loaderbin\">Download loader file</a>";
    } else {
        $lines['Loader file'] = "Loader cannot be found.";
    }
    $lines['Loader found in ini file'] = empty($ini_loader_path)?"No":"Yes";
    if (!empty($ini_loader_path) && (!is_string($loader_path) || $ini_loader_path != $loader_path)) {
        $lines['Loader location found in ini file'] =  $ini_loader_path;
        $loader_system = loader_system($ini_loader_path);
        if (!empty($loader_system)) {
            $lines['Ini Loader OS code'] = $loader_system['oscode'];
            $lines['Ini Loader architecture'] = $loader_system['arch'];
            $lines['Ini Loader word size'] = $loader_system['wordsize'];
            $lines['Ini Loader PHP version'] = $loader_system['php_version'];
            $lines['Ini Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Ini Loader compiler'] = $loader_system['compiler'];
            $lines['Ini Loader version'] = $loader_system['loader_version'];
        }
    }
    $lines["OS extra security"] = (selinux_is_enabled() || possibly_selinux())?"SELinux":(grsecurity_is_enabled()?"Grsecurity":"None");
    $lines['PHPRC is'] = $sys['PHPRC'];
    $lines['INI DIR is'] = $sys['PHP_INI_DIR'];
    $lines['Additional INI files'] = $sys['PHP_INI_ADDITIONAL'];
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    $lines['Server type is'] = server_type_string();
    $lines["PHP uname"] = $ldinf['uname'];
    $lines['Server word size is'] = $ldinf['wordsize'];
    $lines['Disabled functions'] = ini_get('disable_functions');
    $writeable_dirs = writeable_directories();
    $lines['Writeable loader locations'] = (empty($writeable_dirs))?"<em>None</em>":join(", ",$writeable_dirs);
    if (!empty($_SESSION['hostprovider'])) {
        $lines['Hosting provider'] = $_SESSION['hostprovider'];
        $lines['Provider URL'] = $_SESSION['hosturl'];
    }
    foreach ($lines as $h => $i) {
        $v = (empty($i))?'<em>EMPTY</em>':$i;
        echo '<tr><th>'. $h . ':</th>' . '<td>' . $v . '</td></tr>';
    }
    echo "</table>";
    footer(true);
}

function loaderbin_page()
{
    info_disabled_check();
    $loader_path = find_loader(true);
    if (is_string($loader_path)) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. basename($loader_path));
        @readfile($loader_path);
    }
}



function GoDaddy_root($html_root = '')
{
    if (empty($_SESSION['not_go_daddy']) && empty($_SESSION['godaddy_root'])) {
        $godaddy_pattern = "[\\/]home[\\/]content[\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z]+[\\/]html";

        if (empty($html_root)) {
            $html_root =  $_SERVER['DOCUMENT_ROOT'];
        }
        if (preg_match("@$godaddy_pattern@i",$html_root,$matches)) {
            $_SESSION['godaddy_root'] = $matches[0];
        } else {
            $_SESSION['not_go_daddy'] = 1;
            $_SESSION['godaddy_root'] = '';
        } 
    } elseif (!empty($_SESSION['not_go_daddy'])) {
        $_SESSION['godaddy_root'] = '';
    }
    if (!empty($_SESSION['godaddy_root'])) {
        $_SESSION['hostprovider'] = 'GoDaddy';
        $_SESSION['hosturl'] = 'www.godaddy.com';
    }
    return $_SESSION['godaddy_root'];
}

function GoDaddy_windows_instructions()
{
    $instr = "It appears that you are hosted on a Windows server at GoDaddy.<br/>";
    $instr .= "Please change to a Linux hosting plan at GoDaddy.<br />";
    $instr .=  "If you <a href=\"https://help.godaddy.com/\">contact their support team</a> they should be able to switch you to a Linux server.";

    echo $instr;
}

function GoDaddy_linux_instructions($html_dir)
{
    $base = get_base_address();
    $loader_name = get_loader_name();
    $zend_extension_line="<code>zend_extension = $html_dir/ioncube/$loader_name</code>";
    $php_ini_name = is_php_version_or_greater(5,0)?'php5.ini':'php.ini';
    $ini_path = $html_dir . '/' . $php_ini_name;

    $instr = array();
    $instr[] = 'In your html directory, ' . $html_dir . ', create a sub-directory called <b>ioncube</b>.';
    if (@file_exists($ini_path)) {
       $instr[] = "Edit the $php_ini_name in your  $html_dir and add the following line to the <b>top</b> of the file:<br>" . $zend_extension_line ;
    } else {
        $instr[] = "<a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=s&amp;download=1&amp;prepend=1\">Save this $php_ini_name file</a> and upload it to your html directory, $html_dir";
    }
    $instr[] = 'Download the <a target="_blank" href="' . IONCUBE_DOWNLOADS_SERVER . '"/ioncube_loaders_lin_x86.zip">Linux ionCube Loaders</a>.';
    $instr[] = 'Unzip the loaders and upload them into the ioncube directory you created previously.';
    $instr[] = 'The encoded files should now be working.';

    echo '<div class=panel>';
    echo (make_list($instr));
    echo '</div>';
}

function GoDaddy_page()
{
    $base = get_base_address();

    heading();

        $inst_str = '<h4>GoDaddy Installation Instructions</h4>';
        $inst_str .= '<p>It appears that you are hosted with GoDaddy (<a target="_blank" href="https://www.godaddy.com/">www.godaddy.com</a>). ';
        $inst_str .= "If that is <b>not</b> the case then please <a href=\"$base&amp;page=default&amp;host=ngd\">click here to go to the main page of this installation wizard</a>.</p>";
        $inst_str .= "<p>If you have already installed the loader then please <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the loader</a>.</p>";

        echo $inst_str;

        if (is_ms_windows()) {
            GoDaddy_windows_instructions();
        } else {
            GoDaddy_linux_instructions($_SESSION['godaddy_root']);
        }

    send_stats('gd_default');

    footer(true);
}



function get_request_parameter($param_name)
{
    static $request_array;

    if (!isset($request_array)) {
        if (isset($_GET)) {
            $request_array = $_GET;
        } elseif (isset($HTTP_GET_VARS)) {
            $request_array = $HTTP_GET_VARS;
        }
    }

    if (isset($request_array[$param_name])) {
        $return_value = strip_tags($request_array[$param_name]);
    } else {
        $return_value = null;
    }
    return $return_value;
}

function make_list($list_items,$list_type='ol')
{
    $html = '';
    if (!empty($list_items)) {
        $html .= "<$list_type>";
        $html .= '<li>';
        $html .= join('</li><li>',$list_items);
        $html .= '</li>';
        $html .= "</$list_type>";
    }
    return $html;
} 

function make_archive_list($basename,$archives_list = array(),$download_server = IONCUBE_DOWNLOADS_SERVER)
{
    if (empty($archives_list)) {
        $archives_list = array('tar.gz','zip');
    }

    foreach ($archives_list as $a) {
        $link_text = $a;
        $ext_sep = '.';
        $archive_list[] = "<a href=\"$download_server/$basename$ext_sep$a\">$link_text</a>";
    }

    return make_list($archive_list,"ul");
}

function error($m)
{
    die("<b>ERROR:</b> <span class=\"error\">$m</span><p>Please help us improve this script by <a href=\"". SUPPORT_SITE . "\">reporting this error</a> and including the URL to the script so that we can test it.");
}


function filter_server_input($server_var)
{
	$res = htmlspecialchars($_SERVER[$server_var], ENT_QUOTES, "UTF-8");
	return $res;
}

function failsafe_get_self()
{
    $result = '';
    $sfn = filter_server_input('SCRIPT_FILENAME');
    $dr = $_SERVER['DOCUMENT_ROOT'];
    if (!empty($sfn) && !empty($dr)) {
        if ($dr == '/' || $dr == '\\') {
            $result = $sfn;
        } else {
            $drpos = strpos($sfn,$dr);
            if ($drpos === 0) {
                $drlen = strlen($dr);
                $result = substr($sfn,$drlen);
            }
        }
        $result = str_replace('\\','/',$result);
    }
    if (empty($result)) {
        $result = DEFAULT_SELF;
    }
    return $result;
}

function get_self()
{ 
	$page = '';
    if (empty($_SERVER['PHP_SELF'])) {
        if (empty($_SERVER['SCRIPT_NAME'])) {
            if (empty($_SERVER['REQUEST_URI'])) {
                $page = failsafe_get_self();
            } else {
                $page = filter_server_input('REQUEST_URI');
            }
        } else {
            $page = filter_server_input('SCRIPT_NAME');
        }
    } else {
        $page = filter_server_input('PHP_SELF');
    }
	return $page;
}

function get_default_page()
{
    $godaddy_root = GoDaddy_root();
    if (empty($godaddy_root)) {
         $page = 'default';
    } else {
         $page = 'GoDaddy';
    }
    return $page;
}

function get_base_address()
{
    $self = get_self();
    $remote_timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?'timeout=1':'timeout=0';
    $using_ini = (isset($_SESSION['use_ini_method']) && $_SESSION['use_ini_method'])?'ini=1':'ini=0';
    return $self . '?' . $remote_timeout . '&' . $using_ini;
}

function get_default_address($include_timeout = true)
{
    if ($include_timeout) {
        $base =  get_base_address();
        $base .= "&amp;";
    } else {
        $base = get_self();
        $base .= "?";
    }
    $page = get_default_page();

    return $base . 'page=' . $page;
}

function heading()
{
    $self = get_self();

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <meta name="robots" content="noindex, nofollow">
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <script type="text/javascript">
            function showOverlay()
            {
                document.getElementById('overlay').style.display = 'block';
                return true;
            }

            function hideOverlay()
            {
                document.getElementById('overlay').style.display = 'none';
                return true;
            }
        </script>
    </head>
    <body onload="hideOverlay()">
    <div id="overlay">
        <div id="inner_overlay">Checking server configuration<br>Please wait</div>
    </div>
    <div id="header">
        <img src="?page=logo" alt="ionCube logo">
    </div>
	<div id="important">
	<h3 class="important">IMPORTANT: Ensure that This Script Is Removed When No Longer Required</h3>
	</div>
    <div id="main">
    <h2>ionCube Loader Wizard</h2>
EOT;
}

function footer($update_info = null)
{
    $self = get_self();
    $base = get_base_address();
    $default = get_default_address(false);
    $year = gmdate("Y");

    echo "</div>";
    echo "<div id=\"footer\">" .
    "Copyright ionCube Ltd. 2002-$year | " .
    "Loader Wizard version " . script_version() . " ";

    if ($update_info === true) {
        $update_info = check_for_wizard_update(false);  
    }
    $loader_wizard_loc = LOADER_WIZARD_URL;
    $wizard_version_string =<<<EOT
    <script type="text/javascript">
    var xmlhttp;
    function version_check()
    { 
        var body = document.getElementsByTagName('body')[0];
        var ldel = document.getElementById('loading');
        if (!ldel) {
            body.innerHTML += '<div id="loading"></div>';
            ldel = document.getElementById('loading');
        }
        ldel.innerHTML = '<p>Retrieving Wizard version information<br>Please wait</p>';
        ldel.style.display = 'block';
        ldel.style.height = '300px';
        ldel.style.left = '200px';
        ldel.style.border = '4px #660000 solid';
        if (window.XMLHttpRequest) {
            xmlhttp=new XMLHttpRequest();
        } else {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            var loadedOkay = 0;
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                var wizardversion = xmlhttp.responseText;
                var msg;
                clearTimeout(xmlHttpTimeout);
                buttons = '';
                if (wizardversion == '1') {
                    msg = 'You have the current version of the<br>ionCube Loader Wizard'; 
                } else if (wizardversion != '0') {
                    msg = 'A new version, ' + wizardversion + ', of the loader wizard is available';
                    buttons = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; window.open(\'$loader_wizard_loc\'); return false">Get new version</button> &nbsp;'; 
                } else {
                    msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
                }
                buttons += '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>'; 
                ldel.innerHTML = '<p>' + msg +  '<br>' + buttons + '</p>';
            }
        }
        xmlhttp.open("GET",'$self?page=wizardversion&wizard_only=1&clear_info=1',true);
        xmlhttp.send();
        var xmlHttpTimeout=setTimeout(ajaxTimeout,7000);
    }
    function ajaxTimeout(){
       xmlhttp.abort();
       msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
       button = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>';
       var ldel = document.getElementById('loading');
       ldel.innerHTML = '<p>' + msg +  '<br>' + button + '</p>';
    }
    </script>
EOT;

    $wizard_version_string .= '('; 
    if ($update_info === null) {
        $wizard_version_string .= '<a target="_blank" href="' . $loader_wizard_loc . '" onclick="version_check();return false;">check for new version</a>';
    } else if ($update_info !== false) {
        $wizard_version_string .= '<a href="' . LOADERS_PAGE .'" target="_blank">download version ' . $update_info . '</a>';
    } else {
        $wizard_version_string .=  "current";
    }
    $wizard_version_string .= ')'; 
    echo $wizard_version_string;

    $server_type_code = server_type_code();
	
	if (!info_should_be_disabled(true)) {
		echo " | <a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo</a>";
		echo " | <a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a>";
		echo " | <a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional</a>";
	}

    echo " | <a href=\"$default\" onclick=\"showOverlay();\">wizard start</a>";
    echo " | <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">loader test</a>";
    echo ' | <a href="' . LOADERS_PAGE . '" target="loaders">loaders</a>';

    echo "</div>\n";
    echo "\n</body></html>\n";
}

function css_page()
{
    header('Content-Type: text/css');
    echo <<<EOT
    body {
        font-family: verdana, helvetica, arial, sans-serif;
        font-size: 10pt;
        line-height: 150%;
        margin: 0px;
        min-height: 400px;
        position: relative;
    }

    code {
        color: #c00080;
    }

    li {
        margin-top: 10px;
    }
    #overlay {
        display: block;
        z-index: 100;
        position: absolute;
        top: 0;
        left: 0;
        padding: 0;
        margin: 0;
        width: 100%;
        height: 100%;
        background-color: white;
    }
    #inner_overlay {
        display: block;
        z-index: 100;
        position: absolute;
        font-size: 200%;
        color: #660000;
        top: 50%;
        left: 25%;
        width: 460px;
        height: 460px;
        line-height: 200%;
        text-align: center;
        vertical-align: middle;
    }

    #loading {
        display: block;
        position: absolute;
        top: 33%;
        left: 25%;
        margin: auto;
        height: 320px;
        width: 460px;
        padding: 4px;
        color: #660000;
        background-color: white;
        z-index: 100;
    }

    #loading p {
        position: absolute;
        margin-top: 10px;
        text-align: center;
        vertical-align: middle;
        padding-left: 40px;
        padding-right: 30px;
        font-size: 200%;
        line-height: 200%;
    }

    #loading p span#status{
        font-size: 60%;
        line-height: 120%;
    }
    #loading p#noscript {
        font-size: 120%;
        line-height: 120%;
        position: absolute;
        text-align: left;
        padding-top: 10px;
        bottom: 0;
    }
    #loading p#noscript a {
        text-align: center;
    }

    #loading button {
        margin-top: 20px;
        line-height: 100%;
        padding-top: 4px;
        padding-bottom: 4px;
    }


    h4 {
        margin-bottom: 0;
        padding-bottom: 4px;
    }

    p,#main div {
        max-width: 1000px;
        width: 75%;
    }

    #hostinginfo {
        margin-top: 10px;
        margin-left: 20px;
    }
    #hostinginfo table {
        font-size: 1.00em;
    }
    #hostinginfo table td {
        padding-right: 4px;
    }
    #hostinginfo input {
        margin-top: 6px;
    }

    #hostinginfo label {
        margin-left: 6px;
    }

    th {
        text-align: left;
    }
	
	#important {
		margin-top: 12px;
	} 
	h3.important {
		margin: 0;
		border: 0;
        border-top: 1px solid #660000;
		border-bottom: 1px solid #660000;
        padding: 1ex 0 1ex 0;
        background-color: #CB2430;
		text-align: center;
        color: #ffffff; 
        width: 100%;
	}

    .alert {
        margin: 2ex 0;
        border: 1px solid #660000;
        padding: 1ex 1em;
        background-color: #ffeeee;
        color: #660000; 
        width: 75%;
    }

    .warning {
        margin: 2ex 0;
        border: 1px solid #FFBF00;
        padding: 1ex 1em;
        background-color: #FDF5E6;
        color: #000000; 
        width: 75%;
    }

    .success {
        margin: 2ex 0;
        border: 1px solid #006600;
        padding: 1ex 1em;
        background-color: #EEFFEE;
        color: #000000; 
        width: 75%;
    }

    .error {
        color: #FF0000;
    }

    .panel {
        border: 1px solid #c0c0c0;
        background-color: #f0f0f0;
        width: 75%;
        padding: 1ex 1em;
    }
	
	.terminal {
		border: none;
		background-color: #000000;
		color: #ffffff;
		width: 50%;
		padding: 1ex 1em;
	}

    #header {
        background: #fff;
    }

    #footer {
        border-top: 1px solid #404040;
        margin-top: 20px;
        padding-top: 10px;
        padding-left: 20px;
        font-size: 75%;
        text-align: left;
    }

    #main {
        margin: 20px;
    }
	
	
	#main .ic24 {
		position: relative;
		width: 75%;
		height: auto;
		border-width: 1px 1px 1px 1px;
		border-style: solid;
		border-color: #4B8DF8;   
		background-color: #EFEFFF;
		padding: 12px;
		padding-top: 16px;
		padding-bottom: 8px;
		margin-top: 20px;
		overflow: hidden;
	}
	
	#main .ic24 p {
		width: 100%;
	}
	
	
	#main .ic24graphic {
		position: relative;
		width: auto;
		height: auto;
		border: none;
		padding: 0px;
		padding-right: 16px;
		margin: 0px;
		float: left;
		
	}
	
	#main #ic24info {
		position: relative;
		width: auto;
		height: auto;
		float: left;
	}
	
	#main #ic24info a {
		color: #0B4DB8;
		text-decoration: none;
	}
	
	#main #ic24logo {
		max-width: 132px;
		max-height: 132px;
	}
	
EOT;
}

function logo_page()
{
$img_encoded = 'iVBORw0KGgoAAAANSUhEUgAAAakAAACABAMAAABD1osiAAAAKlBMVEUAAAAAAADnHCwAAAAAAAAAAAAAAAAAAABMCQ4AAADnHCznHCznHCwAAAAjcBE1AAAADHRSTlMAeDRHwSqg4BJl/PLTJLuIAAAF1UlEQVR42u2by4vTQBzHp3TTzR6EBtfXYS/+BZW6Pg6FFavgoRDBBx4KFd+HQgWFvQQqiuJhoeL7sP+LR0EPlj6yPfz+F5NMZ77TmmJjM3ZT5nNpOzvNzGcev5lMusxgMBgMBoPBYDAYDAaDwWDQwel5YRnC/jkvbZYdjFV2MFbZwVhlB2OVIVZyb2HIED/n5AfLEj/nhWUJY5UdjFV2MFbZwVgdMqzNZydXz2qrf59Kq2a1NmTsRnfVrLZOfj3VrrkrZuVb/dpBvZEJqzOOc5TNQ75rjXKDtV+ZsNoi6rJ52OhZwxONwiGwsi46zqnt1Kx8r7N8q/wmRfhP3BSsrK7VW/u13krDysGwT8o5kvilxa2YZ/U2eulEC0KhCTlLCo0UrPYff7Tfe+2lWt0glTT6qjB02e0eW6ZVjiZYaF4hq+eXlmll1yik75TL5eMeDVOxsj89hNQyrN5QyDFRm9GCVmCZVrYXBr4OE9w8ZFbBCNr+x646ycAhs/o3moFUj62Y1UY4/txVs9oLrAZs1azCAVhaNSsLgXNpVt/+dlNXZAplx4mLiXecU5hHhcBqN6lV/p3znk1xEYUltfr+t0J/4dN1jwKGWIg+VKuBdL5JAQ9EYj34ILOAjWq12lG+eE2xsk9EF/7CFN7WKOCpq9kK2/CTyp93mFUbpyKRZmwNi2oX4Y0dfgULd8QL4vRdvVavJ+6XYLVPIQjmHq9xAqvbJBTa8paTBCOtVpZHY1DrSmCF7flABotBIiuLJM+RQdJJO1qoVnUKqfLh1pBWrX10YVu0ciuRVXjlfpUiXGSmp85xdFaaT7thZUV95I5DRldaDYJPT8oXmyQqnYP0nFZetL23tgjtsT/e8uc9mKa3XsFqL3Rpy3YsCSufhwmrJgbeGmo/jxUCjd2UzWWFg1EuEzv6rJoY4ftyQapghBRElda5cxKrEfaPvGPWw+Esyx1ps8pHhaP0LqxK8p7KZwFHklt1kEqNcbsNcFfT12a1zgtEv7WFVZehB93xUGVJrPg7MXgPxotDUWlCV5dVhYtgjhV5KuLd+jixktjqYHoHmVcLw9fSt2ry8lDBlrAqKomN5FZI5aX0+Rztqmk7uqywtGKhRQ+KmbeT3AoDDN89gsJQBQ1WWFrFpmgkIruq2kpuhWCASFNBYXxN1GGFKk1XqqLWiXjeOvpv3n2gpBDm4dtL1aqnyaqAcA2bGCu0d3Ir5GkSPasKsFlO3WpNGf68P3wdVhs84tRIRZ/VEUwWfIyxwo4puRUiDh0+q2jntnJWOf6aplVv+VZ5VGMBq3tlhQuarNYnw3V9Zgzkr8PFYiByAi0xcM7ILva+7kJWNeyktVoV5l2FeSI1kluh8UKrlnar6dv2qNhejBVG6yDeaifOajg5X9tR4sH/sLIIBeFTjJV4JMImmd5KNmGFvHxfyV9Guq2mDvnQc9NWyIuOBWrD2BSzZ4fsHi6rzUq26cRdY2e2VSU+ChJ6IDdh1Zi+wylAVa9VfWqu+2y2VYFiO6uGzHsTVj01WOxgsOq3KqB0nMbMsLK96fNxKVASgrDCSogcHjpbq5WNg1WcVsRY4Zi3i1Xblqm7OLFXrHbRWn2GxUG/FduX0yIHwRlWFomD3ojrT+Vxje+KE3tYiQ6ym3JJKKidnW9rscJkuSwOiUdsphXO5P2724y9PPOI+njMMSyxOzWiTViF7/0v4kS6gzEcZA0545X0WbFmVClnk1B4vJXsDYArcPzXitUxCnhW5f070SyXHGfTw1jUYVUgMGKzrTBKQQk/LonYzSlWxToyFuOapaXRim2hqd2/WbFbJEBlLTx8k1a1QNmaai0eUMBAp5XVFFIdNtMqVqs/nhmvpGQuSJRWUmHoMsl5klzRacWsE4Sn3TOswMtH9Mfvbj+L36JNWrFzUgqcE6ofdf8X9PXN6qWjbF5eOverV51ye/ICd+NCWv549er0ha3o69vMYDAYDAaDwWAwGAwGg8FgSJffF2mwYDNbStYAAAAASUVORK5CYII=';

    header('Content-Type: image/png');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}

function ic24logo_page()
{
	$img_encoded = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6b3NiPSJodHRwOi8vd3d3Lm9wZW5zd2F0Y2hib29rLm9yZy91cmkvMjAwOS9vc2IiCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB2ZXJzaW9uPSIxLjAiCiAgIHdpZHRoPSI2OTAiCiAgIGhlaWdodD0iNjkxLjI1IgogICB2aWV3Qm94PSIwIDAgNTUyIDU1MyIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgaWQ9InN2ZzMwMzUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImlvbkN1YmUyNF9jdWJlLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwODMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzQ5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTM1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzMzkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzMxIgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTMzMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzMjUiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzI3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NSIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4ODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NzMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODc1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDEiCiAgICAgICB4MT0iNDQzNS40NDI0IgogICAgICAgeTE9IjI5NDkuMDQyIgogICAgICAgeDI9IjQ4MzQuMzkyMSIKICAgICAgIHkyPSIyOTQ5LjA0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTgiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjAiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxOCIKICAgICBpZD0ibmFtZWR2aWV3MzA4MSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC45NjUzODc0IgogICAgIGlua3NjYXBlOmN4PSI3MjQuNTI3MjIiCiAgICAgaW5rc2NhcGU6Y3k9IjMzMy4xMTQ1MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMzAzNSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMCIKICAgICBmaXQtbWFyZ2luLWxlZnQ9IjAiCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIKICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDM3Ij4KQ3JlYXRlZCBieSBwb3RyYWNlIDEuMTEsIHdyaXR0ZW4gYnkgUGV0ZXIgU2VsaW5nZXIgMjAwMS0yMDEzCjxyZGY6UkRGPgogIDxjYzpXb3JrCiAgICAgcmRmOmFib3V0PSIiPgogICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICA8ZGM6dHlwZQogICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICA8L2NjOldvcms+CjwvcmRmOlJERj4KPC9tZXRhZGF0YT4KICA8ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMSwwLDAsLTAuMSwtNCw1NTcpIgogICAgIGlkPSJnMzAzOSIKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO3N0cm9rZTpub25lIj4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIC0yLDg2OCAtMyw4NjcgLTg2NywzIC04NjgsMiAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA0MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDMiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDM4MjcsNTU2MyBjIC00LC0zIC03LC0zOTUgLTcsLTg3MCBsIDAsLTg2MyA4NzAsMCA4NzAsMCAwLDg3MCAwLDg3MCAtODYzLDAgYyAtNDc1LDAgLTg2NywtMyAtODcwLC03IHoiCiAgICAgICBpZD0icGF0aDMwNDUiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDI4MDAgMCwtODcwIDg2OCwyIDg2NywzIDMsODY4IDIsODY3IC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDciCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDE5MzAsMjgwMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiBtIDEwMzUsNjMwIGMgODAsLTMxIDE1NCwtMTAyIDE5MSwtMTgzIDI1LC01NCAyOCwtNzQgMjksLTE1NyAwLC0xOTAgLTc0LC0zMTggLTM0NCwtNTkyIGwgLTE3NCwtMTc4IDI3NiwwIDI3NywwIDAsLTgwIDAsLTgwIC00MDcsMiAtNDA4LDMgLTMsNTYgLTMsNTUgMTgxLDE3NCBjIDM1NSwzMzkgNDUyLDQ5MyA0MjMsNjY3IC0xOSwxMDYgLTcxLDE2MiAtMTcyLDE4NCAtOTIsMjAgLTIwMiwtNiAtMjkzLC02OSBsIC00NiwtMzEgLTI2LDU4IGMgLTE0LDMyIC0yNiw2MiAtMjYsNjYgMCwyMiAxNDcsOTkgMjI4LDEyMCA4MiwyMSAyMjEsMTQgMjk3LC0xNSB6IgogICAgICAgaWQ9InBhdGgzMDQ5IgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAzODIyLDI4MDMgMywtODY4IDg2OCwtMyA4NjcsLTIgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAyLC04NjcgeiBtIDExNzgsMjQyIDAsLTM5NSA5MCwwIDkwLDAgMCwtNzAgMCwtNzAgLTkwLDAgLTkwLDAgMCwtMTcwIDAsLTE3MCAtODUsMCAtODUsMCAwLDE3MCAwLDE3MCAtMjkwLDAgLTI5MCwwIDAsNjMgMCw2NCAyODEsNDAxIDI4MSw0MDIgOTQsMCA5NCwwIDAsLTM5NSB6IgogICAgICAgaWQ9InBhdGgzMDUxIgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA0NzkwLDMxNzMgYyAtMjQsLTQzIC0xMTEsLTE3MiAtMTk1LC0yODggLTgzLC0xMTUgLTE1NSwtMjE2IC0xNTksLTIyMiAtNiwtMTAgMzUsLTEzIDE5MywtMTMgbCAxOTksMCA0LDI5OCBjIDIsMTYzIDMsMjk4IDIsMzAwIC0xLDIgLTIxLC0zMiAtNDQsLTc1IHoiCiAgICAgICBpZD0icGF0aDMwNTMiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NTM0MSk7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTg1MTYsMTc0MyBjIC0zLC04MzUgLTksLTE1NTMgLTEyLC0xNTk1IGwgLTYsLTc4IDE3MCwwIDE3MCwwIDcsODggYyAzLDQ4IDksMTI3IDEzLDE3NiBsIDcsODkgNDAsLTU5IGMgNTMsLTc3IDE2MCwtMTgxIDIyOSwtMjIzIDEyOCwtNzcgMjQ4LC0xMTEgNDIxLC0xMTggMjEwLC05IDM4NywzOCA1NTIsMTQ3IDI3NiwxODEgNDM4LDQ4MiA0NzQsODc5IDM5LDQzMyAtMTA1LDgzOSAtMzc1LDEwNTYgLTE1NSwxMjUgLTMzMCwxODUgLTU0MSwxODUgLTE5OSwwIC0zNTcsLTQwIC00OTMsLTEyNiAtNzEsLTQ1IC0xODMsLTE1MyAtMjI1LC0yMTkgbCAtMzIsLTUwIC0zLDY4MyAtMiw2ODIgLTE5NCwwIC0xOTQsMCAtNiwtMTUxNyB6IG0gMTE1NSwyMjMgYyAxNDksLTMyIDMwNSwtMTQ4IDM4OCwtMjg5IDc5LC0xMzUgMTIxLC0zMTMgMTIxLC01MTIgMCwtMTk2IC0zNSwtMzU2IC0xMDgsLTUwMCAtNDMsLTg0IC0xNzEsLTIxNyAtMjQ5LC0yNTggLTc3LC00MSAtMTkyLC02NyAtMjk0LC02NyAtMTE2LDAgLTE3NywxMyAtMjc4LDYyIC0xNDYsNjkgLTI1OCwyMDMgLTMxNywzNzggLTE3LDQ5IC0xOSw4OCAtMTksMzYwIDAsMzA1IDAsMzA1IDI3LDM4NSAzNywxMDkgOTEsMTk2IDE2OSwyNzUgNzQsNzQgMTkwLDE0MSAyODYsMTY0IDc2LDE5IDE5MSwxOSAyNzQsMiB6IgogICAgICAgaWQ9InBhdGgzMDU1IgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE3NCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTQ2MTAsMzEzOSBjIC01MTgsLTY1IC05NDQsLTM1NyAtMTE2NCwtNzk3IC0xNDEsLTI4MCAtMjAxLC02MzYgLTE2NiwtOTgzIDcyLC03MTEgNDgwLC0xMTc3IDExNDcsLTEzMTAgMjExLC00MiA1NTcsLTM2IDgxMywxMiAxMTksMjMgMzIwLDg2IDMyNiwxMDMgNiwxNyAtNzIsMzExIC04MiwzMDkgLTUsLTEgLTQ5LC0xNiAtOTcsLTMzIC0xNDcsLTUyIC0yNjIsLTcxIC00NzAsLTc3IC0yMTAsLTYgLTMyMCw0IC00NTcsNDQgLTQzNywxMjYgLTcwNSw0NzIgLTc2MSw5NzkgLTE1LDE0MCAtNSwzODggMjAsNTE0IDYwLDI5OSAxOTgsNTM2IDQwMyw2OTAgMjIzLDE2OSA0NzIsMjM4IDgwOCwyMjcgMTg0LC02IDMwNywtMjggNDQyLC03OCA0NiwtMTYgODksLTMxIDk2LC0zMiA5LC0xIDMwLDQ5IDYyLDE1MyAyNyw4NSA0OCwxNTUgNDcsMTU2IC01Miw0MCAtMjc2LDEwMSAtNDU3LDEyMyAtOTcsMTMgLTQxNCwxMiAtNTEwLDAgeiIKICAgICAgIGlkPSJwYXRoMzA1NyIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNzApIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczNzAsMjg1NSAwLC0xOTUgMjEwLDAgMjEwLDAgMCwxOTUgMCwxOTUgLTIxMCwwIC0yMTAsMCAwLC0xOTUgeiIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNjYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIzODg2LDMwMjQgYyAtOTksLTE4IC0yNjQsLTczIC0zNDgsLTExNSAtNzEsLTM1IC0yMTgsLTEzMCAtMjM3LC0xNTMgLTEwLC0xMiAwLC00MCA1MCwtMTUwIDM0LC03NSA2MywtMTM2IDY1LC0xMzYgMSwwIDM2LDI0IDc3LDUzIDE2NiwxMTkgMzI0LDE3NiA1MTMsMTg0IDMwOCwxNCA1MDMsLTEwOCA1ODAsLTM2MiAxNCwtNDYgMTksLTkzIDE5LC0yMDAgLTEsLTE3MSAtMTksLTI0NyAtMTAwLC00MTAgLTEzMCwtMjYxIC0zODAsLTU0MyAtMTA0NCwtMTE4MCBsIC0yNTAsLTI0MCAtMSwtMTIyIDAsLTEyMyA5MzUsMCA5MzUsMCAwLDE2NSAwLDE2NSAtNjU3LDAgLTY1NywwIDEwOSwxMDEgYyA2MSw1NiAyMTgsMjEwIDM1MCwzNDMgMzQyLDM0NSA1MTgsNTYzIDYzNCw3ODYgMTc5LDM0NSAxOTgsNjc4IDU3LDk2NSAtODEsMTYzIC0xODgsMjcwIC0zNTEsMzUxIC0xNDEsNzAgLTIxOSw4NiAtNDI1LDkwIC0xMjUsMiAtMTk4LC0xIC0yNTQsLTEyIHoiCiAgICAgICBpZD0icGF0aDMwNjEiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE2MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMjY2ODEsMjk3NyBjIC02LC04IC0yOTksLTQyNSAtNjUxLC05MjggbCAtNjQwLC05MTQgMCwtMTMyIDAsLTEzMyA2ODAsMCA2ODAsMCAwLC00MDAgMCwtNDAwIDE4NSwwIDE4NSwwIDAsNDAwIDAsNDAwIDIwNSwwIDIwNSwwIDAsMTU1IDAsMTU1IC0yMDUsMCAtMjA1LDAgMCw5MDUgMCw5MDUgLTIxNCwwIGMgLTE2NiwwIC0yMTYsLTMgLTIyNSwtMTMgeiBtIDcxLC0xMDg0IC0zLC03MTMgLTQ4MCwwIGMgLTM4MiwwIC00NzksMyAtNDczLDEzIDUsNiAxNjYsMjMwIDM1OCw0OTcgMzQ3LDQ4MSAzOTksNTYwIDUzMCw3OTggMzgsNjggNjksMTIyIDcwLDEyMCAwLC0yIDAsLTMyNCAtMiwtNzE1IHoiCiAgICAgICBpZD0icGF0aDMwNjMiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE1OCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTE5MjcsMjI4OCBjIC0xMDgsLTEwIC0yNDgsLTU1IC0zNDEsLTExMCAtODIsLTQ4IC0yMDMsLTE2MCAtMjQ3LC0yMjkgLTE3LC0yNyAtMzQsLTQ3IC0zOCwtNDQgLTMsNCAtMTAsODIgLTE2LDE3MyBsIC0xMCwxNjcgLTE3OSwzIC0xNzgsMiA2LC00NyBjIDQsLTI3IDksLTUxNyAxMiwtMTA5MCBsIDYsLTEwNDMgMTk5LDAgMTk4LDAgMyw3MjcgMyw3MjggMzEsNzIgYyAxMTMsMjYwIDM0MSwzOTggNTk4LDM2MiAxNjQsLTIyIDI3NiwtMTAzIDM0NiwtMjUxIDczLC0xNTQgNzIsLTE0OCA3NywtOTM1IGwgNSwtNzAzIDE5NCwwIDE5NCwwIDAsNzIzIGMgMCw3OTYgLTIsODI0IC02Miw5OTcgLTEyMSwzNDcgLTQyMCw1MzMgLTgwMSw0OTggeiIKICAgICAgIGlkPSJwYXRoMzA2NSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNTQpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczOTAsMTE4MCAwLC0xMTEwIDE5MCwwIDE5MCwwIDAsMTExMCAwLDExMTAgLTE5MCwwIC0xOTAsMCAwLC0xMTEwIHoiCiAgICAgICBpZD0icGF0aDMwNjciCiAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMTUwKSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA5MTk5LDIyODAgYyAtMjIwLC0zNyAtNDE4LC0xMzggLTU3MCwtMjg5IC0xNTAsLTE1MSAtMjQyLC0zMjkgLTI5NSwtNTcxIC0yNiwtMTE5IC0yNywtNDI5IC0xLC01NDcgNTIsLTI0NCAxNDksLTQyNiAzMDUsLTU3NSAxODcsLTE3OCAzOTYsLTI2NCA2NjgsLTI3NSA1MDAsLTIxIDkxMiwyNTEgMTA2NSw3MDQgNTQsMTYxIDY0LDIzMCA2Myw0NDggMCwxNjcgLTMsMjE1IC0yMSwyOTEgLTEwMyw0NDEgLTM5MCw3MzAgLTgwMyw4MDggLTg3LDE3IC0zMjYsMjAgLTQxMSw2IHogbSAzMzQsLTMwNSBjIDI1NSwtNjYgNDM4LC0zMDggNDg3LC02NDQgMTcsLTExNiA4LC0zNDMgLTE4LC00NDIgLTY0LC0yNDMgLTE5NywtNDIzIC0zNzQsLTUwOCAtMTA1LC01MCAtMTg0LC02NiAtMjk2LC01OCAtMjIxLDE1IC0zOTMsMTM2IC01MDgsMzU5IC02NiwxMjkgLTk1LDI1MCAtMTAxLDQyNSAtMTEsMzA4IDY3LDU0NSAyMzYsNzE0IDgxLDgxIDE1OCwxMjYgMjYxLDE1MyA3MywxOSAyNDEsMjAgMzEzLDEgeiIKICAgICAgIGlkPSJwYXRoMzA2OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNDYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIxNzUwLDIyNzUgYyAtMzUyLC03MCAtNjExLC0zMDUgLTczOSwtNjY4IC01OCwtMTY1IC03NSwtMjcxIC03NSwtNDc3IC0xLC0yMDQgMTAsLTI3OSA2NiwtNDQ3IDExOSwtMzYwIDQyMCwtNTk4IDgyNiwtNjUzIDEyNywtMTggMzkyLC04IDU0MiwyMCAxMjIsMjIgMzYwLDk2IDM2MCwxMTEgMCwxOCAtNjMsMjY0IC02OSwyNzEgLTMsNCAtNTEsLTggLTEwNiwtMjcgLTE1NCwtNTEgLTI3MiwtNjggLTQ3NSwtNjggLTIwMywwIC0yNzgsMTUgLTQwOSw4MyAtMjE0LDExMSAtMzI4LDMwMiAtMzU2LDU5OCBsIC03LDcyIDc2NSwwIGMgNjg4LDAgNzY1LDIgNzcxLDE2IDEyLDMyIDYsMzAzIC05LDM5MCAtNDMsMjQ0IC0xMzQsNDMzIC0yNzcsNTcwIC0xMTUsMTEyIC0yMzUsMTc0IC00MDAsMjA4IC05NCwxOSAtMzE0LDIwIC00MDgsMSB6IG0gMzUzLC0yOTUgYyAyMDcsLTY0IDMzOCwtMjU3IDM2MywtNTM1IGwgNywtNzUgLTU3NywwIC01NzYsMCAwLDIzIGMgMCw1MiA0MiwxODcgODYsMjc1IDgyLDE2OCAyMjcsMjkyIDM3NCwzMjEgMzAsNiA2NCwxMyA3NSwxNSA0MSwxMCAxODUsLTUgMjQ4LC0yNCB6IgogICAgICAgaWQ9InBhdGgzMDcxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE0MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gNDAsOTEwIDAsLTg3MCA4NjgsMiA4NjcsMyAzLDg2OCAyLDg2NyAtODcwLDAgLTg3MCwwIDAsLTg3MCB6IgogICAgICAgaWQ9InBhdGgzMDc1IgogICAgICAgc3R5bGU9ImZpbGw6I2MwMWQyZTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDkxMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA3NyIKICAgICAgIHN0eWxlPSJmaWxsOiNjMDFkMmU7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMzgyMCw5MTAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNzkiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICA8L2c+Cjwvc3ZnPgo=';
	header('Content-Type: image/svg+xml');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}
alt-php72-ioncube-loader/README.txt000064400000007751150413456440012666 0ustar00                            The ionCube Loader 
                            ------------------

This package contains:

* ionCube Loaders

* a Loader Wizard script to assist with Loader installation (loader-wizard.php)

* the License document for use of the Loader and encoded files (LICENSE.txt)

* User Guide describing options that can be configured through a php.ini file.  
  There are options that may improve performance, particularly with files on
  a network drive. Options for the ionCube24 intrusion protection and PHP error
  reporting service (ioncube24.com) are also described.


INSTALLATION
============

Quick Guide for experienced system admins
-----------------------------------------

The Loader is a PHP engine extension, so should be referenced with 
a zend_extension line in a php.ini file. It must be the first engine
extension to be installed. 

The Loader must be for the correct operating system, match the 
PHP version, and for whether PHP is built as thread-safe (TS) or not. 
All information required for installing is available on a phpinfo page. 

For example, if your web server is 64 bit Linux, thread safety is disabled,
PHP is version 8.1.8, the main php.ini file is /etc/php.ini and you
have unpacked Loaders to /usr/local/ioncube, you would:

1) edit /etc/php.ini
2) at the top of the php.ini file add

zend_extension = /usr/local/ioncube/ioncube_loader_lin_8.1.so

3) restart the PHP environment (i.e. Apache, php-fpm, etc.)

4) Check a phpinfo page and the Loader should show up in the Zend Engine box.


Assisted Installation with the Loader Wizard
--------------------------------------------

1. Upload the contents of this package to a directory/folder called ioncube
   within the top level of your web scripts area. This is sometimes called the
   "web root" or "document root". Common names for this location are "www",
   "public_html", and "htdocs", but it may be different on your server.

2. Launch the Loader Wizard script in your browser. For example:
     https://yourdomain/ioncube/loader-wizard.php

   If the wizard is not found, check carefully the location on your server
   where you uploaded the Loaders and the wizard script. 

3. Follow the steps given by the Loader Wizard. If you have full access to the 
   server then installation should be easy. If your hosting plan is more limited, 
   you may need to ask your hosting provider for assistance. 

4. The Loader Wizard can automatically create a ticket in our support system
   if installation is unsuccessful, and we are happy to assist in that case.

   YouTube with a search for "ioncube loader wizard" also gives some helpful 
   examples of installation.


WHERE TO INSTALL THE LOADERS
============================

The Loader Wizard should be used to guide the installation process but the
following are the standard locations for the Loader files. Loader file
packages can be obtained from https://www.ioncube.com/loaders.php

Please check that you have the correct package of Loaders for your system.

Installing to a remote SHARED server
------------------------------------

* Upload the Loader files to a directory/folder called ioncube within your
  main web scripts area.  (This will probably be where you placed the
  loader-wizard.php script.)


Installing to a remote UNIX/LINUX DEDICATED or VPS server
---------------------------------------------------------

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, /usr/local/ioncube


** Installing to a remote WINDOWS DEDICATED or VPS server

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, C:\windows\system32


64-BIT LOADERS FOR WINDOWS
--------------------------

64-bit Loaders for Windows are available for PHP 5.5 upwards.
The Loader Wizard will not give directions for installing 64-bit Loaders for
any earlier version of PHP 5.

Copyright (c) 2002-2025 ionCube Ltd.           Last revised January 2025
alt-openssl-devel/c-indentation.el000064400000003147150415544670013200 0ustar00; This Emacs Lisp file defines a C indentation style that closely
; follows most aspects of the one that is used throughout SSLeay,
; and hence in OpenSSL.
; 
; This definition is for the "CC mode" package, which is the default
; mode for editing C source files in Emacs 20, not for the older
; c-mode.el (which was the default in less recent releaes of Emacs 19).
;
; Copy the definition in your .emacs file or use M-x eval-buffer.
; To activate this indentation style, visit a C file, type
; M-x c-set-style <RET> (or C-c . for short), and enter "eay".
; To toggle the auto-newline feature of CC mode, type C-c C-a.
;
; Apparently statement blocks that are not introduced by a statement
; such as "if" and that are not the body of a function cannot
; be handled too well by CC mode with this indentation style,
; so you have to indent them manually (you can use C-q tab).
; 
; For suggesting improvements, please send e-mail to bodo@openssl.org.

(c-add-style "eay"
	     '((c-basic-offset . 8)
	       (indent-tabs-mode . t)
	       (c-comment-only-line-offset . 0)
	       (c-hanging-braces-alist)
	       (c-offsets-alist	. ((defun-open . +)
				   (defun-block-intro . 0)
				   (class-open . +)
				   (class-close . +)
				   (block-open . 0)
				   (block-close . 0)
				   (substatement-open . +)
				   (statement . 0)
				   (statement-block-intro . 0)
				   (statement-case-open . +)
				   (statement-case-intro . +)
				   (case-label . -)
				   (label . -)
				   (arglist-cont-nonempty . +)
				   (topmost-intro . -)
				   (brace-list-close . 0)
				   (brace-list-intro . 0)
				   (brace-list-open . +)
				   ))))

alt-openssl-devel/openssl.txt000064400000133065150415544670012351 0ustar00
This is some preliminary documentation for OpenSSL.

Contents:

 OpenSSL X509V3 extension configuration
 X509V3 Extension code: programmers guide
 PKCS#12 Library


==============================================================================
               OpenSSL X509V3 extension configuration
==============================================================================

OpenSSL X509V3 extension configuration: preliminary documentation.

INTRODUCTION.

For OpenSSL 0.9.2 the extension code has be considerably enhanced. It is now
possible to add and print out common X509 V3 certificate and CRL extensions.

BEGINNERS NOTE

For most simple applications you don't need to know too much about extensions:
the default openssl.cnf values will usually do sensible things.

If you want to know more you can initially quickly look through the sections
describing how the standard OpenSSL utilities display and add extensions and
then the list of supported extensions.

For more technical information about the meaning of extensions see:

http://www.imc.org/ietf-pkix/
http://home.netscape.com/eng/security/certs.html

PRINTING EXTENSIONS.

Extension values are automatically printed out for supported extensions.

openssl x509 -in cert.pem -text
openssl crl -in crl.pem -text

will give information in the extension printout, for example:

        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:TRUE
            X509v3 Subject Key Identifier: 
                73:FE:F7:59:A7:E1:26:84:44:D6:44:36:EE:79:1A:95:7C:B1:4B:15
            X509v3 Authority Key Identifier: 
                keyid:73:FE:F7:59:A7:E1:26:84:44:D6:44:36:EE:79:1A:95:7C:B1:4B:15, DirName:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/Email=email@1.address/Email=email@2.address, serial:00
            X509v3 Key Usage: 
                Certificate Sign, CRL Sign
            X509v3 Subject Alternative Name: 
                email:email@1.address, email:email@2.address

CONFIGURATION FILES.

The OpenSSL utilities 'ca' and 'req' can now have extension sections listing
which certificate extensions to include. In each case a line:

x509_extensions = extension_section

indicates which section contains the extensions. In the case of 'req' the
extension section is used when the -x509 option is present to create a
self signed root certificate.

The 'x509' utility also supports extensions when it signs a certificate.
The -extfile option is used to set the configuration file containing the
extensions. In this case a line with:

extensions = extension_section

in the nameless (default) section is used. If no such line is included then
it uses the default section.

You can also add extensions to CRLs: a line

crl_extensions = crl_extension_section

will include extensions when the -gencrl option is used with the 'ca' utility.
You can add any extension to a CRL but of the supported extensions only
issuerAltName and authorityKeyIdentifier make any real sense. Note: these are
CRL extensions NOT CRL *entry* extensions which cannot currently be generated.
CRL entry extensions can be displayed.

NB. At this time Netscape Communicator rejects V2 CRLs: to get an old V1 CRL
you should not include a crl_extensions line in the configuration file.

As with all configuration files you can use the inbuilt environment expansion
to allow the values to be passed in the environment. Therefore if you have
several extension sections used for different purposes you can have a line:

x509_extensions = $ENV::ENV_EXT

and set the ENV_EXT environment variable before calling the relevant utility.

EXTENSION SYNTAX.

Extensions have the basic form:

extension_name=[critical,] extension_options

the use of the critical option makes the extension critical. Extreme caution
should be made when using the critical flag. If an extension is marked
as critical then any client that does not understand the extension should
reject it as invalid. Some broken software will reject certificates which
have *any* critical extensions (these violates PKIX but we have to live
with it).

There are three main types of extension: string extensions, multi-valued
extensions, and raw extensions.

String extensions simply have a string which contains either the value itself
or how it is obtained.

For example:

nsComment="This is a Comment"

Multi-valued extensions have a short form and a long form. The short form
is a list of names and values:

basicConstraints=critical,CA:true,pathlen:1

The long form allows the values to be placed in a separate section:

basicConstraints=critical,@bs_section

[bs_section]

CA=true
pathlen=1

Both forms are equivalent. However it should be noted that in some cases the
same name can appear multiple times, for example,

subjectAltName=email:steve@here,email:steve@there

in this case an equivalent long form is:

subjectAltName=@alt_section

[alt_section]

email.1=steve@here
email.2=steve@there

This is because the configuration file code cannot handle the same name
occurring twice in the same section.

The syntax of raw extensions is governed by the extension code: it can
for example contain data in multiple sections. The correct syntax to
use is defined by the extension code itself: check out the certificate
policies extension for an example.

There are two ways to encode arbitrary extensions.

The first way is to use the word ASN1 followed by the extension content
using the same syntax as ASN1_generate_nconf(). For example:

1.2.3.4=critical,ASN1:UTF8String:Some random data

1.2.3.4=ASN1:SEQUENCE:seq_sect

[seq_sect]

field1 = UTF8:field1
field2 = UTF8:field2

It is also possible to use the word DER to include arbitrary data in any
extension.

1.2.3.4=critical,DER:01:02:03:04
1.2.3.4=DER:01020304

The value following DER is a hex dump of the DER encoding of the extension
Any extension can be placed in this form to override the default behaviour.
For example:

basicConstraints=critical,DER:00:01:02:03

WARNING: DER should be used with caution. It is possible to create totally
invalid extensions unless care is taken.

CURRENTLY SUPPORTED EXTENSIONS.

If you aren't sure about extensions then they can be largely ignored: its only
when you want to do things like restrict certificate usage when you need to
worry about them. 

The only extension that a beginner might want to look at is Basic Constraints.
If in addition you want to try Netscape object signing the you should also
look at Netscape Certificate Type.

Literal String extensions.

In each case the 'value' of the extension is placed directly in the
extension. Currently supported extensions in this category are: nsBaseUrl,
nsRevocationUrl, nsCaRevocationUrl, nsRenewalUrl, nsCaPolicyUrl,
nsSslServerName and nsComment.

For example:

nsComment="This is a test comment"

Bit Strings.

Bit string extensions just consist of a list of supported bits, currently
two extensions are in this category: PKIX keyUsage and the Netscape specific
nsCertType.

nsCertType (netscape certificate type) takes the flags: client, server, email,
objsign, reserved, sslCA, emailCA, objCA.

keyUsage (PKIX key usage) takes the flags: digitalSignature, nonRepudiation,
keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign,
encipherOnly, decipherOnly.

For example:

nsCertType=server

keyUsage=digitalSignature, nonRepudiation

Hints on Netscape Certificate Type.

Other than Basic Constraints this is the only extension a beginner might
want to use, if you want to try Netscape object signing, otherwise it can
be ignored.

If you want a certificate that can be used just for object signing then:

nsCertType=objsign

will do the job. If you want to use it as a normal end user and server
certificate as well then

nsCertType=objsign,email,server

is more appropriate. You cannot use a self signed certificate for object
signing (well Netscape signtool can but it cheats!) so you need to create
a CA certificate and sign an end user certificate with it.

Side note: If you want to conform to the Netscape specifications then you
should really also set:

nsCertType=objCA

in the *CA* certificate for just an object signing CA and

nsCertType=objCA,emailCA,sslCA

for everything. Current Netscape software doesn't enforce this so it can
be omitted.

Basic Constraints.

This is generally the only extension you need to worry about for simple
applications. If you want your certificate to be usable as a CA certificate
(in addition to an end user certificate) then you set this to:

basicConstraints=CA:TRUE

if you want to be certain the certificate cannot be used as a CA then do:

basicConstraints=CA:FALSE

The rest of this section describes more advanced usage.

Basic constraints is a multi-valued extension that supports a CA and an
optional pathlen option. The CA option takes the values true and false and
pathlen takes an integer. Note if the CA option is false the pathlen option
should be omitted. 

The pathlen parameter indicates the maximum number of CAs that can appear
below this one in a chain. So if you have a CA with a pathlen of zero it can
only be used to sign end user certificates and not further CAs. This all
assumes that the software correctly interprets this extension of course.

Examples:

basicConstraints=CA:TRUE
basicConstraints=critical,CA:TRUE, pathlen:0

NOTE: for a CA to be considered valid it must have the CA option set to
TRUE. An end user certificate MUST NOT have the CA value set to true.
According to PKIX recommendations it should exclude the extension entirely,
however some software may require CA set to FALSE for end entity certificates.

Extended Key Usage.

This extensions consists of a list of usages.

These can either be object short names of the dotted numerical form of OIDs.
While any OID can be used only certain values make sense. In particular the
following PKIX, NS and MS values are meaningful:

Value			Meaning
-----			-------
serverAuth		SSL/TLS Web Server Authentication.
clientAuth		SSL/TLS Web Client Authentication.
codeSigning		Code signing.
emailProtection		E-mail Protection (S/MIME).
timeStamping		Trusted Timestamping
msCodeInd		Microsoft Individual Code Signing (authenticode)
msCodeCom		Microsoft Commercial Code Signing (authenticode)
msCTLSign		Microsoft Trust List Signing
msSGC			Microsoft Server Gated Crypto
msEFS			Microsoft Encrypted File System
nsSGC			Netscape Server Gated Crypto

For example, under IE5 a CA can be used for any purpose: by including a list
of the above usages the CA can be restricted to only authorised uses.

Note: software packages may place additional interpretations on certificate 
use, in particular some usages may only work for selected CAs. Don't for example
expect just including msSGC or nsSGC will automatically mean that a certificate
can be used for SGC ("step up" encryption) otherwise anyone could use it.

Examples:

extendedKeyUsage=critical,codeSigning,1.2.3.4
extendedKeyUsage=nsSGC,msSGC

Subject Key Identifier.

This is really a string extension and can take two possible values. Either
a hex string giving details of the extension value to include or the word
'hash' which then automatically follow PKIX guidelines in selecting and
appropriate key identifier. The use of the hex string is strongly discouraged.

Example: subjectKeyIdentifier=hash

Authority Key Identifier.

The authority key identifier extension permits two options. keyid and issuer:
both can take the optional value "always".

If the keyid option is present an attempt is made to copy the subject key
identifier from the parent certificate. If the value "always" is present
then an error is returned if the option fails.

The issuer option copies the issuer and serial number from the issuer
certificate. Normally this will only be done if the keyid option fails or
is not included: the "always" flag will always include the value.

Subject Alternative Name.

The subject alternative name extension allows various literal values to be
included in the configuration file. These include "email" (an email address)
"URI" a uniform resource indicator, "DNS" (a DNS domain name), RID (a
registered ID: OBJECT IDENTIFIER), IP (and IP address) and otherName.

Also the email option include a special 'copy' value. This will automatically
include and email addresses contained in the certificate subject name in
the extension.

otherName can include arbitrary data associated with an OID: the value
should be the OID followed by a semicolon and the content in standard
ASN1_generate_nconf() format.

Examples:

subjectAltName=email:copy,email:my@other.address,URI:http://my.url.here/
subjectAltName=email:my@other.address,RID:1.2.3.4
subjectAltName=otherName:1.2.3.4;UTF8:some other identifier

Issuer Alternative Name.

The issuer alternative name option supports all the literal options of
subject alternative name. It does *not* support the email:copy option because
that would not make sense. It does support an additional issuer:copy option
that will copy all the subject alternative name values from the issuer 
certificate (if possible).

Example:

issuserAltName = issuer:copy

Authority Info Access.

The authority information access extension gives details about how to access
certain information relating to the CA. Its syntax is accessOID;location
where 'location' has the same syntax as subject alternative name (except
that email:copy is not supported). accessOID can be any valid OID but only
certain values are meaningful for example OCSP and caIssuers. OCSP gives the
location of an OCSP responder: this is used by Netscape PSM and other software.

Example:

authorityInfoAccess = OCSP;URI:http://ocsp.my.host/
authorityInfoAccess = caIssuers;URI:http://my.ca/ca.html

CRL distribution points.

This is a multi-valued extension that supports all the literal options of
subject alternative name. Of the few software packages that currently interpret
this extension most only interpret the URI option.

Currently each option will set a new DistributionPoint with the fullName
field set to the given value.

Other fields like cRLissuer and reasons cannot currently be set or displayed:
at this time no examples were available that used these fields.

If you see this extension with <UNSUPPORTED> when you attempt to print it out
or it doesn't appear to display correctly then let me know, including the
certificate (mail me at steve@openssl.org) .

Examples:

crlDistributionPoints=URI:http://www.myhost.com/myca.crl
crlDistributionPoints=URI:http://www.my.com/my.crl,URI:http://www.oth.com/my.crl

Certificate Policies.

This is a RAW extension. It attempts to display the contents of this extension:
unfortunately this extension is often improperly encoded.

The certificate policies extension will rarely be used in practice: few
software packages interpret it correctly or at all. IE5 does partially
support this extension: but it needs the 'ia5org' option because it will
only correctly support a broken encoding. Of the options below only the
policy OID, explicitText and CPS options are displayed with IE5.

All the fields of this extension can be set by using the appropriate syntax.

If you follow the PKIX recommendations of not including any qualifiers and just
using only one OID then you just include the value of that OID. Multiple OIDs
can be set separated by commas, for example:

certificatePolicies= 1.2.4.5, 1.1.3.4

If you wish to include qualifiers then the policy OID and qualifiers need to
be specified in a separate section: this is done by using the @section syntax
instead of a literal OID value.

The section referred to must include the policy OID using the name
policyIdentifier, cPSuri qualifiers can be included using the syntax:

CPS.nnn=value

userNotice qualifiers can be set using the syntax:

userNotice.nnn=@notice

The value of the userNotice qualifier is specified in the relevant section.
This section can include explicitText, organization and noticeNumbers
options. explicitText and organization are text strings, noticeNumbers is a
comma separated list of numbers. The organization and noticeNumbers options
(if included) must BOTH be present. If you use the userNotice option with IE5
then you need the 'ia5org' option at the top level to modify the encoding:
otherwise it will not be interpreted properly.

Example:

certificatePolicies=ia5org,1.2.3.4,1.5.6.7.8,@polsect

[polsect]

policyIdentifier = 1.3.5.8
CPS.1="http://my.host.name/"
CPS.2="http://my.your.name/"
userNotice.1=@notice

[notice]

explicitText="Explicit Text Here"
organization="Organisation Name"
noticeNumbers=1,2,3,4

TECHNICAL NOTE: the ia5org option changes the type of the 'organization' field,
according to PKIX it should be of type DisplayText but Verisign uses an 
IA5STRING and IE5 needs this too.

Display only extensions.

Some extensions are only partially supported and currently are only displayed
but cannot be set. These include private key usage period, CRL number, and
CRL reason.

==============================================================================
		X509V3 Extension code: programmers guide
==============================================================================

The purpose of the extension code is twofold. It allows an extension to be
created from a string or structure describing its contents and it prints out an
extension in a human or machine readable form.

1. Initialisation and cleanup.

No special initialisation is needed before calling the extension functions.
You used to have to call X509V3_add_standard_extensions(); but this is no longer
required and this function no longer does anything.

void X509V3_EXT_cleanup(void);

This function should be called to cleanup the extension code if any custom
extensions have been added. If no custom extensions have been added then this
call does nothing. After this call all custom extension code is freed up but
you can still use the standard extensions.

2. Printing and parsing extensions.

The simplest way to print out extensions is via the standard X509 printing
routines: if you use the standard X509_print() function, the supported
extensions will be printed out automatically.

The following functions allow finer control over extension display:

int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, int flag, int indent);
int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);

These two functions print out an individual extension to a BIO or FILE pointer.
Currently the flag argument is unused and should be set to 0. The 'indent'
argument is the number of spaces to indent each line.

void *X509V3_EXT_d2i(X509_EXTENSION *ext);

This function parses an extension and returns its internal structure. The
precise structure you get back depends on the extension being parsed. If the
extension if basicConstraints you will get back a pointer to a
BASIC_CONSTRAINTS structure. Check out the source in crypto/x509v3 for more
details about the structures returned. The returned structure should be freed
after use using the relevant free function, BASIC_CONSTRAINTS_free() for 
example.

void	*	X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx);
void	*	X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx);
void	*	X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx);
void 	*	X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx);

These functions combine the operations of searching for extensions and
parsing them. They search a certificate, a CRL a CRL entry or a stack
of extensions respectively for extension whose NID is 'nid' and return
the parsed result of NULL if an error occurred. For example:

BASIC_CONSTRAINTS *bs;
bs = X509_get_ext_d2i(cert, NID_basic_constraints, NULL, NULL);

This will search for the basicConstraints extension and either return
it value or NULL. NULL can mean either the extension was not found, it
occurred more than once or it could not be parsed.

If 'idx' is NULL then an extension is only parsed if it occurs precisely
once. This is standard behaviour because extensions normally cannot occur
more than once. If however more than one extension of the same type can
occur it can be used to parse successive extensions for example:

int i;
void *ext;

i = -1;
for(;;) {
	ext = X509_get_ext_d2i(x, nid, crit, &idx);
	if(ext == NULL) break;
	 /* Do something with ext */
}

If 'crit' is not NULL and the extension was found then the int it points to
is set to 1 for critical extensions and 0 for non critical. Therefore if the
function returns NULL but 'crit' is set to 0 or 1 then the extension was
found but it could not be parsed.

The int pointed to by crit will be set to -1 if the extension was not found
and -2 if the extension occurred more than once (this will only happen if
idx is NULL). In both cases the function will return NULL.

3. Generating extensions.

An extension will typically be generated from a configuration file, or some
other kind of configuration database.

int X509V3_EXT_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section,
								 X509 *cert);
int X509V3_EXT_CRL_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section,
								 X509_CRL *crl);

These functions add all the extensions in the given section to the given
certificate or CRL. They will normally be called just before the certificate
or CRL is due to be signed. Both return 0 on error on non zero for success.

In each case 'conf' is the LHASH pointer of the configuration file to use
and 'section' is the section containing the extension details.

See the 'context functions' section for a description of the ctx parameter.


X509_EXTENSION *X509V3_EXT_conf(LHASH *conf, X509V3_CTX *ctx, char *name,
								 char *value);

This function returns an extension based on a name and value pair, if the
pair will not need to access other sections in a config file (or there is no
config file) then the 'conf' parameter can be set to NULL.

X509_EXTENSION *X509V3_EXT_conf_nid(char *conf, X509V3_CTX *ctx, int nid,
								 char *value);

This function creates an extension in the same way as X509V3_EXT_conf() but
takes the NID of the extension rather than its name.

For example to produce basicConstraints with the CA flag and a path length of
10:

x = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,"CA:TRUE,pathlen:10");


X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc);

This function sets up an extension from its internal structure. The ext_nid
parameter is the NID of the extension and 'crit' is the critical flag.

4. Context functions.

The following functions set and manipulate an extension context structure.
The purpose of the extension context is to allow the extension code to
access various structures relating to the "environment" of the certificate:
for example the issuers certificate or the certificate request.

void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
                                 X509_REQ *req, X509_CRL *crl, int flags);

This function sets up an X509V3_CTX structure with details of the certificate
environment: specifically the issuers certificate, the subject certificate,
the certificate request and the CRL: if these are not relevant or not
available then they can be set to NULL. The 'flags' parameter should be set
to zero.

X509V3_set_ctx_test(ctx)

This macro is used to set the 'ctx' structure to a 'test' value: this is to
allow the syntax of an extension (or configuration file) to be tested.

X509V3_set_ctx_nodb(ctx)

This macro is used when no configuration database is present.

void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH *lhash);

This function is used to set the configuration database when it is an LHASH
structure: typically a configuration file.

The following functions are used to access a configuration database: they
should only be used in RAW extensions.

char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section);

This function returns the value of the parameter "name" in "section", or NULL
if there has been an error.

void X509V3_string_free(X509V3_CTX *ctx, char *str);

This function frees up the string returned by the above function.

STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section);

This function returns a whole section as a STACK_OF(CONF_VALUE) .

void X509V3_section_free( X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section);

This function frees up the STACK returned by the above function.

Note: it is possible to use the extension code with a custom configuration
database. To do this the "db_meth" element of the X509V3_CTX structure should
be set to an X509V3_CTX_METHOD structure. This structure contains the following
function pointers:

char * (*get_string)(void *db, char *section, char *value);
STACK_OF(CONF_VALUE) * (*get_section)(void *db, char *section);
void (*free_string)(void *db, char * string);
void (*free_section)(void *db, STACK_OF(CONF_VALUE) *section);

these will be called and passed the 'db' element in the X509V3_CTX structure
to access the database. If a given function is not implemented or not required
it can be set to NULL.

5. String helper functions.

There are several "i2s" and "s2i" functions that convert structures to and
from ASCII strings. In all the "i2s" cases the returned string should be
freed using Free() after use. Since some of these are part of other extension
code they may take a 'method' parameter. Unless otherwise stated it can be
safely set to NULL.

char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *oct);

This returns a hex string from an ASN1_OCTET_STRING.

char * i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint);
char * i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint);

These return a string decimal representations of an ASN1_INTEGER and an
ASN1_ENUMERATED type, respectively.

ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
                                                   X509V3_CTX *ctx, char *str);

This converts an ASCII hex string to an ASN1_OCTET_STRING.

ASN1_INTEGER * s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, char *value);

This converts a decimal ASCII string into an ASN1_INTEGER.

6. Multi valued extension helper functions.

The following functions can be used to manipulate STACKs of CONF_VALUE
structures, as used by multi valued extensions.

int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool);

This function expects a boolean value in 'value' and sets 'asn1_bool' to
it. That is it sets it to 0 for FALSE or 0xff for TRUE. The following
strings are acceptable: "TRUE", "true", "Y", "y", "YES", "yes", "FALSE"
"false", "N", "n", "NO" or "no".

int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint);

This accepts a decimal integer of arbitrary length and sets an ASN1_INTEGER.

int X509V3_add_value(const char *name, const char *value,
						STACK_OF(CONF_VALUE) **extlist);

This simply adds a string name and value pair.

int X509V3_add_value_uchar(const char *name, const unsigned char *value,
                          			STACK_OF(CONF_VALUE) **extlist);

The same as above but for an unsigned character value.

int X509V3_add_value_bool(const char *name, int asn1_bool,
						STACK_OF(CONF_VALUE) **extlist);

This adds either "TRUE" or "FALSE" depending on the value of 'asn1_bool'

int X509V3_add_value_bool_nf(char *name, int asn1_bool,
						STACK_OF(CONF_VALUE) **extlist);

This is the same as above except it adds nothing if asn1_bool is FALSE.

int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
						STACK_OF(CONF_VALUE) **extlist);

This function adds the value of the ASN1_INTEGER in decimal form.

7. Other helper functions.

<to be added>

ADDING CUSTOM EXTENSIONS.

Currently there are three types of supported extensions. 

String extensions are simple strings where the value is placed directly in the
extensions, and the string returned is printed out.

Multi value extensions are passed a STACK_OF(CONF_VALUE) name and value pairs
or return a STACK_OF(CONF_VALUE).

Raw extensions are just passed a BIO or a value and it is the extensions
responsibility to handle all the necessary printing.

There are two ways to add an extension. One is simply as an alias to an already
existing extension. An alias is an extension that is identical in ASN1 structure
to an existing extension but has a different OBJECT IDENTIFIER. This can be
done by calling:

int X509V3_EXT_add_alias(int nid_to, int nid_from);

'nid_to' is the new extension NID and 'nid_from' is the already existing
extension NID.

Alternatively an extension can be written from scratch. This involves writing
the ASN1 code to encode and decode the extension and functions to print out and
generate the extension from strings. The relevant functions are then placed in
a X509V3_EXT_METHOD structure and int X509V3_EXT_add(X509V3_EXT_METHOD *ext);
called.

The X509V3_EXT_METHOD structure is described below.

struct {
int ext_nid;
int ext_flags;
X509V3_EXT_NEW ext_new;
X509V3_EXT_FREE ext_free;
X509V3_EXT_D2I d2i;
X509V3_EXT_I2D i2d;
X509V3_EXT_I2S i2s;
X509V3_EXT_S2I s2i;
X509V3_EXT_I2V i2v;
X509V3_EXT_V2I v2i;
X509V3_EXT_R2I r2i;
X509V3_EXT_I2R i2r;

void *usr_data;
};

The elements have the following meanings.

ext_nid		is the NID of the object identifier of the extension.

ext_flags	is set of flags. Currently the only external flag is
		X509V3_EXT_MULTILINE which means a multi valued extensions
		should be printed on separate lines.

usr_data	is an extension specific pointer to any relevant data. This
		allows extensions to share identical code but have different
		uses. An example of this is the bit string extension which uses
		usr_data to contain a list of the bit names.

All the remaining elements are function pointers.

ext_new		is a pointer to a function that allocates memory for the
		extension ASN1 structure: for example ASN1_OBJECT_new().

ext_free	is a pointer to a function that free up memory of the extension
		ASN1 structure: for example ASN1_OBJECT_free().

d2i		is the standard ASN1 function that converts a DER buffer into
		the internal ASN1 structure: for example d2i_ASN1_IA5STRING().

i2d		is the standard ASN1 function that converts the internal
		structure into the DER representation: for example
		i2d_ASN1_IA5STRING().

The remaining functions are depend on the type of extension. One i2X and
one X2i should be set and the rest set to NULL. The types set do not need
to match up, for example the extension could be set using the multi valued
v2i function and printed out using the raw i2r.

All functions have the X509V3_EXT_METHOD passed to them in the 'method'
parameter and an X509V3_CTX structure. Extension code can then access the
parent structure via the 'method' parameter to for example make use of the value
of usr_data. If the code needs to use detail relating to the request it can
use the 'ctx' parameter.

A note should be given here about the 'flags' member of the 'ctx' parameter.
If it has the value CTX_TEST then the configuration syntax is being checked
and no actual certificate or CRL exists. Therefore any attempt in the config
file to access such information should silently succeed. If the syntax is OK
then it should simply return a (possibly bogus) extension, otherwise it
should return NULL.

char *i2s(struct v3_ext_method *method, void *ext);

This function takes the internal structure in the ext parameter and returns
a Malloc'ed string representing its value.

void * s2i(struct v3_ext_method *method, struct v3_ext_ctx *ctx, char *str);

This function takes the string representation in the ext parameter and returns
an allocated internal structure: ext_free() will be used on this internal
structure after use.

i2v and v2i handle a STACK_OF(CONF_VALUE):

typedef struct
{
        char *section;
        char *name;
        char *value;
} CONF_VALUE;

Only the name and value members are currently used.

STACK_OF(CONF_VALUE) * i2v(struct v3_ext_method *method, void *ext);

This function is passed the internal structure in the ext parameter and
returns a STACK of CONF_VALUE structures. The values of name, value,
section and the structure itself will be freed up with Free after use.
Several helper functions are available to add values to this STACK.

void * v2i(struct v3_ext_method *method, struct v3_ext_ctx *ctx,
						STACK_OF(CONF_VALUE) *values);

This function takes a STACK_OF(CONF_VALUE) structures and should set the
values of the external structure. This typically uses the name element to
determine which structure element to set and the value element to determine
what to set it to. Several helper functions are available for this
purpose (see above).

int i2r(struct v3_ext_method *method, void *ext, BIO *out, int indent);

This function is passed the internal extension structure in the ext parameter
and sends out a human readable version of the extension to out. The 'indent'
parameter should be noted to determine the necessary amount of indentation
needed on the output.

void * r2i(struct v3_ext_method *method, struct v3_ext_ctx *ctx, char *str);

This is just passed the string representation of the extension. It is intended
to be used for more elaborate extensions where the standard single and multi
valued options are insufficient. They can use the 'ctx' parameter to parse the
configuration database themselves. See the context functions section for details
of how to do this.

Note: although this type takes the same parameters as the "r2s" function there
is a subtle difference. Whereas an "r2i" function can access a configuration
database an "s2i" function MUST NOT. This is so the internal code can safely
assume that an "s2i" function will work without a configuration database.

==============================================================================
                            PKCS#12 Library
==============================================================================

This section describes the internal PKCS#12 support. There are very few
differences between the old external library and the new internal code at
present. This may well change because the external library will not be updated
much in future.

This version now includes a couple of high level PKCS#12 functions which
generally "do the right thing" and should make it much easier to handle PKCS#12
structures.

HIGH LEVEL FUNCTIONS.

For most applications you only need concern yourself with the high level
functions. They can parse and generate simple PKCS#12 files as produced by
Netscape and MSIE or indeed any compliant PKCS#12 file containing a single
private key and certificate pair.

1. Initialisation and cleanup.

No special initialisation is needed for the internal PKCS#12 library: the 
standard SSLeay_add_all_algorithms() is sufficient. If you do not wish to
add all algorithms (you should at least add SHA1 though) then you can manually
initialise the PKCS#12 library with:

PKCS12_PBE_add();

The memory allocated by the PKCS#12 library is freed up when EVP_cleanup() is
called or it can be directly freed with:

EVP_PBE_cleanup();

after this call (or EVP_cleanup() ) no more PKCS#12 library functions should
be called.

2. I/O functions.

i2d_PKCS12_bio(bp, p12)

This writes out a PKCS12 structure to a BIO.

i2d_PKCS12_fp(fp, p12)

This is the same but for a FILE pointer.

d2i_PKCS12_bio(bp, p12)

This reads in a PKCS12 structure from a BIO.

d2i_PKCS12_fp(fp, p12)

This is the same but for a FILE pointer.

3. High level functions.

3.1 Parsing with PKCS12_parse().

int PKCS12_parse(PKCS12 *p12, char *pass, EVP_PKEY **pkey, X509 **cert,
								 STACK **ca);

This function takes a PKCS12 structure and a password (ASCII, null terminated)
and returns the private key, the corresponding certificate and any CA
certificates. If any of these is not required it can be passed as a NULL.
The 'ca' parameter should be either NULL, a pointer to NULL or a valid STACK
structure. Typically to read in a PKCS#12 file you might do:

p12 = d2i_PKCS12_fp(fp, NULL);
PKCS12_parse(p12, password, &pkey, &cert, NULL); 	/* CAs not wanted */
PKCS12_free(p12);

3.2 PKCS#12 creation with PKCS12_create().

PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert,
			STACK *ca, int nid_key, int nid_cert, int iter,
						 int mac_iter, int keytype);

This function will create a PKCS12 structure from a given password, name,
private key, certificate and optional STACK of CA certificates. The remaining
5 parameters can be set to 0 and sensible defaults will be used.

The parameters nid_key and nid_cert are the key and certificate encryption
algorithms, iter is the encryption iteration count, mac_iter is the MAC
iteration count and keytype is the type of private key. If you really want
to know what these last 5 parameters do then read the low level section.

Typically to create a PKCS#12 file the following could be used:

p12 = PKCS12_create(pass, "My Certificate", pkey, cert, NULL, 0,0,0,0,0);
i2d_PKCS12_fp(fp, p12);
PKCS12_free(p12);

3.3 Changing a PKCS#12 structure password.

int PKCS12_newpass(PKCS12 *p12, char *oldpass, char *newpass);

This changes the password of an already existing PKCS#12 structure. oldpass
is the old password and newpass is the new one. An error occurs if the old
password is incorrect.

LOW LEVEL FUNCTIONS.

In some cases the high level functions do not provide the necessary
functionality. For example if you want to generate or parse more complex
PKCS#12 files. The sample pkcs12 application uses the low level functions
to display details about the internal structure of a PKCS#12 file.

Introduction.

This is a brief description of how a PKCS#12 file is represented internally:
some knowledge of PKCS#12 is assumed.

A PKCS#12 object contains several levels.

At the lowest level is a PKCS12_SAFEBAG. This can contain a certificate, a
CRL, a private key, encrypted or unencrypted, a set of safebags (so the
structure can be nested) or other secrets (not documented at present). 
A safebag can optionally have attributes, currently these are: a unicode
friendlyName (a Unicode string) or a localKeyID (a string of bytes).

At the next level is an authSafe which is a set of safebags collected into
a PKCS#7 ContentInfo. This can be just plain data, or encrypted itself.

At the top level is the PKCS12 structure itself which contains a set of
authSafes in an embedded PKCS#7 Contentinfo of type data. In addition it
contains a MAC which is a kind of password protected digest to preserve
integrity (so any unencrypted stuff below can't be tampered with).

The reason for these levels is so various objects can be encrypted in various
ways. For example you might want to encrypt a set of private keys with
triple-DES and then include the related certificates either unencrypted or
with lower encryption. Yes it's the dreaded crypto laws at work again which
allow strong encryption on private keys and only weak encryption on other
stuff.

To build one of these things you turn all certificates and keys into safebags
(with optional attributes). You collect the safebags into (one or more) STACKS
and convert these into authsafes (encrypted or unencrypted).  The authsafes
are collected into a STACK and added to a PKCS12 structure.  Finally a MAC
inserted.

Pulling one apart is basically the reverse process. The MAC is verified against
the given password. The authsafes are extracted and each authsafe split into
a set of safebags (possibly involving decryption). Finally the safebags are
decomposed into the original keys and certificates and the attributes used to
match up private key and certificate pairs.

Anyway here are the functions that do the dirty work.

1. Construction functions.

1.1 Safebag functions.

M_PKCS12_x5092certbag(x509)

This macro takes an X509 structure and returns a certificate bag. The
X509 structure can be freed up after calling this function.

M_PKCS12_x509crl2certbag(crl)

As above but for a CRL.

PKCS8_PRIV_KEY_INFO *PKEY2PKCS8(EVP_PKEY *pkey)

Take a private key and convert it into a PKCS#8 PrivateKeyInfo structure.
Works for both RSA and DSA private keys. NB since the PKCS#8 PrivateKeyInfo
structure contains a private key data in plain text form it should be free'd
up as soon as it has been encrypted for security reasons (freeing up the
structure zeros out the sensitive data). This can be done with
PKCS8_PRIV_KEY_INFO_free().

PKCS8_add_keyusage(PKCS8_PRIV_KEY_INFO *p8, int usage)

This sets the key type when a key is imported into MSIE or Outlook 98. Two
values are currently supported: KEY_EX and KEY_SIG. KEY_EX is an exchange type
key that can also be used for signing but its size is limited in the export
versions of MS software to 512 bits, it is also the default. KEY_SIG is a
signing only key but the keysize is unlimited (well 16K is supposed to work).
If you are using the domestic version of MSIE then you can ignore this because
KEY_EX is not limited and can be used for both.

PKCS12_SAFEBAG *PKCS12_MAKE_KEYBAG(PKCS8_PRIV_KEY_INFO *p8)

Convert a PKCS8 private key structure into a keybag. This routine embeds the
p8 structure in the keybag so p8 should not be freed up or used after it is
called.  The p8 structure will be freed up when the safebag is freed.

PKCS12_SAFEBAG *PKCS12_MAKE_SHKEYBAG(int pbe_nid, unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int iter, PKCS8_PRIV_KEY_INFO *p8)

Convert a PKCS#8 structure into a shrouded key bag (encrypted). p8 is not
embedded and can be freed up after use.

int PKCS12_add_localkeyid(PKCS12_SAFEBAG *bag, unsigned char *name, int namelen)
int PKCS12_add_friendlyname(PKCS12_SAFEBAG *bag, unsigned char *name, int namelen)

Add a local key id or a friendlyname to a safebag.

1.2 Authsafe functions.

PKCS7 *PKCS12_pack_p7data(STACK *sk)
Take a stack of safebags and convert them into an unencrypted authsafe. The
stack of safebags can be freed up after calling this function.

PKCS7 *PKCS12_pack_p7encdata(int pbe_nid, unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int iter, STACK *bags);

As above but encrypted.

1.3 PKCS12 functions.

PKCS12 *PKCS12_init(int mode)

Initialise a PKCS12 structure (currently mode should be NID_pkcs7_data).

M_PKCS12_pack_authsafes(p12, safes)

This macro takes a STACK of authsafes and adds them to a PKCS#12 structure.

int PKCS12_set_mac(PKCS12 *p12, unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int iter, EVP_MD *md_type);

Add a MAC to a PKCS12 structure. If EVP_MD is NULL use SHA-1, the spec suggests
that SHA-1 should be used.

2. Extraction Functions.

2.1 Safebags.

M_PKCS12_bag_type(bag)

Return the type of "bag". Returns one of the following

NID_keyBag
NID_pkcs8ShroudedKeyBag			7
NID_certBag				8
NID_crlBag				9
NID_secretBag				10
NID_safeContentsBag			11

M_PKCS12_cert_bag_type(bag)

Returns type of certificate bag, following are understood.

NID_x509Certificate			14
NID_sdsiCertificate			15

M_PKCS12_crl_bag_type(bag)

Returns crl bag type, currently only NID_crlBag is recognised.

M_PKCS12_certbag2x509(bag)

This macro extracts an X509 certificate from a certificate bag.

M_PKCS12_certbag2x509crl(bag)

As above but for a CRL.

EVP_PKEY * PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8)

Extract a private key from a PKCS8 private key info structure.

M_PKCS12_decrypt_skey(bag, pass, passlen) 

Decrypt a shrouded key bag and return a PKCS8 private key info structure.
Works with both RSA and DSA keys

char *PKCS12_get_friendlyname(bag)

Returns the friendlyName of a bag if present or NULL if none. The returned
string is a null terminated ASCII string allocated with Malloc(). It should 
thus be freed up with Free() after use.

2.2 AuthSafe functions.

M_PKCS12_unpack_p7data(p7)

Extract a STACK of safe bags from a PKCS#7 data ContentInfo.

#define M_PKCS12_unpack_p7encdata(p7, pass, passlen)

As above but for an encrypted content info.

2.3 PKCS12 functions.

M_PKCS12_unpack_authsafes(p12)

Extract a STACK of authsafes from a PKCS12 structure.

M_PKCS12_mac_present(p12)

Check to see if a MAC is present.

int PKCS12_verify_mac(PKCS12 *p12, unsigned char *pass, int passlen)

Verify a MAC on a PKCS12 structure. Returns an error if MAC not present.


Notes.

1. All the function return 0 or NULL on error.
2. Encryption based functions take a common set of parameters. These are
described below.

pass, passlen
ASCII password and length. The password on the MAC is called the "integrity
password" the encryption password is called the "privacy password" in the
PKCS#12 documentation. The passwords do not have to be the same. If -1 is
passed for the length it is worked out by the function itself (currently
this is sometimes done whatever is passed as the length but that may change).

salt, saltlen
A 'salt' if salt is NULL a random salt is used. If saltlen is also zero a
default length is used.

iter
Iteration count. This is a measure of how many times an internal function is
called to encrypt the data. The larger this value is the longer it takes, it
makes dictionary attacks on passwords harder. NOTE: Some implementations do
not support an iteration count on the MAC. If the password for the MAC and
encryption is the same then there is no point in having a high iteration
count for encryption if the MAC has no count. The MAC could be attacked
and the password used for the main decryption.

pbe_nid
This is the NID of the password based encryption method used. The following are
supported.
NID_pbe_WithSHA1And128BitRC4
NID_pbe_WithSHA1And40BitRC4
NID_pbe_WithSHA1And3_Key_TripleDES_CBC
NID_pbe_WithSHA1And2_Key_TripleDES_CBC
NID_pbe_WithSHA1And128BitRC2_CBC
NID_pbe_WithSHA1And40BitRC2_CBC

Which you use depends on the implementation you are exporting to. "Export
grade" (i.e. cryptographically challenged) products cannot support all
algorithms. Typically you may be able to use any encryption on shrouded key
bags but they must then be placed in an unencrypted authsafe. Other authsafes
may only support 40bit encryption. Of course if you are using SSLeay
throughout you can strongly encrypt everything and have high iteration counts
on everything.

3. For decryption routines only the password and length are needed.

4. Unlike the external version the nid's of objects are the values of the
constants: that is NID_certBag is the real nid, therefore there is no 
PKCS12_obj_offset() function.  Note the object constants are not the same as
those of the external version. If you use these constants then you will need
to recompile your code.

5. With the exception of PKCS12_MAKE_KEYBAG(), after calling any function or 
macro of the form PKCS12_MAKE_SOMETHING(other) the "other" structure can be
reused or freed up safely.

alt-openssl/CONTRIBUTING000064400000004772150415544700010656 0ustar00HOW TO CONTRIBUTE TO OpenSSL
----------------------------

(Please visit https://www.openssl.org/community/getting-started.html for
other ideas about how to contribute.)

Development is done on GitHub, https://github.com/openssl/openssl.

To request new features or report bugs, please open an issue on GitHub

To submit a patch, please open a pull request on GitHub.  If you are thinking
of making a large contribution, open an issue for it before starting work,
to get comments from the community.  Someone may be already working on
the same thing or there may be reasons why that feature isn't implemented.

To make it easier to review and accept your pull request, please follow these
guidelines:

    1. Anything other than a trivial contribution requires a Contributor
    License Agreement (CLA), giving us permission to use your code. See
    https://www.openssl.org/policies/cla.html for details.  If your
    contribution is too small to require a CLA, put "CLA: trivial" on a
    line by itself in your commit message body.

    2.  All source files should start with the following text (with
    appropriate comment characters at the start of each line and the
    year(s) updated):

        Copyright 20xx-20yy The OpenSSL Project Authors. All Rights Reserved.

        Licensed under the OpenSSL license (the "License").  You may not use
        this file except in compliance with the License.  You can obtain a copy
        in the file LICENSE in the source distribution or at
        https://www.openssl.org/source/license.html

    3.  Patches should be as current as possible; expect to have to rebase
    often. We do not accept merge commits, you will have to remove them
    (usually by rebasing) before it will be acceptable.

    4.  Patches should follow our coding style (see
    https://www.openssl.org/policies/codingstyle.html) and compile
    without warnings. Where gcc or clang is available you should use the
    --strict-warnings Configure option.  OpenSSL compiles on many varied
    platforms: try to ensure you only use portable features.  Clean builds
    via Travis and AppVeyor are required, and they are started automatically
    whenever a PR is created or updated.

    5.  When at all possible, patches should include tests. These can
    either be added to an existing test, or completely new.  Please see
    test/README for information on the test framework.

    6.  New features or changed functionality must include
    documentation. Please look at the "pod" files in doc for
    examples of our style.
alt-openssl/NEWS000064400000107426150415544700007523 0ustar00
  NEWS
  ====

  This file gives a brief overview of the major changes between each OpenSSL
  release. For more details please read the CHANGES file.

  Major changes between OpenSSL 1.0.2t and OpenSSL 1.0.2u [20 Dec 2019]

      o Fixed an an overflow bug in the x64_64 Montgomery squaring procedure
        used in exponentiation with 512-bit moduli (CVE-2019-1551)

  Major changes between OpenSSL 1.0.2s and OpenSSL 1.0.2t [10 Sep 2019]

      o Fixed a padding oracle in PKCS7_dataDecode and CMS_decrypt_set1_pkey
        (CVE-2019-1563)
      o For built-in EC curves, ensure an EC_GROUP built from the curve name is
        used even when parsing explicit parameters
      o Compute ECC cofactors if not provided during EC_GROUP construction
        (CVE-2019-1547)
      o Document issue with installation paths in diverse Windows builds
        (CVE-2019-1552)

  Major changes between OpenSSL 1.0.2r and OpenSSL 1.0.2s [28 May 2019]

      o None

  Major changes between OpenSSL 1.0.2q and OpenSSL 1.0.2r [26 Feb 2019]

      o 0-byte record padding oracle (CVE-2019-1559)

  Major changes between OpenSSL 1.0.2p and OpenSSL 1.0.2q [20 Nov 2018]

      o Microarchitecture timing vulnerability in ECC scalar multiplication (CVE-2018-5407)
      o Timing vulnerability in DSA signature generation (CVE-2018-0734)

  Major changes between OpenSSL 1.0.2o and OpenSSL 1.0.2p [14 Aug 2018]

      o Client DoS due to large DH parameter (CVE-2018-0732)
      o Cache timing vulnerability in RSA Key Generation (CVE-2018-0737)

  Major changes between OpenSSL 1.0.2n and OpenSSL 1.0.2o [27 Mar 2018]

      o Constructed ASN.1 types with a recursive definition could exceed the
        stack (CVE-2018-0739)

  Major changes between OpenSSL 1.0.2m and OpenSSL 1.0.2n [7 Dec 2017]

      o Read/write after SSL object in error state (CVE-2017-3737)
      o rsaz_1024_mul_avx2 overflow bug on x86_64 (CVE-2017-3738)

  Major changes between OpenSSL 1.0.2l and OpenSSL 1.0.2m [2 Nov 2017]

      o bn_sqrx8x_internal carry bug on x86_64 (CVE-2017-3736)
      o Malformed X.509 IPAddressFamily could cause OOB read (CVE-2017-3735)

  Major changes between OpenSSL 1.0.2k and OpenSSL 1.0.2l [25 May 2017]

      o config now recognises 64-bit mingw and chooses mingw64 instead of mingw

  Major changes between OpenSSL 1.0.2j and OpenSSL 1.0.2k [26 Jan 2017]

      o Truncated packet could crash via OOB read (CVE-2017-3731)
      o BN_mod_exp may produce incorrect results on x86_64 (CVE-2017-3732)
      o Montgomery multiplication may produce incorrect results (CVE-2016-7055)

  Major changes between OpenSSL 1.0.2i and OpenSSL 1.0.2j [26 Sep 2016]

      o Missing CRL sanity check (CVE-2016-7052)

  Major changes between OpenSSL 1.0.2h and OpenSSL 1.0.2i [22 Sep 2016]

      o OCSP Status Request extension unbounded memory growth (CVE-2016-6304)
      o SWEET32 Mitigation (CVE-2016-2183)
      o OOB write in MDC2_Update() (CVE-2016-6303)
      o Malformed SHA512 ticket DoS (CVE-2016-6302)
      o OOB write in BN_bn2dec() (CVE-2016-2182)
      o OOB read in TS_OBJ_print_bio() (CVE-2016-2180)
      o Pointer arithmetic undefined behaviour (CVE-2016-2177)
      o Constant time flag not preserved in DSA signing (CVE-2016-2178)
      o DTLS buffered message DoS (CVE-2016-2179)
      o DTLS replay protection DoS (CVE-2016-2181)
      o Certificate message OOB reads (CVE-2016-6306)

  Major changes between OpenSSL 1.0.2g and OpenSSL 1.0.2h [3 May 2016]

      o Prevent padding oracle in AES-NI CBC MAC check (CVE-2016-2107)
      o Fix EVP_EncodeUpdate overflow (CVE-2016-2105)
      o Fix EVP_EncryptUpdate overflow (CVE-2016-2106)
      o Prevent ASN.1 BIO excessive memory allocation (CVE-2016-2109)
      o EBCDIC overread (CVE-2016-2176)
      o Modify behavior of ALPN to invoke callback after SNI/servername
        callback, such that updates to the SSL_CTX affect ALPN.
      o Remove LOW from the DEFAULT cipher list.  This removes singles DES from
        the default.
      o Only remove the SSLv2 methods with the no-ssl2-method option.

  Major changes between OpenSSL 1.0.2f and OpenSSL 1.0.2g [1 Mar 2016]

      o Disable weak ciphers in SSLv3 and up in default builds of OpenSSL.
      o Disable SSLv2 default build, default negotiation and weak ciphers
        (CVE-2016-0800)
      o Fix a double-free in DSA code (CVE-2016-0705)
      o Disable SRP fake user seed to address a server memory leak
        (CVE-2016-0798)
      o Fix BN_hex2bn/BN_dec2bn NULL pointer deref/heap corruption
        (CVE-2016-0797)
      o Fix memory issues in BIO_*printf functions (CVE-2016-0799)
      o Fix side channel attack on modular exponentiation (CVE-2016-0702)

  Major changes between OpenSSL 1.0.2e and OpenSSL 1.0.2f [28 Jan 2016]

      o DH small subgroups (CVE-2016-0701)
      o SSLv2 doesn't block disabled ciphers (CVE-2015-3197)

  Major changes between OpenSSL 1.0.2d and OpenSSL 1.0.2e [3 Dec 2015]

      o BN_mod_exp may produce incorrect results on x86_64 (CVE-2015-3193)
      o Certificate verify crash with missing PSS parameter (CVE-2015-3194)
      o X509_ATTRIBUTE memory leak (CVE-2015-3195)
      o Rewrite EVP_DecodeUpdate (base64 decoding) to fix several bugs
      o In DSA_generate_parameters_ex, if the provided seed is too short,
        return an error

  Major changes between OpenSSL 1.0.2c and OpenSSL 1.0.2d [9 Jul 2015]

      o Alternate chains certificate forgery (CVE-2015-1793)
      o Race condition handling PSK identify hint (CVE-2015-3196)

  Major changes between OpenSSL 1.0.2b and OpenSSL 1.0.2c [12 Jun 2015]

      o Fix HMAC ABI incompatibility

  Major changes between OpenSSL 1.0.2a and OpenSSL 1.0.2b [11 Jun 2015]

      o Malformed ECParameters causes infinite loop (CVE-2015-1788)
      o Exploitable out-of-bounds read in X509_cmp_time (CVE-2015-1789)
      o PKCS7 crash with missing EnvelopedContent (CVE-2015-1790)
      o CMS verify infinite loop with unknown hash function (CVE-2015-1792)
      o Race condition handling NewSessionTicket (CVE-2015-1791)

  Major changes between OpenSSL 1.0.2 and OpenSSL 1.0.2a [19 Mar 2015]

      o OpenSSL 1.0.2 ClientHello sigalgs DoS fix (CVE-2015-0291)
      o Multiblock corrupted pointer fix (CVE-2015-0290)
      o Segmentation fault in DTLSv1_listen fix (CVE-2015-0207)
      o Segmentation fault in ASN1_TYPE_cmp fix (CVE-2015-0286)
      o Segmentation fault for invalid PSS parameters fix (CVE-2015-0208)
      o ASN.1 structure reuse memory corruption fix (CVE-2015-0287)
      o PKCS7 NULL pointer dereferences fix (CVE-2015-0289)
      o DoS via reachable assert in SSLv2 servers fix (CVE-2015-0293)
      o Empty CKE with client auth and DHE fix (CVE-2015-1787)
      o Handshake with unseeded PRNG fix (CVE-2015-0285)
      o Use After Free following d2i_ECPrivatekey error fix (CVE-2015-0209)
      o X509_to_X509_REQ NULL pointer deref fix (CVE-2015-0288)
      o Removed the export ciphers from the DEFAULT ciphers

  Major changes between OpenSSL 1.0.1l and OpenSSL 1.0.2 [22 Jan 2015]:

      o Suite B support for TLS 1.2 and DTLS 1.2
      o Support for DTLS 1.2
      o TLS automatic EC curve selection.
      o API to set TLS supported signature algorithms and curves
      o SSL_CONF configuration API.
      o TLS Brainpool support.
      o ALPN support.
      o CMS support for RSA-PSS, RSA-OAEP, ECDH and X9.42 DH.

  Major changes between OpenSSL 1.0.1k and OpenSSL 1.0.1l [15 Jan 2015]

      o Build fixes for the Windows and OpenVMS platforms

  Major changes between OpenSSL 1.0.1j and OpenSSL 1.0.1k [8 Jan 2015]

      o Fix for CVE-2014-3571
      o Fix for CVE-2015-0206
      o Fix for CVE-2014-3569
      o Fix for CVE-2014-3572
      o Fix for CVE-2015-0204
      o Fix for CVE-2015-0205
      o Fix for CVE-2014-8275
      o Fix for CVE-2014-3570

  Major changes between OpenSSL 1.0.1i and OpenSSL 1.0.1j [15 Oct 2014]

      o Fix for CVE-2014-3513
      o Fix for CVE-2014-3567
      o Mitigation for CVE-2014-3566 (SSL protocol vulnerability)
      o Fix for CVE-2014-3568

  Major changes between OpenSSL 1.0.1h and OpenSSL 1.0.1i [6 Aug 2014]

      o Fix for CVE-2014-3512
      o Fix for CVE-2014-3511
      o Fix for CVE-2014-3510
      o Fix for CVE-2014-3507
      o Fix for CVE-2014-3506
      o Fix for CVE-2014-3505
      o Fix for CVE-2014-3509
      o Fix for CVE-2014-5139
      o Fix for CVE-2014-3508

  Major changes between OpenSSL 1.0.1g and OpenSSL 1.0.1h [5 Jun 2014]

      o Fix for CVE-2014-0224
      o Fix for CVE-2014-0221
      o Fix for CVE-2014-0198
      o Fix for CVE-2014-0195
      o Fix for CVE-2014-3470
      o Fix for CVE-2010-5298

  Major changes between OpenSSL 1.0.1f and OpenSSL 1.0.1g [7 Apr 2014]

      o Fix for CVE-2014-0160
      o Add TLS padding extension workaround for broken servers.
      o Fix for CVE-2014-0076

  Major changes between OpenSSL 1.0.1e and OpenSSL 1.0.1f [6 Jan 2014]

      o Don't include gmt_unix_time in TLS server and client random values
      o Fix for TLS record tampering bug CVE-2013-4353
      o Fix for TLS version checking bug CVE-2013-6449
      o Fix for DTLS retransmission bug CVE-2013-6450

  Major changes between OpenSSL 1.0.1d and OpenSSL 1.0.1e [11 Feb 2013]:

      o Corrected fix for CVE-2013-0169

  Major changes between OpenSSL 1.0.1c and OpenSSL 1.0.1d [4 Feb 2013]:

      o Fix renegotiation in TLS 1.1, 1.2 by using the correct TLS version.
      o Include the fips configuration module.
      o Fix OCSP bad key DoS attack CVE-2013-0166
      o Fix for SSL/TLS/DTLS CBC plaintext recovery attack CVE-2013-0169
      o Fix for TLS AESNI record handling flaw CVE-2012-2686

  Major changes between OpenSSL 1.0.1b and OpenSSL 1.0.1c [10 May 2012]:

      o Fix TLS/DTLS record length checking bug CVE-2012-2333
      o Don't attempt to use non-FIPS composite ciphers in FIPS mode.

  Major changes between OpenSSL 1.0.1a and OpenSSL 1.0.1b [26 Apr 2012]:

      o Fix compilation error on non-x86 platforms.
      o Make FIPS capable OpenSSL ciphers work in non-FIPS mode.
      o Fix SSL_OP_NO_TLSv1_1 clash with SSL_OP_ALL in OpenSSL 1.0.0

  Major changes between OpenSSL 1.0.1 and OpenSSL 1.0.1a [19 Apr 2012]:

      o Fix for ASN1 overflow bug CVE-2012-2110
      o Workarounds for some servers that hang on long client hellos.
      o Fix SEGV in AES code.

  Major changes between OpenSSL 1.0.0h and OpenSSL 1.0.1 [14 Mar 2012]:

      o TLS/DTLS heartbeat support.
      o SCTP support.
      o RFC 5705 TLS key material exporter.
      o RFC 5764 DTLS-SRTP negotiation.
      o Next Protocol Negotiation.
      o PSS signatures in certificates, requests and CRLs.
      o Support for password based recipient info for CMS.
      o Support TLS v1.2 and TLS v1.1.
      o Preliminary FIPS capability for unvalidated 2.0 FIPS module.
      o SRP support.

  Major changes between OpenSSL 1.0.0g and OpenSSL 1.0.0h [12 Mar 2012]:

      o Fix for CMS/PKCS#7 MMA CVE-2012-0884
      o Corrected fix for CVE-2011-4619
      o Various DTLS fixes.

  Major changes between OpenSSL 1.0.0f and OpenSSL 1.0.0g [18 Jan 2012]:

      o Fix for DTLS DoS issue CVE-2012-0050

  Major changes between OpenSSL 1.0.0e and OpenSSL 1.0.0f [4 Jan 2012]:

      o Fix for DTLS plaintext recovery attack CVE-2011-4108
      o Clear block padding bytes of SSL 3.0 records CVE-2011-4576
      o Only allow one SGC handshake restart for SSL/TLS CVE-2011-4619
      o Check parameters are not NULL in GOST ENGINE CVE-2012-0027
      o Check for malformed RFC3779 data CVE-2011-4577

  Major changes between OpenSSL 1.0.0d and OpenSSL 1.0.0e [6 Sep 2011]:

      o Fix for CRL vulnerability issue CVE-2011-3207
      o Fix for ECDH crashes CVE-2011-3210
      o Protection against EC timing attacks.
      o Support ECDH ciphersuites for certificates using SHA2 algorithms.
      o Various DTLS fixes.

  Major changes between OpenSSL 1.0.0c and OpenSSL 1.0.0d [8 Feb 2011]:

      o Fix for security issue CVE-2011-0014

  Major changes between OpenSSL 1.0.0b and OpenSSL 1.0.0c [2 Dec 2010]:

      o Fix for security issue CVE-2010-4180
      o Fix for CVE-2010-4252
      o Fix mishandling of absent EC point format extension.
      o Fix various platform compilation issues.
      o Corrected fix for security issue CVE-2010-3864.

  Major changes between OpenSSL 1.0.0a and OpenSSL 1.0.0b [16 Nov 2010]:

      o Fix for security issue CVE-2010-3864.
      o Fix for CVE-2010-2939
      o Fix WIN32 build system for GOST ENGINE.

  Major changes between OpenSSL 1.0.0 and OpenSSL 1.0.0a [1 Jun 2010]:

      o Fix for security issue CVE-2010-1633.
      o GOST MAC and CFB fixes.

  Major changes between OpenSSL 0.9.8n and OpenSSL 1.0.0 [29 Mar 2010]:

      o RFC3280 path validation: sufficient to process PKITS tests.
      o Integrated support for PVK files and keyblobs.
      o Change default private key format to PKCS#8.
      o CMS support: able to process all examples in RFC4134
      o Streaming ASN1 encode support for PKCS#7 and CMS.
      o Multiple signer and signer add support for PKCS#7 and CMS.
      o ASN1 printing support.
      o Whirlpool hash algorithm added.
      o RFC3161 time stamp support.
      o New generalised public key API supporting ENGINE based algorithms.
      o New generalised public key API utilities.
      o New ENGINE supporting GOST algorithms.
      o SSL/TLS GOST ciphersuite support.
      o PKCS#7 and CMS GOST support.
      o RFC4279 PSK ciphersuite support.
      o Supported points format extension for ECC ciphersuites.
      o ecdsa-with-SHA224/256/384/512 signature types.
      o dsa-with-SHA224 and dsa-with-SHA256 signature types.
      o Opaque PRF Input TLS extension support.
      o Updated time routines to avoid OS limitations.

  Major changes between OpenSSL 0.9.8m and OpenSSL 0.9.8n [24 Mar 2010]:

      o CFB cipher definition fixes.
      o Fix security issues CVE-2010-0740 and CVE-2010-0433.

  Major changes between OpenSSL 0.9.8l and OpenSSL 0.9.8m [25 Feb 2010]:

      o Cipher definition fixes.
      o Workaround for slow RAND_poll() on some WIN32 versions.
      o Remove MD2 from algorithm tables.
      o SPKAC handling fixes.
      o Support for RFC5746 TLS renegotiation extension.
      o Compression memory leak fixed.
      o Compression session resumption fixed.
      o Ticket and SNI coexistence fixes.
      o Many fixes to DTLS handling. 

  Major changes between OpenSSL 0.9.8k and OpenSSL 0.9.8l [5 Nov 2009]:

      o Temporary work around for CVE-2009-3555: disable renegotiation.

  Major changes between OpenSSL 0.9.8j and OpenSSL 0.9.8k [25 Mar 2009]:

      o Fix various build issues.
      o Fix security issues (CVE-2009-0590, CVE-2009-0591, CVE-2009-0789)

  Major changes between OpenSSL 0.9.8i and OpenSSL 0.9.8j [7 Jan 2009]:

      o Fix security issue (CVE-2008-5077)
      o Merge FIPS 140-2 branch code.

  Major changes between OpenSSL 0.9.8g and OpenSSL 0.9.8h [28 May 2008]:

      o CryptoAPI ENGINE support.
      o Various precautionary measures.
      o Fix for bugs affecting certificate request creation.
      o Support for local machine keyset attribute in PKCS#12 files.

  Major changes between OpenSSL 0.9.8f and OpenSSL 0.9.8g [19 Oct 2007]:

      o Backport of CMS functionality to 0.9.8.
      o Fixes for bugs introduced with 0.9.8f.

  Major changes between OpenSSL 0.9.8e and OpenSSL 0.9.8f [11 Oct 2007]:

      o Add gcc 4.2 support.
      o Add support for AES and SSE2 assembly lanugauge optimization
        for VC++ build.
      o Support for RFC4507bis and server name extensions if explicitly 
        selected at compile time.
      o DTLS improvements.
      o RFC4507bis support.
      o TLS Extensions support.

  Major changes between OpenSSL 0.9.8d and OpenSSL 0.9.8e [23 Feb 2007]:

      o Various ciphersuite selection fixes.
      o RFC3779 support.

  Major changes between OpenSSL 0.9.8c and OpenSSL 0.9.8d [28 Sep 2006]:

      o Introduce limits to prevent malicious key DoS  (CVE-2006-2940)
      o Fix security issues (CVE-2006-2937, CVE-2006-3737, CVE-2006-4343)
      o Changes to ciphersuite selection algorithm

  Major changes between OpenSSL 0.9.8b and OpenSSL 0.9.8c [5 Sep 2006]:

      o Fix Daniel Bleichenbacher forged signature attack, CVE-2006-4339
      o New cipher Camellia

  Major changes between OpenSSL 0.9.8a and OpenSSL 0.9.8b [4 May 2006]:

      o Cipher string fixes.
      o Fixes for VC++ 2005.
      o Updated ECC cipher suite support.
      o New functions EVP_CIPHER_CTX_new() and EVP_CIPHER_CTX_free().
      o Zlib compression usage fixes.
      o Built in dynamic engine compilation support on Win32.
      o Fixes auto dynamic engine loading in Win32.

  Major changes between OpenSSL 0.9.8 and OpenSSL 0.9.8a [11 Oct 2005]:

      o Fix potential SSL 2.0 rollback, CVE-2005-2969
      o Extended Windows CE support

  Major changes between OpenSSL 0.9.7g and OpenSSL 0.9.8 [5 Jul 2005]:

      o Major work on the BIGNUM library for higher efficiency and to
        make operations more streamlined and less contradictory.  This
        is the result of a major audit of the BIGNUM library.
      o Addition of BIGNUM functions for fields GF(2^m) and NIST
        curves, to support the Elliptic Crypto functions.
      o Major work on Elliptic Crypto; ECDH and ECDSA added, including
        the use through EVP, X509 and ENGINE.
      o New ASN.1 mini-compiler that's usable through the OpenSSL
        configuration file.
      o Added support for ASN.1 indefinite length constructed encoding.
      o New PKCS#12 'medium level' API to manipulate PKCS#12 files.
      o Complete rework of shared library construction and linking
        programs with shared or static libraries, through a separate
        Makefile.shared.
      o Rework of the passing of parameters from one Makefile to another.
      o Changed ENGINE framework to load dynamic engine modules
        automatically from specifically given directories.
      o New structure and ASN.1 functions for CertificatePair.
      o Changed the ZLIB compression method to be stateful.
      o Changed the key-generation and primality testing "progress"
        mechanism to take a structure that contains the ticker
        function and an argument.
      o New engine module: GMP (performs private key exponentiation).
      o New engine module: VIA PadLOck ACE extension in VIA C3
        Nehemiah processors.
      o Added support for IPv6 addresses in certificate extensions.
        See RFC 1884, section 2.2.
      o Added support for certificate policy mappings, policy
        constraints and name constraints.
      o Added support for multi-valued AVAs in the OpenSSL
        configuration file.
      o Added support for multiple certificates with the same subject
        in the 'openssl ca' index file.
      o Make it possible to create self-signed certificates using
        'openssl ca -selfsign'.
      o Make it possible to generate a serial number file with
        'openssl ca -create_serial'.
      o New binary search functions with extended functionality.
      o New BUF functions.
      o New STORE structure and library to provide an interface to all
        sorts of data repositories.  Supports storage of public and
        private keys, certificates, CRLs, numbers and arbitrary blobs.
	This library is unfortunately unfinished and unused withing
	OpenSSL.
      o New control functions for the error stack.
      o Changed the PKCS#7 library to support one-pass S/MIME
        processing.
      o Added the possibility to compile without old deprecated
        functionality with the OPENSSL_NO_DEPRECATED macro or the
        'no-deprecated' argument to the config and Configure scripts.
      o Constification of all ASN.1 conversion functions, and other
        affected functions.
      o Improved platform support for PowerPC.
      o New FIPS 180-2 algorithms (SHA-224, -256, -384 and -512).
      o New X509_VERIFY_PARAM structure to support parametrisation
        of X.509 path validation.
      o Major overhaul of RC4 performance on Intel P4, IA-64 and
        AMD64.
      o Changed the Configure script to have some algorithms disabled
        by default.  Those can be explicitely enabled with the new
        argument form 'enable-xxx'.
      o Change the default digest in 'openssl' commands from MD5 to
        SHA-1.
      o Added support for DTLS.
      o New BIGNUM blinding.
      o Added support for the RSA-PSS encryption scheme
      o Added support for the RSA X.931 padding.
      o Added support for BSD sockets on NetWare.
      o Added support for files larger than 2GB.
      o Added initial support for Win64.
      o Added alternate pkg-config files.

  Major changes between OpenSSL 0.9.7l and OpenSSL 0.9.7m [23 Feb 2007]:

      o FIPS 1.1.1 module linking.
      o Various ciphersuite selection fixes.

  Major changes between OpenSSL 0.9.7k and OpenSSL 0.9.7l [28 Sep 2006]:

      o Introduce limits to prevent malicious key DoS  (CVE-2006-2940)
      o Fix security issues (CVE-2006-2937, CVE-2006-3737, CVE-2006-4343)

  Major changes between OpenSSL 0.9.7j and OpenSSL 0.9.7k [5 Sep 2006]:

      o Fix Daniel Bleichenbacher forged signature attack, CVE-2006-4339

  Major changes between OpenSSL 0.9.7i and OpenSSL 0.9.7j [4 May 2006]:

      o Visual C++ 2005 fixes.
      o Update Windows build system for FIPS.

  Major changes between OpenSSL 0.9.7h and OpenSSL 0.9.7i [14 Oct 2005]:

      o Give EVP_MAX_MD_SIZE it's old value, except for a FIPS build.

  Major changes between OpenSSL 0.9.7g and OpenSSL 0.9.7h [11 Oct 2005]:

      o Fix SSL 2.0 Rollback, CVE-2005-2969
      o Allow use of fixed-length exponent on DSA signing
      o Default fixed-window RSA, DSA, DH private-key operations

  Major changes between OpenSSL 0.9.7f and OpenSSL 0.9.7g [11 Apr 2005]:

      o More compilation issues fixed.
      o Adaptation to more modern Kerberos API.
      o Enhanced or corrected configuration for Solaris64, Mingw and Cygwin.
      o Enhanced x86_64 assembler BIGNUM module.
      o More constification.
      o Added processing of proxy certificates (RFC 3820).

  Major changes between OpenSSL 0.9.7e and OpenSSL 0.9.7f [22 Mar 2005]:

      o Several compilation issues fixed.
      o Many memory allocation failure checks added.
      o Improved comparison of X509 Name type.
      o Mandatory basic checks on certificates.
      o Performance improvements.

  Major changes between OpenSSL 0.9.7d and OpenSSL 0.9.7e [25 Oct 2004]:

      o Fix race condition in CRL checking code.
      o Fixes to PKCS#7 (S/MIME) code.

  Major changes between OpenSSL 0.9.7c and OpenSSL 0.9.7d [17 Mar 2004]:

      o Security: Fix Kerberos ciphersuite SSL/TLS handshaking bug
      o Security: Fix null-pointer assignment in do_change_cipher_spec()
      o Allow multiple active certificates with same subject in CA index
      o Multiple X509 verification fixes
      o Speed up HMAC and other operations

  Major changes between OpenSSL 0.9.7b and OpenSSL 0.9.7c [30 Sep 2003]:

      o Security: fix various ASN1 parsing bugs.
      o New -ignore_err option to OCSP utility.
      o Various interop and bug fixes in S/MIME code.
      o SSL/TLS protocol fix for unrequested client certificates.

  Major changes between OpenSSL 0.9.7a and OpenSSL 0.9.7b [10 Apr 2003]:

      o Security: counter the Klima-Pokorny-Rosa extension of
        Bleichbacher's attack 
      o Security: make RSA blinding default.
      o Configuration: Irix fixes, AIX fixes, better mingw support.
      o Support for new platforms: linux-ia64-ecc.
      o Build: shared library support fixes.
      o ASN.1: treat domainComponent correctly.
      o Documentation: fixes and additions.

  Major changes between OpenSSL 0.9.7 and OpenSSL 0.9.7a [19 Feb 2003]:

      o Security: Important security related bugfixes.
      o Enhanced compatibility with MIT Kerberos.
      o Can be built without the ENGINE framework.
      o IA32 assembler enhancements.
      o Support for new platforms: FreeBSD/IA64 and FreeBSD/Sparc64.
      o Configuration: the no-err option now works properly.
      o SSL/TLS: now handles manual certificate chain building.
      o SSL/TLS: certain session ID malfunctions corrected.

  Major changes between OpenSSL 0.9.6 and OpenSSL 0.9.7 [30 Dec 2002]:

      o New library section OCSP.
      o Complete rewrite of ASN1 code.
      o CRL checking in verify code and openssl utility.
      o Extension copying in 'ca' utility.
      o Flexible display options in 'ca' utility.
      o Provisional support for international characters with UTF8.
      o Support for external crypto devices ('engine') is no longer
        a separate distribution.
      o New elliptic curve library section.
      o New AES (Rijndael) library section.
      o Support for new platforms: Windows CE, Tandem OSS, A/UX, AIX 64-bit,
        Linux x86_64, Linux 64-bit on Sparc v9
      o Extended support for some platforms: VxWorks
      o Enhanced support for shared libraries.
      o Now only builds PIC code when shared library support is requested.
      o Support for pkg-config.
      o Lots of new manuals.
      o Makes symbolic links to or copies of manuals to cover all described
        functions.
      o Change DES API to clean up the namespace (some applications link also
        against libdes providing similar functions having the same name).
        Provide macros for backward compatibility (will be removed in the
        future).
      o Unify handling of cryptographic algorithms (software and engine)
        to be available via EVP routines for asymmetric and symmetric ciphers.
      o NCONF: new configuration handling routines.
      o Change API to use more 'const' modifiers to improve error checking
        and help optimizers.
      o Finally remove references to RSAref.
      o Reworked parts of the BIGNUM code.
      o Support for new engines: Broadcom ubsec, Accelerated Encryption
        Processing, IBM 4758.
      o A few new engines added in the demos area.
      o Extended and corrected OID (object identifier) table.
      o PRNG: query at more locations for a random device, automatic query for
        EGD style random sources at several locations.
      o SSL/TLS: allow optional cipher choice according to server's preference.
      o SSL/TLS: allow server to explicitly set new session ids.
      o SSL/TLS: support Kerberos cipher suites (RFC2712).
	Only supports MIT Kerberos for now.
      o SSL/TLS: allow more precise control of renegotiations and sessions.
      o SSL/TLS: add callback to retrieve SSL/TLS messages.
      o SSL/TLS: support AES cipher suites (RFC3268).

  Major changes between OpenSSL 0.9.6j and OpenSSL 0.9.6k [30 Sep 2003]:

      o Security: fix various ASN1 parsing bugs.
      o SSL/TLS protocol fix for unrequested client certificates.

  Major changes between OpenSSL 0.9.6i and OpenSSL 0.9.6j [10 Apr 2003]:

      o Security: counter the Klima-Pokorny-Rosa extension of
        Bleichbacher's attack 
      o Security: make RSA blinding default.
      o Build: shared library support fixes.

  Major changes between OpenSSL 0.9.6h and OpenSSL 0.9.6i [19 Feb 2003]:

      o Important security related bugfixes.

  Major changes between OpenSSL 0.9.6g and OpenSSL 0.9.6h [5 Dec 2002]:

      o New configuration targets for Tandem OSS and A/UX.
      o New OIDs for Microsoft attributes.
      o Better handling of SSL session caching.
      o Better comparison of distinguished names.
      o Better handling of shared libraries in a mixed GNU/non-GNU environment.
      o Support assembler code with Borland C.
      o Fixes for length problems.
      o Fixes for uninitialised variables.
      o Fixes for memory leaks, some unusual crashes and some race conditions.
      o Fixes for smaller building problems.
      o Updates of manuals, FAQ and other instructive documents.

  Major changes between OpenSSL 0.9.6f and OpenSSL 0.9.6g [9 Aug 2002]:

      o Important building fixes on Unix.

  Major changes between OpenSSL 0.9.6e and OpenSSL 0.9.6f [8 Aug 2002]:

      o Various important bugfixes.

  Major changes between OpenSSL 0.9.6d and OpenSSL 0.9.6e [30 Jul 2002]:

      o Important security related bugfixes.
      o Various SSL/TLS library bugfixes.

  Major changes between OpenSSL 0.9.6c and OpenSSL 0.9.6d [9 May 2002]:

      o Various SSL/TLS library bugfixes.
      o Fix DH parameter generation for 'non-standard' generators.

  Major changes between OpenSSL 0.9.6b and OpenSSL 0.9.6c [21 Dec 2001]:

      o Various SSL/TLS library bugfixes.
      o BIGNUM library fixes.
      o RSA OAEP and random number generation fixes.
      o Object identifiers corrected and added.
      o Add assembler BN routines for IA64.
      o Add support for OS/390 Unix, UnixWare with gcc, OpenUNIX 8,
        MIPS Linux; shared library support for Irix, HP-UX.
      o Add crypto accelerator support for AEP, Baltimore SureWare,
        Broadcom and Cryptographic Appliance's keyserver
        [in 0.9.6c-engine release].

  Major changes between OpenSSL 0.9.6a and OpenSSL 0.9.6b [9 Jul 2001]:

      o Security fix: PRNG improvements.
      o Security fix: RSA OAEP check.
      o Security fix: Reinsert and fix countermeasure to Bleichbacher's
        attack.
      o MIPS bug fix in BIGNUM.
      o Bug fix in "openssl enc".
      o Bug fix in X.509 printing routine.
      o Bug fix in DSA verification routine and DSA S/MIME verification.
      o Bug fix to make PRNG thread-safe.
      o Bug fix in RAND_file_name().
      o Bug fix in compatibility mode trust settings.
      o Bug fix in blowfish EVP.
      o Increase default size for BIO buffering filter.
      o Compatibility fixes in some scripts.

  Major changes between OpenSSL 0.9.6 and OpenSSL 0.9.6a [5 Apr 2001]:

      o Security fix: change behavior of OpenSSL to avoid using
        environment variables when running as root.
      o Security fix: check the result of RSA-CRT to reduce the
        possibility of deducing the private key from an incorrectly
        calculated signature.
      o Security fix: prevent Bleichenbacher's DSA attack.
      o Security fix: Zero the premaster secret after deriving the
        master secret in DH ciphersuites.
      o Reimplement SSL_peek(), which had various problems.
      o Compatibility fix: the function des_encrypt() renamed to
        des_encrypt1() to avoid clashes with some Unixen libc.
      o Bug fixes for Win32, HP/UX and Irix.
      o Bug fixes in BIGNUM, SSL, PKCS#7, PKCS#12, X.509, CONF and
        memory checking routines.
      o Bug fixes for RSA operations in threaded environments.
      o Bug fixes in misc. openssl applications.
      o Remove a few potential memory leaks.
      o Add tighter checks of BIGNUM routines.
      o Shared library support has been reworked for generality.
      o More documentation.
      o New function BN_rand_range().
      o Add "-rand" option to openssl s_client and s_server.

  Major changes between OpenSSL 0.9.5a and OpenSSL 0.9.6 [10 Oct 2000]:

      o Some documentation for BIO and SSL libraries.
      o Enhanced chain verification using key identifiers.
      o New sign and verify options to 'dgst' application.
      o Support for DER and PEM encoded messages in 'smime' application.
      o New 'rsautl' application, low level RSA utility.
      o MD4 now included.
      o Bugfix for SSL rollback padding check.
      o Support for external crypto devices [1].
      o Enhanced EVP interface.

    [1] The support for external crypto devices is currently a separate
        distribution.  See the file README.ENGINE.

  Major changes between OpenSSL 0.9.5 and OpenSSL 0.9.5a [1 Apr 2000]:

      o Bug fixes for Win32, SuSE Linux, NeXTSTEP and FreeBSD 2.2.8 
      o Shared library support for HPUX and Solaris-gcc
      o Support of Linux/IA64
      o Assembler support for Mingw32
      o New 'rand' application
      o New way to check for existence of algorithms from scripts

  Major changes between OpenSSL 0.9.4 and OpenSSL 0.9.5 [25 May 2000]:

      o S/MIME support in new 'smime' command
      o Documentation for the OpenSSL command line application
      o Automation of 'req' application
      o Fixes to make s_client, s_server work under Windows
      o Support for multiple fieldnames in SPKACs
      o New SPKAC command line utilty and associated library functions
      o Options to allow passwords to be obtained from various sources
      o New public key PEM format and options to handle it
      o Many other fixes and enhancements to command line utilities
      o Usable certificate chain verification
      o Certificate purpose checking
      o Certificate trust settings
      o Support of authority information access extension
      o Extensions in certificate requests
      o Simplified X509 name and attribute routines
      o Initial (incomplete) support for international character sets
      o New DH_METHOD, DSA_METHOD and enhanced RSA_METHOD
      o Read only memory BIOs and simplified creation function
      o TLS/SSL protocol bugfixes: Accept TLS 'client hello' in SSL 3.0
        record; allow fragmentation and interleaving of handshake and other
        data
      o TLS/SSL code now "tolerates" MS SGC
      o Work around for Netscape client certificate hang bug
      o RSA_NULL option that removes RSA patent code but keeps other
        RSA functionality
      o Memory leak detection now allows applications to add extra information
        via a per-thread stack
      o PRNG robustness improved
      o EGD support
      o BIGNUM library bug fixes
      o Faster DSA parameter generation
      o Enhanced support for Alpha Linux
      o Experimental MacOS support

  Major changes between OpenSSL 0.9.3 and OpenSSL 0.9.4 [9 Aug 1999]:

      o Transparent support for PKCS#8 format private keys: these are used
        by several software packages and are more secure than the standard
        form
      o PKCS#5 v2.0 implementation
      o Password callbacks have a new void * argument for application data
      o Avoid various memory leaks
      o New pipe-like BIO that allows using the SSL library when actual I/O
        must be handled by the application (BIO pair)

  Major changes between OpenSSL 0.9.2b and OpenSSL 0.9.3 [24 May 1999]:
      o Lots of enhancements and cleanups to the Configuration mechanism
      o RSA OEAP related fixes
      o Added `openssl ca -revoke' option for revoking a certificate
      o Source cleanups: const correctness, type-safe stacks and ASN.1 SETs
      o Source tree cleanups: removed lots of obsolete files
      o Thawte SXNet, certificate policies and CRL distribution points
        extension support
      o Preliminary (experimental) S/MIME support
      o Support for ASN.1 UTF8String and VisibleString
      o Full integration of PKCS#12 code
      o Sparc assembler bignum implementation, optimized hash functions
      o Option to disable selected ciphers

  Major changes between OpenSSL 0.9.1c and OpenSSL 0.9.2b [22 Mar 1999]:
      o Fixed a security hole related to session resumption
      o Fixed RSA encryption routines for the p < q case
      o "ALL" in cipher lists now means "everything except NULL ciphers"
      o Support for Triple-DES CBCM cipher
      o Support of Optimal Asymmetric Encryption Padding (OAEP) for RSA
      o First support for new TLSv1 ciphers
      o Added a few new BIOs (syslog BIO, reliable BIO)
      o Extended support for DSA certificate/keys.
      o Extended support for Certificate Signing Requests (CSR)
      o Initial support for X.509v3 extensions
      o Extended support for compression inside the SSL record layer
      o Overhauled Win32 builds
      o Cleanups and fixes to the Big Number (BN) library
      o Support for ASN.1 GeneralizedTime
      o Splitted ASN.1 SETs from SEQUENCEs
      o ASN1 and PEM support for Netscape Certificate Sequences
      o Overhauled Perl interface
      o Lots of source tree cleanups.
      o Lots of memory leak fixes.
      o Lots of bug fixes.

  Major changes between SSLeay 0.9.0b and OpenSSL 0.9.1c [23 Dec 1998]:
      o Integration of the popular NO_RSA/NO_DSA patches
      o Initial support for compression inside the SSL record layer
      o Added BIO proxy and filtering functionality
      o Extended Big Number (BN) library
      o Added RIPE MD160 message digest
      o Addeed support for RC2/64bit cipher
      o Extended ASN.1 parser routines
      o Adjustations of the source tree for CVS
      o Support for various new platforms

alt-openssl/CHANGES000064400001746736150415544700010035 0ustar00
 OpenSSL CHANGES
 _______________

 This is a high-level summary of the most important changes.
 For a full list of changes, see the git commit log; for example,
 https://github.com/openssl/openssl/commits/ and pick the appropriate
 release branch.

 Changes between 1.0.2t and 1.0.2u [20 Dec 2019]

  *) Fixed an an overflow bug in the x64_64 Montgomery squaring procedure
     used in exponentiation with 512-bit moduli. No EC algorithms are
     affected. Analysis suggests that attacks against 2-prime RSA1024,
     3-prime RSA1536, and DSA1024 as a result of this defect would be very
     difficult to perform and are not believed likely. Attacks against DH512
     are considered just feasible. However, for an attack the target would
     have to re-use the DH512 private key, which is not recommended anyway.
     Also applications directly using the low level API BN_mod_exp may be
     affected if they use BN_FLG_CONSTTIME.
     (CVE-2019-1551)
     [Andy Polyakov]

 Changes between 1.0.2s and 1.0.2t [10 Sep 2019]

   *) For built-in EC curves, ensure an EC_GROUP built from the curve name is
      used even when parsing explicit parameters, when loading a serialized key
      or calling `EC_GROUP_new_from_ecpkparameters()`/
      `EC_GROUP_new_from_ecparameters()`.
      This prevents bypass of security hardening and performance gains,
      especially for curves with specialized EC_METHODs.
      By default, if a key encoded with explicit parameters is loaded and later
      serialized, the output is still encoded with explicit parameters, even if
      internally a "named" EC_GROUP is used for computation.
      [Nicola Tuveri]

  *) Compute ECC cofactors if not provided during EC_GROUP construction. Before
     this change, EC_GROUP_set_generator would accept order and/or cofactor as
     NULL. After this change, only the cofactor parameter can be NULL. It also
     does some minimal sanity checks on the passed order.
     (CVE-2019-1547)
     [Billy Bob Brumley]

  *) Fixed a padding oracle in PKCS7_dataDecode and CMS_decrypt_set1_pkey.
     An attack is simple, if the first CMS_recipientInfo is valid but the
     second CMS_recipientInfo is chosen ciphertext. If the second
     recipientInfo decodes to PKCS #1 v1.5 form plaintext, the correct
     encryption key will be replaced by garbage, and the message cannot be
     decoded, but if the RSA decryption fails, the correct encryption key is
     used and the recipient will not notice the attack.
     As a work around for this potential attack the length of the decrypted
     key must be equal to the cipher default key length, in case the
     certifiate is not given and all recipientInfo are tried out.
     The old behaviour can be re-enabled in the CMS code by setting the
     CMS_DEBUG_DECRYPT flag.
     (CVE-2019-1563)
     [Bernd Edlinger]

  *) Document issue with installation paths in diverse Windows builds

     '/usr/local/ssl' is an unsafe prefix for location to install OpenSSL
     binaries and run-time config file.
     (CVE-2019-1552)
     [Richard Levitte]

 Changes between 1.0.2r and 1.0.2s [28 May 2019]

  *) Change the default RSA, DSA and DH size to 2048 bit instead of 1024.
     This changes the size when using the genpkey app when no size is given. It
     fixes an omission in earlier changes that changed all RSA, DSA and DH
     generation apps to use 2048 bits by default.
     [Kurt Roeckx]

  *) Add FIPS support for Android Arm 64-bit

     Support for Android Arm 64-bit was added to the OpenSSL FIPS Object
     Module in Version 2.0.10. For some reason, the corresponding target
     'android64-aarch64' was missing OpenSSL 1.0.2, whence it could not be
     built with FIPS support on Android Arm 64-bit. This omission has been
     fixed.
     [Matthias St. Pierre]

 Changes between 1.0.2q and 1.0.2r [26 Feb 2019]

  *) 0-byte record padding oracle

     If an application encounters a fatal protocol error and then calls
     SSL_shutdown() twice (once to send a close_notify, and once to receive one)
     then OpenSSL can respond differently to the calling application if a 0 byte
     record is received with invalid padding compared to if a 0 byte record is
     received with an invalid MAC. If the application then behaves differently
     based on that in a way that is detectable to the remote peer, then this
     amounts to a padding oracle that could be used to decrypt data.

     In order for this to be exploitable "non-stitched" ciphersuites must be in
     use. Stitched ciphersuites are optimised implementations of certain
     commonly used ciphersuites. Also the application must call SSL_shutdown()
     twice even if a protocol error has occurred (applications should not do
     this but some do anyway).

     This issue was discovered by Juraj Somorovsky, Robert Merget and Nimrod
     Aviram, with additional investigation by Steven Collison and Andrew
     Hourselt. It was reported to OpenSSL on 10th December 2018.
     (CVE-2019-1559)
     [Matt Caswell]

  *) Move strictness check from EVP_PKEY_asn1_new() to EVP_PKEY_asn1_add0().
     [Richard Levitte]

 Changes between 1.0.2p and 1.0.2q [20 Nov 2018]

  *) Microarchitecture timing vulnerability in ECC scalar multiplication

     OpenSSL ECC scalar multiplication, used in e.g. ECDSA and ECDH, has been
     shown to be vulnerable to a microarchitecture timing side channel attack.
     An attacker with sufficient access to mount local timing attacks during
     ECDSA signature generation could recover the private key.

     This issue was reported to OpenSSL on 26th October 2018 by Alejandro
     Cabrera Aldaya, Billy Brumley, Sohaib ul Hassan, Cesar Pereida Garcia and
     Nicola Tuveri.
     (CVE-2018-5407)
     [Billy Brumley]

  *) Timing vulnerability in DSA signature generation

     The OpenSSL DSA signature algorithm has been shown to be vulnerable to a
     timing side channel attack. An attacker could use variations in the signing
     algorithm to recover the private key.

     This issue was reported to OpenSSL on 16th October 2018 by Samuel Weiser.
     (CVE-2018-0734)
     [Paul Dale]

  *) Resolve a compatibility issue in EC_GROUP handling with the FIPS Object
     Module, accidentally introduced while backporting security fixes from the
     development branch and hindering the use of ECC in FIPS mode.
     [Nicola Tuveri]

 Changes between 1.0.2o and 1.0.2p [14 Aug 2018]

  *) Client DoS due to large DH parameter

     During key agreement in a TLS handshake using a DH(E) based ciphersuite a
     malicious server can send a very large prime value to the client. This will
     cause the client to spend an unreasonably long period of time generating a
     key for this prime resulting in a hang until the client has finished. This
     could be exploited in a Denial Of Service attack.

     This issue was reported to OpenSSL on 5th June 2018 by Guido Vranken
     (CVE-2018-0732)
     [Guido Vranken]

  *) Cache timing vulnerability in RSA Key Generation

     The OpenSSL RSA Key generation algorithm has been shown to be vulnerable to
     a cache timing side channel attack. An attacker with sufficient access to
     mount cache timing attacks during the RSA key generation process could
     recover the private key.

     This issue was reported to OpenSSL on 4th April 2018 by Alejandro Cabrera
     Aldaya, Billy Brumley, Cesar Pereida Garcia and Luis Manuel Alvarez Tapia.
     (CVE-2018-0737)
     [Billy Brumley]

  *) Make EVP_PKEY_asn1_new() a bit stricter about its input.  A NULL pem_str
     parameter is no longer accepted, as it leads to a corrupt table.  NULL
     pem_str is reserved for alias entries only.
     [Richard Levitte]

  *) Revert blinding in ECDSA sign and instead make problematic addition
     length-invariant. Switch even to fixed-length Montgomery multiplication.
     [Andy Polyakov]

  *) Change generating and checking of primes so that the error rate of not
     being prime depends on the intended use based on the size of the input.
     For larger primes this will result in more rounds of Miller-Rabin.
     The maximal error rate for primes with more than 1080 bits is lowered
     to 2^-128.
     [Kurt Roeckx, Annie Yousar]

  *) Increase the number of Miller-Rabin rounds for DSA key generating to 64.
     [Kurt Roeckx]

  *) Add blinding to ECDSA and DSA signatures to protect against side channel
     attacks discovered by Keegan Ryan (NCC Group).
     [Matt Caswell]

  *) When unlocking a pass phrase protected PEM file or PKCS#8 container, we
     now allow empty (zero character) pass phrases.
     [Richard Levitte]

  *) Certificate time validation (X509_cmp_time) enforces stricter
     compliance with RFC 5280. Fractional seconds and timezone offsets
     are no longer allowed.
     [Emilia Käsper]

 Changes between 1.0.2n and 1.0.2o [27 Mar 2018]

  *) Constructed ASN.1 types with a recursive definition could exceed the stack

     Constructed ASN.1 types with a recursive definition (such as can be found
     in PKCS7) could eventually exceed the stack given malicious input with
     excessive recursion. This could result in a Denial Of Service attack. There
     are no such structures used within SSL/TLS that come from untrusted sources
     so this is considered safe.

     This issue was reported to OpenSSL on 4th January 2018 by the OSS-fuzz
     project.
     (CVE-2018-0739)
     [Matt Caswell]

 Changes between 1.0.2m and 1.0.2n [7 Dec 2017]

  *) Read/write after SSL object in error state

     OpenSSL 1.0.2 (starting from version 1.0.2b) introduced an "error state"
     mechanism. The intent was that if a fatal error occurred during a handshake
     then OpenSSL would move into the error state and would immediately fail if
     you attempted to continue the handshake. This works as designed for the
     explicit handshake functions (SSL_do_handshake(), SSL_accept() and
     SSL_connect()), however due to a bug it does not work correctly if
     SSL_read() or SSL_write() is called directly. In that scenario, if the
     handshake fails then a fatal error will be returned in the initial function
     call. If SSL_read()/SSL_write() is subsequently called by the application
     for the same SSL object then it will succeed and the data is passed without
     being decrypted/encrypted directly from the SSL/TLS record layer.

     In order to exploit this issue an application bug would have to be present
     that resulted in a call to SSL_read()/SSL_write() being issued after having
     already received a fatal error.

     This issue was reported to OpenSSL by David Benjamin (Google).
     (CVE-2017-3737)
     [Matt Caswell]

  *) rsaz_1024_mul_avx2 overflow bug on x86_64

     There is an overflow bug in the AVX2 Montgomery multiplication procedure
     used in exponentiation with 1024-bit moduli. No EC algorithms are affected.
     Analysis suggests that attacks against RSA and DSA as a result of this
     defect would be very difficult to perform and are not believed likely.
     Attacks against DH1024 are considered just feasible, because most of the
     work necessary to deduce information about a private key may be performed
     offline. The amount of resources required for such an attack would be
     significant. However, for an attack on TLS to be meaningful, the server
     would have to share the DH1024 private key among multiple clients, which is
     no longer an option since CVE-2016-0701.

     This only affects processors that support the AVX2 but not ADX extensions
     like Intel Haswell (4th generation).

     This issue was reported to OpenSSL by David Benjamin (Google). The issue
     was originally found via the OSS-Fuzz project.
     (CVE-2017-3738)
     [Andy Polyakov]

 Changes between 1.0.2l and 1.0.2m [2 Nov 2017]

  *) bn_sqrx8x_internal carry bug on x86_64

     There is a carry propagating bug in the x86_64 Montgomery squaring
     procedure. No EC algorithms are affected. Analysis suggests that attacks
     against RSA and DSA as a result of this defect would be very difficult to
     perform and are not believed likely. Attacks against DH are considered just
     feasible (although very difficult) because most of the work necessary to
     deduce information about a private key may be performed offline. The amount
     of resources required for such an attack would be very significant and
     likely only accessible to a limited number of attackers. An attacker would
     additionally need online access to an unpatched system using the target
     private key in a scenario with persistent DH parameters and a private
     key that is shared between multiple clients.

     This only affects processors that support the BMI1, BMI2 and ADX extensions
     like Intel Broadwell (5th generation) and later or AMD Ryzen.

     This issue was reported to OpenSSL by the OSS-Fuzz project.
     (CVE-2017-3736)
     [Andy Polyakov]

  *) Malformed X.509 IPAddressFamily could cause OOB read

     If an X.509 certificate has a malformed IPAddressFamily extension,
     OpenSSL could do a one-byte buffer overread. The most likely result
     would be an erroneous display of the certificate in text format.

     This issue was reported to OpenSSL by the OSS-Fuzz project.
     (CVE-2017-3735)
     [Rich Salz]

 Changes between 1.0.2k and 1.0.2l [25 May 2017]

  *) Have 'config' recognise 64-bit mingw and choose 'mingw64' as the target
     platform rather than 'mingw'.
     [Richard Levitte]

 Changes between 1.0.2j and 1.0.2k [26 Jan 2017]

  *) Truncated packet could crash via OOB read

     If one side of an SSL/TLS path is running on a 32-bit host and a specific
     cipher is being used, then a truncated packet can cause that host to
     perform an out-of-bounds read, usually resulting in a crash.

     This issue was reported to OpenSSL by Robert Święcki of Google.
     (CVE-2017-3731)
     [Andy Polyakov]

  *) BN_mod_exp may produce incorrect results on x86_64

     There is a carry propagating bug in the x86_64 Montgomery squaring
     procedure. No EC algorithms are affected. Analysis suggests that attacks
     against RSA and DSA as a result of this defect would be very difficult to
     perform and are not believed likely. Attacks against DH are considered just
     feasible (although very difficult) because most of the work necessary to
     deduce information about a private key may be performed offline. The amount
     of resources required for such an attack would be very significant and
     likely only accessible to a limited number of attackers. An attacker would
     additionally need online access to an unpatched system using the target
     private key in a scenario with persistent DH parameters and a private
     key that is shared between multiple clients. For example this can occur by
     default in OpenSSL DHE based SSL/TLS ciphersuites. Note: This issue is very
     similar to CVE-2015-3193 but must be treated as a separate problem.

     This issue was reported to OpenSSL by the OSS-Fuzz project.
     (CVE-2017-3732)
     [Andy Polyakov]

  *) Montgomery multiplication may produce incorrect results

     There is a carry propagating bug in the Broadwell-specific Montgomery
     multiplication procedure that handles input lengths divisible by, but
     longer than 256 bits. Analysis suggests that attacks against RSA, DSA
     and DH private keys are impossible. This is because the subroutine in
     question is not used in operations with the private key itself and an input
     of the attacker's direct choice. Otherwise the bug can manifest itself as
     transient authentication and key negotiation failures or reproducible
     erroneous outcome of public-key operations with specially crafted input.
     Among EC algorithms only Brainpool P-512 curves are affected and one
     presumably can attack ECDH key negotiation. Impact was not analyzed in
     detail, because pre-requisites for attack are considered unlikely. Namely
     multiple clients have to choose the curve in question and the server has to
     share the private key among them, neither of which is default behaviour.
     Even then only clients that chose the curve will be affected.

     This issue was publicly reported as transient failures and was not
     initially recognized as a security issue. Thanks to Richard Morgan for
     providing reproducible case.
     (CVE-2016-7055)
     [Andy Polyakov]

  *) OpenSSL now fails if it receives an unrecognised record type in TLS1.0
     or TLS1.1. Previously this only happened in SSLv3 and TLS1.2. This is to
     prevent issues where no progress is being made and the peer continually
     sends unrecognised record types, using up resources processing them.
     [Matt Caswell]

 Changes between 1.0.2i and 1.0.2j [26 Sep 2016]

  *) Missing CRL sanity check

     A bug fix which included a CRL sanity check was added to OpenSSL 1.1.0
     but was omitted from OpenSSL 1.0.2i. As a result any attempt to use
     CRLs in OpenSSL 1.0.2i will crash with a null pointer exception.

     This issue only affects the OpenSSL 1.0.2i
     (CVE-2016-7052)
     [Matt Caswell]

 Changes between 1.0.2h and 1.0.2i [22 Sep 2016]

  *) OCSP Status Request extension unbounded memory growth

     A malicious client can send an excessively large OCSP Status Request
     extension. If that client continually requests renegotiation, sending a
     large OCSP Status Request extension each time, then there will be unbounded
     memory growth on the server. This will eventually lead to a Denial Of
     Service attack through memory exhaustion. Servers with a default
     configuration are vulnerable even if they do not support OCSP. Builds using
     the "no-ocsp" build time option are not affected.

     This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.)
     (CVE-2016-6304)
     [Matt Caswell]

  *) In order to mitigate the SWEET32 attack, the DES ciphers were moved from
     HIGH to MEDIUM.

     This issue was reported to OpenSSL Karthikeyan Bhargavan and Gaetan
     Leurent (INRIA)
     (CVE-2016-2183)
     [Rich Salz]

  *) OOB write in MDC2_Update()

     An overflow can occur in MDC2_Update() either if called directly or
     through the EVP_DigestUpdate() function using MDC2. If an attacker
     is able to supply very large amounts of input data after a previous
     call to EVP_EncryptUpdate() with a partial block then a length check
     can overflow resulting in a heap corruption.

     The amount of data needed is comparable to SIZE_MAX which is impractical
     on most platforms.

     This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.)
     (CVE-2016-6303)
     [Stephen Henson]

  *) Malformed SHA512 ticket DoS

     If a server uses SHA512 for TLS session ticket HMAC it is vulnerable to a
     DoS attack where a malformed ticket will result in an OOB read which will
     ultimately crash.

     The use of SHA512 in TLS session tickets is comparatively rare as it requires
     a custom server callback and ticket lookup mechanism.

     This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.)
     (CVE-2016-6302)
     [Stephen Henson]

  *) OOB write in BN_bn2dec()

     The function BN_bn2dec() does not check the return value of BN_div_word().
     This can cause an OOB write if an application uses this function with an
     overly large BIGNUM. This could be a problem if an overly large certificate
     or CRL is printed out from an untrusted source. TLS is not affected because
     record limits will reject an oversized certificate before it is parsed.

     This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.)
     (CVE-2016-2182)
     [Stephen Henson]

  *) OOB read in TS_OBJ_print_bio()

     The function TS_OBJ_print_bio() misuses OBJ_obj2txt(): the return value is
     the total length the OID text representation would use and not the amount
     of data written. This will result in OOB reads when large OIDs are
     presented.

     This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.)
     (CVE-2016-2180)
     [Stephen Henson]

  *) Pointer arithmetic undefined behaviour

     Avoid some undefined pointer arithmetic

     A common idiom in the codebase is to check limits in the following manner:
     "p + len > limit"

     Where "p" points to some malloc'd data of SIZE bytes and
     limit == p + SIZE

     "len" here could be from some externally supplied data (e.g. from a TLS
     message).

     The rules of C pointer arithmetic are such that "p + len" is only well
     defined where len <= SIZE. Therefore the above idiom is actually
     undefined behaviour.

     For example this could cause problems if some malloc implementation
     provides an address for "p" such that "p + len" actually overflows for
     values of len that are too big and therefore p + len < limit.

     This issue was reported to OpenSSL by Guido Vranken
     (CVE-2016-2177)
     [Matt Caswell]

  *) Constant time flag not preserved in DSA signing

     Operations in the DSA signing algorithm should run in constant time in
     order to avoid side channel attacks. A flaw in the OpenSSL DSA
     implementation means that a non-constant time codepath is followed for
     certain operations. This has been demonstrated through a cache-timing
     attack to be sufficient for an attacker to recover the private DSA key.

     This issue was reported by César Pereida (Aalto University), Billy Brumley
     (Tampere University of Technology), and Yuval Yarom (The University of
     Adelaide and NICTA).
     (CVE-2016-2178)
     [César Pereida]

  *) DTLS buffered message DoS

     In a DTLS connection where handshake messages are delivered out-of-order
     those messages that OpenSSL is not yet ready to process will be buffered
     for later use. Under certain circumstances, a flaw in the logic means that
     those messages do not get removed from the buffer even though the handshake
     has been completed. An attacker could force up to approx. 15 messages to
     remain in the buffer when they are no longer required. These messages will
     be cleared when the DTLS connection is closed. The default maximum size for
     a message is 100k. Therefore the attacker could force an additional 1500k
     to be consumed per connection. By opening many simulataneous connections an
     attacker could cause a DoS attack through memory exhaustion.

     This issue was reported to OpenSSL by Quan Luo.
     (CVE-2016-2179)
     [Matt Caswell]

  *) DTLS replay protection DoS

     A flaw in the DTLS replay attack protection mechanism means that records
     that arrive for future epochs update the replay protection "window" before
     the MAC for the record has been validated. This could be exploited by an
     attacker by sending a record for the next epoch (which does not have to
     decrypt or have a valid MAC), with a very large sequence number. This means
     that all subsequent legitimate packets are dropped causing a denial of
     service for a specific DTLS connection.

     This issue was reported to OpenSSL by the OCAP audit team.
     (CVE-2016-2181)
     [Matt Caswell]

  *) Certificate message OOB reads

     In OpenSSL 1.0.2 and earlier some missing message length checks can result
     in OOB reads of up to 2 bytes beyond an allocated buffer. There is a
     theoretical DoS risk but this has not been observed in practice on common
     platforms.

     The messages affected are client certificate, client certificate request
     and server certificate. As a result the attack can only be performed
     against a client or a server which enables client authentication.

     This issue was reported to OpenSSL by Shi Lei (Gear Team, Qihoo 360 Inc.)
     (CVE-2016-6306)
     [Stephen Henson]

 Changes between 1.0.2g and 1.0.2h [3 May 2016]

  *) Prevent padding oracle in AES-NI CBC MAC check

     A MITM attacker can use a padding oracle attack to decrypt traffic
     when the connection uses an AES CBC cipher and the server support
     AES-NI.

     This issue was introduced as part of the fix for Lucky 13 padding
     attack (CVE-2013-0169). The padding check was rewritten to be in
     constant time by making sure that always the same bytes are read and
     compared against either the MAC or padding bytes. But it no longer
     checked that there was enough data to have both the MAC and padding
     bytes.

     This issue was reported by Juraj Somorovsky using TLS-Attacker.
     (CVE-2016-2107)
     [Kurt Roeckx]

  *) Fix EVP_EncodeUpdate overflow

     An overflow can occur in the EVP_EncodeUpdate() function which is used for
     Base64 encoding of binary data. If an attacker is able to supply very large
     amounts of input data then a length check can overflow resulting in a heap
     corruption.

     Internally to OpenSSL the EVP_EncodeUpdate() function is primarly used by
     the PEM_write_bio* family of functions. These are mainly used within the
     OpenSSL command line applications, so any application which processes data
     from an untrusted source and outputs it as a PEM file should be considered
     vulnerable to this issue. User applications that call these APIs directly
     with large amounts of untrusted data may also be vulnerable.

     This issue was reported by Guido Vranken.
     (CVE-2016-2105)
     [Matt Caswell]

  *) Fix EVP_EncryptUpdate overflow

     An overflow can occur in the EVP_EncryptUpdate() function. If an attacker
     is able to supply very large amounts of input data after a previous call to
     EVP_EncryptUpdate() with a partial block then a length check can overflow
     resulting in a heap corruption. Following an analysis of all OpenSSL
     internal usage of the EVP_EncryptUpdate() function all usage is one of two
     forms. The first form is where the EVP_EncryptUpdate() call is known to be
     the first called function after an EVP_EncryptInit(), and therefore that
     specific call must be safe. The second form is where the length passed to
     EVP_EncryptUpdate() can be seen from the code to be some small value and
     therefore there is no possibility of an overflow. Since all instances are
     one of these two forms, it is believed that there can be no overflows in
     internal code due to this problem. It should be noted that
     EVP_DecryptUpdate() can call EVP_EncryptUpdate() in certain code paths.
     Also EVP_CipherUpdate() is a synonym for EVP_EncryptUpdate(). All instances
     of these calls have also been analysed too and it is believed there are no
     instances in internal usage where an overflow could occur.

     This issue was reported by Guido Vranken.
     (CVE-2016-2106)
     [Matt Caswell]

  *) Prevent ASN.1 BIO excessive memory allocation

     When ASN.1 data is read from a BIO using functions such as d2i_CMS_bio()
     a short invalid encoding can casuse allocation of large amounts of memory
     potentially consuming excessive resources or exhausting memory.

     Any application parsing untrusted data through d2i BIO functions is
     affected. The memory based functions such as d2i_X509() are *not* affected.
     Since the memory based functions are used by the TLS library, TLS
     applications are not affected.

     This issue was reported by Brian Carpenter.
     (CVE-2016-2109)
     [Stephen Henson]

  *) EBCDIC overread

     ASN1 Strings that are over 1024 bytes can cause an overread in applications
     using the X509_NAME_oneline() function on EBCDIC systems. This could result
     in arbitrary stack data being returned in the buffer.

     This issue was reported by Guido Vranken.
     (CVE-2016-2176)
     [Matt Caswell]

  *) Modify behavior of ALPN to invoke callback after SNI/servername
     callback, such that updates to the SSL_CTX affect ALPN.
     [Todd Short]

  *) Remove LOW from the DEFAULT cipher list.  This removes singles DES from the
     default.
     [Kurt Roeckx]

  *) Only remove the SSLv2 methods with the no-ssl2-method option. When the
     methods are enabled and ssl2 is disabled the methods return NULL.
     [Kurt Roeckx]

 Changes between 1.0.2f and 1.0.2g [1 Mar 2016]

  * Disable weak ciphers in SSLv3 and up in default builds of OpenSSL.
    Builds that are not configured with "enable-weak-ssl-ciphers" will not
    provide any "EXPORT" or "LOW" strength ciphers.
    [Viktor Dukhovni]

  * Disable SSLv2 default build, default negotiation and weak ciphers.  SSLv2
    is by default disabled at build-time.  Builds that are not configured with
    "enable-ssl2" will not support SSLv2.  Even if "enable-ssl2" is used,
    users who want to negotiate SSLv2 via the version-flexible SSLv23_method()
    will need to explicitly call either of:

        SSL_CTX_clear_options(ctx, SSL_OP_NO_SSLv2);
    or
        SSL_clear_options(ssl, SSL_OP_NO_SSLv2);

    as appropriate.  Even if either of those is used, or the application
    explicitly uses the version-specific SSLv2_method() or its client and
    server variants, SSLv2 ciphers vulnerable to exhaustive search key
    recovery have been removed.  Specifically, the SSLv2 40-bit EXPORT
    ciphers, and SSLv2 56-bit DES are no longer available.
    (CVE-2016-0800)
    [Viktor Dukhovni]

  *) Fix a double-free in DSA code

     A double free bug was discovered when OpenSSL parses malformed DSA private
     keys and could lead to a DoS attack or memory corruption for applications
     that receive DSA private keys from untrusted sources.  This scenario is
     considered rare.

     This issue was reported to OpenSSL by Adam Langley(Google/BoringSSL) using
     libFuzzer.
     (CVE-2016-0705)
     [Stephen Henson]

  *) Disable SRP fake user seed to address a server memory leak.

     Add a new method SRP_VBASE_get1_by_user that handles the seed properly.

     SRP_VBASE_get_by_user had inconsistent memory management behaviour.
     In order to fix an unavoidable memory leak, SRP_VBASE_get_by_user
     was changed to ignore the "fake user" SRP seed, even if the seed
     is configured.

     Users should use SRP_VBASE_get1_by_user instead. Note that in
     SRP_VBASE_get1_by_user, caller must free the returned value. Note
     also that even though configuring the SRP seed attempts to hide
     invalid usernames by continuing the handshake with fake
     credentials, this behaviour is not constant time and no strong
     guarantees are made that the handshake is indistinguishable from
     that of a valid user.
     (CVE-2016-0798)
     [Emilia Käsper]

  *) Fix BN_hex2bn/BN_dec2bn NULL pointer deref/heap corruption

     In the BN_hex2bn function the number of hex digits is calculated using an
     int value |i|. Later |bn_expand| is called with a value of |i * 4|. For
     large values of |i| this can result in |bn_expand| not allocating any
     memory because |i * 4| is negative. This can leave the internal BIGNUM data
     field as NULL leading to a subsequent NULL ptr deref. For very large values
     of |i|, the calculation |i * 4| could be a positive value smaller than |i|.
     In this case memory is allocated to the internal BIGNUM data field, but it
     is insufficiently sized leading to heap corruption. A similar issue exists
     in BN_dec2bn. This could have security consequences if BN_hex2bn/BN_dec2bn
     is ever called by user applications with very large untrusted hex/dec data.
     This is anticipated to be a rare occurrence.

     All OpenSSL internal usage of these functions use data that is not expected
     to be untrusted, e.g. config file data or application command line
     arguments. If user developed applications generate config file data based
     on untrusted data then it is possible that this could also lead to security
     consequences. This is also anticipated to be rare.

     This issue was reported to OpenSSL by Guido Vranken.
     (CVE-2016-0797)
     [Matt Caswell]

  *) Fix memory issues in BIO_*printf functions

     The internal |fmtstr| function used in processing a "%s" format string in
     the BIO_*printf functions could overflow while calculating the length of a
     string and cause an OOB read when printing very long strings.

     Additionally the internal |doapr_outch| function can attempt to write to an
     OOB memory location (at an offset from the NULL pointer) in the event of a
     memory allocation failure. In 1.0.2 and below this could be caused where
     the size of a buffer to be allocated is greater than INT_MAX. E.g. this
     could be in processing a very long "%s" format string. Memory leaks can
     also occur.

     The first issue may mask the second issue dependent on compiler behaviour.
     These problems could enable attacks where large amounts of untrusted data
     is passed to the BIO_*printf functions. If applications use these functions
     in this way then they could be vulnerable. OpenSSL itself uses these
     functions when printing out human-readable dumps of ASN.1 data. Therefore
     applications that print this data could be vulnerable if the data is from
     untrusted sources. OpenSSL command line applications could also be
     vulnerable where they print out ASN.1 data, or if untrusted data is passed
     as command line arguments.

     Libssl is not considered directly vulnerable. Additionally certificates etc
     received via remote connections via libssl are also unlikely to be able to
     trigger these issues because of message size limits enforced within libssl.

     This issue was reported to OpenSSL Guido Vranken.
     (CVE-2016-0799)
     [Matt Caswell]

  *) Side channel attack on modular exponentiation

     A side-channel attack was found which makes use of cache-bank conflicts on
     the Intel Sandy-Bridge microarchitecture which could lead to the recovery
     of RSA keys.  The ability to exploit this issue is limited as it relies on
     an attacker who has control of code in a thread running on the same
     hyper-threaded core as the victim thread which is performing decryptions.

     This issue was reported to OpenSSL by Yuval Yarom, The University of
     Adelaide and NICTA, Daniel Genkin, Technion and Tel Aviv University, and
     Nadia Heninger, University of Pennsylvania with more information at
     http://cachebleed.info.
     (CVE-2016-0702)
     [Andy Polyakov]

  *) Change the req app to generate a 2048-bit RSA/DSA key by default,
     if no keysize is specified with default_bits. This fixes an
     omission in an earlier change that changed all RSA/DSA key generation
     apps to use 2048 bits by default.
     [Emilia Käsper]

 Changes between 1.0.2e and 1.0.2f [28 Jan 2016]

  *) DH small subgroups

     Historically OpenSSL only ever generated DH parameters based on "safe"
     primes. More recently (in version 1.0.2) support was provided for
     generating X9.42 style parameter files such as those required for RFC 5114
     support. The primes used in such files may not be "safe". Where an
     application is using DH configured with parameters based on primes that are
     not "safe" then an attacker could use this fact to find a peer's private
     DH exponent. This attack requires that the attacker complete multiple
     handshakes in which the peer uses the same private DH exponent. For example
     this could be used to discover a TLS server's private DH exponent if it's
     reusing the private DH exponent or it's using a static DH ciphersuite.

     OpenSSL provides the option SSL_OP_SINGLE_DH_USE for ephemeral DH (DHE) in
     TLS. It is not on by default. If the option is not set then the server
     reuses the same private DH exponent for the life of the server process and
     would be vulnerable to this attack. It is believed that many popular
     applications do set this option and would therefore not be at risk.

     The fix for this issue adds an additional check where a "q" parameter is
     available (as is the case in X9.42 based parameters). This detects the
     only known attack, and is the only possible defense for static DH
     ciphersuites. This could have some performance impact.

     Additionally the SSL_OP_SINGLE_DH_USE option has been switched on by
     default and cannot be disabled. This could have some performance impact.

     This issue was reported to OpenSSL by Antonio Sanso (Adobe).
     (CVE-2016-0701)
     [Matt Caswell]

  *) SSLv2 doesn't block disabled ciphers

     A malicious client can negotiate SSLv2 ciphers that have been disabled on
     the server and complete SSLv2 handshakes even if all SSLv2 ciphers have
     been disabled, provided that the SSLv2 protocol was not also disabled via
     SSL_OP_NO_SSLv2.

     This issue was reported to OpenSSL on 26th December 2015 by Nimrod Aviram
     and Sebastian Schinzel.
     (CVE-2015-3197)
     [Viktor Dukhovni]

  *) Reject DH handshakes with parameters shorter than 1024 bits.
     [Kurt Roeckx]

 Changes between 1.0.2d and 1.0.2e [3 Dec 2015]

  *) BN_mod_exp may produce incorrect results on x86_64

     There is a carry propagating bug in the x86_64 Montgomery squaring
     procedure. No EC algorithms are affected. Analysis suggests that attacks
     against RSA and DSA as a result of this defect would be very difficult to
     perform and are not believed likely. Attacks against DH are considered just
     feasible (although very difficult) because most of the work necessary to
     deduce information about a private key may be performed offline. The amount
     of resources required for such an attack would be very significant and
     likely only accessible to a limited number of attackers. An attacker would
     additionally need online access to an unpatched system using the target
     private key in a scenario with persistent DH parameters and a private
     key that is shared between multiple clients. For example this can occur by
     default in OpenSSL DHE based SSL/TLS ciphersuites.

     This issue was reported to OpenSSL by Hanno Böck.
     (CVE-2015-3193)
     [Andy Polyakov]

  *) Certificate verify crash with missing PSS parameter

     The signature verification routines will crash with a NULL pointer
     dereference if presented with an ASN.1 signature using the RSA PSS
     algorithm and absent mask generation function parameter. Since these
     routines are used to verify certificate signature algorithms this can be
     used to crash any certificate verification operation and exploited in a
     DoS attack. Any application which performs certificate verification is
     vulnerable including OpenSSL clients and servers which enable client
     authentication.

     This issue was reported to OpenSSL by Loïc Jonas Etienne (Qnective AG).
     (CVE-2015-3194)
     [Stephen Henson]

  *) X509_ATTRIBUTE memory leak

     When presented with a malformed X509_ATTRIBUTE structure OpenSSL will leak
     memory. This structure is used by the PKCS#7 and CMS routines so any
     application which reads PKCS#7 or CMS data from untrusted sources is
     affected. SSL/TLS is not affected.

     This issue was reported to OpenSSL by Adam Langley (Google/BoringSSL) using
     libFuzzer.
     (CVE-2015-3195)
     [Stephen Henson]

  *) Rewrite EVP_DecodeUpdate (base64 decoding) to fix several bugs.
     This changes the decoding behaviour for some invalid messages,
     though the change is mostly in the more lenient direction, and
     legacy behaviour is preserved as much as possible.
     [Emilia Käsper]

  *) In DSA_generate_parameters_ex, if the provided seed is too short,
     use a random seed, as already documented.
     [Rich Salz and Ismo Puustinen <ismo.puustinen@intel.com>]

 Changes between 1.0.2c and 1.0.2d [9 Jul 2015]

  *) Alternate chains certificate forgery

     During certificate verfification, OpenSSL will attempt to find an
     alternative certificate chain if the first attempt to build such a chain
     fails. An error in the implementation of this logic can mean that an
     attacker could cause certain checks on untrusted certificates to be
     bypassed, such as the CA flag, enabling them to use a valid leaf
     certificate to act as a CA and "issue" an invalid certificate.

     This issue was reported to OpenSSL by Adam Langley/David Benjamin
     (Google/BoringSSL).
     (CVE-2015-1793)
     [Matt Caswell]

  *) Race condition handling PSK identify hint

     If PSK identity hints are received by a multi-threaded client then
     the values are wrongly updated in the parent SSL_CTX structure. This can
     result in a race condition potentially leading to a double free of the
     identify hint data.
     (CVE-2015-3196)
     [Stephen Henson]

 Changes between 1.0.2b and 1.0.2c [12 Jun 2015]

  *) Fix HMAC ABI incompatibility. The previous version introduced an ABI
     incompatibility in the handling of HMAC. The previous ABI has now been
     restored.

 Changes between 1.0.2a and 1.0.2b [11 Jun 2015]

  *) Malformed ECParameters causes infinite loop

     When processing an ECParameters structure OpenSSL enters an infinite loop
     if the curve specified is over a specially malformed binary polynomial
     field.

     This can be used to perform denial of service against any
     system which processes public keys, certificate requests or
     certificates.  This includes TLS clients and TLS servers with
     client authentication enabled.

     This issue was reported to OpenSSL by Joseph Barr-Pixton.
     (CVE-2015-1788)
     [Andy Polyakov]

  *) Exploitable out-of-bounds read in X509_cmp_time

     X509_cmp_time does not properly check the length of the ASN1_TIME
     string and can read a few bytes out of bounds. In addition,
     X509_cmp_time accepts an arbitrary number of fractional seconds in the
     time string.

     An attacker can use this to craft malformed certificates and CRLs of
     various sizes and potentially cause a segmentation fault, resulting in
     a DoS on applications that verify certificates or CRLs. TLS clients
     that verify CRLs are affected. TLS clients and servers with client
     authentication enabled may be affected if they use custom verification
     callbacks.

     This issue was reported to OpenSSL by Robert Swiecki (Google), and
     independently by Hanno Böck.
     (CVE-2015-1789)
     [Emilia Käsper]

  *) PKCS7 crash with missing EnvelopedContent

     The PKCS#7 parsing code does not handle missing inner EncryptedContent
     correctly. An attacker can craft malformed ASN.1-encoded PKCS#7 blobs
     with missing content and trigger a NULL pointer dereference on parsing.

     Applications that decrypt PKCS#7 data or otherwise parse PKCS#7
     structures from untrusted sources are affected. OpenSSL clients and
     servers are not affected.

     This issue was reported to OpenSSL by Michal Zalewski (Google).
     (CVE-2015-1790)
     [Emilia Käsper]

  *) CMS verify infinite loop with unknown hash function

     When verifying a signedData message the CMS code can enter an infinite loop
     if presented with an unknown hash function OID. This can be used to perform
     denial of service against any system which verifies signedData messages using
     the CMS code.
     This issue was reported to OpenSSL by Johannes Bauer.
     (CVE-2015-1792)
     [Stephen Henson]

  *) Race condition handling NewSessionTicket

     If a NewSessionTicket is received by a multi-threaded client when attempting to
     reuse a previous ticket then a race condition can occur potentially leading to
     a double free of the ticket data.
     (CVE-2015-1791)
     [Matt Caswell]

  *) Removed support for the two export grade static DH ciphersuites
     EXP-DH-RSA-DES-CBC-SHA and EXP-DH-DSS-DES-CBC-SHA. These two ciphersuites
     were newly added (along with a number of other static DH ciphersuites) to
     1.0.2. However the two export ones have *never* worked since they were
     introduced. It seems strange in any case to be adding new export
     ciphersuites, and given "logjam" it also does not seem correct to fix them.
     [Matt Caswell]

  *) Only support 256-bit or stronger elliptic curves with the
     'ecdh_auto' setting (server) or by default (client). Of supported
     curves, prefer P-256 (both).
     [Emilia Kasper]

  *) Reject DH handshakes with parameters shorter than 768 bits.
     [Kurt Roeckx and Emilia Kasper]

 Changes between 1.0.2 and 1.0.2a [19 Mar 2015]

  *) ClientHello sigalgs DoS fix

     If a client connects to an OpenSSL 1.0.2 server and renegotiates with an
     invalid signature algorithms extension a NULL pointer dereference will
     occur. This can be exploited in a DoS attack against the server.

     This issue was was reported to OpenSSL by David Ramos of Stanford
     University.
     (CVE-2015-0291)
     [Stephen Henson and Matt Caswell]

  *) Multiblock corrupted pointer fix

     OpenSSL 1.0.2 introduced the "multiblock" performance improvement. This
     feature only applies on 64 bit x86 architecture platforms that support AES
     NI instructions. A defect in the implementation of "multiblock" can cause
     OpenSSL's internal write buffer to become incorrectly set to NULL when
     using non-blocking IO. Typically, when the user application is using a
     socket BIO for writing, this will only result in a failed connection.
     However if some other BIO is used then it is likely that a segmentation
     fault will be triggered, thus enabling a potential DoS attack.

     This issue was reported to OpenSSL by Daniel Danner and Rainer Mueller.
     (CVE-2015-0290)
     [Matt Caswell]

  *) Segmentation fault in DTLSv1_listen fix

     The DTLSv1_listen function is intended to be stateless and processes the
     initial ClientHello from many peers. It is common for user code to loop
     over the call to DTLSv1_listen until a valid ClientHello is received with
     an associated cookie. A defect in the implementation of DTLSv1_listen means
     that state is preserved in the SSL object from one invocation to the next
     that can lead to a segmentation fault. Errors processing the initial
     ClientHello can trigger this scenario. An example of such an error could be
     that a DTLS1.0 only client is attempting to connect to a DTLS1.2 only
     server.

     This issue was reported to OpenSSL by Per Allansson.
     (CVE-2015-0207)
     [Matt Caswell]

  *) Segmentation fault in ASN1_TYPE_cmp fix

     The function ASN1_TYPE_cmp will crash with an invalid read if an attempt is
     made to compare ASN.1 boolean types. Since ASN1_TYPE_cmp is used to check
     certificate signature algorithm consistency this can be used to crash any
     certificate verification operation and exploited in a DoS attack. Any
     application which performs certificate verification is vulnerable including
     OpenSSL clients and servers which enable client authentication.
     (CVE-2015-0286)
     [Stephen Henson]

  *) Segmentation fault for invalid PSS parameters fix

     The signature verification routines will crash with a NULL pointer
     dereference if presented with an ASN.1 signature using the RSA PSS
     algorithm and invalid parameters. Since these routines are used to verify
     certificate signature algorithms this can be used to crash any
     certificate verification operation and exploited in a DoS attack. Any
     application which performs certificate verification is vulnerable including
     OpenSSL clients and servers which enable client authentication.

     This issue was was reported to OpenSSL by Brian Carpenter.
     (CVE-2015-0208)
     [Stephen Henson]

  *) ASN.1 structure reuse memory corruption fix

     Reusing a structure in ASN.1 parsing may allow an attacker to cause
     memory corruption via an invalid write. Such reuse is and has been
     strongly discouraged and is believed to be rare.

     Applications that parse structures containing CHOICE or ANY DEFINED BY
     components may be affected. Certificate parsing (d2i_X509 and related
     functions) are however not affected. OpenSSL clients and servers are
     not affected.
     (CVE-2015-0287)
     [Stephen Henson]

  *) PKCS7 NULL pointer dereferences fix

     The PKCS#7 parsing code does not handle missing outer ContentInfo
     correctly. An attacker can craft malformed ASN.1-encoded PKCS#7 blobs with
     missing content and trigger a NULL pointer dereference on parsing.

     Applications that verify PKCS#7 signatures, decrypt PKCS#7 data or
     otherwise parse PKCS#7 structures from untrusted sources are
     affected. OpenSSL clients and servers are not affected.

     This issue was reported to OpenSSL by Michal Zalewski (Google).
     (CVE-2015-0289)
     [Emilia Käsper]

  *) DoS via reachable assert in SSLv2 servers fix

     A malicious client can trigger an OPENSSL_assert (i.e., an abort) in
     servers that both support SSLv2 and enable export cipher suites by sending
     a specially crafted SSLv2 CLIENT-MASTER-KEY message.

     This issue was discovered by Sean Burford (Google) and Emilia Käsper
     (OpenSSL development team).
     (CVE-2015-0293)
     [Emilia Käsper]

  *) Empty CKE with client auth and DHE fix

     If client auth is used then a server can seg fault in the event of a DHE
     ciphersuite being selected and a zero length ClientKeyExchange message
     being sent by the client. This could be exploited in a DoS attack.
     (CVE-2015-1787)
     [Matt Caswell]

  *) Handshake with unseeded PRNG fix

     Under certain conditions an OpenSSL 1.0.2 client can complete a handshake
     with an unseeded PRNG. The conditions are:
     - The client is on a platform where the PRNG has not been seeded
     automatically, and the user has not seeded manually
     - A protocol specific client method version has been used (i.e. not
     SSL_client_methodv23)
     - A ciphersuite is used that does not require additional random data from
     the PRNG beyond the initial ClientHello client random (e.g. PSK-RC4-SHA).

     If the handshake succeeds then the client random that has been used will
     have been generated from a PRNG with insufficient entropy and therefore the
     output may be predictable.

     For example using the following command with an unseeded openssl will
     succeed on an unpatched platform:

     openssl s_client -psk 1a2b3c4d -tls1_2 -cipher PSK-RC4-SHA
     (CVE-2015-0285)
     [Matt Caswell]

  *) Use After Free following d2i_ECPrivatekey error fix

     A malformed EC private key file consumed via the d2i_ECPrivateKey function
     could cause a use after free condition. This, in turn, could cause a double
     free in several private key parsing functions (such as d2i_PrivateKey
     or EVP_PKCS82PKEY) and could lead to a DoS attack or memory corruption
     for applications that receive EC private keys from untrusted
     sources. This scenario is considered rare.

     This issue was discovered by the BoringSSL project and fixed in their
     commit 517073cd4b.
     (CVE-2015-0209)
     [Matt Caswell]

  *) X509_to_X509_REQ NULL pointer deref fix

     The function X509_to_X509_REQ will crash with a NULL pointer dereference if
     the certificate key is invalid. This function is rarely used in practice.

     This issue was discovered by Brian Carpenter.
     (CVE-2015-0288)
     [Stephen Henson]

  *) Removed the export ciphers from the DEFAULT ciphers
     [Kurt Roeckx]

 Changes between 1.0.1l and 1.0.2 [22 Jan 2015]

  *) Change RSA and DH/DSA key generation apps to generate 2048-bit
     keys by default.
     [Kurt Roeckx]

  *) Facilitate "universal" ARM builds targeting range of ARM ISAs, e.g.
     ARMv5 through ARMv8, as opposite to "locking" it to single one.
     So far those who have to target multiple plaforms would compromise
     and argue that binary targeting say ARMv5 would still execute on
     ARMv8. "Universal" build resolves this compromise by providing
     near-optimal performance even on newer platforms.
     [Andy Polyakov]

  *) Accelerated NIST P-256 elliptic curve implementation for x86_64
     (other platforms pending).
     [Shay Gueron & Vlad Krasnov (Intel Corp), Andy Polyakov]

  *) Add support for the SignedCertificateTimestampList certificate and
     OCSP response extensions from RFC6962.
     [Rob Stradling]

  *) Fix ec_GFp_simple_points_make_affine (thus, EC_POINTs_mul etc.)
     for corner cases. (Certain input points at infinity could lead to
     bogus results, with non-infinity inputs mapped to infinity too.)
     [Bodo Moeller]

  *) Initial support for PowerISA 2.0.7, first implemented in POWER8.
     This covers AES, SHA256/512 and GHASH. "Initial" means that most
     common cases are optimized and there still is room for further
     improvements. Vector Permutation AES for Altivec is also added.
     [Andy Polyakov]

  *) Add support for little-endian ppc64 Linux target.
     [Marcelo Cerri (IBM)]

  *) Initial support for AMRv8 ISA crypto extensions. This covers AES,
     SHA1, SHA256 and GHASH. "Initial" means that most common cases
     are optimized and there still is room for further improvements.
     Both 32- and 64-bit modes are supported.
     [Andy Polyakov, Ard Biesheuvel (Linaro)]

  *) Improved ARMv7 NEON support.
     [Andy Polyakov]

  *) Support for SPARC Architecture 2011 crypto extensions, first
     implemented in SPARC T4. This covers AES, DES, Camellia, SHA1,
     SHA256/512, MD5, GHASH and modular exponentiation.
     [Andy Polyakov, David Miller]

  *) Accelerated modular exponentiation for Intel processors, a.k.a.
     RSAZ.
     [Shay Gueron & Vlad Krasnov (Intel Corp)]

  *) Support for new and upcoming Intel processors, including AVX2,
     BMI and SHA ISA extensions. This includes additional "stitched"
     implementations, AESNI-SHA256 and GCM, and multi-buffer support
     for TLS encrypt.

     This work was sponsored by Intel Corp.
     [Andy Polyakov]

  *) Support for DTLS 1.2. This adds two sets of DTLS methods: DTLS_*_method()
     supports both DTLS 1.2 and 1.0 and should use whatever version the peer
     supports and DTLSv1_2_*_method() which supports DTLS 1.2 only.
     [Steve Henson]

  *) Use algorithm specific chains in SSL_CTX_use_certificate_chain_file():
     this fixes a limiation in previous versions of OpenSSL.
     [Steve Henson]

  *) Extended RSA OAEP support via EVP_PKEY API. Options to specify digest,
     MGF1 digest and OAEP label.
     [Steve Henson]

  *) Add EVP support for key wrapping algorithms, to avoid problems with
     existing code the flag EVP_CIPHER_CTX_WRAP_ALLOW has to be set in
     the EVP_CIPHER_CTX or an error is returned. Add AES and DES3 wrap
     algorithms and include tests cases.
     [Steve Henson]

  *) Add functions to allocate and set the fields of an ECDSA_METHOD
     structure.
     [Douglas E. Engert, Steve Henson]

  *) New functions OPENSSL_gmtime_diff and ASN1_TIME_diff to find the
     difference in days and seconds between two tm or ASN1_TIME structures.
     [Steve Henson]

  *) Add -rev test option to s_server to just reverse order of characters
     received by client and send back to server. Also prints an abbreviated
     summary of the connection parameters.
     [Steve Henson]

  *) New option -brief for s_client and s_server to print out a brief summary
     of connection parameters.
     [Steve Henson]

  *) Add callbacks for arbitrary TLS extensions.
     [Trevor Perrin <trevp@trevp.net> and Ben Laurie]

  *) New option -crl_download in several openssl utilities to download CRLs
     from CRLDP extension in certificates.
     [Steve Henson]

  *) New options -CRL and -CRLform for s_client and s_server for CRLs.
     [Steve Henson]

  *) New function X509_CRL_diff to generate a delta CRL from the difference
     of two full CRLs. Add support to "crl" utility.
     [Steve Henson]

  *) New functions to set lookup_crls function and to retrieve
     X509_STORE from X509_STORE_CTX.
     [Steve Henson]

  *) Print out deprecated issuer and subject unique ID fields in
     certificates.
     [Steve Henson]

  *) Extend OCSP I/O functions so they can be used for simple general purpose
     HTTP as well as OCSP. New wrapper function which can be used to download
     CRLs using the OCSP API.
     [Steve Henson]

  *) Delegate command line handling in s_client/s_server to SSL_CONF APIs.
     [Steve Henson]

  *) SSL_CONF* functions. These provide a common framework for application
     configuration using configuration files or command lines.
     [Steve Henson]

  *) SSL/TLS tracing code. This parses out SSL/TLS records using the
     message callback and prints the results. Needs compile time option
     "enable-ssl-trace". New options to s_client and s_server to enable
     tracing.
     [Steve Henson]

  *) New ctrl and macro to retrieve supported points extensions.
     Print out extension in s_server and s_client.
     [Steve Henson]

  *) New functions to retrieve certificate signature and signature
     OID NID.
     [Steve Henson]

  *) Add functions to retrieve and manipulate the raw cipherlist sent by a
     client to OpenSSL.
     [Steve Henson]

  *) New Suite B modes for TLS code. These use and enforce the requirements
     of RFC6460: restrict ciphersuites, only permit Suite B algorithms and
     only use Suite B curves. The Suite B modes can be set by using the
     strings "SUITEB128", "SUITEB192" or "SUITEB128ONLY" for the cipherstring.
     [Steve Henson]

  *) New chain verification flags for Suite B levels of security. Check
     algorithms are acceptable when flags are set in X509_verify_cert.
     [Steve Henson]

  *) Make tls1_check_chain return a set of flags indicating checks passed
     by a certificate chain. Add additional tests to handle client
     certificates: checks for matching certificate type and issuer name
     comparison.
     [Steve Henson]

  *) If an attempt is made to use a signature algorithm not in the peer
     preference list abort the handshake. If client has no suitable
     signature algorithms in response to a certificate request do not
     use the certificate.
     [Steve Henson]

  *) If server EC tmp key is not in client preference list abort handshake.
     [Steve Henson]

  *) Add support for certificate stores in CERT structure. This makes it
     possible to have different stores per SSL structure or one store in
     the parent SSL_CTX. Include distint stores for certificate chain
     verification and chain building. New ctrl SSL_CTRL_BUILD_CERT_CHAIN
     to build and store a certificate chain in CERT structure: returing
     an error if the chain cannot be built: this will allow applications
     to test if a chain is correctly configured.

     Note: if the CERT based stores are not set then the parent SSL_CTX
     store is used to retain compatibility with existing behaviour.

     [Steve Henson]

  *) New function ssl_set_client_disabled to set a ciphersuite disabled
     mask based on the current session, check mask when sending client
     hello and checking the requested ciphersuite.
     [Steve Henson]

  *) New ctrls to retrieve and set certificate types in a certificate
     request message. Print out received values in s_client. If certificate
     types is not set with custom values set sensible values based on
     supported signature algorithms.
     [Steve Henson]

  *) Support for distinct client and server supported signature algorithms.
     [Steve Henson]

  *) Add certificate callback. If set this is called whenever a certificate
     is required by client or server. An application can decide which
     certificate chain to present based on arbitrary criteria: for example
     supported signature algorithms. Add very simple example to s_server.
     This fixes many of the problems and restrictions of the existing client
     certificate callback: for example you can now clear an existing
     certificate and specify the whole chain.
     [Steve Henson]

  *) Add new "valid_flags" field to CERT_PKEY structure which determines what
     the certificate can be used for (if anything). Set valid_flags field 
     in new tls1_check_chain function. Simplify ssl_set_cert_masks which used
     to have similar checks in it.

     Add new "cert_flags" field to CERT structure and include a "strict mode".
     This enforces some TLS certificate requirements (such as only permitting
     certificate signature algorithms contained in the supported algorithms
     extension) which some implementations ignore: this option should be used
     with caution as it could cause interoperability issues.
     [Steve Henson]

  *) Update and tidy signature algorithm extension processing. Work out
     shared signature algorithms based on preferences and peer algorithms
     and print them out in s_client and s_server. Abort handshake if no
     shared signature algorithms.
     [Steve Henson]

  *) Add new functions to allow customised supported signature algorithms
     for SSL and SSL_CTX structures. Add options to s_client and s_server
     to support them.
     [Steve Henson]

  *) New function SSL_certs_clear() to delete all references to certificates
     from an SSL structure. Before this once a certificate had been added
     it couldn't be removed.
     [Steve Henson]

  *) Integrate hostname, email address and IP address checking with certificate
     verification. New verify options supporting checking in opensl utility.
     [Steve Henson]

  *) Fixes and wildcard matching support to hostname and email checking
     functions. Add manual page.
     [Florian Weimer (Red Hat Product Security Team)]

  *) New functions to check a hostname email or IP address against a
     certificate. Add options x509 utility to print results of checks against
     a certificate.
     [Steve Henson]

  *) Fix OCSP checking.
     [Rob Stradling <rob.stradling@comodo.com> and Ben Laurie]

  *) Initial experimental support for explicitly trusted non-root CAs. 
     OpenSSL still tries to build a complete chain to a root but if an
     intermediate CA has a trust setting included that is used. The first
     setting is used: whether to trust (e.g., -addtrust option to the x509
     utility) or reject.
     [Steve Henson]

  *) Add -trusted_first option which attempts to find certificates in the
     trusted store even if an untrusted chain is also supplied.
     [Steve Henson]

  *) MIPS assembly pack updates: support for MIPS32r2 and SmartMIPS ASE,
     platform support for Linux and Android.
     [Andy Polyakov]

  *) Support for linux-x32, ILP32 environment in x86_64 framework.
     [Andy Polyakov]

  *) Experimental multi-implementation support for FIPS capable OpenSSL.
     When in FIPS mode the approved implementations are used as normal,
     when not in FIPS mode the internal unapproved versions are used instead.
     This means that the FIPS capable OpenSSL isn't forced to use the
     (often lower perfomance) FIPS implementations outside FIPS mode.
     [Steve Henson]

  *) Transparently support X9.42 DH parameters when calling
     PEM_read_bio_DHparameters. This means existing applications can handle
     the new parameter format automatically.
     [Steve Henson]

  *) Initial experimental support for X9.42 DH parameter format: mainly
     to support use of 'q' parameter for RFC5114 parameters.
     [Steve Henson]

  *) Add DH parameters from RFC5114 including test data to dhtest.
     [Steve Henson]

  *) Support for automatic EC temporary key parameter selection. If enabled
     the most preferred EC parameters are automatically used instead of
     hardcoded fixed parameters. Now a server just has to call:
     SSL_CTX_set_ecdh_auto(ctx, 1) and the server will automatically
     support ECDH and use the most appropriate parameters.
     [Steve Henson]

  *) Enhance and tidy EC curve and point format TLS extension code. Use
     static structures instead of allocation if default values are used.
     New ctrls to set curves we wish to support and to retrieve shared curves.
     Print out shared curves in s_server. New options to s_server and s_client
     to set list of supported curves.
     [Steve Henson]

  *) New ctrls to retrieve supported signature algorithms and 
     supported curve values as an array of NIDs. Extend openssl utility
     to print out received values.
     [Steve Henson]

  *) Add new APIs EC_curve_nist2nid and EC_curve_nid2nist which convert
     between NIDs and the more common NIST names such as "P-256". Enhance
     ecparam utility and ECC method to recognise the NIST names for curves.
     [Steve Henson]

  *) Enhance SSL/TLS certificate chain handling to support different
     chains for each certificate instead of one chain in the parent SSL_CTX.
     [Steve Henson]

  *) Support for fixed DH ciphersuite client authentication: where both
     server and client use DH certificates with common parameters.
     [Steve Henson]

  *) Support for fixed DH ciphersuites: those requiring DH server
     certificates.
     [Steve Henson]

  *) New function i2d_re_X509_tbs for re-encoding the TBS portion of
     the certificate.
     Note: Related 1.0.2-beta specific macros X509_get_cert_info,
     X509_CINF_set_modified, X509_CINF_get_issuer, X509_CINF_get_extensions and
     X509_CINF_get_signature were reverted post internal team review.

 Changes between 1.0.1k and 1.0.1l [15 Jan 2015]

  *) Build fixes for the Windows and OpenVMS platforms
     [Matt Caswell and Richard Levitte]

 Changes between 1.0.1j and 1.0.1k [8 Jan 2015]

  *) Fix DTLS segmentation fault in dtls1_get_record. A carefully crafted DTLS
     message can cause a segmentation fault in OpenSSL due to a NULL pointer
     dereference. This could lead to a Denial Of Service attack. Thanks to
     Markus Stenberg of Cisco Systems, Inc. for reporting this issue.
     (CVE-2014-3571)
     [Steve Henson]

  *) Fix DTLS memory leak in dtls1_buffer_record. A memory leak can occur in the
     dtls1_buffer_record function under certain conditions. In particular this
     could occur if an attacker sent repeated DTLS records with the same
     sequence number but for the next epoch. The memory leak could be exploited
     by an attacker in a Denial of Service attack through memory exhaustion.
     Thanks to Chris Mueller for reporting this issue.
     (CVE-2015-0206)
     [Matt Caswell]

  *) Fix issue where no-ssl3 configuration sets method to NULL. When openssl is
     built with the no-ssl3 option and a SSL v3 ClientHello is received the ssl
     method would be set to NULL which could later result in a NULL pointer
     dereference. Thanks to Frank Schmirler for reporting this issue.
     (CVE-2014-3569)
     [Kurt Roeckx]

  *) Abort handshake if server key exchange message is omitted for ephemeral
     ECDH ciphersuites.

     Thanks to Karthikeyan Bhargavan of the PROSECCO team at INRIA for
     reporting this issue.
     (CVE-2014-3572)
     [Steve Henson]

  *) Remove non-export ephemeral RSA code on client and server. This code
     violated the TLS standard by allowing the use of temporary RSA keys in
     non-export ciphersuites and could be used by a server to effectively
     downgrade the RSA key length used to a value smaller than the server
     certificate. Thanks for Karthikeyan Bhargavan of the PROSECCO team at
     INRIA or reporting this issue.
     (CVE-2015-0204)
     [Steve Henson]

  *) Fixed issue where DH client certificates are accepted without verification.
     An OpenSSL server will accept a DH certificate for client authentication
     without the certificate verify message. This effectively allows a client to
     authenticate without the use of a private key. This only affects servers
     which trust a client certificate authority which issues certificates
     containing DH keys: these are extremely rare and hardly ever encountered.
     Thanks for Karthikeyan Bhargavan of the PROSECCO team at INRIA or reporting
     this issue.
     (CVE-2015-0205)
     [Steve Henson]

  *) Ensure that the session ID context of an SSL is updated when its
     SSL_CTX is updated via SSL_set_SSL_CTX.

     The session ID context is typically set from the parent SSL_CTX,
     and can vary with the CTX.
     [Adam Langley]

  *) Fix various certificate fingerprint issues.

     By using non-DER or invalid encodings outside the signed portion of a
     certificate the fingerprint can be changed without breaking the signature.
     Although no details of the signed portion of the certificate can be changed
     this can cause problems with some applications: e.g. those using the
     certificate fingerprint for blacklists.

     1. Reject signatures with non zero unused bits.

     If the BIT STRING containing the signature has non zero unused bits reject
     the signature. All current signature algorithms require zero unused bits.

     2. Check certificate algorithm consistency.

     Check the AlgorithmIdentifier inside TBS matches the one in the
     certificate signature. NB: this will result in signature failure
     errors for some broken certificates.

     Thanks to Konrad Kraszewski from Google for reporting this issue.

     3. Check DSA/ECDSA signatures use DER.

     Reencode DSA/ECDSA signatures and compare with the original received
     signature. Return an error if there is a mismatch.

     This will reject various cases including garbage after signature
     (thanks to Antti Karjalainen and Tuomo Untinen from the Codenomicon CROSS
     program for discovering this case) and use of BER or invalid ASN.1 INTEGERs
     (negative or with leading zeroes).

     Further analysis was conducted and fixes were developed by Stephen Henson
     of the OpenSSL core team.

     (CVE-2014-8275)
     [Steve Henson]

   *) Correct Bignum squaring. Bignum squaring (BN_sqr) may produce incorrect
      results on some platforms, including x86_64. This bug occurs at random
      with a very low probability, and is not known to be exploitable in any
      way, though its exact impact is difficult to determine. Thanks to Pieter
      Wuille (Blockstream) who reported this issue and also suggested an initial
      fix. Further analysis was conducted by the OpenSSL development team and
      Adam Langley of Google. The final fix was developed by Andy Polyakov of
      the OpenSSL core team.
      (CVE-2014-3570)
      [Andy Polyakov]

   *) Do not resume sessions on the server if the negotiated protocol
      version does not match the session's version. Resuming with a different
      version, while not strictly forbidden by the RFC, is of questionable
      sanity and breaks all known clients.
      [David Benjamin, Emilia Käsper]

   *) Tighten handling of the ChangeCipherSpec (CCS) message: reject
      early CCS messages during renegotiation. (Note that because
      renegotiation is encrypted, this early CCS was not exploitable.)
      [Emilia Käsper]

   *) Tighten client-side session ticket handling during renegotiation:
      ensure that the client only accepts a session ticket if the server sends
      the extension anew in the ServerHello. Previously, a TLS client would
      reuse the old extension state and thus accept a session ticket if one was
      announced in the initial ServerHello.

      Similarly, ensure that the client requires a session ticket if one
      was advertised in the ServerHello. Previously, a TLS client would
      ignore a missing NewSessionTicket message.
      [Emilia Käsper]

 Changes between 1.0.1i and 1.0.1j [15 Oct 2014]

  *) SRTP Memory Leak.

     A flaw in the DTLS SRTP extension parsing code allows an attacker, who
     sends a carefully crafted handshake message, to cause OpenSSL to fail
     to free up to 64k of memory causing a memory leak. This could be
     exploited in a Denial Of Service attack. This issue affects OpenSSL
     1.0.1 server implementations for both SSL/TLS and DTLS regardless of
     whether SRTP is used or configured. Implementations of OpenSSL that
     have been compiled with OPENSSL_NO_SRTP defined are not affected.

     The fix was developed by the OpenSSL team.
     (CVE-2014-3513)
     [OpenSSL team]

  *) Session Ticket Memory Leak.

     When an OpenSSL SSL/TLS/DTLS server receives a session ticket the
     integrity of that ticket is first verified. In the event of a session
     ticket integrity check failing, OpenSSL will fail to free memory
     causing a memory leak. By sending a large number of invalid session
     tickets an attacker could exploit this issue in a Denial Of Service
     attack.
     (CVE-2014-3567)
     [Steve Henson]

  *) Build option no-ssl3 is incomplete.

     When OpenSSL is configured with "no-ssl3" as a build option, servers
     could accept and complete a SSL 3.0 handshake, and clients could be
     configured to send them.
     (CVE-2014-3568)
     [Akamai and the OpenSSL team]

  *) Add support for TLS_FALLBACK_SCSV.
     Client applications doing fallback retries should call
     SSL_set_mode(s, SSL_MODE_SEND_FALLBACK_SCSV).
     (CVE-2014-3566)
     [Adam Langley, Bodo Moeller]

  *) Add additional DigestInfo checks.
 
     Reencode DigestInto in DER and check against the original when
     verifying RSA signature: this will reject any improperly encoded
     DigestInfo structures.

     Note: this is a precautionary measure and no attacks are currently known.

     [Steve Henson]

 Changes between 1.0.1h and 1.0.1i [6 Aug 2014]

  *) Fix SRP buffer overrun vulnerability. Invalid parameters passed to the
     SRP code can be overrun an internal buffer. Add sanity check that
     g, A, B < N to SRP code.

     Thanks to Sean Devlin and Watson Ladd of Cryptography Services, NCC
     Group for discovering this issue.
     (CVE-2014-3512)
     [Steve Henson]

  *) A flaw in the OpenSSL SSL/TLS server code causes the server to negotiate
     TLS 1.0 instead of higher protocol versions when the ClientHello message
     is badly fragmented. This allows a man-in-the-middle attacker to force a
     downgrade to TLS 1.0 even if both the server and the client support a
     higher protocol version, by modifying the client's TLS records.

     Thanks to David Benjamin and Adam Langley (Google) for discovering and
     researching this issue.
     (CVE-2014-3511)
     [David Benjamin]

  *) OpenSSL DTLS clients enabling anonymous (EC)DH ciphersuites are subject
     to a denial of service attack. A malicious server can crash the client
     with a null pointer dereference (read) by specifying an anonymous (EC)DH
     ciphersuite and sending carefully crafted handshake messages.

     Thanks to Felix Gröbert (Google) for discovering and researching this
     issue.
     (CVE-2014-3510)
     [Emilia Käsper]

  *) By sending carefully crafted DTLS packets an attacker could cause openssl
     to leak memory. This can be exploited through a Denial of Service attack.
     Thanks to Adam Langley for discovering and researching this issue.
     (CVE-2014-3507)
     [Adam Langley]

  *) An attacker can force openssl to consume large amounts of memory whilst
     processing DTLS handshake messages. This can be exploited through a
     Denial of Service attack.
     Thanks to Adam Langley for discovering and researching this issue.
     (CVE-2014-3506)
     [Adam Langley]

  *) An attacker can force an error condition which causes openssl to crash
     whilst processing DTLS packets due to memory being freed twice. This
     can be exploited through a Denial of Service attack.
     Thanks to Adam Langley and Wan-Teh Chang for discovering and researching
     this issue.
     (CVE-2014-3505)
     [Adam Langley]

  *) If a multithreaded client connects to a malicious server using a resumed
     session and the server sends an ec point format extension it could write
     up to 255 bytes to freed memory.

     Thanks to Gabor Tyukasz (LogMeIn Inc) for discovering and researching this
     issue.
     (CVE-2014-3509)
     [Gabor Tyukasz]

  *) A malicious server can crash an OpenSSL client with a null pointer
     dereference (read) by specifying an SRP ciphersuite even though it was not
     properly negotiated with the client. This can be exploited through a
     Denial of Service attack.

     Thanks to Joonas Kuorilehto and Riku Hietamäki (Codenomicon) for
     discovering and researching this issue.
     (CVE-2014-5139)
     [Steve Henson]

  *) A flaw in OBJ_obj2txt may cause pretty printing functions such as
     X509_name_oneline, X509_name_print_ex et al. to leak some information
     from the stack. Applications may be affected if they echo pretty printing
     output to the attacker.

     Thanks to Ivan Fratric (Google) for discovering this issue.
     (CVE-2014-3508)
     [Emilia Käsper, and Steve Henson]

  *) Fix ec_GFp_simple_points_make_affine (thus, EC_POINTs_mul etc.)
     for corner cases. (Certain input points at infinity could lead to
     bogus results, with non-infinity inputs mapped to infinity too.)
     [Bodo Moeller]

 Changes between 1.0.1g and 1.0.1h [5 Jun 2014]

  *) Fix for SSL/TLS MITM flaw. An attacker using a carefully crafted
     handshake can force the use of weak keying material in OpenSSL
     SSL/TLS clients and servers.

     Thanks to KIKUCHI Masashi (Lepidum Co. Ltd.) for discovering and
     researching this issue. (CVE-2014-0224)
     [KIKUCHI Masashi, Steve Henson]

  *) Fix DTLS recursion flaw. By sending an invalid DTLS handshake to an
     OpenSSL DTLS client the code can be made to recurse eventually crashing
     in a DoS attack.

     Thanks to Imre Rad (Search-Lab Ltd.) for discovering this issue.
     (CVE-2014-0221)
     [Imre Rad, Steve Henson]

  *) Fix DTLS invalid fragment vulnerability. A buffer overrun attack can
     be triggered by sending invalid DTLS fragments to an OpenSSL DTLS
     client or server. This is potentially exploitable to run arbitrary
     code on a vulnerable client or server.

     Thanks to Jüri Aedla for reporting this issue. (CVE-2014-0195)
     [Jüri Aedla, Steve Henson]

  *) Fix bug in TLS code where clients enable anonymous ECDH ciphersuites
     are subject to a denial of service attack.

     Thanks to Felix Gröbert and Ivan Fratric at Google for discovering
     this issue. (CVE-2014-3470)
     [Felix Gröbert, Ivan Fratric, Steve Henson]

  *) Harmonize version and its documentation. -f flag is used to display
     compilation flags.
     [mancha <mancha1@zoho.com>]

  *) Fix eckey_priv_encode so it immediately returns an error upon a failure
     in i2d_ECPrivateKey.  Thanks to Ted Unangst for feedback on this issue.
     [mancha <mancha1@zoho.com>]

  *) Fix some double frees. These are not thought to be exploitable.
     [mancha <mancha1@zoho.com>]

 Changes between 1.0.1f and 1.0.1g [7 Apr 2014]

  *) A missing bounds check in the handling of the TLS heartbeat extension
     can be used to reveal up to 64k of memory to a connected client or
     server.

     Thanks for Neel Mehta of Google Security for discovering this bug and to
     Adam Langley <agl@chromium.org> and Bodo Moeller <bmoeller@acm.org> for
     preparing the fix (CVE-2014-0160)
     [Adam Langley, Bodo Moeller]

  *) Fix for the attack described in the paper "Recovering OpenSSL
     ECDSA Nonces Using the FLUSH+RELOAD Cache Side-channel Attack"
     by Yuval Yarom and Naomi Benger. Details can be obtained from:
     http://eprint.iacr.org/2014/140

     Thanks to Yuval Yarom and Naomi Benger for discovering this
     flaw and to Yuval Yarom for supplying a fix (CVE-2014-0076)
     [Yuval Yarom and Naomi Benger]

  *) TLS pad extension: draft-agl-tls-padding-03

     Workaround for the "TLS hang bug" (see FAQ and PR#2771): if the
     TLS client Hello record length value would otherwise be > 255 and
     less that 512 pad with a dummy extension containing zeroes so it
     is at least 512 bytes long.

     [Adam Langley, Steve Henson]

 Changes between 1.0.1e and 1.0.1f [6 Jan 2014]

  *) Fix for TLS record tampering bug. A carefully crafted invalid 
     handshake could crash OpenSSL with a NULL pointer exception.
     Thanks to Anton Johansson for reporting this issues.
     (CVE-2013-4353)

  *) Keep original DTLS digest and encryption contexts in retransmission
     structures so we can use the previous session parameters if they need
     to be resent. (CVE-2013-6450)
     [Steve Henson]

  *) Add option SSL_OP_SAFARI_ECDHE_ECDSA_BUG (part of SSL_OP_ALL) which
     avoids preferring ECDHE-ECDSA ciphers when the client appears to be
     Safari on OS X.  Safari on OS X 10.8..10.8.3 advertises support for
     several ECDHE-ECDSA ciphers, but fails to negotiate them.  The bug
     is fixed in OS X 10.8.4, but Apple have ruled out both hot fixing
     10.8..10.8.3 and forcing users to upgrade to 10.8.4 or newer.
     [Rob Stradling, Adam Langley]

 Changes between 1.0.1d and 1.0.1e [11 Feb 2013]

  *) Correct fix for CVE-2013-0169. The original didn't work on AES-NI
     supporting platforms or when small records were transferred.
     [Andy Polyakov, Steve Henson]

 Changes between 1.0.1c and 1.0.1d [5 Feb 2013]

  *) Make the decoding of SSLv3, TLS and DTLS CBC records constant time.

     This addresses the flaw in CBC record processing discovered by 
     Nadhem Alfardan and Kenny Paterson. Details of this attack can be found
     at: http://www.isg.rhul.ac.uk/tls/     

     Thanks go to Nadhem Alfardan and Kenny Paterson of the Information
     Security Group at Royal Holloway, University of London
     (www.isg.rhul.ac.uk) for discovering this flaw and Adam Langley and
     Emilia Käsper for the initial patch.
     (CVE-2013-0169)
     [Emilia Käsper, Adam Langley, Ben Laurie, Andy Polyakov, Steve Henson]

  *) Fix flaw in AESNI handling of TLS 1.2 and 1.1 records for CBC mode
     ciphersuites which can be exploited in a denial of service attack.
     Thanks go to and to Adam Langley <agl@chromium.org> for discovering
     and detecting this bug and to Wolfgang Ettlinger
     <wolfgang.ettlinger@gmail.com> for independently discovering this issue.
     (CVE-2012-2686)
     [Adam Langley]

  *) Return an error when checking OCSP signatures when key is NULL.
     This fixes a DoS attack. (CVE-2013-0166)
     [Steve Henson]

  *) Make openssl verify return errors.
     [Chris Palmer <palmer@google.com> and Ben Laurie]

  *) Call OCSP Stapling callback after ciphersuite has been chosen, so
     the right response is stapled. Also change SSL_get_certificate()
     so it returns the certificate actually sent.
     See http://rt.openssl.org/Ticket/Display.html?id=2836.
     [Rob Stradling <rob.stradling@comodo.com>]

  *) Fix possible deadlock when decoding public keys.
     [Steve Henson]

  *) Don't use TLS 1.0 record version number in initial client hello
     if renegotiating.
     [Steve Henson]

 Changes between 1.0.1b and 1.0.1c [10 May 2012]

  *) Sanity check record length before skipping explicit IV in TLS
     1.2, 1.1 and DTLS to fix DoS attack.

     Thanks to Codenomicon for discovering this issue using Fuzz-o-Matic
     fuzzing as a service testing platform.
     (CVE-2012-2333)
     [Steve Henson]

  *) Initialise tkeylen properly when encrypting CMS messages.
     Thanks to Solar Designer of Openwall for reporting this issue.
     [Steve Henson]

  *) In FIPS mode don't try to use composite ciphers as they are not
     approved.
     [Steve Henson]

 Changes between 1.0.1a and 1.0.1b [26 Apr 2012]

  *) OpenSSL 1.0.0 sets SSL_OP_ALL to 0x80000FFFL and OpenSSL 1.0.1 and
     1.0.1a set SSL_OP_NO_TLSv1_1 to 0x00000400L which would unfortunately
     mean any application compiled against OpenSSL 1.0.0 headers setting
     SSL_OP_ALL would also set SSL_OP_NO_TLSv1_1, unintentionally disablng
     TLS 1.1 also. Fix this by changing the value of SSL_OP_NO_TLSv1_1 to
     0x10000000L Any application which was previously compiled against
     OpenSSL 1.0.1 or 1.0.1a headers and which cares about SSL_OP_NO_TLSv1_1
     will need to be recompiled as a result. Letting be results in
     inability to disable specifically TLS 1.1 and in client context,
     in unlike event, limit maximum offered version to TLS 1.0 [see below].
     [Steve Henson]

  *) In order to ensure interoperabilty SSL_OP_NO_protocolX does not
     disable just protocol X, but all protocols above X *if* there are
     protocols *below* X still enabled. In more practical terms it means
     that if application wants to disable TLS1.0 in favor of TLS1.1 and
     above, it's not sufficient to pass SSL_OP_NO_TLSv1, one has to pass
     SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. This applies to
     client side.
     [Andy Polyakov]

 Changes between 1.0.1 and 1.0.1a [19 Apr 2012]

  *) Check for potentially exploitable overflows in asn1_d2i_read_bio
     BUF_mem_grow and BUF_mem_grow_clean. Refuse attempts to shrink buffer
     in CRYPTO_realloc_clean.

     Thanks to Tavis Ormandy, Google Security Team, for discovering this
     issue and to Adam Langley <agl@chromium.org> for fixing it.
     (CVE-2012-2110)
     [Adam Langley (Google), Tavis Ormandy, Google Security Team]

  *) Don't allow TLS 1.2 SHA-256 ciphersuites in TLS 1.0, 1.1 connections.
     [Adam Langley]

  *) Workarounds for some broken servers that "hang" if a client hello
     record length exceeds 255 bytes.

     1. Do not use record version number > TLS 1.0 in initial client
        hello: some (but not all) hanging servers will now work.
     2. If we set OPENSSL_MAX_TLS1_2_CIPHER_LENGTH this will truncate
	the number of ciphers sent in the client hello. This should be
        set to an even number, such as 50, for example by passing:
        -DOPENSSL_MAX_TLS1_2_CIPHER_LENGTH=50 to config or Configure.
        Most broken servers should now work.
     3. If all else fails setting OPENSSL_NO_TLS1_2_CLIENT will disable
	TLS 1.2 client support entirely.
     [Steve Henson]

  *) Fix SEGV in Vector Permutation AES module observed in OpenSSH.
     [Andy Polyakov]

 Changes between 1.0.0h and 1.0.1  [14 Mar 2012]

  *) Add compatibility with old MDC2 signatures which use an ASN1 OCTET
     STRING form instead of a DigestInfo.
     [Steve Henson]

  *) The format used for MDC2 RSA signatures is inconsistent between EVP
     and the RSA_sign/RSA_verify functions. This was made more apparent when
     OpenSSL used RSA_sign/RSA_verify for some RSA signatures in particular
     those which went through EVP_PKEY_METHOD in 1.0.0 and later. Detect 
     the correct format in RSA_verify so both forms transparently work.
     [Steve Henson]

  *) Some servers which support TLS 1.0 can choke if we initially indicate
     support for TLS 1.2 and later renegotiate using TLS 1.0 in the RSA
     encrypted premaster secret. As a workaround use the maximum pemitted
     client version in client hello, this should keep such servers happy
     and still work with previous versions of OpenSSL.
     [Steve Henson]

  *) Add support for TLS/DTLS heartbeats.
     [Robin Seggelmann <seggelmann@fh-muenster.de>]

  *) Add support for SCTP.
     [Robin Seggelmann <seggelmann@fh-muenster.de>]

  *) Improved PRNG seeding for VOS.
     [Paul Green <Paul.Green@stratus.com>]

  *) Extensive assembler packs updates, most notably:

	- x86[_64]:     AES-NI, PCLMULQDQ, RDRAND support;
	- x86[_64]:     SSSE3 support (SHA1, vector-permutation AES);
	- x86_64:       bit-sliced AES implementation;
	- ARM:          NEON support, contemporary platforms optimizations;
	- s390x:        z196 support;
	- *:            GHASH and GF(2^m) multiplication implementations;

     [Andy Polyakov]

  *) Make TLS-SRP code conformant with RFC 5054 API cleanup
     (removal of unnecessary code)
     [Peter Sylvester <peter.sylvester@edelweb.fr>]

  *) Add TLS key material exporter from RFC 5705.
     [Eric Rescorla]

  *) Add DTLS-SRTP negotiation from RFC 5764.
     [Eric Rescorla]

  *) Add Next Protocol Negotiation,
     http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-00. Can be
     disabled with a no-npn flag to config or Configure. Code donated
     by Google.
     [Adam Langley <agl@google.com> and Ben Laurie]

  *) Add optional 64-bit optimized implementations of elliptic curves NIST-P224,
     NIST-P256, NIST-P521, with constant-time single point multiplication on
     typical inputs. Compiler support for the nonstandard type __uint128_t is
     required to use this (present in gcc 4.4 and later, for 64-bit builds).
     Code made available under Apache License version 2.0.

     Specify "enable-ec_nistp_64_gcc_128" on the Configure (or config) command
     line to include this in your build of OpenSSL, and run "make depend" (or
     "make update"). This enables the following EC_METHODs:

         EC_GFp_nistp224_method()
         EC_GFp_nistp256_method()
         EC_GFp_nistp521_method()

     EC_GROUP_new_by_curve_name() will automatically use these (while
     EC_GROUP_new_curve_GFp() currently prefers the more flexible
     implementations).
     [Emilia Käsper, Adam Langley, Bodo Moeller (Google)]

  *) Use type ossl_ssize_t instad of ssize_t which isn't available on
     all platforms. Move ssize_t definition from e_os.h to the public
     header file e_os2.h as it now appears in public header file cms.h
     [Steve Henson]

  *) New -sigopt option to the ca, req and x509 utilities. Additional
     signature parameters can be passed using this option and in
     particular PSS. 
     [Steve Henson]

  *) Add RSA PSS signing function. This will generate and set the
     appropriate AlgorithmIdentifiers for PSS based on those in the
     corresponding EVP_MD_CTX structure. No application support yet.
     [Steve Henson]

  *) Support for companion algorithm specific ASN1 signing routines.
     New function ASN1_item_sign_ctx() signs a pre-initialised
     EVP_MD_CTX structure and sets AlgorithmIdentifiers based on
     the appropriate parameters.
     [Steve Henson]

  *) Add new algorithm specific ASN1 verification initialisation function
     to EVP_PKEY_ASN1_METHOD: this is not in EVP_PKEY_METHOD since the ASN1
     handling will be the same no matter what EVP_PKEY_METHOD is used.
     Add a PSS handler to support verification of PSS signatures: checked
     against a number of sample certificates.
     [Steve Henson]

  *) Add signature printing for PSS. Add PSS OIDs.
     [Steve Henson, Martin Kaiser <lists@kaiser.cx>]

  *) Add algorithm specific signature printing. An individual ASN1 method
     can now print out signatures instead of the standard hex dump. 

     More complex signatures (e.g. PSS) can print out more meaningful
     information. Include DSA version that prints out the signature
     parameters r, s.
     [Steve Henson]

  *) Password based recipient info support for CMS library: implementing
     RFC3211.
     [Steve Henson]

  *) Split password based encryption into PBES2 and PBKDF2 functions. This
     neatly separates the code into cipher and PBE sections and is required
     for some algorithms that split PBES2 into separate pieces (such as
     password based CMS).
     [Steve Henson]

  *) Session-handling fixes:
     - Fix handling of connections that are resuming with a session ID,
       but also support Session Tickets.
     - Fix a bug that suppressed issuing of a new ticket if the client
       presented a ticket with an expired session.
     - Try to set the ticket lifetime hint to something reasonable.
     - Make tickets shorter by excluding irrelevant information.
     - On the client side, don't ignore renewed tickets.
     [Adam Langley, Bodo Moeller (Google)]

  *) Fix PSK session representation.
     [Bodo Moeller]

  *) Add RC4-MD5 and AESNI-SHA1 "stitched" implementations.

     This work was sponsored by Intel.
     [Andy Polyakov]

  *) Add GCM support to TLS library. Some custom code is needed to split
     the IV between the fixed (from PRF) and explicit (from TLS record)
     portions. This adds all GCM ciphersuites supported by RFC5288 and 
     RFC5289. Generalise some AES* cipherstrings to inlclude GCM and
     add a special AESGCM string for GCM only.
     [Steve Henson]

  *) Expand range of ctrls for AES GCM. Permit setting invocation
     field on decrypt and retrieval of invocation field only on encrypt.
     [Steve Henson]

  *) Add HMAC ECC ciphersuites from RFC5289. Include SHA384 PRF support.
     As required by RFC5289 these ciphersuites cannot be used if for
     versions of TLS earlier than 1.2.
     [Steve Henson]

  *) For FIPS capable OpenSSL interpret a NULL default public key method
     as unset and return the appopriate default but do *not* set the default.
     This means we can return the appopriate method in applications that
     swicth between FIPS and non-FIPS modes.
     [Steve Henson]

  *) Redirect HMAC and CMAC operations to FIPS module in FIPS mode. If an
     ENGINE is used then we cannot handle that in the FIPS module so we
     keep original code iff non-FIPS operations are allowed.
     [Steve Henson]

  *) Add -attime option to openssl utilities.
     [Peter Eckersley <pde@eff.org>, Ben Laurie and Steve Henson]

  *) Redirect DSA and DH operations to FIPS module in FIPS mode.
     [Steve Henson]

  *) Redirect ECDSA and ECDH operations to FIPS module in FIPS mode. Also use
     FIPS EC methods unconditionally for now.
     [Steve Henson]

  *) New build option no-ec2m to disable characteristic 2 code.
     [Steve Henson]

  *) Backport libcrypto audit of return value checking from 1.1.0-dev; not
     all cases can be covered as some introduce binary incompatibilities.
     [Steve Henson]

  *) Redirect RSA operations to FIPS module including keygen,
     encrypt, decrypt, sign and verify. Block use of non FIPS RSA methods.
     [Steve Henson]

  *) Add similar low level API blocking to ciphers.
     [Steve Henson]

  *) Low level digest APIs are not approved in FIPS mode: any attempt
     to use these will cause a fatal error. Applications that *really* want
     to use them can use the private_* version instead.
     [Steve Henson]

  *) Redirect cipher operations to FIPS module for FIPS builds. 
     [Steve Henson]

  *) Redirect digest operations to FIPS module for FIPS builds. 
     [Steve Henson]

  *) Update build system to add "fips" flag which will link in fipscanister.o
     for static and shared library builds embedding a signature if needed.
     [Steve Henson]

  *) Output TLS supported curves in preference order instead of numerical
     order. This is currently hardcoded for the highest order curves first.
     This should be configurable so applications can judge speed vs strength.
     [Steve Henson]

  *) Add TLS v1.2 server support for client authentication. 
     [Steve Henson]

  *) Add support for FIPS mode in ssl library: disable SSLv3, non-FIPS ciphers
     and enable MD5.
     [Steve Henson]

  *) Functions FIPS_mode_set() and FIPS_mode() which call the underlying
     FIPS modules versions.
     [Steve Henson]

  *) Add TLS v1.2 client side support for client authentication. Keep cache
     of handshake records longer as we don't know the hash algorithm to use
     until after the certificate request message is received.
     [Steve Henson]

  *) Initial TLS v1.2 client support. Add a default signature algorithms
     extension including all the algorithms we support. Parse new signature
     format in client key exchange. Relax some ECC signing restrictions for
     TLS v1.2 as indicated in RFC5246.
     [Steve Henson]

  *) Add server support for TLS v1.2 signature algorithms extension. Switch
     to new signature format when needed using client digest preference.
     All server ciphersuites should now work correctly in TLS v1.2. No client
     support yet and no support for client certificates.
     [Steve Henson]

  *) Initial TLS v1.2 support. Add new SHA256 digest to ssl code, switch
     to SHA256 for PRF when using TLS v1.2 and later. Add new SHA256 based
     ciphersuites. At present only RSA key exchange ciphersuites work with
     TLS v1.2. Add new option for TLS v1.2 replacing the old and obsolete
     SSL_OP_PKCS1_CHECK flags with SSL_OP_NO_TLSv1_2. New TLSv1.2 methods
     and version checking.
     [Steve Henson]

  *) New option OPENSSL_NO_SSL_INTERN. If an application can be compiled
     with this defined it will not be affected by any changes to ssl internal
     structures. Add several utility functions to allow openssl application
     to work with OPENSSL_NO_SSL_INTERN defined.
     [Steve Henson]

  *) A long standing patch to add support for SRP from EdelWeb (Peter
     Sylvester and Christophe Renou) was integrated.
     [Christophe Renou <christophe.renou@edelweb.fr>, Peter Sylvester
     <peter.sylvester@edelweb.fr>, Tom Wu <tjw@cs.stanford.edu>, and
     Ben Laurie]

  *) Add functions to copy EVP_PKEY_METHOD and retrieve flags and id.
     [Steve Henson]

  *) Permit abbreviated handshakes when renegotiating using the function
     SSL_renegotiate_abbreviated().
     [Robin Seggelmann <seggelmann@fh-muenster.de>]

  *) Add call to ENGINE_register_all_complete() to
     ENGINE_load_builtin_engines(), so some implementations get used
     automatically instead of needing explicit application support.
     [Steve Henson]

  *) Add support for TLS key exporter as described in RFC5705.
     [Robin Seggelmann <seggelmann@fh-muenster.de>, Steve Henson]

  *) Initial TLSv1.1 support. Since TLSv1.1 is very similar to TLS v1.0 only
     a few changes are required:

       Add SSL_OP_NO_TLSv1_1 flag.
       Add TLSv1_1 methods.
       Update version checking logic to handle version 1.1.
       Add explicit IV handling (ported from DTLS code).
       Add command line options to s_client/s_server.
     [Steve Henson]

 Changes between 1.0.0g and 1.0.0h [12 Mar 2012]

  *) Fix MMA (Bleichenbacher's attack on PKCS #1 v1.5 RSA padding) weakness
     in CMS and PKCS7 code. When RSA decryption fails use a random key for
     content decryption and always return the same error. Note: this attack
     needs on average 2^20 messages so it only affects automated senders. The
     old behaviour can be reenabled in the CMS code by setting the
     CMS_DEBUG_DECRYPT flag: this is useful for debugging and testing where
     an MMA defence is not necessary.
     Thanks to Ivan Nestlerode <inestlerode@us.ibm.com> for discovering
     this issue. (CVE-2012-0884)
     [Steve Henson]

  *) Fix CVE-2011-4619: make sure we really are receiving a 
     client hello before rejecting multiple SGC restarts. Thanks to
     Ivan Nestlerode <inestlerode@us.ibm.com> for discovering this bug.
     [Steve Henson]

 Changes between 1.0.0f and 1.0.0g [18 Jan 2012]

  *) Fix for DTLS DoS issue introduced by fix for CVE-2011-4109.
     Thanks to Antonio Martin, Enterprise Secure Access Research and
     Development, Cisco Systems, Inc. for discovering this bug and
     preparing a fix. (CVE-2012-0050)
     [Antonio Martin]

 Changes between 1.0.0e and 1.0.0f [4 Jan 2012]

  *) Nadhem Alfardan and Kenny Paterson have discovered an extension
     of the Vaudenay padding oracle attack on CBC mode encryption
     which enables an efficient plaintext recovery attack against
     the OpenSSL implementation of DTLS. Their attack exploits timing
     differences arising during decryption processing. A research
     paper describing this attack can be found at:
                  http://www.isg.rhul.ac.uk/~kp/dtls.pdf
     Thanks go to Nadhem Alfardan and Kenny Paterson of the Information
     Security Group at Royal Holloway, University of London
     (www.isg.rhul.ac.uk) for discovering this flaw and to Robin Seggelmann
     <seggelmann@fh-muenster.de> and Michael Tuexen <tuexen@fh-muenster.de>
     for preparing the fix. (CVE-2011-4108)
     [Robin Seggelmann, Michael Tuexen]

  *) Clear bytes used for block padding of SSL 3.0 records.
     (CVE-2011-4576)
     [Adam Langley (Google)]

  *) Only allow one SGC handshake restart for SSL/TLS. Thanks to George
     Kadianakis <desnacked@gmail.com> for discovering this issue and
     Adam Langley for preparing the fix. (CVE-2011-4619)
     [Adam Langley (Google)]

  *) Check parameters are not NULL in GOST ENGINE. (CVE-2012-0027)
     [Andrey Kulikov <amdeich@gmail.com>]

  *) Prevent malformed RFC3779 data triggering an assertion failure.
     Thanks to Andrew Chi, BBN Technologies, for discovering the flaw
     and Rob Austein <sra@hactrn.net> for fixing it. (CVE-2011-4577)
     [Rob Austein <sra@hactrn.net>]

  *) Improved PRNG seeding for VOS.
     [Paul Green <Paul.Green@stratus.com>]

  *) Fix ssl_ciph.c set-up race.
     [Adam Langley (Google)]

  *) Fix spurious failures in ecdsatest.c.
     [Emilia Käsper (Google)]

  *) Fix the BIO_f_buffer() implementation (which was mixing different
     interpretations of the '..._len' fields).
     [Adam Langley (Google)]

  *) Fix handling of BN_BLINDING: now BN_BLINDING_invert_ex (rather than
     BN_BLINDING_invert_ex) calls BN_BLINDING_update, ensuring that concurrent
     threads won't reuse the same blinding coefficients.

     This also avoids the need to obtain the CRYPTO_LOCK_RSA_BLINDING
     lock to call BN_BLINDING_invert_ex, and avoids one use of
     BN_BLINDING_update for each BN_BLINDING structure (previously,
     the last update always remained unused).
     [Emilia Käsper (Google)]

  *) In ssl3_clear, preserve s3->init_extra along with s3->rbuf.
     [Bob Buckholz (Google)]

 Changes between 1.0.0d and 1.0.0e [6 Sep 2011]

  *) Fix bug where CRLs with nextUpdate in the past are sometimes accepted
     by initialising X509_STORE_CTX properly. (CVE-2011-3207)
     [Kaspar Brand <ossl@velox.ch>]

  *) Fix SSL memory handling for (EC)DH ciphersuites, in particular
     for multi-threaded use of ECDH. (CVE-2011-3210)
     [Adam Langley (Google)]

  *) Fix x509_name_ex_d2i memory leak on bad inputs.
     [Bodo Moeller]

  *) Remove hard coded ecdsaWithSHA1 signature tests in ssl code and check
     signature public key algorithm by using OID xref utilities instead.
     Before this you could only use some ECC ciphersuites with SHA1 only.
     [Steve Henson]

  *) Add protection against ECDSA timing attacks as mentioned in the paper
     by Billy Bob Brumley and Nicola Tuveri, see:

	http://eprint.iacr.org/2011/232.pdf

     [Billy Bob Brumley and Nicola Tuveri]

 Changes between 1.0.0c and 1.0.0d [8 Feb 2011]

  *) Fix parsing of OCSP stapling ClientHello extension. CVE-2011-0014
     [Neel Mehta, Adam Langley, Bodo Moeller (Google)]

  *) Fix bug in string printing code: if *any* escaping is enabled we must
     escape the escape character (backslash) or the resulting string is
     ambiguous.
     [Steve Henson]

 Changes between 1.0.0b and 1.0.0c  [2 Dec 2010]

  *) Disable code workaround for ancient and obsolete Netscape browsers
     and servers: an attacker can use it in a ciphersuite downgrade attack.
     Thanks to Martin Rex for discovering this bug. CVE-2010-4180
     [Steve Henson]

  *) Fixed J-PAKE implementation error, originally discovered by
     Sebastien Martini, further info and confirmation from Stefan
     Arentz and Feng Hao. Note that this fix is a security fix. CVE-2010-4252
     [Ben Laurie]

 Changes between 1.0.0a and 1.0.0b  [16 Nov 2010]

  *) Fix extension code to avoid race conditions which can result in a buffer
     overrun vulnerability: resumed sessions must not be modified as they can
     be shared by multiple threads. CVE-2010-3864
     [Steve Henson]

  *) Fix WIN32 build system to correctly link an ENGINE directory into
     a DLL. 
     [Steve Henson]

 Changes between 1.0.0 and 1.0.0a  [01 Jun 2010]

  *) Check return value of int_rsa_verify in pkey_rsa_verifyrecover 
     (CVE-2010-1633)
     [Steve Henson, Peter-Michael Hager <hager@dortmund.net>]

 Changes between 0.9.8n and 1.0.0  [29 Mar 2010]

  *) Add "missing" function EVP_CIPHER_CTX_copy(). This copies a cipher
     context. The operation can be customised via the ctrl mechanism in
     case ENGINEs want to include additional functionality.
     [Steve Henson]

  *) Tolerate yet another broken PKCS#8 key format: private key value negative.
     [Steve Henson]

  *) Add new -subject_hash_old and -issuer_hash_old options to x509 utility to
     output hashes compatible with older versions of OpenSSL.
     [Willy Weisz <weisz@vcpc.univie.ac.at>]

  *) Fix compression algorithm handling: if resuming a session use the
     compression algorithm of the resumed session instead of determining
     it from client hello again. Don't allow server to change algorithm.
     [Steve Henson]

  *) Add load_crls() function to apps tidying load_certs() too. Add option
     to verify utility to allow additional CRLs to be included.
     [Steve Henson]

  *) Update OCSP request code to permit adding custom headers to the request:
     some responders need this.
     [Steve Henson]

  *) The function EVP_PKEY_sign() returns <=0 on error: check return code
     correctly.
     [Julia Lawall <julia@diku.dk>]

  *) Update verify callback code in apps/s_cb.c and apps/verify.c, it
     needlessly dereferenced structures, used obsolete functions and
     didn't handle all updated verify codes correctly.
     [Steve Henson]

  *) Disable MD2 in the default configuration.
     [Steve Henson]

  *) In BIO_pop() and BIO_push() use the ctrl argument (which was NULL) to
     indicate the initial BIO being pushed or popped. This makes it possible
     to determine whether the BIO is the one explicitly called or as a result
     of the ctrl being passed down the chain. Fix BIO_pop() and SSL BIOs so
     it handles reference counts correctly and doesn't zero out the I/O bio
     when it is not being explicitly popped. WARNING: applications which
     included workarounds for the old buggy behaviour will need to be modified
     or they could free up already freed BIOs.
     [Steve Henson]

  *) Extend the uni2asc/asc2uni => OPENSSL_uni2asc/OPENSSL_asc2uni
     renaming to all platforms (within the 0.9.8 branch, this was
     done conditionally on Netware platforms to avoid a name clash).
     [Guenter <lists@gknw.net>]

  *) Add ECDHE and PSK support to DTLS.
     [Michael Tuexen <tuexen@fh-muenster.de>]

  *) Add CHECKED_STACK_OF macro to safestack.h, otherwise safestack can't
     be used on C++.
     [Steve Henson]

  *) Add "missing" function EVP_MD_flags() (without this the only way to
     retrieve a digest flags is by accessing the structure directly. Update
     EVP_MD_do_all*() and EVP_CIPHER_do_all*() to include the name a digest
     or cipher is registered as in the "from" argument. Print out all
     registered digests in the dgst usage message instead of manually 
     attempting to work them out.
     [Steve Henson]

  *) If no SSLv2 ciphers are used don't use an SSLv2 compatible client hello:
     this allows the use of compression and extensions. Change default cipher
     string to remove SSLv2 ciphersuites. This effectively avoids ancient SSLv2
     by default unless an application cipher string requests it.
     [Steve Henson]

  *) Alter match criteria in PKCS12_parse(). It used to try to use local
     key ids to find matching certificates and keys but some PKCS#12 files
     don't follow the (somewhat unwritten) rules and this strategy fails.
     Now just gather all certificates together and the first private key
     then look for the first certificate that matches the key.
     [Steve Henson]

  *) Support use of registered digest and cipher names for dgst and cipher
     commands instead of having to add each one as a special case. So now
     you can do:

        openssl sha256 foo

     as well as:

        openssl dgst -sha256 foo

     and this works for ENGINE based algorithms too.

     [Steve Henson]

  *) Update Gost ENGINE to support parameter files.
     [Victor B. Wagner <vitus@cryptocom.ru>]

  *) Support GeneralizedTime in ca utility. 
     [Oliver Martin <oliver@volatilevoid.net>, Steve Henson]

  *) Enhance the hash format used for certificate directory links. The new
     form uses the canonical encoding (meaning equivalent names will work
     even if they aren't identical) and uses SHA1 instead of MD5. This form
     is incompatible with the older format and as a result c_rehash should
     be used to rebuild symbolic links.
     [Steve Henson]

  *) Make PKCS#8 the default write format for private keys, replacing the
     traditional format. This form is standardised, more secure and doesn't
     include an implicit MD5 dependency.
     [Steve Henson]

  *) Add a $gcc_devteam_warn option to Configure. The idea is that any code
     committed to OpenSSL should pass this lot as a minimum.
     [Steve Henson]

  *) Add session ticket override functionality for use by EAP-FAST.
     [Jouni Malinen <j@w1.fi>]

  *) Modify HMAC functions to return a value. Since these can be implemented
     in an ENGINE errors can occur.
     [Steve Henson]

  *) Type-checked OBJ_bsearch_ex.
     [Ben Laurie]

  *) Type-checked OBJ_bsearch. Also some constification necessitated
     by type-checking.  Still to come: TXT_DB, bsearch(?),
     OBJ_bsearch_ex, qsort, CRYPTO_EX_DATA, ASN1_VALUE, ASN1_STRING,
     CONF_VALUE.
     [Ben Laurie]

  *) New function OPENSSL_gmtime_adj() to add a specific number of days and
     seconds to a tm structure directly, instead of going through OS
     specific date routines. This avoids any issues with OS routines such
     as the year 2038 bug. New *_adj() functions for ASN1 time structures
     and X509_time_adj_ex() to cover the extended range. The existing
     X509_time_adj() is still usable and will no longer have any date issues.
     [Steve Henson]

  *) Delta CRL support. New use deltas option which will attempt to locate
     and search any appropriate delta CRLs available.

     This work was sponsored by Google.
     [Steve Henson]

  *) Support for CRLs partitioned by reason code. Reorganise CRL processing
     code and add additional score elements. Validate alternate CRL paths
     as part of the CRL checking and indicate a new error "CRL path validation
     error" in this case. Applications wanting additional details can use
     the verify callback and check the new "parent" field. If this is not
     NULL CRL path validation is taking place. Existing applications wont
     see this because it requires extended CRL support which is off by
     default.

     This work was sponsored by Google.
     [Steve Henson]

  *) Support for freshest CRL extension.

     This work was sponsored by Google.
     [Steve Henson]

  *) Initial indirect CRL support. Currently only supported in the CRLs
     passed directly and not via lookup. Process certificate issuer
     CRL entry extension and lookup CRL entries by bother issuer name
     and serial number. Check and process CRL issuer entry in IDP extension.

     This work was sponsored by Google.
     [Steve Henson]

  *) Add support for distinct certificate and CRL paths. The CRL issuer
     certificate is validated separately in this case. Only enabled if
     an extended CRL support flag is set: this flag will enable additional
     CRL functionality in future.

     This work was sponsored by Google.
     [Steve Henson]

  *) Add support for policy mappings extension.

     This work was sponsored by Google.
     [Steve Henson]

  *) Fixes to pathlength constraint, self issued certificate handling,
     policy processing to align with RFC3280 and PKITS tests.

     This work was sponsored by Google.
     [Steve Henson]

  *) Support for name constraints certificate extension. DN, email, DNS
     and URI types are currently supported.

     This work was sponsored by Google.
     [Steve Henson]

  *) To cater for systems that provide a pointer-based thread ID rather
     than numeric, deprecate the current numeric thread ID mechanism and
     replace it with a structure and associated callback type. This
     mechanism allows a numeric "hash" to be extracted from a thread ID in
     either case, and on platforms where pointers are larger than 'long',
     mixing is done to help ensure the numeric 'hash' is usable even if it
     can't be guaranteed unique. The default mechanism is to use "&errno"
     as a pointer-based thread ID to distinguish between threads.

     Applications that want to provide their own thread IDs should now use
     CRYPTO_THREADID_set_callback() to register a callback that will call
     either CRYPTO_THREADID_set_numeric() or CRYPTO_THREADID_set_pointer().

     Note that ERR_remove_state() is now deprecated, because it is tied
     to the assumption that thread IDs are numeric.  ERR_remove_state(0)
     to free the current thread's error state should be replaced by
     ERR_remove_thread_state(NULL).

     (This new approach replaces the functions CRYPTO_set_idptr_callback(),
     CRYPTO_get_idptr_callback(), and CRYPTO_thread_idptr() that existed in
     OpenSSL 0.9.9-dev between June 2006 and August 2008. Also, if an
     application was previously providing a numeric thread callback that
     was inappropriate for distinguishing threads, then uniqueness might
     have been obtained with &errno that happened immediately in the
     intermediate development versions of OpenSSL; this is no longer the
     case, the numeric thread callback will now override the automatic use
     of &errno.)
     [Geoff Thorpe, with help from Bodo Moeller]

  *) Initial support for different CRL issuing certificates. This covers a
     simple case where the self issued certificates in the chain exist and
     the real CRL issuer is higher in the existing chain.

     This work was sponsored by Google.
     [Steve Henson]

  *) Removed effectively defunct crypto/store from the build.
     [Ben Laurie]

  *) Revamp of STACK to provide stronger type-checking. Still to come:
     TXT_DB, bsearch(?), OBJ_bsearch, qsort, CRYPTO_EX_DATA, ASN1_VALUE,
     ASN1_STRING, CONF_VALUE.
     [Ben Laurie]

  *) Add a new SSL_MODE_RELEASE_BUFFERS mode flag to release unused buffer
     RAM on SSL connections.  This option can save about 34k per idle SSL.
     [Nick Mathewson]

  *) Revamp of LHASH to provide stronger type-checking. Still to come:
     STACK, TXT_DB, bsearch, qsort.
     [Ben Laurie]

  *) Initial support for Cryptographic Message Syntax (aka CMS) based
     on RFC3850, RFC3851 and RFC3852. New cms directory and cms utility,
     support for data, signedData, compressedData, digestedData and
     encryptedData, envelopedData types included. Scripts to check against
     RFC4134 examples draft and interop and consistency checks of many
     content types and variants.
     [Steve Henson]

  *) Add options to enc utility to support use of zlib compression BIO.
     [Steve Henson]

  *) Extend mk1mf to support importing of options and assembly language
     files from Configure script, currently only included in VC-WIN32.
     The assembly language rules can now optionally generate the source
     files from the associated perl scripts.
     [Steve Henson]

  *) Implement remaining functionality needed to support GOST ciphersuites.
     Interop testing has been performed using CryptoPro implementations.
     [Victor B. Wagner <vitus@cryptocom.ru>]

  *) s390x assembler pack.
     [Andy Polyakov]

  *) ARMv4 assembler pack. ARMv4 refers to v4 and later ISA, not CPU
     "family."
     [Andy Polyakov]

  *) Implement Opaque PRF Input TLS extension as specified in
     draft-rescorla-tls-opaque-prf-input-00.txt.  Since this is not an
     official specification yet and no extension type assignment by
     IANA exists, this extension (for now) will have to be explicitly
     enabled when building OpenSSL by providing the extension number
     to use.  For example, specify an option

         -DTLSEXT_TYPE_opaque_prf_input=0x9527

     to the "config" or "Configure" script to enable the extension,
     assuming extension number 0x9527 (which is a completely arbitrary
     and unofficial assignment based on the MD5 hash of the Internet
     Draft).  Note that by doing so, you potentially lose
     interoperability with other TLS implementations since these might
     be using the same extension number for other purposes.

     SSL_set_tlsext_opaque_prf_input(ssl, src, len) is used to set the
     opaque PRF input value to use in the handshake.  This will create
     an interal copy of the length-'len' string at 'src', and will
     return non-zero for success.

     To get more control and flexibility, provide a callback function
     by using

          SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb)
          SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg)

     where

          int (*cb)(SSL *, void *peerinput, size_t len, void *arg);
          void *arg;

     Callback function 'cb' will be called in handshakes, and is
     expected to use SSL_set_tlsext_opaque_prf_input() as appropriate.
     Argument 'arg' is for application purposes (the value as given to
     SSL_CTX_set_tlsext_opaque_prf_input_callback_arg() will directly
     be provided to the callback function).  The callback function
     has to return non-zero to report success: usually 1 to use opaque
     PRF input just if possible, or 2 to enforce use of the opaque PRF
     input.  In the latter case, the library will abort the handshake
     if opaque PRF input is not successfully negotiated.

     Arguments 'peerinput' and 'len' given to the callback function
     will always be NULL and 0 in the case of a client.  A server will
     see the client's opaque PRF input through these variables if
     available (NULL and 0 otherwise).  Note that if the server
     provides an opaque PRF input, the length must be the same as the
     length of the client's opaque PRF input.

     Note that the callback function will only be called when creating
     a new session (session resumption can resume whatever was
     previously negotiated), and will not be called in SSL 2.0
     handshakes; thus, SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) or
     SSL_set_options(ssl, SSL_OP_NO_SSLv2) is especially recommended
     for applications that need to enforce opaque PRF input.

     [Bodo Moeller]

  *) Update ssl code to support digests other than SHA1+MD5 for handshake
     MAC. 

     [Victor B. Wagner <vitus@cryptocom.ru>]

  *) Add RFC4507 support to OpenSSL. This includes the corrections in
     RFC4507bis. The encrypted ticket format is an encrypted encoded
     SSL_SESSION structure, that way new session features are automatically
     supported.

     If a client application caches session in an SSL_SESSION structure
     support is transparent because tickets are now stored in the encoded
     SSL_SESSION.
     
     The SSL_CTX structure automatically generates keys for ticket
     protection in servers so again support should be possible
     with no application modification.

     If a client or server wishes to disable RFC4507 support then the option
     SSL_OP_NO_TICKET can be set.

     Add a TLS extension debugging callback to allow the contents of any client
     or server extensions to be examined.

     This work was sponsored by Google.
     [Steve Henson]

  *) Final changes to avoid use of pointer pointer casts in OpenSSL.
     OpenSSL should now compile cleanly on gcc 4.2
     [Peter Hartley <pdh@utter.chaos.org.uk>, Steve Henson]

  *) Update SSL library to use new EVP_PKEY MAC API. Include generic MAC
     support including streaming MAC support: this is required for GOST
     ciphersuite support.
     [Victor B. Wagner <vitus@cryptocom.ru>, Steve Henson]

  *) Add option -stream to use PKCS#7 streaming in smime utility. New
     function i2d_PKCS7_bio_stream() and PEM_write_PKCS7_bio_stream()
     to output in BER and PEM format.
     [Steve Henson]

  *) Experimental support for use of HMAC via EVP_PKEY interface. This
     allows HMAC to be handled via the EVP_DigestSign*() interface. The
     EVP_PKEY "key" in this case is the HMAC key, potentially allowing
     ENGINE support for HMAC keys which are unextractable. New -mac and
     -macopt options to dgst utility.
     [Steve Henson]

  *) New option -sigopt to dgst utility. Update dgst to use
     EVP_Digest{Sign,Verify}*. These two changes make it possible to use
     alternative signing paramaters such as X9.31 or PSS in the dgst 
     utility.
     [Steve Henson]

  *) Change ssl_cipher_apply_rule(), the internal function that does
     the work each time a ciphersuite string requests enabling
     ("foo+bar"), moving ("+foo+bar"), disabling ("-foo+bar", or
     removing ("!foo+bar") a class of ciphersuites: Now it maintains
     the order of disabled ciphersuites such that those ciphersuites
     that most recently went from enabled to disabled not only stay
     in order with respect to each other, but also have higher priority
     than other disabled ciphersuites the next time ciphersuites are
     enabled again.

     This means that you can now say, e.g., "PSK:-PSK:HIGH" to enable
     the same ciphersuites as with "HIGH" alone, but in a specific
     order where the PSK ciphersuites come first (since they are the
     most recently disabled ciphersuites when "HIGH" is parsed).

     Also, change ssl_create_cipher_list() (using this new
     funcionality) such that between otherwise identical
     cihpersuites, ephemeral ECDH is preferred over ephemeral DH in
     the default order.
     [Bodo Moeller]

  *) Change ssl_create_cipher_list() so that it automatically
     arranges the ciphersuites in reasonable order before starting
     to process the rule string.  Thus, the definition for "DEFAULT"
     (SSL_DEFAULT_CIPHER_LIST) now is just "ALL:!aNULL:!eNULL", but
     remains equivalent to "AES:ALL:!aNULL:!eNULL:+aECDH:+kRSA:+RC4:@STRENGTH".
     This makes it much easier to arrive at a reasonable default order
     in applications for which anonymous ciphers are OK (meaning
     that you can't actually use DEFAULT).
     [Bodo Moeller; suggested by Victor Duchovni]

  *) Split the SSL/TLS algorithm mask (as used for ciphersuite string
     processing) into multiple integers instead of setting
     "SSL_MKEY_MASK" bits, "SSL_AUTH_MASK" bits, "SSL_ENC_MASK",
     "SSL_MAC_MASK", and "SSL_SSL_MASK" bits all in a single integer.
     (These masks as well as the individual bit definitions are hidden
     away into the non-exported interface ssl/ssl_locl.h, so this
     change to the definition of the SSL_CIPHER structure shouldn't
     affect applications.)  This give us more bits for each of these
     categories, so there is no longer a need to coagulate AES128 and
     AES256 into a single algorithm bit, and to coagulate Camellia128
     and Camellia256 into a single algorithm bit, which has led to all
     kinds of kludges.

     Thus, among other things, the kludge introduced in 0.9.7m and
     0.9.8e for masking out AES256 independently of AES128 or masking
     out Camellia256 independently of AES256 is not needed here in 0.9.9.

     With the change, we also introduce new ciphersuite aliases that
     so far were missing: "AES128", "AES256", "CAMELLIA128", and
     "CAMELLIA256".
     [Bodo Moeller]

  *) Add support for dsa-with-SHA224 and dsa-with-SHA256.
     Use the leftmost N bytes of the signature input if the input is
     larger than the prime q (with N being the size in bytes of q).
     [Nils Larsch]

  *) Very *very* experimental PKCS#7 streaming encoder support. Nothing uses
     it yet and it is largely untested.
     [Steve Henson]

  *) Add support for the ecdsa-with-SHA224/256/384/512 signature types.
     [Nils Larsch]

  *) Initial incomplete changes to avoid need for function casts in OpenSSL
     some compilers (gcc 4.2 and later) reject their use. Safestack is
     reimplemented.  Update ASN1 to avoid use of legacy functions. 
     [Steve Henson]

  *) Win32/64 targets are linked with Winsock2.
     [Andy Polyakov]

  *) Add an X509_CRL_METHOD structure to allow CRL processing to be redirected
     to external functions. This can be used to increase CRL handling 
     efficiency especially when CRLs are very large by (for example) storing
     the CRL revoked certificates in a database.
     [Steve Henson]

  *) Overhaul of by_dir code. Add support for dynamic loading of CRLs so
     new CRLs added to a directory can be used. New command line option
     -verify_return_error to s_client and s_server. This causes real errors
     to be returned by the verify callback instead of carrying on no matter
     what. This reflects the way a "real world" verify callback would behave.
     [Steve Henson]

  *) GOST engine, supporting several GOST algorithms and public key formats.
     Kindly donated by Cryptocom.
     [Cryptocom]

  *) Partial support for Issuing Distribution Point CRL extension. CRLs
     partitioned by DP are handled but no indirect CRL or reason partitioning
     (yet). Complete overhaul of CRL handling: now the most suitable CRL is
     selected via a scoring technique which handles IDP and AKID in CRLs.
     [Steve Henson]

  *) New X509_STORE_CTX callbacks lookup_crls() and lookup_certs() which
     will ultimately be used for all verify operations: this will remove the
     X509_STORE dependency on certificate verification and allow alternative
     lookup methods.  X509_STORE based implementations of these two callbacks.
     [Steve Henson]

  *) Allow multiple CRLs to exist in an X509_STORE with matching issuer names.
     Modify get_crl() to find a valid (unexpired) CRL if possible.
     [Steve Henson]

  *) New function X509_CRL_match() to check if two CRLs are identical. Normally
     this would be called X509_CRL_cmp() but that name is already used by
     a function that just compares CRL issuer names. Cache several CRL 
     extensions in X509_CRL structure and cache CRLDP in X509.
     [Steve Henson]

  *) Store a "canonical" representation of X509_NAME structure (ASN1 Name)
     this maps equivalent X509_NAME structures into a consistent structure.
     Name comparison can then be performed rapidly using memcmp().
     [Steve Henson]

  *) Non-blocking OCSP request processing. Add -timeout option to ocsp 
     utility.
     [Steve Henson]

  *) Allow digests to supply their own micalg string for S/MIME type using
     the ctrl EVP_MD_CTRL_MICALG.
     [Steve Henson]

  *) During PKCS7 signing pass the PKCS7 SignerInfo structure to the
     EVP_PKEY_METHOD before and after signing via the EVP_PKEY_CTRL_PKCS7_SIGN
     ctrl. It can then customise the structure before and/or after signing
     if necessary.
     [Steve Henson]

  *) New function OBJ_add_sigid() to allow application defined signature OIDs
     to be added to OpenSSLs internal tables. New function OBJ_sigid_free()
     to free up any added signature OIDs.
     [Steve Henson]

  *) New functions EVP_CIPHER_do_all(), EVP_CIPHER_do_all_sorted(),
     EVP_MD_do_all() and EVP_MD_do_all_sorted() to enumerate internal
     digest and cipher tables. New options added to openssl utility:
     list-message-digest-algorithms and list-cipher-algorithms.
     [Steve Henson]

  *) Change the array representation of binary polynomials: the list
     of degrees of non-zero coefficients is now terminated with -1.
     Previously it was terminated with 0, which was also part of the
     value; thus, the array representation was not applicable to
     polynomials where t^0 has coefficient zero.  This change makes
     the array representation useful in a more general context.
     [Douglas Stebila]

  *) Various modifications and fixes to SSL/TLS cipher string
     handling.  For ECC, the code now distinguishes between fixed ECDH
     with RSA certificates on the one hand and with ECDSA certificates
     on the other hand, since these are separate ciphersuites.  The
     unused code for Fortezza ciphersuites has been removed.

     For consistency with EDH, ephemeral ECDH is now called "EECDH"
     (not "ECDHE").  For consistency with the code for DH
     certificates, use of ECDH certificates is now considered ECDH
     authentication, not RSA or ECDSA authentication (the latter is
     merely the CA's signing algorithm and not actively used in the
     protocol).

     The temporary ciphersuite alias "ECCdraft" is no longer
     available, and ECC ciphersuites are no longer excluded from "ALL"
     and "DEFAULT".  The following aliases now exist for RFC 4492
     ciphersuites, most of these by analogy with the DH case:

         kECDHr   - ECDH cert, signed with RSA
         kECDHe   - ECDH cert, signed with ECDSA
         kECDH    - ECDH cert (signed with either RSA or ECDSA)
         kEECDH   - ephemeral ECDH
         ECDH     - ECDH cert or ephemeral ECDH

         aECDH    - ECDH cert
         aECDSA   - ECDSA cert
         ECDSA    - ECDSA cert

         AECDH    - anonymous ECDH
         EECDH    - non-anonymous ephemeral ECDH (equivalent to "kEECDH:-AECDH")

     [Bodo Moeller]

  *) Add additional S/MIME capabilities for AES and GOST ciphers if supported.
     Use correct micalg parameters depending on digest(s) in signed message.
     [Steve Henson]

  *) Add engine support for EVP_PKEY_ASN1_METHOD. Add functions to process
     an ENGINE asn1 method. Support ENGINE lookups in the ASN1 code.
     [Steve Henson]

  *) Initial engine support for EVP_PKEY_METHOD. New functions to permit
     an engine to register a method. Add ENGINE lookups for methods and
     functional reference processing.
     [Steve Henson]

  *) New functions EVP_Digest{Sign,Verify)*. These are enchance versions of
     EVP_{Sign,Verify}* which allow an application to customise the signature
     process.
     [Steve Henson]

  *) New -resign option to smime utility. This adds one or more signers
     to an existing PKCS#7 signedData structure. Also -md option to use an
     alternative message digest algorithm for signing.
     [Steve Henson]

  *) Tidy up PKCS#7 routines and add new functions to make it easier to
     create PKCS7 structures containing multiple signers. Update smime
     application to support multiple signers.
     [Steve Henson]

  *) New -macalg option to pkcs12 utility to allow setting of an alternative
     digest MAC.
     [Steve Henson]

  *) Initial support for PKCS#5 v2.0 PRFs other than default SHA1 HMAC.
     Reorganize PBE internals to lookup from a static table using NIDs,
     add support for HMAC PBE OID translation. Add a EVP_CIPHER ctrl:
     EVP_CTRL_PBE_PRF_NID this allows a cipher to specify an alternative
     PRF which will be automatically used with PBES2.
     [Steve Henson]

  *) Replace the algorithm specific calls to generate keys in "req" with the
     new API.
     [Steve Henson]

  *) Update PKCS#7 enveloped data routines to use new API. This is now
     supported by any public key method supporting the encrypt operation. A
     ctrl is added to allow the public key algorithm to examine or modify
     the PKCS#7 RecipientInfo structure if it needs to: for RSA this is
     a no op.
     [Steve Henson]

  *) Add a ctrl to asn1 method to allow a public key algorithm to express
     a default digest type to use. In most cases this will be SHA1 but some
     algorithms (such as GOST) need to specify an alternative digest. The
     return value indicates how strong the prefernce is 1 means optional and
     2 is mandatory (that is it is the only supported type). Modify
     ASN1_item_sign() to accept a NULL digest argument to indicate it should
     use the default md. Update openssl utilities to use the default digest
     type for signing if it is not explicitly indicated.
     [Steve Henson]

  *) Use OID cross reference table in ASN1_sign() and ASN1_verify(). New 
     EVP_MD flag EVP_MD_FLAG_PKEY_METHOD_SIGNATURE. This uses the relevant
     signing method from the key type. This effectively removes the link
     between digests and public key types.
     [Steve Henson]

  *) Add an OID cross reference table and utility functions. Its purpose is to
     translate between signature OIDs such as SHA1WithrsaEncryption and SHA1,
     rsaEncryption. This will allow some of the algorithm specific hackery
     needed to use the correct OID to be removed. 
     [Steve Henson]

  *) Remove algorithm specific dependencies when setting PKCS7_SIGNER_INFO
     structures for PKCS7_sign(). They are now set up by the relevant public
     key ASN1 method.
     [Steve Henson]

  *) Add provisional EC pkey method with support for ECDSA and ECDH.
     [Steve Henson]

  *) Add support for key derivation (agreement) in the API, DH method and
     pkeyutl.
     [Steve Henson]

  *) Add DSA pkey method and DH pkey methods, extend DH ASN1 method to support
     public and private key formats. As a side effect these add additional 
     command line functionality not previously available: DSA signatures can be
     generated and verified using pkeyutl and DH key support and generation in
     pkey, genpkey.
     [Steve Henson]

  *) BeOS support.
     [Oliver Tappe <zooey@hirschkaefer.de>]

  *) New make target "install_html_docs" installs HTML renditions of the
     manual pages.
     [Oliver Tappe <zooey@hirschkaefer.de>]

  *) New utility "genpkey" this is analagous to "genrsa" etc except it can
     generate keys for any algorithm. Extend and update EVP_PKEY_METHOD to
     support key and parameter generation and add initial key generation
     functionality for RSA.
     [Steve Henson]

  *) Add functions for main EVP_PKEY_method operations. The undocumented
     functions EVP_PKEY_{encrypt,decrypt} have been renamed to
     EVP_PKEY_{encrypt,decrypt}_old. 
     [Steve Henson]

  *) Initial definitions for EVP_PKEY_METHOD. This will be a high level public
     key API, doesn't do much yet.
     [Steve Henson]

  *) New function EVP_PKEY_asn1_get0_info() to retrieve information about
     public key algorithms. New option to openssl utility:
     "list-public-key-algorithms" to print out info.
     [Steve Henson]

  *) Implement the Supported Elliptic Curves Extension for
     ECC ciphersuites from draft-ietf-tls-ecc-12.txt.
     [Douglas Stebila]

  *) Don't free up OIDs in OBJ_cleanup() if they are in use by EVP_MD or
     EVP_CIPHER structures to avoid later problems in EVP_cleanup().
     [Steve Henson]

  *) New utilities pkey and pkeyparam. These are similar to algorithm specific
     utilities such as rsa, dsa, dsaparam etc except they process any key
     type.
     [Steve Henson]

  *) Transfer public key printing routines to EVP_PKEY_ASN1_METHOD. New 
     functions EVP_PKEY_print_public(), EVP_PKEY_print_private(),
     EVP_PKEY_print_param() to print public key data from an EVP_PKEY
     structure.
     [Steve Henson]

  *) Initial support for pluggable public key ASN1.
     De-spaghettify the public key ASN1 handling. Move public and private
     key ASN1 handling to a new EVP_PKEY_ASN1_METHOD structure. Relocate
     algorithm specific handling to a single module within the relevant
     algorithm directory. Add functions to allow (near) opaque processing
     of public and private key structures.
     [Steve Henson]

  *) Implement the Supported Point Formats Extension for
     ECC ciphersuites from draft-ietf-tls-ecc-12.txt.
     [Douglas Stebila]

  *) Add initial support for RFC 4279 PSK TLS ciphersuites. Add members
     for the psk identity [hint] and the psk callback functions to the
     SSL_SESSION, SSL and SSL_CTX structure.
     
     New ciphersuites:
         PSK-RC4-SHA, PSK-3DES-EDE-CBC-SHA, PSK-AES128-CBC-SHA,
         PSK-AES256-CBC-SHA
 
     New functions:
         SSL_CTX_use_psk_identity_hint
         SSL_get_psk_identity_hint
         SSL_get_psk_identity
         SSL_use_psk_identity_hint

     [Mika Kousa and Pasi Eronen of Nokia Corporation]

  *) Add RFC 3161 compliant time stamp request creation, response generation
     and response verification functionality.
     [Zoltán Glózik <zglozik@opentsa.org>, The OpenTSA Project]

  *) Add initial support for TLS extensions, specifically for the server_name
     extension so far.  The SSL_SESSION, SSL_CTX, and SSL data structures now
     have new members for a host name.  The SSL data structure has an
     additional member SSL_CTX *initial_ctx so that new sessions can be
     stored in that context to allow for session resumption, even after the
     SSL has been switched to a new SSL_CTX in reaction to a client's
     server_name extension.

     New functions (subject to change):

         SSL_get_servername()
         SSL_get_servername_type()
         SSL_set_SSL_CTX()

     New CTRL codes and macros (subject to change):

         SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
                                 - SSL_CTX_set_tlsext_servername_callback()
         SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG
                                      - SSL_CTX_set_tlsext_servername_arg()
         SSL_CTRL_SET_TLSEXT_HOSTNAME           - SSL_set_tlsext_host_name()

     openssl s_client has a new '-servername ...' option.

     openssl s_server has new options '-servername_host ...', '-cert2 ...',
     '-key2 ...', '-servername_fatal' (subject to change).  This allows
     testing the HostName extension for a specific single host name ('-cert'
     and '-key' remain fallbacks for handshakes without HostName
     negotiation).  If the unrecogninzed_name alert has to be sent, this by
     default is a warning; it becomes fatal with the '-servername_fatal'
     option.

     [Peter Sylvester,  Remy Allais, Christophe Renou]

  *) Whirlpool hash implementation is added.
     [Andy Polyakov]

  *) BIGNUM code on 64-bit SPARCv9 targets is switched from bn(64,64) to
     bn(64,32). Because of instruction set limitations it doesn't have
     any negative impact on performance. This was done mostly in order
     to make it possible to share assembler modules, such as bn_mul_mont
     implementations, between 32- and 64-bit builds without hassle.
     [Andy Polyakov]

  *) Move code previously exiled into file crypto/ec/ec2_smpt.c
     to ec2_smpl.c, and no longer require the OPENSSL_EC_BIN_PT_COMP
     macro.
     [Bodo Moeller]

  *) New candidate for BIGNUM assembler implementation, bn_mul_mont,
     dedicated Montgomery multiplication procedure, is introduced.
     BN_MONT_CTX is modified to allow bn_mul_mont to reach for higher
     "64-bit" performance on certain 32-bit targets.
     [Andy Polyakov]

  *) New option SSL_OP_NO_COMP to disable use of compression selectively
     in SSL structures. New SSL ctrl to set maximum send fragment size. 
     Save memory by seeting the I/O buffer sizes dynamically instead of
     using the maximum available value.
     [Steve Henson]

  *) New option -V for 'openssl ciphers'. This prints the ciphersuite code
     in addition to the text details.
     [Bodo Moeller]

  *) Very, very preliminary EXPERIMENTAL support for printing of general
     ASN1 structures. This currently produces rather ugly output and doesn't
     handle several customised structures at all.
     [Steve Henson]

  *) Integrated support for PVK file format and some related formats such
     as MS PUBLICKEYBLOB and PRIVATEKEYBLOB. Command line switches to support
     these in the 'rsa' and 'dsa' utilities.
     [Steve Henson]

  *) Support for PKCS#1 RSAPublicKey format on rsa utility command line.
     [Steve Henson]

  *) Remove the ancient ASN1_METHOD code. This was only ever used in one
     place for the (very old) "NETSCAPE" format certificates which are now
     handled using new ASN1 code equivalents.
     [Steve Henson]

  *) Let the TLSv1_method() etc. functions return a 'const' SSL_METHOD
     pointer and make the SSL_METHOD parameter in SSL_CTX_new,
     SSL_CTX_set_ssl_version and SSL_set_ssl_method 'const'.
     [Nils Larsch]

  *) Modify CRL distribution points extension code to print out previously
     unsupported fields. Enhance extension setting code to allow setting of
     all fields.
     [Steve Henson]

  *) Add print and set support for Issuing Distribution Point CRL extension.
     [Steve Henson]

  *) Change 'Configure' script to enable Camellia by default.
     [NTT]

 Changes between 0.9.8m and 0.9.8n [24 Mar 2010]

  *) When rejecting SSL/TLS records due to an incorrect version number, never
     update s->server with a new major version number.  As of
     - OpenSSL 0.9.8m if 'short' is a 16-bit type,
     - OpenSSL 0.9.8f if 'short' is longer than 16 bits,
     the previous behavior could result in a read attempt at NULL when
     receiving specific incorrect SSL/TLS records once record payload
     protection is active.  (CVE-2010-0740)
     [Bodo Moeller, Adam Langley <agl@chromium.org>]

  *) Fix for CVE-2010-0433 where some kerberos enabled versions of OpenSSL 
     could be crashed if the relevant tables were not present (e.g. chrooted).
     [Tomas Hoger <thoger@redhat.com>]

 Changes between 0.9.8l and 0.9.8m [25 Feb 2010]

  *) Always check bn_wexpend() return values for failure.  (CVE-2009-3245)
     [Martin Olsson, Neel Mehta]

  *) Fix X509_STORE locking: Every 'objs' access requires a lock (to
     accommodate for stack sorting, always a write lock!).
     [Bodo Moeller]

  *) On some versions of WIN32 Heap32Next is very slow. This can cause
     excessive delays in the RAND_poll(): over a minute. As a workaround
     include a time check in the inner Heap32Next loop too.
     [Steve Henson]

  *) The code that handled flushing of data in SSL/TLS originally used the
     BIO_CTRL_INFO ctrl to see if any data was pending first. This caused
     the problem outlined in PR#1949. The fix suggested there however can
     trigger problems with buggy BIO_CTRL_WPENDING (e.g. some versions
     of Apache). So instead simplify the code to flush unconditionally.
     This should be fine since flushing with no data to flush is a no op.
     [Steve Henson]

  *) Handle TLS versions 2.0 and later properly and correctly use the
     highest version of TLS/SSL supported. Although TLS >= 2.0 is some way
     off ancient servers have a habit of sticking around for a while...
     [Steve Henson]

  *) Modify compression code so it frees up structures without using the
     ex_data callbacks. This works around a problem where some applications
     call CRYPTO_cleanup_all_ex_data() before application exit (e.g. when
     restarting) then use compression (e.g. SSL with compression) later.
     This results in significant per-connection memory leaks and
     has caused some security issues including CVE-2008-1678 and
     CVE-2009-4355.
     [Steve Henson]

  *) Constify crypto/cast (i.e., <openssl/cast.h>): a CAST_KEY doesn't
     change when encrypting or decrypting.
     [Bodo Moeller]

  *) Add option SSL_OP_LEGACY_SERVER_CONNECT which will allow clients to
     connect and renegotiate with servers which do not support RI.
     Until RI is more widely deployed this option is enabled by default.
     [Steve Henson]

  *) Add "missing" ssl ctrls to clear options and mode.
     [Steve Henson]

  *) If client attempts to renegotiate and doesn't support RI respond with
     a no_renegotiation alert as required by RFC5746.  Some renegotiating
     TLS clients will continue a connection gracefully when they receive
     the alert. Unfortunately OpenSSL mishandled this alert and would hang
     waiting for a server hello which it will never receive. Now we treat a
     received no_renegotiation alert as a fatal error. This is because
     applications requesting a renegotiation might well expect it to succeed
     and would have no code in place to handle the server denying it so the
     only safe thing to do is to terminate the connection.
     [Steve Henson]

  *) Add ctrl macro SSL_get_secure_renegotiation_support() which returns 1 if
     peer supports secure renegotiation and 0 otherwise. Print out peer
     renegotiation support in s_client/s_server.
     [Steve Henson]

  *) Replace the highly broken and deprecated SPKAC certification method with
     the updated NID creation version. This should correctly handle UTF8.
     [Steve Henson]

  *) Implement RFC5746. Re-enable renegotiation but require the extension
     as needed. Unfortunately, SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
     turns out to be a bad idea. It has been replaced by
     SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION which can be set with
     SSL_CTX_set_options(). This is really not recommended unless you
     know what you are doing.
     [Eric Rescorla <ekr@networkresonance.com>, Ben Laurie, Steve Henson]

  *) Fixes to stateless session resumption handling. Use initial_ctx when
     issuing and attempting to decrypt tickets in case it has changed during
     servername handling. Use a non-zero length session ID when attempting
     stateless session resumption: this makes it possible to determine if
     a resumption has occurred immediately after receiving server hello
     (several places in OpenSSL subtly assume this) instead of later in
     the handshake.
     [Steve Henson]

  *) The functions ENGINE_ctrl(), OPENSSL_isservice(),
     CMS_get1_RecipientRequest() and RAND_bytes() can return <=0 on error
     fixes for a few places where the return code is not checked
     correctly.
     [Julia Lawall <julia@diku.dk>]

  *) Add --strict-warnings option to Configure script to include devteam
     warnings in other configurations.
     [Steve Henson]

  *) Add support for --libdir option and LIBDIR variable in makefiles. This
     makes it possible to install openssl libraries in locations which
     have names other than "lib", for example "/usr/lib64" which some
     systems need.
     [Steve Henson, based on patch from Jeremy Utley]

  *) Don't allow the use of leading 0x80 in OIDs. This is a violation of
     X690 8.9.12 and can produce some misleading textual output of OIDs.
     [Steve Henson, reported by Dan Kaminsky]

  *) Delete MD2 from algorithm tables. This follows the recommendation in
     several standards that it is not used in new applications due to
     several cryptographic weaknesses. For binary compatibility reasons
     the MD2 API is still compiled in by default.
     [Steve Henson]

  *) Add compression id to {d2i,i2d}_SSL_SESSION so it is correctly saved
     and restored.
     [Steve Henson]

  *) Rename uni2asc and asc2uni functions to OPENSSL_uni2asc and
     OPENSSL_asc2uni conditionally on Netware platforms to avoid a name
     clash.
     [Guenter <lists@gknw.net>]

  *) Fix the server certificate chain building code to use X509_verify_cert(),
     it used to have an ad-hoc builder which was unable to cope with anything
     other than a simple chain.
     [David Woodhouse <dwmw2@infradead.org>, Steve Henson]

  *) Don't check self signed certificate signatures in X509_verify_cert()
     by default (a flag can override this): it just wastes time without
     adding any security. As a useful side effect self signed root CAs
     with non-FIPS digests are now usable in FIPS mode.
     [Steve Henson]

  *) In dtls1_process_out_of_seq_message() the check if the current message
     is already buffered was missing. For every new message was memory
     allocated, allowing an attacker to perform an denial of service attack
     with sending out of seq handshake messages until there is no memory
     left. Additionally every future messege was buffered, even if the
     sequence number made no sense and would be part of another handshake.
     So only messages with sequence numbers less than 10 in advance will be
     buffered.  (CVE-2009-1378)
     [Robin Seggelmann, discovered by Daniel Mentz] 	

  *) Records are buffered if they arrive with a future epoch to be
     processed after finishing the corresponding handshake. There is
     currently no limitation to this buffer allowing an attacker to perform
     a DOS attack with sending records with future epochs until there is no
     memory left. This patch adds the pqueue_size() function to detemine
     the size of a buffer and limits the record buffer to 100 entries.
     (CVE-2009-1377)
     [Robin Seggelmann, discovered by Daniel Mentz] 	

  *) Keep a copy of frag->msg_header.frag_len so it can be used after the
     parent structure is freed.  (CVE-2009-1379)
     [Daniel Mentz] 	

  *) Handle non-blocking I/O properly in SSL_shutdown() call.
     [Darryl Miles <darryl-mailinglists@netbauds.net>]

  *) Add 2.5.4.* OIDs
     [Ilya O. <vrghost@gmail.com>]

 Changes between 0.9.8k and 0.9.8l  [5 Nov 2009]

  *) Disable renegotiation completely - this fixes a severe security
     problem (CVE-2009-3555) at the cost of breaking all
     renegotiation. Renegotiation can be re-enabled by setting
     SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION in s3->flags at
     run-time. This is really not recommended unless you know what
     you're doing.
     [Ben Laurie]

 Changes between 0.9.8j and 0.9.8k  [25 Mar 2009]

  *) Don't set val to NULL when freeing up structures, it is freed up by
     underlying code. If sizeof(void *) > sizeof(long) this can result in
     zeroing past the valid field. (CVE-2009-0789)
     [Paolo Ganci <Paolo.Ganci@AdNovum.CH>]

  *) Fix bug where return value of CMS_SignerInfo_verify_content() was not
     checked correctly. This would allow some invalid signed attributes to
     appear to verify correctly. (CVE-2009-0591)
     [Ivan Nestlerode <inestlerode@us.ibm.com>]

  *) Reject UniversalString and BMPString types with invalid lengths. This
     prevents a crash in ASN1_STRING_print_ex() which assumes the strings have
     a legal length. (CVE-2009-0590)
     [Steve Henson]

  *) Set S/MIME signing as the default purpose rather than setting it 
     unconditionally. This allows applications to override it at the store
     level.
     [Steve Henson]

  *) Permit restricted recursion of ASN1 strings. This is needed in practice
     to handle some structures.
     [Steve Henson]

  *) Improve efficiency of mem_gets: don't search whole buffer each time
     for a '\n'
     [Jeremy Shapiro <jnshapir@us.ibm.com>]

  *) New -hex option for openssl rand.
     [Matthieu Herrb]

  *) Print out UTF8String and NumericString when parsing ASN1.
     [Steve Henson]

  *) Support NumericString type for name components.
     [Steve Henson]

  *) Allow CC in the environment to override the automatically chosen
     compiler. Note that nothing is done to ensure flags work with the
     chosen compiler.
     [Ben Laurie]

 Changes between 0.9.8i and 0.9.8j  [07 Jan 2009]

  *) Properly check EVP_VerifyFinal() and similar return values
     (CVE-2008-5077).
     [Ben Laurie, Bodo Moeller, Google Security Team]

  *) Enable TLS extensions by default.
     [Ben Laurie]

  *) Allow the CHIL engine to be loaded, whether the application is
     multithreaded or not. (This does not release the developer from the
     obligation to set up the dynamic locking callbacks.)
     [Sander Temme <sander@temme.net>]

  *) Use correct exit code if there is an error in dgst command.
     [Steve Henson; problem pointed out by Roland Dirlewanger]

  *) Tweak Configure so that you need to say "experimental-jpake" to enable
     JPAKE, and need to use -DOPENSSL_EXPERIMENTAL_JPAKE in applications.
     [Bodo Moeller]

  *) Add experimental JPAKE support, including demo authentication in
     s_client and s_server.
     [Ben Laurie]

  *) Set the comparison function in v3_addr_canonize().
     [Rob Austein <sra@hactrn.net>]

  *) Add support for XMPP STARTTLS in s_client.
     [Philip Paeps <philip@freebsd.org>]

  *) Change the server-side SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG behavior
     to ensure that even with this option, only ciphersuites in the
     server's preference list will be accepted.  (Note that the option
     applies only when resuming a session, so the earlier behavior was
     just about the algorithm choice for symmetric cryptography.)
     [Bodo Moeller]

 Changes between 0.9.8h and 0.9.8i  [15 Sep 2008]

  *) Fix NULL pointer dereference if a DTLS server received
     ChangeCipherSpec as first record (CVE-2009-1386).
     [PR #1679]

  *) Fix a state transitition in s3_srvr.c and d1_srvr.c
     (was using SSL3_ST_CW_CLNT_HELLO_B, should be ..._ST_SW_SRVR_...).
     [Nagendra Modadugu]

  *) The fix in 0.9.8c that supposedly got rid of unsafe
     double-checked locking was incomplete for RSA blinding,
     addressing just one layer of what turns out to have been
     doubly unsafe triple-checked locking.

     So now fix this for real by retiring the MONT_HELPER macro
     in crypto/rsa/rsa_eay.c.

     [Bodo Moeller; problem pointed out by Marius Schilder]

  *) Various precautionary measures:

     - Avoid size_t integer overflow in HASH_UPDATE (md32_common.h).

     - Avoid a buffer overflow in d2i_SSL_SESSION() (ssl_asn1.c).
       (NB: This would require knowledge of the secret session ticket key
       to exploit, in which case you'd be SOL either way.)

     - Change bn_nist.c so that it will properly handle input BIGNUMs
       outside the expected range.

     - Enforce the 'num' check in BN_div() (bn_div.c) for non-BN_DEBUG
       builds.

     [Neel Mehta, Bodo Moeller]

  *) Allow engines to be "soft loaded" - i.e. optionally don't die if
     the load fails. Useful for distros.
     [Ben Laurie and the FreeBSD team]

  *) Add support for Local Machine Keyset attribute in PKCS#12 files.
     [Steve Henson]

  *) Fix BN_GF2m_mod_arr() top-bit cleanup code.
     [Huang Ying]

  *) Expand ENGINE to support engine supplied SSL client certificate functions.

     This work was sponsored by Logica.
     [Steve Henson]

  *) Add CryptoAPI ENGINE to support use of RSA and DSA keys held in Windows
     keystores. Support for SSL/TLS client authentication too.
     Not compiled unless enable-capieng specified to Configure.

     This work was sponsored by Logica.
     [Steve Henson]

  *) Fix bug in X509_ATTRIBUTE creation: dont set attribute using
     ASN1_TYPE_set1 if MBSTRING flag set. This bug would crash certain
     attribute creation routines such as certifcate requests and PKCS#12
     files.
     [Steve Henson]

 Changes between 0.9.8g and 0.9.8h  [28 May 2008]

  *) Fix flaw if 'Server Key exchange message' is omitted from a TLS
     handshake which could lead to a cilent crash as found using the
     Codenomicon TLS test suite (CVE-2008-1672) 
     [Steve Henson, Mark Cox]

  *) Fix double free in TLS server name extensions which could lead to
     a remote crash found by Codenomicon TLS test suite (CVE-2008-0891) 
     [Joe Orton]

  *) Clear error queue in SSL_CTX_use_certificate_chain_file()

     Clear the error queue to ensure that error entries left from
     older function calls do not interfere with the correct operation.
     [Lutz Jaenicke, Erik de Castro Lopo]

  *) Remove root CA certificates of commercial CAs:

     The OpenSSL project does not recommend any specific CA and does not
     have any policy with respect to including or excluding any CA.
     Therefore it does not make any sense to ship an arbitrary selection
     of root CA certificates with the OpenSSL software.
     [Lutz Jaenicke]

  *) RSA OAEP patches to fix two separate invalid memory reads.
     The first one involves inputs when 'lzero' is greater than
     'SHA_DIGEST_LENGTH' (it would read about SHA_DIGEST_LENGTH bytes
     before the beginning of from). The second one involves inputs where
     the 'db' section contains nothing but zeroes (there is a one-byte
     invalid read after the end of 'db').
     [Ivan Nestlerode <inestlerode@us.ibm.com>]

  *) Partial backport from 0.9.9-dev:

     Introduce bn_mul_mont (dedicated Montgomery multiplication
     procedure) as a candidate for BIGNUM assembler implementation.
     While 0.9.9-dev uses assembler for various architectures, only
     x86_64 is available by default here in the 0.9.8 branch, and
     32-bit x86 is available through a compile-time setting.

     To try the 32-bit x86 assembler implementation, use Configure
     option "enable-montasm" (which exists only for this backport).

     As "enable-montasm" for 32-bit x86 disclaims code stability
     anyway, in this constellation we activate additional code
     backported from 0.9.9-dev for further performance improvements,
     namely BN_from_montgomery_word.  (To enable this otherwise,
     e.g. x86_64, try "-DMONT_FROM_WORD___NON_DEFAULT_0_9_8_BUILD".)

     [Andy Polyakov (backport partially by Bodo Moeller)]

  *) Add TLS session ticket callback. This allows an application to set
     TLS ticket cipher and HMAC keys rather than relying on hardcoded fixed
     values. This is useful for key rollover for example where several key
     sets may exist with different names.
     [Steve Henson]

  *) Reverse ENGINE-internal logic for caching default ENGINE handles.
     This was broken until now in 0.9.8 releases, such that the only way
     a registered ENGINE could be used (assuming it initialises
     successfully on the host) was to explicitly set it as the default
     for the relevant algorithms. This is in contradiction with 0.9.7
     behaviour and the documentation. With this fix, when an ENGINE is
     registered into a given algorithm's table of implementations, the
     'uptodate' flag is reset so that auto-discovery will be used next
     time a new context for that algorithm attempts to select an
     implementation.
     [Ian Lister (tweaked by Geoff Thorpe)]

  *) Backport of CMS code to OpenSSL 0.9.8. This differs from the 0.9.9
     implemention in the following ways:

     Lack of EVP_PKEY_ASN1_METHOD means algorithm parameters have to be
     hard coded.

     Lack of BER streaming support means one pass streaming processing is
     only supported if data is detached: setting the streaming flag is
     ignored for embedded content.

     CMS support is disabled by default and must be explicitly enabled
     with the enable-cms configuration option.
     [Steve Henson]

  *) Update the GMP engine glue to do direct copies between BIGNUM and
     mpz_t when openssl and GMP use the same limb size. Otherwise the
     existing "conversion via a text string export" trick is still used.
     [Paul Sheer <paulsheer@gmail.com>]

  *) Zlib compression BIO. This is a filter BIO which compressed and
     uncompresses any data passed through it.
     [Steve Henson]

  *) Add AES_wrap_key() and AES_unwrap_key() functions to implement
     RFC3394 compatible AES key wrapping.
     [Steve Henson]

  *) Add utility functions to handle ASN1 structures. ASN1_STRING_set0():
     sets string data without copying. X509_ALGOR_set0() and
     X509_ALGOR_get0(): set and retrieve X509_ALGOR (AlgorithmIdentifier)
     data. Attribute function X509at_get0_data_by_OBJ(): retrieves data
     from an X509_ATTRIBUTE structure optionally checking it occurs only
     once. ASN1_TYPE_set1(): set and ASN1_TYPE structure copying supplied
     data.
     [Steve Henson]

  *) Fix BN flag handling in RSA_eay_mod_exp() and BN_MONT_CTX_set()
     to get the expected BN_FLG_CONSTTIME behavior.
     [Bodo Moeller (Google)]
  
  *) Netware support:

     - fixed wrong usage of ioctlsocket() when build for LIBC BSD sockets
     - fixed do_tests.pl to run the test suite with CLIB builds too (CLIB_OPT)
     - added some more tests to do_tests.pl
     - fixed RunningProcess usage so that it works with newer LIBC NDKs too
     - removed usage of BN_LLONG for CLIB builds to avoid runtime dependency
     - added new Configure targets netware-clib-bsdsock, netware-clib-gcc,
       netware-clib-bsdsock-gcc, netware-libc-bsdsock-gcc
     - various changes to netware.pl to enable gcc-cross builds on Win32
       platform
     - changed crypto/bio/b_sock.c to work with macro functions (CLIB BSD)
     - various changes to fix missing prototype warnings
     - fixed x86nasm.pl to create correct asm files for NASM COFF output
     - added AES, WHIRLPOOL and CPUID assembler code to build files
     - added missing AES assembler make rules to mk1mf.pl
     - fixed order of includes in apps/ocsp.c so that e_os.h settings apply
     [Guenter Knauf <eflash@gmx.net>]

  *) Implement certificate status request TLS extension defined in RFC3546.
     A client can set the appropriate parameters and receive the encoded
     OCSP response via a callback. A server can query the supplied parameters
     and set the encoded OCSP response in the callback. Add simplified examples
     to s_client and s_server.
     [Steve Henson]

 Changes between 0.9.8f and 0.9.8g  [19 Oct 2007]

  *) Fix various bugs:
     + Binary incompatibility of ssl_ctx_st structure
     + DTLS interoperation with non-compliant servers
     + Don't call get_session_cb() without proposed session
     + Fix ia64 assembler code
     [Andy Polyakov, Steve Henson]

 Changes between 0.9.8e and 0.9.8f  [11 Oct 2007]

  *) DTLS Handshake overhaul. There were longstanding issues with
     OpenSSL DTLS implementation, which were making it impossible for
     RFC 4347 compliant client to communicate with OpenSSL server.
     Unfortunately just fixing these incompatibilities would "cut off"
     pre-0.9.8f clients. To allow for hassle free upgrade post-0.9.8e
     server keeps tolerating non RFC compliant syntax. The opposite is
     not true, 0.9.8f client can not communicate with earlier server.
     This update even addresses CVE-2007-4995.
     [Andy Polyakov]

  *) Changes to avoid need for function casts in OpenSSL: some compilers
     (gcc 4.2 and later) reject their use.
     [Kurt Roeckx <kurt@roeckx.be>, Peter Hartley <pdh@utter.chaos.org.uk>,
      Steve Henson]
  
  *) Add RFC4507 support to OpenSSL. This includes the corrections in
     RFC4507bis. The encrypted ticket format is an encrypted encoded
     SSL_SESSION structure, that way new session features are automatically
     supported.

     If a client application caches session in an SSL_SESSION structure
     support is transparent because tickets are now stored in the encoded
     SSL_SESSION.
     
     The SSL_CTX structure automatically generates keys for ticket
     protection in servers so again support should be possible
     with no application modification.

     If a client or server wishes to disable RFC4507 support then the option
     SSL_OP_NO_TICKET can be set.

     Add a TLS extension debugging callback to allow the contents of any client
     or server extensions to be examined.

     This work was sponsored by Google.
     [Steve Henson]

  *) Add initial support for TLS extensions, specifically for the server_name
     extension so far.  The SSL_SESSION, SSL_CTX, and SSL data structures now
     have new members for a host name.  The SSL data structure has an
     additional member SSL_CTX *initial_ctx so that new sessions can be
     stored in that context to allow for session resumption, even after the
     SSL has been switched to a new SSL_CTX in reaction to a client's
     server_name extension.

     New functions (subject to change):

         SSL_get_servername()
         SSL_get_servername_type()
         SSL_set_SSL_CTX()

     New CTRL codes and macros (subject to change):

         SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
                                 - SSL_CTX_set_tlsext_servername_callback()
         SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG
                                      - SSL_CTX_set_tlsext_servername_arg()
         SSL_CTRL_SET_TLSEXT_HOSTNAME           - SSL_set_tlsext_host_name()

     openssl s_client has a new '-servername ...' option.

     openssl s_server has new options '-servername_host ...', '-cert2 ...',
     '-key2 ...', '-servername_fatal' (subject to change).  This allows
     testing the HostName extension for a specific single host name ('-cert'
     and '-key' remain fallbacks for handshakes without HostName
     negotiation).  If the unrecogninzed_name alert has to be sent, this by
     default is a warning; it becomes fatal with the '-servername_fatal'
     option.

     [Peter Sylvester,  Remy Allais, Christophe Renou, Steve Henson]

  *) Add AES and SSE2 assembly language support to VC++ build.
     [Steve Henson]

  *) Mitigate attack on final subtraction in Montgomery reduction.
     [Andy Polyakov]

  *) Fix crypto/ec/ec_mult.c to work properly with scalars of value 0
     (which previously caused an internal error).
     [Bodo Moeller]

  *) Squeeze another 10% out of IGE mode when in != out.
     [Ben Laurie]

  *) AES IGE mode speedup.
     [Dean Gaudet (Google)]

  *) Add the Korean symmetric 128-bit cipher SEED (see
     http://www.kisa.or.kr/kisa/seed/jsp/seed_eng.jsp) and
     add SEED ciphersuites from RFC 4162:

        TLS_RSA_WITH_SEED_CBC_SHA      =  "SEED-SHA"
        TLS_DHE_DSS_WITH_SEED_CBC_SHA  =  "DHE-DSS-SEED-SHA"
        TLS_DHE_RSA_WITH_SEED_CBC_SHA  =  "DHE-RSA-SEED-SHA"
        TLS_DH_anon_WITH_SEED_CBC_SHA  =  "ADH-SEED-SHA"

     To minimize changes between patchlevels in the OpenSSL 0.9.8
     series, SEED remains excluded from compilation unless OpenSSL
     is configured with 'enable-seed'.
     [KISA, Bodo Moeller]

  *) Mitigate branch prediction attacks, which can be practical if a
     single processor is shared, allowing a spy process to extract
     information.  For detailed background information, see
     http://eprint.iacr.org/2007/039 (O. Aciicmez, S. Gueron,
     J.-P. Seifert, "New Branch Prediction Vulnerabilities in OpenSSL
     and Necessary Software Countermeasures").  The core of the change
     are new versions BN_div_no_branch() and
     BN_mod_inverse_no_branch() of BN_div() and BN_mod_inverse(),
     respectively, which are slower, but avoid the security-relevant
     conditional branches.  These are automatically called by BN_div()
     and BN_mod_inverse() if the flag BN_FLG_CONSTTIME is set for one
     of the input BIGNUMs.  Also, BN_is_bit_set() has been changed to
     remove a conditional branch.

     BN_FLG_CONSTTIME is the new name for the previous
     BN_FLG_EXP_CONSTTIME flag, since it now affects more than just
     modular exponentiation.  (Since OpenSSL 0.9.7h, setting this flag
     in the exponent causes BN_mod_exp_mont() to use the alternative
     implementation in BN_mod_exp_mont_consttime().)  The old name
     remains as a deprecated alias.

     Similary, RSA_FLAG_NO_EXP_CONSTTIME is replaced by a more general
     RSA_FLAG_NO_CONSTTIME flag since the RSA implementation now uses
     constant-time implementations for more than just exponentiation.
     Here too the old name is kept as a deprecated alias.

     BN_BLINDING_new() will now use BN_dup() for the modulus so that
     the BN_BLINDING structure gets an independent copy of the
     modulus.  This means that the previous "BIGNUM *m" argument to
     BN_BLINDING_new() and to BN_BLINDING_create_param() now
     essentially becomes "const BIGNUM *m", although we can't actually
     change this in the header file before 0.9.9.  It allows
     RSA_setup_blinding() to use BN_with_flags() on the modulus to
     enable BN_FLG_CONSTTIME.

     [Matthew D Wood (Intel Corp)]

  *) In the SSL/TLS server implementation, be strict about session ID
     context matching (which matters if an application uses a single
     external cache for different purposes).  Previously,
     out-of-context reuse was forbidden only if SSL_VERIFY_PEER was
     set.  This did ensure strict client verification, but meant that,
     with applications using a single external cache for quite
     different requirements, clients could circumvent ciphersuite
     restrictions for a given session ID context by starting a session
     in a different context.
     [Bodo Moeller]

  *) Include "!eNULL" in SSL_DEFAULT_CIPHER_LIST to make sure that
     a ciphersuite string such as "DEFAULT:RSA" cannot enable
     authentication-only ciphersuites.
     [Bodo Moeller]

  *) Update the SSL_get_shared_ciphers() fix CVE-2006-3738 which was
     not complete and could lead to a possible single byte overflow
     (CVE-2007-5135) [Ben Laurie]

 Changes between 0.9.8d and 0.9.8e  [23 Feb 2007]

  *) Since AES128 and AES256 (and similarly Camellia128 and
     Camellia256) share a single mask bit in the logic of
     ssl/ssl_ciph.c, the code for masking out disabled ciphers needs a
     kludge to work properly if AES128 is available and AES256 isn't
     (or if Camellia128 is available and Camellia256 isn't).
     [Victor Duchovni]

  *) Fix the BIT STRING encoding generated by crypto/ec/ec_asn1.c
     (within i2d_ECPrivateKey, i2d_ECPKParameters, i2d_ECParameters):
     When a point or a seed is encoded in a BIT STRING, we need to
     prevent the removal of trailing zero bits to get the proper DER
     encoding.  (By default, crypto/asn1/a_bitstr.c assumes the case
     of a NamedBitList, for which trailing 0 bits need to be removed.)
     [Bodo Moeller]

  *) Have SSL/TLS server implementation tolerate "mismatched" record
     protocol version while receiving ClientHello even if the
     ClientHello is fragmented.  (The server can't insist on the
     particular protocol version it has chosen before the ServerHello
     message has informed the client about his choice.)
     [Bodo Moeller]

  *) Add RFC 3779 support.
     [Rob Austein for ARIN, Ben Laurie]

  *) Load error codes if they are not already present instead of using a
     static variable. This allows them to be cleanly unloaded and reloaded.
     Improve header file function name parsing.
     [Steve Henson]

  *) extend SMTP and IMAP protocol emulation in s_client to use EHLO
     or CAPABILITY handshake as required by RFCs.
     [Goetz Babin-Ebell]

 Changes between 0.9.8c and 0.9.8d  [28 Sep 2006]

  *) Introduce limits to prevent malicious keys being able to
     cause a denial of service.  (CVE-2006-2940)
     [Steve Henson, Bodo Moeller]

  *) Fix ASN.1 parsing of certain invalid structures that can result
     in a denial of service.  (CVE-2006-2937)  [Steve Henson]

  *) Fix buffer overflow in SSL_get_shared_ciphers() function. 
     (CVE-2006-3738) [Tavis Ormandy and Will Drewry, Google Security Team]

  *) Fix SSL client code which could crash if connecting to a
     malicious SSLv2 server.  (CVE-2006-4343)
     [Tavis Ormandy and Will Drewry, Google Security Team]

  *) Since 0.9.8b, ciphersuite strings naming explicit ciphersuites
     match only those.  Before that, "AES256-SHA" would be interpreted
     as a pattern and match "AES128-SHA" too (since AES128-SHA got
     the same strength classification in 0.9.7h) as we currently only
     have a single AES bit in the ciphersuite description bitmap.
     That change, however, also applied to ciphersuite strings such as
     "RC4-MD5" that intentionally matched multiple ciphersuites --
     namely, SSL 2.0 ciphersuites in addition to the more common ones
     from SSL 3.0/TLS 1.0.

     So we change the selection algorithm again: Naming an explicit
     ciphersuite selects this one ciphersuite, and any other similar
     ciphersuite (same bitmap) from *other* protocol versions.
     Thus, "RC4-MD5" again will properly select both the SSL 2.0
     ciphersuite and the SSL 3.0/TLS 1.0 ciphersuite.

     Since SSL 2.0 does not have any ciphersuites for which the
     128/256 bit distinction would be relevant, this works for now.
     The proper fix will be to use different bits for AES128 and
     AES256, which would have avoided the problems from the beginning;
     however, bits are scarce, so we can only do this in a new release
     (not just a patchlevel) when we can change the SSL_CIPHER
     definition to split the single 'unsigned long mask' bitmap into
     multiple values to extend the available space.

     [Bodo Moeller]

 Changes between 0.9.8b and 0.9.8c  [05 Sep 2006]

  *) Avoid PKCS #1 v1.5 signature attack discovered by Daniel Bleichenbacher
     (CVE-2006-4339)  [Ben Laurie and Google Security Team]

  *) Add AES IGE and biIGE modes.
     [Ben Laurie]

  *) Change the Unix randomness entropy gathering to use poll() when
     possible instead of select(), since the latter has some
     undesirable limitations.
     [Darryl Miles via Richard Levitte and Bodo Moeller]

  *) Disable "ECCdraft" ciphersuites more thoroughly.  Now special
     treatment in ssl/ssl_ciph.s makes sure that these ciphersuites
     cannot be implicitly activated as part of, e.g., the "AES" alias.
     However, please upgrade to OpenSSL 0.9.9[-dev] for
     non-experimental use of the ECC ciphersuites to get TLS extension
     support, which is required for curve and point format negotiation
     to avoid potential handshake problems.
     [Bodo Moeller]

  *) Disable rogue ciphersuites:

      - SSLv2 0x08 0x00 0x80 ("RC4-64-MD5")
      - SSLv3/TLSv1 0x00 0x61 ("EXP1024-RC2-CBC-MD5")
      - SSLv3/TLSv1 0x00 0x60 ("EXP1024-RC4-MD5")

     The latter two were purportedly from
     draft-ietf-tls-56-bit-ciphersuites-0[01].txt, but do not really
     appear there.

     Also deactivate the remaining ciphersuites from
     draft-ietf-tls-56-bit-ciphersuites-01.txt.  These are just as
     unofficial, and the ID has long expired.
     [Bodo Moeller]

  *) Fix RSA blinding Heisenbug (problems sometimes occured on
     dual-core machines) and other potential thread-safety issues.
     [Bodo Moeller]

  *) Add the symmetric cipher Camellia (128-bit, 192-bit, 256-bit key
     versions), which is now available for royalty-free use
     (see http://info.isl.ntt.co.jp/crypt/eng/info/chiteki.html).
     Also, add Camellia TLS ciphersuites from RFC 4132.

     To minimize changes between patchlevels in the OpenSSL 0.9.8
     series, Camellia remains excluded from compilation unless OpenSSL
     is configured with 'enable-camellia'.
     [NTT]

  *) Disable the padding bug check when compression is in use. The padding
     bug check assumes the first packet is of even length, this is not
     necessarily true if compresssion is enabled and can result in false
     positives causing handshake failure. The actual bug test is ancient
     code so it is hoped that implementations will either have fixed it by
     now or any which still have the bug do not support compression.
     [Steve Henson]

 Changes between 0.9.8a and 0.9.8b  [04 May 2006]

  *) When applying a cipher rule check to see if string match is an explicit
     cipher suite and only match that one cipher suite if it is.
     [Steve Henson]

  *) Link in manifests for VC++ if needed.
     [Austin Ziegler <halostatue@gmail.com>]

  *) Update support for ECC-based TLS ciphersuites according to
     draft-ietf-tls-ecc-12.txt with proposed changes (but without
     TLS extensions, which are supported starting with the 0.9.9
     branch, not in the OpenSSL 0.9.8 branch).
     [Douglas Stebila]

  *) New functions EVP_CIPHER_CTX_new() and EVP_CIPHER_CTX_free() to support
     opaque EVP_CIPHER_CTX handling.
     [Steve Henson]

  *) Fixes and enhancements to zlib compression code. We now only use
     "zlib1.dll" and use the default __cdecl calling convention on Win32
     to conform with the standards mentioned here:
           http://www.zlib.net/DLL_FAQ.txt
     Static zlib linking now works on Windows and the new --with-zlib-include
     --with-zlib-lib options to Configure can be used to supply the location
     of the headers and library. Gracefully handle case where zlib library
     can't be loaded.
     [Steve Henson]

  *) Several fixes and enhancements to the OID generation code. The old code
     sometimes allowed invalid OIDs (1.X for X >= 40 for example), couldn't
     handle numbers larger than ULONG_MAX, truncated printing and had a
     non standard OBJ_obj2txt() behaviour.
     [Steve Henson]

  *) Add support for building of engines under engine/ as shared libraries
     under VC++ build system.
     [Steve Henson]

  *) Corrected the numerous bugs in the Win32 path splitter in DSO.
     Hopefully, we will not see any false combination of paths any more.
     [Richard Levitte]

 Changes between 0.9.8 and 0.9.8a  [11 Oct 2005]

  *) Remove the functionality of SSL_OP_MSIE_SSLV2_RSA_PADDING
     (part of SSL_OP_ALL).  This option used to disable the
     countermeasure against man-in-the-middle protocol-version
     rollback in the SSL 2.0 server implementation, which is a bad
     idea.  (CVE-2005-2969)

     [Bodo Moeller; problem pointed out by Yutaka Oiwa (Research Center
     for Information Security, National Institute of Advanced Industrial
     Science and Technology [AIST], Japan)]

  *) Add two function to clear and return the verify parameter flags.
     [Steve Henson]

  *) Keep cipherlists sorted in the source instead of sorting them at
     runtime, thus removing the need for a lock.
     [Nils Larsch]

  *) Avoid some small subgroup attacks in Diffie-Hellman.
     [Nick Mathewson and Ben Laurie]

  *) Add functions for well-known primes.
     [Nick Mathewson]

  *) Extended Windows CE support.
     [Satoshi Nakamura and Andy Polyakov]

  *) Initialize SSL_METHOD structures at compile time instead of during
     runtime, thus removing the need for a lock.
     [Steve Henson]

  *) Make PKCS7_decrypt() work even if no certificate is supplied by
     attempting to decrypt each encrypted key in turn. Add support to
     smime utility.
     [Steve Henson]

 Changes between 0.9.7h and 0.9.8  [05 Jul 2005]

  [NB: OpenSSL 0.9.7i and later 0.9.7 patch levels were released after
  OpenSSL 0.9.8.]

  *) Add libcrypto.pc and libssl.pc for those who feel they need them.
     [Richard Levitte]

  *) Change CA.sh and CA.pl so they don't bundle the CSR and the private
     key into the same file any more.
     [Richard Levitte]

  *) Add initial support for Win64, both IA64 and AMD64/x64 flavors.
     [Andy Polyakov]

  *) Add -utf8 command line and config file option to 'ca'.
     [Stefan <stf@udoma.org]

  *) Removed the macro des_crypt(), as it seems to conflict with some
     libraries.  Use DES_crypt().
     [Richard Levitte]

  *) Correct naming of the 'chil' and '4758cca' ENGINEs. This
     involves renaming the source and generated shared-libs for
     both. The engines will accept the corrected or legacy ids
     ('ncipher' and '4758_cca' respectively) when binding. NB,
     this only applies when building 'shared'.
     [Corinna Vinschen <vinschen@redhat.com> and Geoff Thorpe]

  *) Add attribute functions to EVP_PKEY structure. Modify
     PKCS12_create() to recognize a CSP name attribute and
     use it. Make -CSP option work again in pkcs12 utility.
     [Steve Henson]

  *) Add new functionality to the bn blinding code:
     - automatic re-creation of the BN_BLINDING parameters after
       a fixed number of uses (currently 32)
     - add new function for parameter creation
     - introduce flags to control the update behaviour of the
       BN_BLINDING parameters
     - hide BN_BLINDING structure
     Add a second BN_BLINDING slot to the RSA structure to improve
     performance when a single RSA object is shared among several
     threads.
     [Nils Larsch]

  *) Add support for DTLS.
     [Nagendra Modadugu <nagendra@cs.stanford.edu> and Ben Laurie]

  *) Add support for DER encoded private keys (SSL_FILETYPE_ASN1)
     to SSL_CTX_use_PrivateKey_file() and SSL_use_PrivateKey_file()
     [Walter Goulet]

  *) Remove buggy and incompletet DH cert support from
     ssl/ssl_rsa.c and ssl/s3_both.c
     [Nils Larsch]

  *) Use SHA-1 instead of MD5 as the default digest algorithm for
     the apps/openssl applications.
     [Nils Larsch]

  *) Compile clean with "-Wall -Wmissing-prototypes
     -Wstrict-prototypes -Wmissing-declarations -Werror". Currently
     DEBUG_SAFESTACK must also be set.
     [Ben Laurie]

  *) Change ./Configure so that certain algorithms can be disabled by default.
     The new counterpiece to "no-xxx" is "enable-xxx".

     The patented RC5 and MDC2 algorithms will now be disabled unless
     "enable-rc5" and "enable-mdc2", respectively, are specified.

     (IDEA remains enabled despite being patented.  This is because IDEA
     is frequently required for interoperability, and there is no license
     fee for non-commercial use.  As before, "no-idea" can be used to
     avoid this algorithm.)

     [Bodo Moeller]

  *) Add processing of proxy certificates (see RFC 3820).  This work was
     sponsored by KTH (The Royal Institute of Technology in Stockholm) and
     EGEE (Enabling Grids for E-science in Europe).
     [Richard Levitte]

  *) RC4 performance overhaul on modern architectures/implementations, such
     as Intel P4, IA-64 and AMD64.
     [Andy Polyakov]

  *) New utility extract-section.pl. This can be used specify an alternative
     section number in a pod file instead of having to treat each file as
     a separate case in Makefile. This can be done by adding two lines to the
     pod file:

     =for comment openssl_section:XXX

     The blank line is mandatory.

     [Steve Henson]

  *) New arguments -certform, -keyform and -pass for s_client and s_server
     to allow alternative format key and certificate files and passphrase
     sources.
     [Steve Henson]

  *) New structure X509_VERIFY_PARAM which combines current verify parameters,
     update associated structures and add various utility functions.

     Add new policy related verify parameters, include policy checking in 
     standard verify code. Enhance 'smime' application with extra parameters
     to support policy checking and print out.
     [Steve Henson]

  *) Add a new engine to support VIA PadLock ACE extensions in the VIA C3
     Nehemiah processors. These extensions support AES encryption in hardware
     as well as RNG (though RNG support is currently disabled).
     [Michal Ludvig <michal@logix.cz>, with help from Andy Polyakov]

  *) Deprecate BN_[get|set]_params() functions (they were ignored internally).
     [Geoff Thorpe]

  *) New FIPS 180-2 algorithms, SHA-224/-256/-384/-512 are implemented.
     [Andy Polyakov and a number of other people]

  *) Improved PowerPC platform support. Most notably BIGNUM assembler
     implementation contributed by IBM.
     [Suresh Chari, Peter Waltenberg, Andy Polyakov]

  *) The new 'RSA_generate_key_ex' function now takes a BIGNUM for the public
     exponent rather than 'unsigned long'. There is a corresponding change to
     the new 'rsa_keygen' element of the RSA_METHOD structure.
     [Jelte Jansen, Geoff Thorpe]

  *) Functionality for creating the initial serial number file is now
     moved from CA.pl to the 'ca' utility with a new option -create_serial.

     (Before OpenSSL 0.9.7e, CA.pl used to initialize the serial
     number file to 1, which is bound to cause problems.  To avoid
     the problems while respecting compatibility between different 0.9.7
     patchlevels, 0.9.7e  employed 'openssl x509 -next_serial' in
     CA.pl for serial number initialization.  With the new release 0.9.8,
     we can fix the problem directly in the 'ca' utility.)
     [Steve Henson]

  *) Reduced header interdepencies by declaring more opaque objects in
     ossl_typ.h. As a consequence, including some headers (eg. engine.h) will
     give fewer recursive includes, which could break lazy source code - so
     this change is covered by the OPENSSL_NO_DEPRECATED symbol. As always,
     developers should define this symbol when building and using openssl to
     ensure they track the recommended behaviour, interfaces, [etc], but
     backwards-compatible behaviour prevails when this isn't defined.
     [Geoff Thorpe]

  *) New function X509_POLICY_NODE_print() which prints out policy nodes.
     [Steve Henson]

  *) Add new EVP function EVP_CIPHER_CTX_rand_key and associated functionality.
     This will generate a random key of the appropriate length based on the 
     cipher context. The EVP_CIPHER can provide its own random key generation
     routine to support keys of a specific form. This is used in the des and 
     3des routines to generate a key of the correct parity. Update S/MIME
     code to use new functions and hence generate correct parity DES keys.
     Add EVP_CHECK_DES_KEY #define to return an error if the key is not 
     valid (weak or incorrect parity).
     [Steve Henson]

  *) Add a local set of CRLs that can be used by X509_verify_cert() as well
     as looking them up. This is useful when the verified structure may contain
     CRLs, for example PKCS#7 signedData. Modify PKCS7_verify() to use any CRLs
     present unless the new PKCS7_NO_CRL flag is asserted.
     [Steve Henson]

  *) Extend ASN1 oid configuration module. It now additionally accepts the
     syntax:

     shortName = some long name, 1.2.3.4
     [Steve Henson]

  *) Reimplemented the BN_CTX implementation. There is now no more static
     limitation on the number of variables it can handle nor the depth of the
     "stack" handling for BN_CTX_start()/BN_CTX_end() pairs. The stack
     information can now expand as required, and rather than having a single
     static array of bignums, BN_CTX now uses a linked-list of such arrays
     allowing it to expand on demand whilst maintaining the usefulness of
     BN_CTX's "bundling".
     [Geoff Thorpe]

  *) Add a missing BN_CTX parameter to the 'rsa_mod_exp' callback in RSA_METHOD
     to allow all RSA operations to function using a single BN_CTX.
     [Geoff Thorpe]

  *) Preliminary support for certificate policy evaluation and checking. This
     is initially intended to pass the tests outlined in "Conformance Testing
     of Relying Party Client Certificate Path Processing Logic" v1.07.
     [Steve Henson]

  *) bn_dup_expand() has been deprecated, it was introduced in 0.9.7 and
     remained unused and not that useful. A variety of other little bignum
     tweaks and fixes have also been made continuing on from the audit (see
     below).
     [Geoff Thorpe]

  *) Constify all or almost all d2i, c2i, s2i and r2i functions, along with
     associated ASN1, EVP and SSL functions and old ASN1 macros.
     [Richard Levitte]

  *) BN_zero() only needs to set 'top' and 'neg' to zero for correct results,
     and this should never fail. So the return value from the use of
     BN_set_word() (which can fail due to needless expansion) is now deprecated;
     if OPENSSL_NO_DEPRECATED is defined, BN_zero() is a void macro.
     [Geoff Thorpe]

  *) BN_CTX_get() should return zero-valued bignums, providing the same
     initialised value as BN_new().
     [Geoff Thorpe, suggested by Ulf Möller]

  *) Support for inhibitAnyPolicy certificate extension.
     [Steve Henson]

  *) An audit of the BIGNUM code is underway, for which debugging code is
     enabled when BN_DEBUG is defined. This makes stricter enforcements on what
     is considered valid when processing BIGNUMs, and causes execution to
     assert() when a problem is discovered. If BN_DEBUG_RAND is defined,
     further steps are taken to deliberately pollute unused data in BIGNUM
     structures to try and expose faulty code further on. For now, openssl will
     (in its default mode of operation) continue to tolerate the inconsistent
     forms that it has tolerated in the past, but authors and packagers should
     consider trying openssl and their own applications when compiled with
     these debugging symbols defined. It will help highlight potential bugs in
     their own code, and will improve the test coverage for OpenSSL itself. At
     some point, these tighter rules will become openssl's default to improve
     maintainability, though the assert()s and other overheads will remain only
     in debugging configurations. See bn.h for more details.
     [Geoff Thorpe, Nils Larsch, Ulf Möller]

  *) BN_CTX_init() has been deprecated, as BN_CTX is an opaque structure
     that can only be obtained through BN_CTX_new() (which implicitly
     initialises it). The presence of this function only made it possible
     to overwrite an existing structure (and cause memory leaks).
     [Geoff Thorpe]

  *) Because of the callback-based approach for implementing LHASH as a
     template type, lh_insert() adds opaque objects to hash-tables and
     lh_doall() or lh_doall_arg() are typically used with a destructor callback
     to clean up those corresponding objects before destroying the hash table
     (and losing the object pointers). So some over-zealous constifications in
     LHASH have been relaxed so that lh_insert() does not take (nor store) the
     objects as "const" and the lh_doall[_arg] callback wrappers are not
     prototyped to have "const" restrictions on the object pointers they are
     given (and so aren't required to cast them away any more).
     [Geoff Thorpe]

  *) The tmdiff.h API was so ugly and minimal that our own timing utility
     (speed) prefers to use its own implementation. The two implementations
     haven't been consolidated as yet (volunteers?) but the tmdiff API has had
     its object type properly exposed (MS_TM) instead of casting to/from "char
     *". This may still change yet if someone realises MS_TM and "ms_time_***"
     aren't necessarily the greatest nomenclatures - but this is what was used
     internally to the implementation so I've used that for now.
     [Geoff Thorpe]

  *) Ensure that deprecated functions do not get compiled when
     OPENSSL_NO_DEPRECATED is defined. Some "openssl" subcommands and a few of
     the self-tests were still using deprecated key-generation functions so
     these have been updated also.
     [Geoff Thorpe]

  *) Reorganise PKCS#7 code to separate the digest location functionality
     into PKCS7_find_digest(), digest addtion into PKCS7_bio_add_digest().
     New function PKCS7_set_digest() to set the digest type for PKCS#7
     digestedData type. Add additional code to correctly generate the
     digestedData type and add support for this type in PKCS7 initialization
     functions.
     [Steve Henson]

  *) New function PKCS7_set0_type_other() this initializes a PKCS7 
     structure of type "other".
     [Steve Henson]

  *) Fix prime generation loop in crypto/bn/bn_prime.pl by making
     sure the loop does correctly stop and breaking ("division by zero")
     modulus operations are not performed. The (pre-generated) prime
     table crypto/bn/bn_prime.h was already correct, but it could not be
     re-generated on some platforms because of the "division by zero"
     situation in the script.
     [Ralf S. Engelschall]

  *) Update support for ECC-based TLS ciphersuites according to
     draft-ietf-tls-ecc-03.txt: the KDF1 key derivation function with
     SHA-1 now is only used for "small" curves (where the
     representation of a field element takes up to 24 bytes); for
     larger curves, the field element resulting from ECDH is directly
     used as premaster secret.
     [Douglas Stebila (Sun Microsystems Laboratories)]

  *) Add code for kP+lQ timings to crypto/ec/ectest.c, and add SEC2
     curve secp160r1 to the tests.
     [Douglas Stebila (Sun Microsystems Laboratories)]

  *) Add the possibility to load symbols globally with DSO.
     [Götz Babin-Ebell <babin-ebell@trustcenter.de> via Richard Levitte]

  *) Add the functions ERR_set_mark() and ERR_pop_to_mark() for better
     control of the error stack.
     [Richard Levitte]

  *) Add support for STORE in ENGINE.
     [Richard Levitte]

  *) Add the STORE type.  The intention is to provide a common interface
     to certificate and key stores, be they simple file-based stores, or
     HSM-type store, or LDAP stores, or...
     NOTE: The code is currently UNTESTED and isn't really used anywhere.
     [Richard Levitte]

  *) Add a generic structure called OPENSSL_ITEM.  This can be used to
     pass a list of arguments to any function as well as provide a way
     for a function to pass data back to the caller.
     [Richard Levitte]

  *) Add the functions BUF_strndup() and BUF_memdup().  BUF_strndup()
     works like BUF_strdup() but can be used to duplicate a portion of
     a string.  The copy gets NUL-terminated.  BUF_memdup() duplicates
     a memory area.
     [Richard Levitte]

  *) Add the function sk_find_ex() which works like sk_find(), but will
     return an index to an element even if an exact match couldn't be
     found.  The index is guaranteed to point at the element where the
     searched-for key would be inserted to preserve sorting order.
     [Richard Levitte]

  *) Add the function OBJ_bsearch_ex() which works like OBJ_bsearch() but
     takes an extra flags argument for optional functionality.  Currently,
     the following flags are defined:

	OBJ_BSEARCH_VALUE_ON_NOMATCH
	This one gets OBJ_bsearch_ex() to return a pointer to the first
	element where the comparing function returns a negative or zero
	number.

	OBJ_BSEARCH_FIRST_VALUE_ON_MATCH
	This one gets OBJ_bsearch_ex() to return a pointer to the first
	element where the comparing function returns zero.  This is useful
	if there are more than one element where the comparing function
	returns zero.
     [Richard Levitte]

  *) Make it possible to create self-signed certificates with 'openssl ca'
     in such a way that the self-signed certificate becomes part of the
     CA database and uses the same mechanisms for serial number generation
     as all other certificate signing.  The new flag '-selfsign' enables
     this functionality.  Adapt CA.sh and CA.pl.in.
     [Richard Levitte]

  *) Add functionality to check the public key of a certificate request
     against a given private.  This is useful to check that a certificate
     request can be signed by that key (self-signing).
     [Richard Levitte]

  *) Make it possible to have multiple active certificates with the same
     subject in the CA index file.  This is done only if the keyword
     'unique_subject' is set to 'no' in the main CA section (default
     if 'CA_default') of the configuration file.  The value is saved
     with the database itself in a separate index attribute file,
     named like the index file with '.attr' appended to the name.
     [Richard Levitte]

  *) Generate muti valued AVAs using '+' notation in config files for
     req and dirName.
     [Steve Henson]

  *) Support for nameConstraints certificate extension.
     [Steve Henson]

  *) Support for policyConstraints certificate extension.
     [Steve Henson]

  *) Support for policyMappings certificate extension.
     [Steve Henson]

  *) Make sure the default DSA_METHOD implementation only uses its
     dsa_mod_exp() and/or bn_mod_exp() handlers if they are non-NULL,
     and change its own handlers to be NULL so as to remove unnecessary
     indirection. This lets alternative implementations fallback to the
     default implementation more easily.
     [Geoff Thorpe]

  *) Support for directoryName in GeneralName related extensions
     in config files.
     [Steve Henson]

  *) Make it possible to link applications using Makefile.shared.
     Make that possible even when linking against static libraries!
     [Richard Levitte]

  *) Support for single pass processing for S/MIME signing. This now
     means that S/MIME signing can be done from a pipe, in addition
     cleartext signing (multipart/signed type) is effectively streaming
     and the signed data does not need to be all held in memory.

     This is done with a new flag PKCS7_STREAM. When this flag is set
     PKCS7_sign() only initializes the PKCS7 structure and the actual signing
     is done after the data is output (and digests calculated) in
     SMIME_write_PKCS7().
     [Steve Henson]

  *) Add full support for -rpath/-R, both in shared libraries and
     applications, at least on the platforms where it's known how
     to do it.
     [Richard Levitte]

  *) In crypto/ec/ec_mult.c, implement fast point multiplication with
     precomputation, based on wNAF splitting: EC_GROUP_precompute_mult()
     will now compute a table of multiples of the generator that
     makes subsequent invocations of EC_POINTs_mul() or EC_POINT_mul()
     faster (notably in the case of a single point multiplication,
     scalar * generator).
     [Nils Larsch, Bodo Moeller]

  *) IPv6 support for certificate extensions. The various extensions
     which use the IP:a.b.c.d can now take IPv6 addresses using the
     formats of RFC1884 2.2 . IPv6 addresses are now also displayed
     correctly.
     [Steve Henson]

  *) Added an ENGINE that implements RSA by performing private key
     exponentiations with the GMP library. The conversions to and from
     GMP's mpz_t format aren't optimised nor are any montgomery forms
     cached, and on x86 it appears OpenSSL's own performance has caught up.
     However there are likely to be other architectures where GMP could
     provide a boost. This ENGINE is not built in by default, but it can be
     specified at Configure time and should be accompanied by the necessary
     linker additions, eg;
         ./config -DOPENSSL_USE_GMP -lgmp
     [Geoff Thorpe]

  *) "openssl engine" will not display ENGINE/DSO load failure errors when
     testing availability of engines with "-t" - the old behaviour is
     produced by increasing the feature's verbosity with "-tt".
     [Geoff Thorpe]

  *) ECDSA routines: under certain error conditions uninitialized BN objects
     could be freed. Solution: make sure initialization is performed early
     enough. (Reported and fix supplied by Nils Larsch <nla@trustcenter.de>
     via PR#459)
     [Lutz Jaenicke]

  *) Key-generation can now be implemented in RSA_METHOD, DSA_METHOD
     and DH_METHOD (eg. by ENGINE implementations) to override the normal
     software implementations. For DSA and DH, parameter generation can
     also be overriden by providing the appropriate method callbacks.
     [Geoff Thorpe]

  *) Change the "progress" mechanism used in key-generation and
     primality testing to functions that take a new BN_GENCB pointer in
     place of callback/argument pairs. The new API functions have "_ex"
     postfixes and the older functions are reimplemented as wrappers for
     the new ones. The OPENSSL_NO_DEPRECATED symbol can be used to hide
     declarations of the old functions to help (graceful) attempts to
     migrate to the new functions. Also, the new key-generation API
     functions operate on a caller-supplied key-structure and return
     success/failure rather than returning a key or NULL - this is to
     help make "keygen" another member function of RSA_METHOD etc.

     Example for using the new callback interface:

          int (*my_callback)(int a, int b, BN_GENCB *cb) = ...;
          void *my_arg = ...;
          BN_GENCB my_cb;

          BN_GENCB_set(&my_cb, my_callback, my_arg);

          return BN_is_prime_ex(some_bignum, BN_prime_checks, NULL, &cb);
          /* For the meaning of a, b in calls to my_callback(), see the
           * documentation of the function that calls the callback.
           * cb will point to my_cb; my_arg can be retrieved as cb->arg.
           * my_callback should return 1 if it wants BN_is_prime_ex()
           * to continue, or 0 to stop.
           */

     [Geoff Thorpe]

  *) Change the ZLIB compression method to be stateful, and make it
     available to TLS with the number defined in 
     draft-ietf-tls-compression-04.txt.
     [Richard Levitte]

  *) Add the ASN.1 structures and functions for CertificatePair, which
     is defined as follows (according to X.509_4thEditionDraftV6.pdf):

     CertificatePair ::= SEQUENCE {
        forward		[0]	Certificate OPTIONAL,
        reverse		[1]	Certificate OPTIONAL,
        -- at least one of the pair shall be present -- }

     Also implement the PEM functions to read and write certificate
     pairs, and defined the PEM tag as "CERTIFICATE PAIR".

     This needed to be defined, mostly for the sake of the LDAP
     attribute crossCertificatePair, but may prove useful elsewhere as
     well.
     [Richard Levitte]

  *) Make it possible to inhibit symlinking of shared libraries in
     Makefile.shared, for Cygwin's sake.
     [Richard Levitte]

  *) Extend the BIGNUM API by creating a function 
          void BN_set_negative(BIGNUM *a, int neg);
     and a macro that behave like
          int  BN_is_negative(const BIGNUM *a);

     to avoid the need to access 'a->neg' directly in applications.
     [Nils Larsch]

  *) Implement fast modular reduction for pseudo-Mersenne primes
     used in NIST curves (crypto/bn/bn_nist.c, crypto/ec/ecp_nist.c).
     EC_GROUP_new_curve_GFp() will now automatically use this
     if applicable.
     [Nils Larsch <nla@trustcenter.de>]

  *) Add new lock type (CRYPTO_LOCK_BN).
     [Bodo Moeller]

  *) Change the ENGINE framework to automatically load engines
     dynamically from specific directories unless they could be
     found to already be built in or loaded.  Move all the
     current engines except for the cryptodev one to a new
     directory engines/.
     The engines in engines/ are built as shared libraries if
     the "shared" options was given to ./Configure or ./config.
     Otherwise, they are inserted in libcrypto.a.
     /usr/local/ssl/engines is the default directory for dynamic
     engines, but that can be overriden at configure time through
     the usual use of --prefix and/or --openssldir, and at run
     time with the environment variable OPENSSL_ENGINES.
     [Geoff Thorpe and Richard Levitte]

  *) Add Makefile.shared, a helper makefile to build shared
     libraries.  Addapt Makefile.org.
     [Richard Levitte]

  *) Add version info to Win32 DLLs.
     [Peter 'Luna' Runestig" <peter@runestig.com>]

  *) Add new 'medium level' PKCS#12 API. Certificates and keys
     can be added using this API to created arbitrary PKCS#12
     files while avoiding the low level API.

     New options to PKCS12_create(), key or cert can be NULL and
     will then be omitted from the output file. The encryption
     algorithm NIDs can be set to -1 for no encryption, the mac
     iteration count can be set to 0 to omit the mac.

     Enhance pkcs12 utility by making the -nokeys and -nocerts
     options work when creating a PKCS#12 file. New option -nomac
     to omit the mac, NONE can be set for an encryption algorithm.
     New code is modified to use the enhanced PKCS12_create()
     instead of the low level API.
     [Steve Henson]

  *) Extend ASN1 encoder to support indefinite length constructed
     encoding. This can output sequences tags and octet strings in
     this form. Modify pk7_asn1.c to support indefinite length
     encoding. This is experimental and needs additional code to
     be useful, such as an ASN1 bio and some enhanced streaming
     PKCS#7 code.

     Extend template encode functionality so that tagging is passed
     down to the template encoder.
     [Steve Henson]

  *) Let 'openssl req' fail if an argument to '-newkey' is not
     recognized instead of using RSA as a default.
     [Bodo Moeller]

  *) Add support for ECC-based ciphersuites from draft-ietf-tls-ecc-01.txt.
     As these are not official, they are not included in "ALL";
     the "ECCdraft" ciphersuite group alias can be used to select them.
     [Vipul Gupta and Sumit Gupta (Sun Microsystems Laboratories)]

  *) Add ECDH engine support.
     [Nils Gura and Douglas Stebila (Sun Microsystems Laboratories)]

  *) Add ECDH in new directory crypto/ecdh/.
     [Douglas Stebila (Sun Microsystems Laboratories)]

  *) Let BN_rand_range() abort with an error after 100 iterations
     without success (which indicates a broken PRNG).
     [Bodo Moeller]

  *) Change BN_mod_sqrt() so that it verifies that the input value
     is really the square of the return value.  (Previously,
     BN_mod_sqrt would show GIGO behaviour.)
     [Bodo Moeller]

  *) Add named elliptic curves over binary fields from X9.62, SECG,
     and WAP/WTLS; add OIDs that were still missing.

     [Sheueling Chang Shantz and Douglas Stebila
     (Sun Microsystems Laboratories)]

  *) Extend the EC library for elliptic curves over binary fields
     (new files ec2_smpl.c, ec2_smpt.c, ec2_mult.c in crypto/ec/).
     New EC_METHOD:

          EC_GF2m_simple_method

     New API functions:

          EC_GROUP_new_curve_GF2m
          EC_GROUP_set_curve_GF2m
          EC_GROUP_get_curve_GF2m
          EC_POINT_set_affine_coordinates_GF2m
          EC_POINT_get_affine_coordinates_GF2m
          EC_POINT_set_compressed_coordinates_GF2m

     Point compression for binary fields is disabled by default for
     patent reasons (compile with OPENSSL_EC_BIN_PT_COMP defined to
     enable it).

     As binary polynomials are represented as BIGNUMs, various members
     of the EC_GROUP and EC_POINT data structures can be shared
     between the implementations for prime fields and binary fields;
     the above ..._GF2m functions (except for EX_GROUP_new_curve_GF2m)
     are essentially identical to their ..._GFp counterparts.
     (For simplicity, the '..._GFp' prefix has been dropped from
     various internal method names.)

     An internal 'field_div' method (similar to 'field_mul' and
     'field_sqr') has been added; this is used only for binary fields.

     [Sheueling Chang Shantz and Douglas Stebila
     (Sun Microsystems Laboratories)]

  *) Optionally dispatch EC_POINT_mul(), EC_POINT_precompute_mult()
     through methods ('mul', 'precompute_mult').

     The generic implementations (now internally called 'ec_wNAF_mul'
     and 'ec_wNAF_precomputed_mult') remain the default if these
     methods are undefined.

     [Sheueling Chang Shantz and Douglas Stebila
     (Sun Microsystems Laboratories)]

  *) New function EC_GROUP_get_degree, which is defined through
     EC_METHOD.  For curves over prime fields, this returns the bit
     length of the modulus.

     [Sheueling Chang Shantz and Douglas Stebila
     (Sun Microsystems Laboratories)]

  *) New functions EC_GROUP_dup, EC_POINT_dup.
     (These simply call ..._new  and ..._copy).

     [Sheueling Chang Shantz and Douglas Stebila
     (Sun Microsystems Laboratories)]

  *) Add binary polynomial arithmetic software in crypto/bn/bn_gf2m.c.
     Polynomials are represented as BIGNUMs (where the sign bit is not
     used) in the following functions [macros]:  

          BN_GF2m_add
          BN_GF2m_sub             [= BN_GF2m_add]
          BN_GF2m_mod             [wrapper for BN_GF2m_mod_arr]
          BN_GF2m_mod_mul         [wrapper for BN_GF2m_mod_mul_arr]
          BN_GF2m_mod_sqr         [wrapper for BN_GF2m_mod_sqr_arr]
          BN_GF2m_mod_inv
          BN_GF2m_mod_exp         [wrapper for BN_GF2m_mod_exp_arr]
          BN_GF2m_mod_sqrt        [wrapper for BN_GF2m_mod_sqrt_arr]
          BN_GF2m_mod_solve_quad  [wrapper for BN_GF2m_mod_solve_quad_arr]
          BN_GF2m_cmp             [= BN_ucmp]

     (Note that only the 'mod' functions are actually for fields GF(2^m).
     BN_GF2m_add() is misnomer, but this is for the sake of consistency.)

     For some functions, an the irreducible polynomial defining a
     field can be given as an 'unsigned int[]' with strictly
     decreasing elements giving the indices of those bits that are set;
     i.e., p[] represents the polynomial
          f(t) = t^p[0] + t^p[1] + ... + t^p[k]
     where
          p[0] > p[1] > ... > p[k] = 0.
     This applies to the following functions:

          BN_GF2m_mod_arr
          BN_GF2m_mod_mul_arr
          BN_GF2m_mod_sqr_arr
          BN_GF2m_mod_inv_arr        [wrapper for BN_GF2m_mod_inv]
          BN_GF2m_mod_div_arr        [wrapper for BN_GF2m_mod_div]
          BN_GF2m_mod_exp_arr
          BN_GF2m_mod_sqrt_arr
          BN_GF2m_mod_solve_quad_arr
          BN_GF2m_poly2arr
          BN_GF2m_arr2poly

     Conversion can be performed by the following functions:

          BN_GF2m_poly2arr
          BN_GF2m_arr2poly

     bntest.c has additional tests for binary polynomial arithmetic.

     Two implementations for BN_GF2m_mod_div() are available.
     The default algorithm simply uses BN_GF2m_mod_inv() and
     BN_GF2m_mod_mul().  The alternative algorithm is compiled in only
     if OPENSSL_SUN_GF2M_DIV is defined (patent pending; read the
     copyright notice in crypto/bn/bn_gf2m.c before enabling it).

     [Sheueling Chang Shantz and Douglas Stebila
     (Sun Microsystems Laboratories)]

  *) Add new error code 'ERR_R_DISABLED' that can be used when some
     functionality is disabled at compile-time.
     [Douglas Stebila <douglas.stebila@sun.com>]

  *) Change default behaviour of 'openssl asn1parse' so that more
     information is visible when viewing, e.g., a certificate:

     Modify asn1_parse2 (crypto/asn1/asn1_par.c) so that in non-'dump'
     mode the content of non-printable OCTET STRINGs is output in a
     style similar to INTEGERs, but with '[HEX DUMP]' prepended to
     avoid the appearance of a printable string.
     [Nils Larsch <nla@trustcenter.de>]

  *) Add 'asn1_flag' and 'asn1_form' member to EC_GROUP with access
     functions
          EC_GROUP_set_asn1_flag()
          EC_GROUP_get_asn1_flag()
          EC_GROUP_set_point_conversion_form()
          EC_GROUP_get_point_conversion_form()
     These control ASN1 encoding details:
     - Curves (i.e., groups) are encoded explicitly unless asn1_flag
       has been set to OPENSSL_EC_NAMED_CURVE.
     - Points are encoded in uncompressed form by default; options for
       asn1_for are as for point2oct, namely
          POINT_CONVERSION_COMPRESSED
          POINT_CONVERSION_UNCOMPRESSED
          POINT_CONVERSION_HYBRID

     Also add 'seed' and 'seed_len' members to EC_GROUP with access
     functions
          EC_GROUP_set_seed()
          EC_GROUP_get0_seed()
          EC_GROUP_get_seed_len()
     This is used only for ASN1 purposes (so far).
     [Nils Larsch <nla@trustcenter.de>]

  *) Add 'field_type' member to EC_METHOD, which holds the NID
     of the appropriate field type OID.  The new function
     EC_METHOD_get_field_type() returns this value.
     [Nils Larsch <nla@trustcenter.de>]

  *) Add functions 
          EC_POINT_point2bn()
          EC_POINT_bn2point()
          EC_POINT_point2hex()
          EC_POINT_hex2point()
     providing useful interfaces to EC_POINT_point2oct() and
     EC_POINT_oct2point().
     [Nils Larsch <nla@trustcenter.de>]

  *) Change internals of the EC library so that the functions
          EC_GROUP_set_generator()
          EC_GROUP_get_generator()
          EC_GROUP_get_order()
          EC_GROUP_get_cofactor()
     are implemented directly in crypto/ec/ec_lib.c and not dispatched
     to methods, which would lead to unnecessary code duplication when
     adding different types of curves.
     [Nils Larsch <nla@trustcenter.de> with input by Bodo Moeller]

  *) Implement compute_wNAF (crypto/ec/ec_mult.c) without BIGNUM
     arithmetic, and such that modified wNAFs are generated
     (which avoid length expansion in many cases).
     [Bodo Moeller]

  *) Add a function EC_GROUP_check_discriminant() (defined via
     EC_METHOD) that verifies that the curve discriminant is non-zero.

     Add a function EC_GROUP_check() that makes some sanity tests
     on a EC_GROUP, its generator and order.  This includes
     EC_GROUP_check_discriminant().
     [Nils Larsch <nla@trustcenter.de>]

  *) Add ECDSA in new directory crypto/ecdsa/.

     Add applications 'openssl ecparam' and 'openssl ecdsa'
     (these are based on 'openssl dsaparam' and 'openssl dsa').

     ECDSA support is also included in various other files across the
     library.  Most notably,
     - 'openssl req' now has a '-newkey ecdsa:file' option;
     - EVP_PKCS82PKEY (crypto/evp/evp_pkey.c) now can handle ECDSA;
     - X509_PUBKEY_get (crypto/asn1/x_pubkey.c) and
       d2i_PublicKey (crypto/asn1/d2i_pu.c) have been modified to make
       them suitable for ECDSA where domain parameters must be
       extracted before the specific public key;
     - ECDSA engine support has been added.
     [Nils Larsch <nla@trustcenter.de>]

  *) Include some named elliptic curves, and add OIDs from X9.62,
     SECG, and WAP/WTLS.  Each curve can be obtained from the new
     function
          EC_GROUP_new_by_curve_name(),
     and the list of available named curves can be obtained with
          EC_get_builtin_curves().
     Also add a 'curve_name' member to EC_GROUP objects, which can be
     accessed via
         EC_GROUP_set_curve_name()
         EC_GROUP_get_curve_name()
     [Nils Larsch <larsch@trustcenter.de, Bodo Moeller]
 
  *) Remove a few calls to bn_wexpand() in BN_sqr() (the one in there
     was actually never needed) and in BN_mul().  The removal in BN_mul()
     required a small change in bn_mul_part_recursive() and the addition
     of the functions bn_cmp_part_words(), bn_sub_part_words() and
     bn_add_part_words(), which do the same thing as bn_cmp_words(),
     bn_sub_words() and bn_add_words() except they take arrays with
     differing sizes.
     [Richard Levitte]

 Changes between 0.9.7l and 0.9.7m  [23 Feb 2007]

  *) Cleanse PEM buffers before freeing them since they may contain 
     sensitive data.
     [Benjamin Bennett <ben@psc.edu>]

  *) Include "!eNULL" in SSL_DEFAULT_CIPHER_LIST to make sure that
     a ciphersuite string such as "DEFAULT:RSA" cannot enable
     authentication-only ciphersuites.
     [Bodo Moeller]

  *) Since AES128 and AES256 share a single mask bit in the logic of
     ssl/ssl_ciph.c, the code for masking out disabled ciphers needs a
     kludge to work properly if AES128 is available and AES256 isn't.
     [Victor Duchovni]

  *) Expand security boundary to match 1.1.1 module.
     [Steve Henson]

  *) Remove redundant features: hash file source, editing of test vectors
     modify fipsld to use external fips_premain.c signature.
     [Steve Henson]

  *) New perl script mkfipsscr.pl to create shell scripts or batch files to
     run algorithm test programs.
     [Steve Henson]

  *) Make algorithm test programs more tolerant of whitespace.
     [Steve Henson]

  *) Have SSL/TLS server implementation tolerate "mismatched" record
     protocol version while receiving ClientHello even if the
     ClientHello is fragmented.  (The server can't insist on the
     particular protocol version it has chosen before the ServerHello
     message has informed the client about his choice.)
     [Bodo Moeller]

  *) Load error codes if they are not already present instead of using a
     static variable. This allows them to be cleanly unloaded and reloaded.
     [Steve Henson]

 Changes between 0.9.7k and 0.9.7l  [28 Sep 2006]

  *) Introduce limits to prevent malicious keys being able to
     cause a denial of service.  (CVE-2006-2940)
     [Steve Henson, Bodo Moeller]

  *) Fix ASN.1 parsing of certain invalid structures that can result
     in a denial of service.  (CVE-2006-2937)  [Steve Henson]

  *) Fix buffer overflow in SSL_get_shared_ciphers() function. 
     (CVE-2006-3738) [Tavis Ormandy and Will Drewry, Google Security Team]

  *) Fix SSL client code which could crash if connecting to a
     malicious SSLv2 server.  (CVE-2006-4343)
     [Tavis Ormandy and Will Drewry, Google Security Team]

  *) Change ciphersuite string processing so that an explicit
     ciphersuite selects this one ciphersuite (so that "AES256-SHA"
     will no longer include "AES128-SHA"), and any other similar
     ciphersuite (same bitmap) from *other* protocol versions (so that
     "RC4-MD5" will still include both the SSL 2.0 ciphersuite and the
     SSL 3.0/TLS 1.0 ciphersuite).  This is a backport combining
     changes from 0.9.8b and 0.9.8d.
     [Bodo Moeller]

 Changes between 0.9.7j and 0.9.7k  [05 Sep 2006]

  *) Avoid PKCS #1 v1.5 signature attack discovered by Daniel Bleichenbacher
     (CVE-2006-4339)  [Ben Laurie and Google Security Team]

  *) Change the Unix randomness entropy gathering to use poll() when
     possible instead of select(), since the latter has some
     undesirable limitations.
     [Darryl Miles via Richard Levitte and Bodo Moeller]

  *) Disable rogue ciphersuites:

      - SSLv2 0x08 0x00 0x80 ("RC4-64-MD5")
      - SSLv3/TLSv1 0x00 0x61 ("EXP1024-RC2-CBC-MD5")
      - SSLv3/TLSv1 0x00 0x60 ("EXP1024-RC4-MD5")

     The latter two were purportedly from
     draft-ietf-tls-56-bit-ciphersuites-0[01].txt, but do not really
     appear there.

     Also deactive the remaining ciphersuites from
     draft-ietf-tls-56-bit-ciphersuites-01.txt.  These are just as
     unofficial, and the ID has long expired.
     [Bodo Moeller]

  *) Fix RSA blinding Heisenbug (problems sometimes occured on
     dual-core machines) and other potential thread-safety issues.
     [Bodo Moeller]

 Changes between 0.9.7i and 0.9.7j  [04 May 2006]

  *) Adapt fipsld and the build system to link against the validated FIPS
     module in FIPS mode.
     [Steve Henson]

  *) Fixes for VC++ 2005 build under Windows.
     [Steve Henson]

  *) Add new Windows build target VC-32-GMAKE for VC++. This uses GNU make 
     from a Windows bash shell such as MSYS. It is autodetected from the
     "config" script when run from a VC++ environment. Modify standard VC++
     build to use fipscanister.o from the GNU make build. 
     [Steve Henson]

 Changes between 0.9.7h and 0.9.7i  [14 Oct 2005]

  *) Wrapped the definition of EVP_MAX_MD_SIZE in a #ifdef OPENSSL_FIPS.
     The value now differs depending on if you build for FIPS or not.
     BEWARE!  A program linked with a shared FIPSed libcrypto can't be
     safely run with a non-FIPSed libcrypto, as it may crash because of
     the difference induced by this change.
     [Andy Polyakov]

 Changes between 0.9.7g and 0.9.7h  [11 Oct 2005]

  *) Remove the functionality of SSL_OP_MSIE_SSLV2_RSA_PADDING
     (part of SSL_OP_ALL).  This option used to disable the
     countermeasure against man-in-the-middle protocol-version
     rollback in the SSL 2.0 server implementation, which is a bad
     idea.  (CVE-2005-2969)

     [Bodo Moeller; problem pointed out by Yutaka Oiwa (Research Center
     for Information Security, National Institute of Advanced Industrial
     Science and Technology [AIST], Japan)]

  *) Minimal support for X9.31 signatures and PSS padding modes. This is
     mainly for FIPS compliance and not fully integrated at this stage.
     [Steve Henson]

  *) For DSA signing, unless DSA_FLAG_NO_EXP_CONSTTIME is set, perform
     the exponentiation using a fixed-length exponent.  (Otherwise,
     the information leaked through timing could expose the secret key
     after many signatures; cf. Bleichenbacher's attack on DSA with
     biased k.)
     [Bodo Moeller]

  *) Make a new fixed-window mod_exp implementation the default for
     RSA, DSA, and DH private-key operations so that the sequence of
     squares and multiplies and the memory access pattern are
     independent of the particular secret key.  This will mitigate
     cache-timing and potential related attacks.

     BN_mod_exp_mont_consttime() is the new exponentiation implementation,
     and this is automatically used by BN_mod_exp_mont() if the new flag
     BN_FLG_EXP_CONSTTIME is set for the exponent.  RSA, DSA, and DH
     will use this BN flag for private exponents unless the flag
     RSA_FLAG_NO_EXP_CONSTTIME, DSA_FLAG_NO_EXP_CONSTTIME, or
     DH_FLAG_NO_EXP_CONSTTIME, respectively, is set.

     [Matthew D Wood (Intel Corp), with some changes by Bodo Moeller]

  *) Change the client implementation for SSLv23_method() and
     SSLv23_client_method() so that is uses the SSL 3.0/TLS 1.0
     Client Hello message format if the SSL_OP_NO_SSLv2 option is set.
     (Previously, the SSL 2.0 backwards compatible Client Hello
     message format would be used even with SSL_OP_NO_SSLv2.)
     [Bodo Moeller]

  *) Add support for smime-type MIME parameter in S/MIME messages which some
     clients need.
     [Steve Henson]

  *) New function BN_MONT_CTX_set_locked() to set montgomery parameters in
     a threadsafe manner. Modify rsa code to use new function and add calls
     to dsa and dh code (which had race conditions before).
     [Steve Henson]

  *) Include the fixed error library code in the C error file definitions
     instead of fixing them up at runtime. This keeps the error code
     structures constant.
     [Steve Henson]

 Changes between 0.9.7f and 0.9.7g  [11 Apr 2005]

  [NB: OpenSSL 0.9.7h and later 0.9.7 patch levels were released after
  OpenSSL 0.9.8.]

  *) Fixes for newer kerberos headers. NB: the casts are needed because
     the 'length' field is signed on one version and unsigned on another
     with no (?) obvious way to tell the difference, without these VC++
     complains. Also the "definition" of FAR (blank) is no longer included
     nor is the error ENOMEM. KRB5_PRIVATE has to be set to 1 to pick up
     some needed definitions.
     [Steve Henson]

  *) Undo Cygwin change.
     [Ulf Möller]

  *) Added support for proxy certificates according to RFC 3820.
     Because they may be a security thread to unaware applications,
     they must be explicitely allowed in run-time.  See
     docs/HOWTO/proxy_certificates.txt for further information.
     [Richard Levitte]

 Changes between 0.9.7e and 0.9.7f  [22 Mar 2005]

  *) Use (SSL_RANDOM_VALUE - 4) bytes of pseudo random data when generating
     server and client random values. Previously
     (SSL_RANDOM_VALUE - sizeof(time_t)) would be used which would result in
     less random data when sizeof(time_t) > 4 (some 64 bit platforms).

     This change has negligible security impact because:

     1. Server and client random values still have 24 bytes of pseudo random
        data.

     2. Server and client random values are sent in the clear in the initial
        handshake.

     3. The master secret is derived using the premaster secret (48 bytes in
        size for static RSA ciphersuites) as well as client server and random
        values.

     The OpenSSL team would like to thank the UK NISCC for bringing this issue
     to our attention. 

     [Stephen Henson, reported by UK NISCC]

  *) Use Windows randomness collection on Cygwin.
     [Ulf Möller]

  *) Fix hang in EGD/PRNGD query when communication socket is closed
     prematurely by EGD/PRNGD.
     [Darren Tucker <dtucker@zip.com.au> via Lutz Jänicke, resolves #1014]

  *) Prompt for pass phrases when appropriate for PKCS12 input format.
     [Steve Henson]

  *) Back-port of selected performance improvements from development
     branch, as well as improved support for PowerPC platforms.
     [Andy Polyakov]

  *) Add lots of checks for memory allocation failure, error codes to indicate
     failure and freeing up memory if a failure occurs.
     [Nauticus Networks SSL Team <openssl@nauticusnet.com>, Steve Henson]

  *) Add new -passin argument to dgst.
     [Steve Henson]

  *) Perform some character comparisons of different types in X509_NAME_cmp:
     this is needed for some certificates that reencode DNs into UTF8Strings
     (in violation of RFC3280) and can't or wont issue name rollover
     certificates.
     [Steve Henson]

  *) Make an explicit check during certificate validation to see that
     the CA setting in each certificate on the chain is correct.  As a
     side effect always do the following basic checks on extensions,
     not just when there's an associated purpose to the check:

      - if there is an unhandled critical extension (unless the user
        has chosen to ignore this fault)
      - if the path length has been exceeded (if one is set at all)
      - that certain extensions fit the associated purpose (if one has
        been given)
     [Richard Levitte]

 Changes between 0.9.7d and 0.9.7e  [25 Oct 2004]

  *) Avoid a race condition when CRLs are checked in a multi threaded 
     environment. This would happen due to the reordering of the revoked
     entries during signature checking and serial number lookup. Now the
     encoding is cached and the serial number sort performed under a lock.
     Add new STACK function sk_is_sorted().
     [Steve Henson]

  *) Add Delta CRL to the extension code.
     [Steve Henson]

  *) Various fixes to s3_pkt.c so alerts are sent properly.
     [David Holmes <d.holmes@f5.com>]

  *) Reduce the chances of duplicate issuer name and serial numbers (in
     violation of RFC3280) using the OpenSSL certificate creation utilities.
     This is done by creating a random 64 bit value for the initial serial
     number when a serial number file is created or when a self signed
     certificate is created using 'openssl req -x509'. The initial serial
     number file is created using 'openssl x509 -next_serial' in CA.pl
     rather than being initialized to 1.
     [Steve Henson]

 Changes between 0.9.7c and 0.9.7d  [17 Mar 2004]

  *) Fix null-pointer assignment in do_change_cipher_spec() revealed           
     by using the Codenomicon TLS Test Tool (CVE-2004-0079)                    
     [Joe Orton, Steve Henson]   

  *) Fix flaw in SSL/TLS handshaking when using Kerberos ciphersuites
     (CVE-2004-0112)
     [Joe Orton, Steve Henson]   

  *) Make it possible to have multiple active certificates with the same
     subject in the CA index file.  This is done only if the keyword
     'unique_subject' is set to 'no' in the main CA section (default
     if 'CA_default') of the configuration file.  The value is saved
     with the database itself in a separate index attribute file,
     named like the index file with '.attr' appended to the name.
     [Richard Levitte]

  *) X509 verify fixes. Disable broken certificate workarounds when 
     X509_V_FLAGS_X509_STRICT is set. Check CRL issuer has cRLSign set if
     keyUsage extension present. Don't accept CRLs with unhandled critical
     extensions: since verify currently doesn't process CRL extensions this
     rejects a CRL with *any* critical extensions. Add new verify error codes
     for these cases.
     [Steve Henson]

  *) When creating an OCSP nonce use an OCTET STRING inside the extnValue.
     A clarification of RFC2560 will require the use of OCTET STRINGs and 
     some implementations cannot handle the current raw format. Since OpenSSL
     copies and compares OCSP nonces as opaque blobs without any attempt at
     parsing them this should not create any compatibility issues.
     [Steve Henson]

  *) New md flag EVP_MD_CTX_FLAG_REUSE this allows md_data to be reused when
     calling EVP_MD_CTX_copy_ex() to avoid calling OPENSSL_malloc(). Without
     this HMAC (and other) operations are several times slower than OpenSSL
     < 0.9.7.
     [Steve Henson]

  *) Print out GeneralizedTime and UTCTime in ASN1_STRING_print_ex().
     [Peter Sylvester <Peter.Sylvester@EdelWeb.fr>]

  *) Use the correct content when signing type "other".
     [Steve Henson]

 Changes between 0.9.7b and 0.9.7c  [30 Sep 2003]

  *) Fix various bugs revealed by running the NISCC test suite:

     Stop out of bounds reads in the ASN1 code when presented with
     invalid tags (CVE-2003-0543 and CVE-2003-0544).
     
     Free up ASN1_TYPE correctly if ANY type is invalid (CVE-2003-0545).

     If verify callback ignores invalid public key errors don't try to check
     certificate signature with the NULL public key.

     [Steve Henson]

  *) New -ignore_err option in ocsp application to stop the server
     exiting on the first error in a request.
     [Steve Henson]

  *) In ssl3_accept() (ssl/s3_srvr.c) only accept a client certificate
     if the server requested one: as stated in TLS 1.0 and SSL 3.0
     specifications.
     [Steve Henson]

  *) In ssl3_get_client_hello() (ssl/s3_srvr.c), tolerate additional
     extra data after the compression methods not only for TLS 1.0
     but also for SSL 3.0 (as required by the specification).
     [Bodo Moeller; problem pointed out by Matthias Loepfe]

  *) Change X509_certificate_type() to mark the key as exported/exportable
     when it's 512 *bits* long, not 512 bytes.
     [Richard Levitte]

  *) Change AES_cbc_encrypt() so it outputs exact multiple of
     blocks during encryption.
     [Richard Levitte]

  *) Various fixes to base64 BIO and non blocking I/O. On write 
     flushes were not handled properly if the BIO retried. On read
     data was not being buffered properly and had various logic bugs.
     This also affects blocking I/O when the data being decoded is a
     certain size.
     [Steve Henson]

  *) Various S/MIME bugfixes and compatibility changes:
     output correct application/pkcs7 MIME type if
     PKCS7_NOOLDMIMETYPE is set. Tolerate some broken signatures.
     Output CR+LF for EOL if PKCS7_CRLFEOL is set (this makes opening
     of files as .eml work). Correctly handle very long lines in MIME
     parser.
     [Steve Henson]

 Changes between 0.9.7a and 0.9.7b  [10 Apr 2003]

  *) Countermeasure against the Klima-Pokorny-Rosa extension of
     Bleichbacher's attack on PKCS #1 v1.5 padding: treat
     a protocol version number mismatch like a decryption error
     in ssl3_get_client_key_exchange (ssl/s3_srvr.c).
     [Bodo Moeller]

  *) Turn on RSA blinding by default in the default implementation
     to avoid a timing attack. Applications that don't want it can call
     RSA_blinding_off() or use the new flag RSA_FLAG_NO_BLINDING.
     They would be ill-advised to do so in most cases.
     [Ben Laurie, Steve Henson, Geoff Thorpe, Bodo Moeller]

  *) Change RSA blinding code so that it works when the PRNG is not
     seeded (in this case, the secret RSA exponent is abused as
     an unpredictable seed -- if it is not unpredictable, there
     is no point in blinding anyway).  Make RSA blinding thread-safe
     by remembering the creator's thread ID in rsa->blinding and
     having all other threads use local one-time blinding factors
     (this requires more computation than sharing rsa->blinding, but
     avoids excessive locking; and if an RSA object is not shared
     between threads, blinding will still be very fast).
     [Bodo Moeller]

  *) Fixed a typo bug that would cause ENGINE_set_default() to set an
     ENGINE as defaults for all supported algorithms irrespective of
     the 'flags' parameter. 'flags' is now honoured, so applications
     should make sure they are passing it correctly.
     [Geoff Thorpe]

  *) Target "mingw" now allows native Windows code to be generated in
     the Cygwin environment as well as with the MinGW compiler.
     [Ulf Moeller] 

 Changes between 0.9.7 and 0.9.7a  [19 Feb 2003]

  *) In ssl3_get_record (ssl/s3_pkt.c), minimize information leaked
     via timing by performing a MAC computation even if incorrrect
     block cipher padding has been found.  This is a countermeasure
     against active attacks where the attacker has to distinguish
     between bad padding and a MAC verification error. (CVE-2003-0078)

     [Bodo Moeller; problem pointed out by Brice Canvel (EPFL),
     Alain Hiltgen (UBS), Serge Vaudenay (EPFL), and
     Martin Vuagnoux (EPFL, Ilion)]

  *) Make the no-err option work as intended.  The intention with no-err
     is not to have the whole error stack handling routines removed from
     libcrypto, it's only intended to remove all the function name and
     reason texts, thereby removing some of the footprint that may not
     be interesting if those errors aren't displayed anyway.

     NOTE: it's still possible for any application or module to have it's
     own set of error texts inserted.  The routines are there, just not
     used by default when no-err is given.
     [Richard Levitte]

  *) Add support for FreeBSD on IA64.
     [dirk.meyer@dinoex.sub.org via Richard Levitte, resolves #454]

  *) Adjust DES_cbc_cksum() so it returns the same value as the MIT
     Kerberos function mit_des_cbc_cksum().  Before this change,
     the value returned by DES_cbc_cksum() was like the one from
     mit_des_cbc_cksum(), except the bytes were swapped.
     [Kevin Greaney <Kevin.Greaney@hp.com> and Richard Levitte]

  *) Allow an application to disable the automatic SSL chain building.
     Before this a rather primitive chain build was always performed in
     ssl3_output_cert_chain(): an application had no way to send the 
     correct chain if the automatic operation produced an incorrect result.

     Now the chain builder is disabled if either:

     1. Extra certificates are added via SSL_CTX_add_extra_chain_cert().

     2. The mode flag SSL_MODE_NO_AUTO_CHAIN is set.

     The reasoning behind this is that an application would not want the
     auto chain building to take place if extra chain certificates are
     present and it might also want a means of sending no additional
     certificates (for example the chain has two certificates and the
     root is omitted).
     [Steve Henson]

  *) Add the possibility to build without the ENGINE framework.
     [Steven Reddie <smr@essemer.com.au> via Richard Levitte]

  *) Under Win32 gmtime() can return NULL: check return value in
     OPENSSL_gmtime(). Add error code for case where gmtime() fails.
     [Steve Henson]

  *) DSA routines: under certain error conditions uninitialized BN objects
     could be freed. Solution: make sure initialization is performed early
     enough. (Reported and fix supplied by Ivan D Nestlerode <nestler@MIT.EDU>,
     Nils Larsch <nla@trustcenter.de> via PR#459)
     [Lutz Jaenicke]

  *) Another fix for SSLv2 session ID handling: the session ID was incorrectly
     checked on reconnect on the client side, therefore session resumption
     could still fail with a "ssl session id is different" error. This
     behaviour is masked when SSL_OP_ALL is used due to
     SSL_OP_MICROSOFT_SESS_ID_BUG being set.
     Behaviour observed by Crispin Flowerday <crispin@flowerday.cx> as
     followup to PR #377.
     [Lutz Jaenicke]

  *) IA-32 assembler support enhancements: unified ELF targets, support
     for SCO/Caldera platforms, fix for Cygwin shared build.
     [Andy Polyakov]

  *) Add support for FreeBSD on sparc64.  As a consequence, support for
     FreeBSD on non-x86 processors is separate from x86 processors on
     the config script, much like the NetBSD support.
     [Richard Levitte & Kris Kennaway <kris@obsecurity.org>]

 Changes between 0.9.6h and 0.9.7  [31 Dec 2002]

  [NB: OpenSSL 0.9.6i and later 0.9.6 patch levels were released after
  OpenSSL 0.9.7.]

  *) Fix session ID handling in SSLv2 client code: the SERVER FINISHED
     code (06) was taken as the first octet of the session ID and the last
     octet was ignored consequently. As a result SSLv2 client side session
     caching could not have worked due to the session ID mismatch between
     client and server.
     Behaviour observed by Crispin Flowerday <crispin@flowerday.cx> as
     PR #377.
     [Lutz Jaenicke]

  *) Change the declaration of needed Kerberos libraries to use EX_LIBS
     instead of the special (and badly supported) LIBKRB5.  LIBKRB5 is
     removed entirely.
     [Richard Levitte]

  *) The hw_ncipher.c engine requires dynamic locks.  Unfortunately, it
     seems that in spite of existing for more than a year, many application
     author have done nothing to provide the necessary callbacks, which
     means that this particular engine will not work properly anywhere.
     This is a very unfortunate situation which forces us, in the name
     of usability, to give the hw_ncipher.c a static lock, which is part
     of libcrypto.
     NOTE: This is for the 0.9.7 series ONLY.  This hack will never
     appear in 0.9.8 or later.  We EXPECT application authors to have
     dealt properly with this when 0.9.8 is released (unless we actually
     make such changes in the libcrypto locking code that changes will
     have to be made anyway).
     [Richard Levitte]

  *) In asn1_d2i_read_bio() repeatedly call BIO_read() until all content
     octets have been read, EOF or an error occurs. Without this change
     some truncated ASN1 structures will not produce an error.
     [Steve Henson]

  *) Disable Heimdal support, since it hasn't been fully implemented.
     Still give the possibility to force the use of Heimdal, but with
     warnings and a request that patches get sent to openssl-dev.
     [Richard Levitte]

  *) Add the VC-CE target, introduce the WINCE sysname, and add
     INSTALL.WCE and appropriate conditionals to make it build.
     [Steven Reddie <smr@essemer.com.au> via Richard Levitte]

  *) Change the DLL names for Cygwin to cygcrypto-x.y.z.dll and
     cygssl-x.y.z.dll, where x, y and z are the major, minor and
     edit numbers of the version.
     [Corinna Vinschen <vinschen@redhat.com> and Richard Levitte]

  *) Introduce safe string copy and catenation functions
     (BUF_strlcpy() and BUF_strlcat()).
     [Ben Laurie (CHATS) and Richard Levitte]

  *) Avoid using fixed-size buffers for one-line DNs.
     [Ben Laurie (CHATS)]

  *) Add BUF_MEM_grow_clean() to avoid information leakage when
     resizing buffers containing secrets, and use where appropriate.
     [Ben Laurie (CHATS)]

  *) Avoid using fixed size buffers for configuration file location.
     [Ben Laurie (CHATS)]

  *) Avoid filename truncation for various CA files.
     [Ben Laurie (CHATS)]

  *) Use sizeof in preference to magic numbers.
     [Ben Laurie (CHATS)]

  *) Avoid filename truncation in cert requests.
     [Ben Laurie (CHATS)]

  *) Add assertions to check for (supposedly impossible) buffer
     overflows.
     [Ben Laurie (CHATS)]

  *) Don't cache truncated DNS entries in the local cache (this could
     potentially lead to a spoofing attack).
     [Ben Laurie (CHATS)]

  *) Fix various buffers to be large enough for hex/decimal
     representations in a platform independent manner.
     [Ben Laurie (CHATS)]

  *) Add CRYPTO_realloc_clean() to avoid information leakage when
     resizing buffers containing secrets, and use where appropriate.
     [Ben Laurie (CHATS)]

  *) Add BIO_indent() to avoid much slightly worrying code to do
     indents.
     [Ben Laurie (CHATS)]

  *) Convert sprintf()/BIO_puts() to BIO_printf().
     [Ben Laurie (CHATS)]

  *) buffer_gets() could terminate with the buffer only half
     full. Fixed.
     [Ben Laurie (CHATS)]

  *) Add assertions to prevent user-supplied crypto functions from
     overflowing internal buffers by having large block sizes, etc.
     [Ben Laurie (CHATS)]

  *) New OPENSSL_assert() macro (similar to assert(), but enabled
     unconditionally).
     [Ben Laurie (CHATS)]

  *) Eliminate unused copy of key in RC4.
     [Ben Laurie (CHATS)]

  *) Eliminate unused and incorrectly sized buffers for IV in pem.h.
     [Ben Laurie (CHATS)]

  *) Fix off-by-one error in EGD path.
     [Ben Laurie (CHATS)]

  *) If RANDFILE path is too long, ignore instead of truncating.
     [Ben Laurie (CHATS)]

  *) Eliminate unused and incorrectly sized X.509 structure
     CBCParameter.
     [Ben Laurie (CHATS)]

  *) Eliminate unused and dangerous function knumber().
     [Ben Laurie (CHATS)]

  *) Eliminate unused and dangerous structure, KSSL_ERR.
     [Ben Laurie (CHATS)]

  *) Protect against overlong session ID context length in an encoded
     session object. Since these are local, this does not appear to be
     exploitable.
     [Ben Laurie (CHATS)]

  *) Change from security patch (see 0.9.6e below) that did not affect
     the 0.9.6 release series:

     Remote buffer overflow in SSL3 protocol - an attacker could
     supply an oversized master key in Kerberos-enabled versions.
     (CVE-2002-0657)
     [Ben Laurie (CHATS)]

  *) Change the SSL kerb5 codes to match RFC 2712.
     [Richard Levitte]

  *) Make -nameopt work fully for req and add -reqopt switch.
     [Michael Bell <michael.bell@rz.hu-berlin.de>, Steve Henson]

  *) The "block size" for block ciphers in CFB and OFB mode should be 1.
     [Steve Henson, reported by Yngve Nysaeter Pettersen <yngve@opera.com>]

  *) Make sure tests can be performed even if the corresponding algorithms
     have been removed entirely.  This was also the last step to make
     OpenSSL compilable with DJGPP under all reasonable conditions.
     [Richard Levitte, Doug Kaufman <dkaufman@rahul.net>]

  *) Add cipher selection rules COMPLEMENTOFALL and COMPLEMENTOFDEFAULT
     to allow version independent disabling of normally unselected ciphers,
     which may be activated as a side-effect of selecting a single cipher.

     (E.g., cipher list string "RSA" enables ciphersuites that are left
     out of "ALL" because they do not provide symmetric encryption.
     "RSA:!COMPLEMEMENTOFALL" avoids these unsafe ciphersuites.)
     [Lutz Jaenicke, Bodo Moeller]

  *) Add appropriate support for separate platform-dependent build
     directories.  The recommended way to make a platform-dependent
     build directory is the following (tested on Linux), maybe with
     some local tweaks:

	# Place yourself outside of the OpenSSL source tree.  In
	# this example, the environment variable OPENSSL_SOURCE
	# is assumed to contain the absolute OpenSSL source directory.
	mkdir -p objtree/"`uname -s`-`uname -r`-`uname -m`"
	cd objtree/"`uname -s`-`uname -r`-`uname -m`"
	(cd $OPENSSL_SOURCE; find . -type f) | while read F; do
		mkdir -p `dirname $F`
		ln -s $OPENSSL_SOURCE/$F $F
	done

     To be absolutely sure not to disturb the source tree, a "make clean"
     is a good thing.  If it isn't successfull, don't worry about it,
     it probably means the source directory is very clean.
     [Richard Levitte]

  *) Make sure any ENGINE control commands make local copies of string
     pointers passed to them whenever necessary. Otherwise it is possible
     the caller may have overwritten (or deallocated) the original string
     data when a later ENGINE operation tries to use the stored values.
     [Götz Babin-Ebell <babinebell@trustcenter.de>]

  *) Improve diagnostics in file reading and command-line digests.
     [Ben Laurie aided and abetted by Solar Designer <solar@openwall.com>]

  *) Add AES modes CFB and OFB to the object database.  Correct an
     error in AES-CFB decryption.
     [Richard Levitte]

  *) Remove most calls to EVP_CIPHER_CTX_cleanup() in evp_enc.c, this 
     allows existing EVP_CIPHER_CTX structures to be reused after
     calling EVP_*Final(). This behaviour is used by encryption
     BIOs and some applications. This has the side effect that
     applications must explicitly clean up cipher contexts with
     EVP_CIPHER_CTX_cleanup() or they will leak memory.
     [Steve Henson]

  *) Check the values of dna and dnb in bn_mul_recursive before calling
     bn_mul_comba (a non zero value means the a or b arrays do not contain
     n2 elements) and fallback to bn_mul_normal if either is not zero.
     [Steve Henson]

  *) Fix escaping of non-ASCII characters when using the -subj option
     of the "openssl req" command line tool. (Robert Joop <joop@fokus.gmd.de>)
     [Lutz Jaenicke]

  *) Make object definitions compliant to LDAP (RFC2256): SN is the short
     form for "surname", serialNumber has no short form.
     Use "mail" as the short name for "rfc822Mailbox" according to RFC2798;
     therefore remove "mail" short name for "internet 7".
     The OID for unique identifiers in X509 certificates is
     x500UniqueIdentifier, not uniqueIdentifier.
     Some more OID additions. (Michael Bell <michael.bell@rz.hu-berlin.de>)
     [Lutz Jaenicke]

  *) Add an "init" command to the ENGINE config module and auto initialize
     ENGINEs. Without any "init" command the ENGINE will be initialized 
     after all ctrl commands have been executed on it. If init=1 the 
     ENGINE is initailized at that point (ctrls before that point are run
     on the uninitialized ENGINE and after on the initialized one). If
     init=0 then the ENGINE will not be iniatialized at all.
     [Steve Henson]

  *) Fix the 'app_verify_callback' interface so that the user-defined
     argument is actually passed to the callback: In the
     SSL_CTX_set_cert_verify_callback() prototype, the callback
     declaration has been changed from
          int (*cb)()
     into
          int (*cb)(X509_STORE_CTX *,void *);
     in ssl_verify_cert_chain (ssl/ssl_cert.c), the call
          i=s->ctx->app_verify_callback(&ctx)
     has been changed into
          i=s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg).

     To update applications using SSL_CTX_set_cert_verify_callback(),
     a dummy argument can be added to their callback functions.
     [D. K. Smetters <smetters@parc.xerox.com>]

  *) Added the '4758cca' ENGINE to support IBM 4758 cards.
     [Maurice Gittens <maurice@gittens.nl>, touchups by Geoff Thorpe]

  *) Add and OPENSSL_LOAD_CONF define which will cause
     OpenSSL_add_all_algorithms() to load the openssl.cnf config file.
     This allows older applications to transparently support certain
     OpenSSL features: such as crypto acceleration and dynamic ENGINE loading.
     Two new functions OPENSSL_add_all_algorithms_noconf() which will never
     load the config file and OPENSSL_add_all_algorithms_conf() which will
     always load it have also been added.
     [Steve Henson]

  *) Add the OFB, CFB and CTR (all with 128 bit feedback) to AES.
     Adjust NIDs and EVP layer.
     [Stephen Sprunk <stephen@sprunk.org> and Richard Levitte]

  *) Config modules support in openssl utility.

     Most commands now load modules from the config file,
     though in a few (such as version) this isn't done 
     because it couldn't be used for anything.

     In the case of ca and req the config file used is
     the same as the utility itself: that is the -config
     command line option can be used to specify an
     alternative file.
     [Steve Henson]

  *) Move default behaviour from OPENSSL_config(). If appname is NULL
     use "openssl_conf" if filename is NULL use default openssl config file.
     [Steve Henson]

  *) Add an argument to OPENSSL_config() to allow the use of an alternative
     config section name. Add a new flag to tolerate a missing config file
     and move code to CONF_modules_load_file().
     [Steve Henson]

  *) Support for crypto accelerator cards from Accelerated Encryption
     Processing, www.aep.ie.  (Use engine 'aep')
     The support was copied from 0.9.6c [engine] and adapted/corrected
     to work with the new engine framework.
     [AEP Inc. and Richard Levitte]

  *) Support for SureWare crypto accelerator cards from Baltimore
     Technologies.  (Use engine 'sureware')
     The support was copied from 0.9.6c [engine] and adapted
     to work with the new engine framework.
     [Richard Levitte]

  *) Have the CHIL engine fork-safe (as defined by nCipher) and actually
     make the newer ENGINE framework commands for the CHIL engine work.
     [Toomas Kiisk <vix@cyber.ee> and Richard Levitte]

  *) Make it possible to produce shared libraries on ReliantUNIX.
     [Robert Dahlem <Robert.Dahlem@ffm2.siemens.de> via Richard Levitte]

  *) Add the configuration target debug-linux-ppro.
     Make 'openssl rsa' use the general key loading routines
     implemented in apps.c, and make those routines able to
     handle the key format FORMAT_NETSCAPE and the variant
     FORMAT_IISSGC.
     [Toomas Kiisk <vix@cyber.ee> via Richard Levitte]

 *) Fix a crashbug and a logic bug in hwcrhk_load_pubkey().
     [Toomas Kiisk <vix@cyber.ee> via Richard Levitte]

  *) Add -keyform to rsautl, and document -engine.
     [Richard Levitte, inspired by Toomas Kiisk <vix@cyber.ee>]

  *) Change BIO_new_file (crypto/bio/bss_file.c) to use new
     BIO_R_NO_SUCH_FILE error code rather than the generic
     ERR_R_SYS_LIB error code if fopen() fails with ENOENT.
     [Ben Laurie]

  *) Add new functions
          ERR_peek_last_error
          ERR_peek_last_error_line
          ERR_peek_last_error_line_data.
     These are similar to
          ERR_peek_error
          ERR_peek_error_line
          ERR_peek_error_line_data,
     but report on the latest error recorded rather than the first one
     still in the error queue.
     [Ben Laurie, Bodo Moeller]
        
  *) default_algorithms option in ENGINE config module. This allows things
     like:
     default_algorithms = ALL
     default_algorithms = RSA, DSA, RAND, CIPHERS, DIGESTS
     [Steve Henson]

  *) Prelminary ENGINE config module.
     [Steve Henson]

  *) New experimental application configuration code.
     [Steve Henson]

  *) Change the AES code to follow the same name structure as all other
     symmetric ciphers, and behave the same way.  Move everything to
     the directory crypto/aes, thereby obsoleting crypto/rijndael.
     [Stephen Sprunk <stephen@sprunk.org> and Richard Levitte]

  *) SECURITY: remove unsafe setjmp/signal interaction from ui_openssl.c.
     [Ben Laurie and Theo de Raadt]

  *) Add option to output public keys in req command.
     [Massimiliano Pala madwolf@openca.org]

  *) Use wNAFs in EC_POINTs_mul() for improved efficiency
     (up to about 10% better than before for P-192 and P-224).
     [Bodo Moeller]

  *) New functions/macros

          SSL_CTX_set_msg_callback(ctx, cb)
          SSL_CTX_set_msg_callback_arg(ctx, arg)
          SSL_set_msg_callback(ssl, cb)
          SSL_set_msg_callback_arg(ssl, arg)

     to request calling a callback function

          void cb(int write_p, int version, int content_type,
                  const void *buf, size_t len, SSL *ssl, void *arg)

     whenever a protocol message has been completely received
     (write_p == 0) or sent (write_p == 1).  Here 'version' is the
     protocol version  according to which the SSL library interprets
     the current protocol message (SSL2_VERSION, SSL3_VERSION, or
     TLS1_VERSION).  'content_type' is 0 in the case of SSL 2.0, or
     the content type as defined in the SSL 3.0/TLS 1.0 protocol
     specification (change_cipher_spec(20), alert(21), handshake(22)).
     'buf' and 'len' point to the actual message, 'ssl' to the
     SSL object, and 'arg' is the application-defined value set by
     SSL[_CTX]_set_msg_callback_arg().

     'openssl s_client' and 'openssl s_server' have new '-msg' options
     to enable a callback that displays all protocol messages.
     [Bodo Moeller]

  *) Change the shared library support so shared libraries are built as
     soon as the corresponding static library is finished, and thereby get
     openssl and the test programs linked against the shared library.
     This still only happens when the keyword "shard" has been given to
     the configuration scripts.

     NOTE: shared library support is still an experimental thing, and
     backward binary compatibility is still not guaranteed.
     ["Maciej W. Rozycki" <macro@ds2.pg.gda.pl> and Richard Levitte]

  *) Add support for Subject Information Access extension.
     [Peter Sylvester <Peter.Sylvester@EdelWeb.fr>]

  *) Make BUF_MEM_grow() behaviour more consistent: Initialise to zero
     additional bytes when new memory had to be allocated, not just
     when reusing an existing buffer.
     [Bodo Moeller]

  *) New command line and configuration option 'utf8' for the req command.
     This allows field values to be specified as UTF8 strings.
     [Steve Henson]

  *) Add -multi and -mr options to "openssl speed" - giving multiple parallel
     runs for the former and machine-readable output for the latter.
     [Ben Laurie]

  *) Add '-noemailDN' option to 'openssl ca'.  This prevents inclusion
     of the e-mail address in the DN (i.e., it will go into a certificate
     extension only).  The new configuration file option 'email_in_dn = no'
     has the same effect.
     [Massimiliano Pala madwolf@openca.org]

  *) Change all functions with names starting with des_ to be starting
     with DES_ instead.  Add wrappers that are compatible with libdes,
     but are named _ossl_old_des_*.  Finally, add macros that map the
     des_* symbols to the corresponding _ossl_old_des_* if libdes
     compatibility is desired.  If OpenSSL 0.9.6c compatibility is
     desired, the des_* symbols will be mapped to DES_*, with one
     exception.

     Since we provide two compatibility mappings, the user needs to
     define the macro OPENSSL_DES_LIBDES_COMPATIBILITY if libdes
     compatibility is desired.  The default (i.e., when that macro
     isn't defined) is OpenSSL 0.9.6c compatibility.

     There are also macros that enable and disable the support of old
     des functions altogether.  Those are OPENSSL_ENABLE_OLD_DES_SUPPORT
     and OPENSSL_DISABLE_OLD_DES_SUPPORT.  If none or both of those
     are defined, the default will apply: to support the old des routines.

     In either case, one must include openssl/des.h to get the correct
     definitions.  Do not try to just include openssl/des_old.h, that
     won't work.

     NOTE: This is a major break of an old API into a new one.  Software
     authors are encouraged to switch to the DES_ style functions.  Some
     time in the future, des_old.h and the libdes compatibility functions
     will be disable (i.e. OPENSSL_DISABLE_OLD_DES_SUPPORT will be the
     default), and then completely removed.
     [Richard Levitte]

  *) Test for certificates which contain unsupported critical extensions.
     If such a certificate is found during a verify operation it is 
     rejected by default: this behaviour can be overridden by either
     handling the new error X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION or
     by setting the verify flag X509_V_FLAG_IGNORE_CRITICAL. A new function
     X509_supported_extension() has also been added which returns 1 if a
     particular extension is supported.
     [Steve Henson]

  *) Modify the behaviour of EVP cipher functions in similar way to digests
     to retain compatibility with existing code.
     [Steve Henson]

  *) Modify the behaviour of EVP_DigestInit() and EVP_DigestFinal() to retain
     compatibility with existing code. In particular the 'ctx' parameter does
     not have to be to be initialized before the call to EVP_DigestInit() and
     it is tidied up after a call to EVP_DigestFinal(). New function
     EVP_DigestFinal_ex() which does not tidy up the ctx. Similarly function
     EVP_MD_CTX_copy() changed to not require the destination to be
     initialized valid and new function EVP_MD_CTX_copy_ex() added which
     requires the destination to be valid.

     Modify all the OpenSSL digest calls to use EVP_DigestInit_ex(),
     EVP_DigestFinal_ex() and EVP_MD_CTX_copy_ex().
     [Steve Henson]

  *) Change ssl3_get_message (ssl/s3_both.c) and the functions using it
     so that complete 'Handshake' protocol structures are kept in memory
     instead of overwriting 'msg_type' and 'length' with 'body' data.
     [Bodo Moeller]

  *) Add an implementation of SSL_add_dir_cert_subjects_to_stack for Win32.
     [Massimo Santin via Richard Levitte]

  *) Major restructuring to the underlying ENGINE code. This includes
     reduction of linker bloat, separation of pure "ENGINE" manipulation
     (initialisation, etc) from functionality dealing with implementations
     of specific crypto iterfaces. This change also introduces integrated
     support for symmetric ciphers and digest implementations - so ENGINEs
     can now accelerate these by providing EVP_CIPHER and EVP_MD
     implementations of their own. This is detailed in crypto/engine/README
     as it couldn't be adequately described here. However, there are a few
     API changes worth noting - some RSA, DSA, DH, and RAND functions that
     were changed in the original introduction of ENGINE code have now
     reverted back - the hooking from this code to ENGINE is now a good
     deal more passive and at run-time, operations deal directly with
     RSA_METHODs, DSA_METHODs (etc) as they did before, rather than
     dereferencing through an ENGINE pointer any more. Also, the ENGINE
     functions dealing with BN_MOD_EXP[_CRT] handlers have been removed -
     they were not being used by the framework as there is no concept of a
     BIGNUM_METHOD and they could not be generalised to the new
     'ENGINE_TABLE' mechanism that underlies the new code. Similarly,
     ENGINE_cpy() has been removed as it cannot be consistently defined in
     the new code.
     [Geoff Thorpe]

  *) Change ASN1_GENERALIZEDTIME_check() to allow fractional seconds.
     [Steve Henson]

  *) Change mkdef.pl to sort symbols that get the same entry number,
     and make sure the automatically generated functions ERR_load_*
     become part of libeay.num as well.
     [Richard Levitte]

  *) New function SSL_renegotiate_pending().  This returns true once
     renegotiation has been requested (either SSL_renegotiate() call
     or HelloRequest/ClientHello receveived from the peer) and becomes
     false once a handshake has been completed.
     (For servers, SSL_renegotiate() followed by SSL_do_handshake()
     sends a HelloRequest, but does not ensure that a handshake takes
     place.  SSL_renegotiate_pending() is useful for checking if the
     client has followed the request.)
     [Bodo Moeller]

  *) New SSL option SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION.
     By default, clients may request session resumption even during
     renegotiation (if session ID contexts permit); with this option,
     session resumption is possible only in the first handshake.

     SSL_OP_ALL is now 0x00000FFFL instead of 0x000FFFFFL.  This makes
     more bits available for options that should not be part of
     SSL_OP_ALL (such as SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION).
     [Bodo Moeller]

  *) Add some demos for certificate and certificate request creation.
     [Steve Henson]

  *) Make maximum certificate chain size accepted from the peer application
     settable (SSL*_get/set_max_cert_list()), as proposed by
     "Douglas E. Engert" <deengert@anl.gov>.
     [Lutz Jaenicke]

  *) Add support for shared libraries for Unixware-7
     (Boyd Lynn Gerber <gerberb@zenez.com>).
     [Lutz Jaenicke]

  *) Add a "destroy" handler to ENGINEs that allows structural cleanup to
     be done prior to destruction. Use this to unload error strings from
     ENGINEs that load their own error strings. NB: This adds two new API
     functions to "get" and "set" this destroy handler in an ENGINE.
     [Geoff Thorpe]

  *) Alter all existing ENGINE implementations (except "openssl" and
     "openbsd") to dynamically instantiate their own error strings. This
     makes them more flexible to be built both as statically-linked ENGINEs
     and self-contained shared-libraries loadable via the "dynamic" ENGINE.
     Also, add stub code to each that makes building them as self-contained
     shared-libraries easier (see README.ENGINE).
     [Geoff Thorpe]

  *) Add a "dynamic" ENGINE that provides a mechanism for binding ENGINE
     implementations into applications that are completely implemented in
     self-contained shared-libraries. The "dynamic" ENGINE exposes control
     commands that can be used to configure what shared-library to load and
     to control aspects of the way it is handled. Also, made an update to
     the README.ENGINE file that brings its information up-to-date and
     provides some information and instructions on the "dynamic" ENGINE
     (ie. how to use it, how to build "dynamic"-loadable ENGINEs, etc).
     [Geoff Thorpe]

  *) Make it possible to unload ranges of ERR strings with a new
     "ERR_unload_strings" function.
     [Geoff Thorpe]

  *) Add a copy() function to EVP_MD.
     [Ben Laurie]

  *) Make EVP_MD routines take a context pointer instead of just the
     md_data void pointer.
     [Ben Laurie]

  *) Add flags to EVP_MD and EVP_MD_CTX. EVP_MD_FLAG_ONESHOT indicates
     that the digest can only process a single chunk of data
     (typically because it is provided by a piece of
     hardware). EVP_MD_CTX_FLAG_ONESHOT indicates that the application
     is only going to provide a single chunk of data, and hence the
     framework needn't accumulate the data for oneshot drivers.
     [Ben Laurie]

  *) As with "ERR", make it possible to replace the underlying "ex_data"
     functions. This change also alters the storage and management of global
     ex_data state - it's now all inside ex_data.c and all "class" code (eg.
     RSA, BIO, SSL_CTX, etc) no longer stores its own STACKS and per-class
     index counters. The API functions that use this state have been changed
     to take a "class_index" rather than pointers to the class's local STACK
     and counter, and there is now an API function to dynamically create new
     classes. This centralisation allows us to (a) plug a lot of the
     thread-safety problems that existed, and (b) makes it possible to clean
     up all allocated state using "CRYPTO_cleanup_all_ex_data()". W.r.t. (b)
     such data would previously have always leaked in application code and
     workarounds were in place to make the memory debugging turn a blind eye
     to it. Application code that doesn't use this new function will still
     leak as before, but their memory debugging output will announce it now
     rather than letting it slide.

     Besides the addition of CRYPTO_cleanup_all_ex_data(), another API change
     induced by the "ex_data" overhaul is that X509_STORE_CTX_init() now
     has a return value to indicate success or failure.
     [Geoff Thorpe]

  *) Make it possible to replace the underlying "ERR" functions such that the
     global state (2 LHASH tables and 2 locks) is only used by the "default"
     implementation. This change also adds two functions to "get" and "set"
     the implementation prior to it being automatically set the first time
     any other ERR function takes place. Ie. an application can call "get",
     pass the return value to a module it has just loaded, and that module
     can call its own "set" function using that value. This means the
     module's "ERR" operations will use (and modify) the error state in the
     application and not in its own statically linked copy of OpenSSL code.
     [Geoff Thorpe]

  *) Give DH, DSA, and RSA types their own "**_up_ref()" function to increment
     reference counts. This performs normal REF_PRINT/REF_CHECK macros on
     the operation, and provides a more encapsulated way for external code
     (crypto/evp/ and ssl/) to do this. Also changed the evp and ssl code
     to use these functions rather than manually incrementing the counts.

     Also rename "DSO_up()" function to more descriptive "DSO_up_ref()".
     [Geoff Thorpe]

  *) Add EVP test program.
     [Ben Laurie]

  *) Add symmetric cipher support to ENGINE. Expect the API to change!
     [Ben Laurie]

  *) New CRL functions: X509_CRL_set_version(), X509_CRL_set_issuer_name()
     X509_CRL_set_lastUpdate(), X509_CRL_set_nextUpdate(), X509_CRL_sort(),
     X509_REVOKED_set_serialNumber(), and X509_REVOKED_set_revocationDate().
     These allow a CRL to be built without having to access X509_CRL fields
     directly. Modify 'ca' application to use new functions.
     [Steve Henson]

  *) Move SSL_OP_TLS_ROLLBACK_BUG out of the SSL_OP_ALL list of recommended
     bug workarounds. Rollback attack detection is a security feature.
     The problem will only arise on OpenSSL servers when TLSv1 is not
     available (sslv3_server_method() or SSL_OP_NO_TLSv1).
     Software authors not wanting to support TLSv1 will have special reasons
     for their choice and can explicitly enable this option.
     [Bodo Moeller, Lutz Jaenicke]

  *) Rationalise EVP so it can be extended: don't include a union of
     cipher/digest structures, add init/cleanup functions for EVP_MD_CTX
     (similar to those existing for EVP_CIPHER_CTX).
     Usage example:

         EVP_MD_CTX md;

         EVP_MD_CTX_init(&md);             /* new function call */
         EVP_DigestInit(&md, EVP_sha1());
         EVP_DigestUpdate(&md, in, len);
         EVP_DigestFinal(&md, out, NULL);
         EVP_MD_CTX_cleanup(&md);          /* new function call */

     [Ben Laurie]

  *) Make DES key schedule conform to the usual scheme, as well as
     correcting its structure. This means that calls to DES functions
     now have to pass a pointer to a des_key_schedule instead of a
     plain des_key_schedule (which was actually always a pointer
     anyway): E.g.,

         des_key_schedule ks;

	 des_set_key_checked(..., &ks);
	 des_ncbc_encrypt(..., &ks, ...);

     (Note that a later change renames 'des_...' into 'DES_...'.)
     [Ben Laurie]

  *) Initial reduction of linker bloat: the use of some functions, such as
     PEM causes large amounts of unused functions to be linked in due to
     poor organisation. For example pem_all.c contains every PEM function
     which has a knock on effect of linking in large amounts of (unused)
     ASN1 code. Grouping together similar functions and splitting unrelated
     functions prevents this.
     [Steve Henson]

  *) Cleanup of EVP macros.
     [Ben Laurie]

  *) Change historical references to {NID,SN,LN}_des_ede and ede3 to add the
     correct _ecb suffix.
     [Ben Laurie]

  *) Add initial OCSP responder support to ocsp application. The
     revocation information is handled using the text based index
     use by the ca application. The responder can either handle
     requests generated internally, supplied in files (for example
     via a CGI script) or using an internal minimal server.
     [Steve Henson]

  *) Add configuration choices to get zlib compression for TLS.
     [Richard Levitte]

  *) Changes to Kerberos SSL for RFC 2712 compliance:
     1.  Implemented real KerberosWrapper, instead of just using
         KRB5 AP_REQ message.  [Thanks to Simon Wilkinson <sxw@sxw.org.uk>]
     2.  Implemented optional authenticator field of KerberosWrapper.

     Added openssl-style ASN.1 macros for Kerberos ticket, ap_req,
     and authenticator structs; see crypto/krb5/.

     Generalized Kerberos calls to support multiple Kerberos libraries.
     [Vern Staats <staatsvr@asc.hpc.mil>,
      Jeffrey Altman <jaltman@columbia.edu>
      via Richard Levitte]

  *) Cause 'openssl speed' to use fully hard-coded DSA keys as it
     already does with RSA. testdsa.h now has 'priv_key/pub_key'
     values for each of the key sizes rather than having just
     parameters (and 'speed' generating keys each time).
     [Geoff Thorpe]

  *) Speed up EVP routines.
     Before:
encrypt
type              8 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
des-cbc           4408.85k     5560.51k     5778.46k     5862.20k     5825.16k
des-cbc           4389.55k     5571.17k     5792.23k     5846.91k     5832.11k
des-cbc           4394.32k     5575.92k     5807.44k     5848.37k     5841.30k
decrypt
des-cbc           3482.66k     5069.49k     5496.39k     5614.16k     5639.28k
des-cbc           3480.74k     5068.76k     5510.34k     5609.87k     5635.52k
des-cbc           3483.72k     5067.62k     5504.60k     5708.01k     5724.80k
     After:
encrypt
des-cbc           4660.16k     5650.19k     5807.19k     5827.13k     5783.32k
decrypt
des-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
     [Ben Laurie]

  *) Added the OS2-EMX target.
     ["Brian Havard" <brianh@kheldar.apana.org.au> and Richard Levitte]

  *) Rewrite apps to use NCONF routines instead of the old CONF. New functions
     to support NCONF routines in extension code. New function CONF_set_nconf()
     to allow functions which take an NCONF to also handle the old LHASH
     structure: this means that the old CONF compatible routines can be
     retained (in particular wrt extensions) without having to duplicate the
     code. New function X509V3_add_ext_nconf_sk to add extensions to a stack.
     [Steve Henson]

  *) Enhance the general user interface with mechanisms for inner control
     and with possibilities to have yes/no kind of prompts.
     [Richard Levitte]

  *) Change all calls to low level digest routines in the library and
     applications to use EVP. Add missing calls to HMAC_cleanup() and
     don't assume HMAC_CTX can be copied using memcpy().
     [Verdon Walker <VWalker@novell.com>, Steve Henson]

  *) Add the possibility to control engines through control names but with
     arbitrary arguments instead of just a string.
     Change the key loaders to take a UI_METHOD instead of a callback
     function pointer.  NOTE: this breaks binary compatibility with earlier
     versions of OpenSSL [engine].
     Adapt the nCipher code for these new conditions and add a card insertion
     callback.
     [Richard Levitte]

  *) Enhance the general user interface with mechanisms to better support
     dialog box interfaces, application-defined prompts, the possibility
     to use defaults (for example default passwords from somewhere else)
     and interrupts/cancellations.
     [Richard Levitte]

  *) Tidy up PKCS#12 attribute handling. Add support for the CSP name
     attribute in PKCS#12 files, add new -CSP option to pkcs12 utility.
     [Steve Henson]

  *) Fix a memory leak in 'sk_dup()' in the case reallocation fails. (Also
     tidy up some unnecessarily weird code in 'sk_new()').
     [Geoff, reported by Diego Tartara <dtartara@novamens.com>]

  *) Change the key loading routines for ENGINEs to use the same kind
     callback (pem_password_cb) as all other routines that need this
     kind of callback.
     [Richard Levitte]

  *) Increase ENTROPY_NEEDED to 32 bytes, as Rijndael can operate with
     256 bit (=32 byte) keys. Of course seeding with more entropy bytes
     than this minimum value is recommended.
     [Lutz Jaenicke]

  *) New random seeder for OpenVMS, using the system process statistics
     that are easily reachable.
     [Richard Levitte]

  *) Windows apparently can't transparently handle global
     variables defined in DLLs. Initialisations such as:

        const ASN1_ITEM *it = &ASN1_INTEGER_it;

     wont compile. This is used by the any applications that need to
     declare their own ASN1 modules. This was fixed by adding the option
     EXPORT_VAR_AS_FN to all Win32 platforms, although this isn't strictly
     needed for static libraries under Win32.
     [Steve Henson]

  *) New functions X509_PURPOSE_set() and X509_TRUST_set() to handle
     setting of purpose and trust fields. New X509_STORE trust and
     purpose functions and tidy up setting in other SSL functions.
     [Steve Henson]

  *) Add copies of X509_STORE_CTX fields and callbacks to X509_STORE
     structure. These are inherited by X509_STORE_CTX when it is 
     initialised. This allows various defaults to be set in the
     X509_STORE structure (such as flags for CRL checking and custom
     purpose or trust settings) for functions which only use X509_STORE_CTX
     internally such as S/MIME.

     Modify X509_STORE_CTX_purpose_inherit() so it only sets purposes and
     trust settings if they are not set in X509_STORE. This allows X509_STORE
     purposes and trust (in S/MIME for example) to override any set by default.

     Add command line options for CRL checking to smime, s_client and s_server
     applications.
     [Steve Henson]

  *) Initial CRL based revocation checking. If the CRL checking flag(s)
     are set then the CRL is looked up in the X509_STORE structure and
     its validity and signature checked, then if the certificate is found
     in the CRL the verify fails with a revoked error.

     Various new CRL related callbacks added to X509_STORE_CTX structure.

     Command line options added to 'verify' application to support this.

     This needs some additional work, such as being able to handle multiple
     CRLs with different times, extension based lookup (rather than just
     by subject name) and ultimately more complete V2 CRL extension
     handling.
     [Steve Henson]

  *) Add a general user interface API (crypto/ui/).  This is designed
     to replace things like des_read_password and friends (backward
     compatibility functions using this new API are provided).
     The purpose is to remove prompting functions from the DES code
     section as well as provide for prompting through dialog boxes in
     a window system and the like.
     [Richard Levitte]

  *) Add "ex_data" support to ENGINE so implementations can add state at a
     per-structure level rather than having to store it globally.
     [Geoff]

  *) Make it possible for ENGINE structures to be copied when retrieved by
     ENGINE_by_id() if the ENGINE specifies a new flag: ENGINE_FLAGS_BY_ID_COPY.
     This causes the "original" ENGINE structure to act like a template,
     analogous to the RSA vs. RSA_METHOD type of separation. Because of this
     operational state can be localised to each ENGINE structure, despite the
     fact they all share the same "methods". New ENGINE structures returned in
     this case have no functional references and the return value is the single
     structural reference. This matches the single structural reference returned
     by ENGINE_by_id() normally, when it is incremented on the pre-existing
     ENGINE structure.
     [Geoff]

  *) Fix ASN1 decoder when decoding type ANY and V_ASN1_OTHER: since this
     needs to match any other type at all we need to manually clear the
     tag cache.
     [Steve Henson]

  *) Changes to the "openssl engine" utility to include;
     - verbosity levels ('-v', '-vv', and '-vvv') that provide information
       about an ENGINE's available control commands.
     - executing control commands from command line arguments using the
       '-pre' and '-post' switches. '-post' is only used if '-t' is
       specified and the ENGINE is successfully initialised. The syntax for
       the individual commands are colon-separated, for example;
	 openssl engine chil -pre FORK_CHECK:0 -pre SO_PATH:/lib/test.so
     [Geoff]

  *) New dynamic control command support for ENGINEs. ENGINEs can now
     declare their own commands (numbers), names (strings), descriptions,
     and input types for run-time discovery by calling applications. A
     subset of these commands are implicitly classed as "executable"
     depending on their input type, and only these can be invoked through
     the new string-based API function ENGINE_ctrl_cmd_string(). (Eg. this
     can be based on user input, config files, etc). The distinction is
     that "executable" commands cannot return anything other than a boolean
     result and can only support numeric or string input, whereas some
     discoverable commands may only be for direct use through
     ENGINE_ctrl(), eg. supporting the exchange of binary data, function
     pointers, or other custom uses. The "executable" commands are to
     support parameterisations of ENGINE behaviour that can be
     unambiguously defined by ENGINEs and used consistently across any
     OpenSSL-based application. Commands have been added to all the
     existing hardware-supporting ENGINEs, noticeably "SO_PATH" to allow
     control over shared-library paths without source code alterations.
     [Geoff]

  *) Changed all ENGINE implementations to dynamically allocate their
     ENGINEs rather than declaring them statically. Apart from this being
     necessary with the removal of the ENGINE_FLAGS_MALLOCED distinction,
     this also allows the implementations to compile without using the
     internal engine_int.h header.
     [Geoff]

  *) Minor adjustment to "rand" code. RAND_get_rand_method() now returns a
     'const' value. Any code that should be able to modify a RAND_METHOD
     should already have non-const pointers to it (ie. they should only
     modify their own ones).
     [Geoff]

  *) Made a variety of little tweaks to the ENGINE code.
     - "atalla" and "ubsec" string definitions were moved from header files
       to C code. "nuron" string definitions were placed in variables
       rather than hard-coded - allowing parameterisation of these values
       later on via ctrl() commands.
     - Removed unused "#if 0"'d code.
     - Fixed engine list iteration code so it uses ENGINE_free() to release
       structural references.
     - Constified the RAND_METHOD element of ENGINE structures.
     - Constified various get/set functions as appropriate and added
       missing functions (including a catch-all ENGINE_cpy that duplicates
       all ENGINE values onto a new ENGINE except reference counts/state).
     - Removed NULL parameter checks in get/set functions. Setting a method
       or function to NULL is a way of cancelling out a previously set
       value.  Passing a NULL ENGINE parameter is just plain stupid anyway
       and doesn't justify the extra error symbols and code.
     - Deprecate the ENGINE_FLAGS_MALLOCED define and move the area for
       flags from engine_int.h to engine.h.
     - Changed prototypes for ENGINE handler functions (init(), finish(),
       ctrl(), key-load functions, etc) to take an (ENGINE*) parameter.
     [Geoff]

  *) Implement binary inversion algorithm for BN_mod_inverse in addition
     to the algorithm using long division.  The binary algorithm can be
     used only if the modulus is odd.  On 32-bit systems, it is faster
     only for relatively small moduli (roughly 20-30% for 128-bit moduli,
     roughly 5-15% for 256-bit moduli), so we use it only for moduli
     up to 450 bits.  In 64-bit environments, the binary algorithm
     appears to be advantageous for much longer moduli; here we use it
     for moduli up to 2048 bits.
     [Bodo Moeller]

  *) Rewrite CHOICE field setting in ASN1_item_ex_d2i(). The old code
     could not support the combine flag in choice fields.
     [Steve Henson]

  *) Add a 'copy_extensions' option to the 'ca' utility. This copies
     extensions from a certificate request to the certificate.
     [Steve Henson]

  *) Allow multiple 'certopt' and 'nameopt' options to be separated
     by commas. Add 'namopt' and 'certopt' options to the 'ca' config
     file: this allows the display of the certificate about to be
     signed to be customised, to allow certain fields to be included
     or excluded and extension details. The old system didn't display
     multicharacter strings properly, omitted fields not in the policy
     and couldn't display additional details such as extensions.
     [Steve Henson]

  *) Function EC_POINTs_mul for multiple scalar multiplication
     of an arbitrary number of elliptic curve points
          \sum scalars[i]*points[i],
     optionally including the generator defined for the EC_GROUP:
          scalar*generator +  \sum scalars[i]*points[i].

     EC_POINT_mul is a simple wrapper function for the typical case
     that the point list has just one item (besides the optional
     generator).
     [Bodo Moeller]

  *) First EC_METHODs for curves over GF(p):

     EC_GFp_simple_method() uses the basic BN_mod_mul and BN_mod_sqr
     operations and provides various method functions that can also
     operate with faster implementations of modular arithmetic.     

     EC_GFp_mont_method() reuses most functions that are part of
     EC_GFp_simple_method, but uses Montgomery arithmetic.

     [Bodo Moeller; point addition and point doubling
     implementation directly derived from source code provided by
     Lenka Fibikova <fibikova@exp-math.uni-essen.de>]

  *) Framework for elliptic curves (crypto/ec/ec.h, crypto/ec/ec_lcl.h,
     crypto/ec/ec_lib.c):

     Curves are EC_GROUP objects (with an optional group generator)
     based on EC_METHODs that are built into the library.

     Points are EC_POINT objects based on EC_GROUP objects.

     Most of the framework would be able to handle curves over arbitrary
     finite fields, but as there are no obvious types for fields other
     than GF(p), some functions are limited to that for now.
     [Bodo Moeller]

  *) Add the -HTTP option to s_server.  It is similar to -WWW, but requires
     that the file contains a complete HTTP response.
     [Richard Levitte]

  *) Add the ec directory to mkdef.pl and mkfiles.pl. In mkdef.pl
     change the def and num file printf format specifier from "%-40sXXX"
     to "%-39s XXX". The latter will always guarantee a space after the
     field while the former will cause them to run together if the field
     is 40 of more characters long.
     [Steve Henson]

  *) Constify the cipher and digest 'method' functions and structures
     and modify related functions to take constant EVP_MD and EVP_CIPHER
     pointers.
     [Steve Henson]

  *) Hide BN_CTX structure details in bn_lcl.h instead of publishing them
     in <openssl/bn.h>.  Also further increase BN_CTX_NUM to 32.
     [Bodo Moeller]

  *) Modify EVP_Digest*() routines so they now return values. Although the
     internal software routines can never fail additional hardware versions
     might.
     [Steve Henson]

  *) Clean up crypto/err/err.h and change some error codes to avoid conflicts:

     Previously ERR_R_FATAL was too small and coincided with ERR_LIB_PKCS7
     (= ERR_R_PKCS7_LIB); it is now 64 instead of 32.

     ASN1 error codes
          ERR_R_NESTED_ASN1_ERROR
          ...
          ERR_R_MISSING_ASN1_EOS
     were 4 .. 9, conflicting with
          ERR_LIB_RSA (= ERR_R_RSA_LIB)
          ...
          ERR_LIB_PEM (= ERR_R_PEM_LIB).
     They are now 58 .. 63 (i.e., just below ERR_R_FATAL).

     Add new error code 'ERR_R_INTERNAL_ERROR'.
     [Bodo Moeller]

  *) Don't overuse locks in crypto/err/err.c: For data retrieval, CRYPTO_r_lock
     suffices.
     [Bodo Moeller]

  *) New option '-subj arg' for 'openssl req' and 'openssl ca'.  This
     sets the subject name for a new request or supersedes the
     subject name in a given request. Formats that can be parsed are
          'CN=Some Name, OU=myOU, C=IT'
     and
          'CN=Some Name/OU=myOU/C=IT'.

     Add options '-batch' and '-verbose' to 'openssl req'.
     [Massimiliano Pala <madwolf@hackmasters.net>]

  *) Introduce the possibility to access global variables through
     functions on platform were that's the best way to handle exporting
     global variables in shared libraries.  To enable this functionality,
     one must configure with "EXPORT_VAR_AS_FN" or defined the C macro
     "OPENSSL_EXPORT_VAR_AS_FUNCTION" in crypto/opensslconf.h (the latter
     is normally done by Configure or something similar).

     To implement a global variable, use the macro OPENSSL_IMPLEMENT_GLOBAL
     in the source file (foo.c) like this:

	OPENSSL_IMPLEMENT_GLOBAL(int,foo)=1;
	OPENSSL_IMPLEMENT_GLOBAL(double,bar);

     To declare a global variable, use the macros OPENSSL_DECLARE_GLOBAL
     and OPENSSL_GLOBAL_REF in the header file (foo.h) like this:

	OPENSSL_DECLARE_GLOBAL(int,foo);
	#define foo OPENSSL_GLOBAL_REF(foo)
	OPENSSL_DECLARE_GLOBAL(double,bar);
	#define bar OPENSSL_GLOBAL_REF(bar)

     The #defines are very important, and therefore so is including the
     header file everywhere where the defined globals are used.

     The macro OPENSSL_EXPORT_VAR_AS_FUNCTION also affects the definition
     of ASN.1 items, but that structure is a bit different.

     The largest change is in util/mkdef.pl which has been enhanced with
     better and easier to understand logic to choose which symbols should
     go into the Windows .def files as well as a number of fixes and code
     cleanup (among others, algorithm keywords are now sorted
     lexicographically to avoid constant rewrites).
     [Richard Levitte]

  *) In BN_div() keep a copy of the sign of 'num' before writing the
     result to 'rm' because if rm==num the value will be overwritten
     and produce the wrong result if 'num' is negative: this caused
     problems with BN_mod() and BN_nnmod().
     [Steve Henson]

  *) Function OCSP_request_verify(). This checks the signature on an
     OCSP request and verifies the signer certificate. The signer
     certificate is just checked for a generic purpose and OCSP request
     trust settings.
     [Steve Henson]

  *) Add OCSP_check_validity() function to check the validity of OCSP
     responses. OCSP responses are prepared in real time and may only
     be a few seconds old. Simply checking that the current time lies
     between thisUpdate and nextUpdate max reject otherwise valid responses
     caused by either OCSP responder or client clock inaccuracy. Instead
     we allow thisUpdate and nextUpdate to fall within a certain period of
     the current time. The age of the response can also optionally be
     checked. Two new options -validity_period and -status_age added to
     ocsp utility.
     [Steve Henson]

  *) If signature or public key algorithm is unrecognized print out its
     OID rather that just UNKNOWN.
     [Steve Henson]

  *) Change OCSP_cert_to_id() to tolerate a NULL subject certificate and
     OCSP_cert_id_new() a NULL serialNumber. This allows a partial certificate
     ID to be generated from the issuer certificate alone which can then be
     passed to OCSP_id_issuer_cmp().
     [Steve Henson]

  *) New compilation option ASN1_ITEM_FUNCTIONS. This causes the new
     ASN1 modules to export functions returning ASN1_ITEM pointers
     instead of the ASN1_ITEM structures themselves. This adds several
     new macros which allow the underlying ASN1 function/structure to
     be accessed transparently. As a result code should not use ASN1_ITEM
     references directly (such as &X509_it) but instead use the relevant
     macros (such as ASN1_ITEM_rptr(X509)). This option is to allow
     use of the new ASN1 code on platforms where exporting structures
     is problematical (for example in shared libraries) but exporting
     functions returning pointers to structures is not.
     [Steve Henson]

  *) Add support for overriding the generation of SSL/TLS session IDs.
     These callbacks can be registered either in an SSL_CTX or per SSL.
     The purpose of this is to allow applications to control, if they wish,
     the arbitrary values chosen for use as session IDs, particularly as it
     can be useful for session caching in multiple-server environments. A
     command-line switch for testing this (and any client code that wishes
     to use such a feature) has been added to "s_server".
     [Geoff Thorpe, Lutz Jaenicke]

  *) Modify mkdef.pl to recognise and parse preprocessor conditionals
     of the form '#if defined(...) || defined(...) || ...' and
     '#if !defined(...) && !defined(...) && ...'.  This also avoids
     the growing number of special cases it was previously handling.
     [Richard Levitte]

  *) Make all configuration macros available for application by making
     sure they are available in opensslconf.h, by giving them names starting
     with "OPENSSL_" to avoid conflicts with other packages and by making
     sure e_os2.h will cover all platform-specific cases together with
     opensslconf.h.
     Additionally, it is now possible to define configuration/platform-
     specific names (called "system identities").  In the C code, these
     are prefixed with "OPENSSL_SYSNAME_".  e_os2.h will create another
     macro with the name beginning with "OPENSSL_SYS_", which is determined
     from "OPENSSL_SYSNAME_*" or compiler-specific macros depending on
     what is available.
     [Richard Levitte]

  *) New option -set_serial to 'req' and 'x509' this allows the serial
     number to use to be specified on the command line. Previously self
     signed certificates were hard coded with serial number 0 and the 
     CA options of 'x509' had to use a serial number in a file which was
     auto incremented.
     [Steve Henson]

  *) New options to 'ca' utility to support V2 CRL entry extensions.
     Currently CRL reason, invalidity date and hold instruction are
     supported. Add new CRL extensions to V3 code and some new objects.
     [Steve Henson]

  *) New function EVP_CIPHER_CTX_set_padding() this is used to
     disable standard block padding (aka PKCS#5 padding) in the EVP
     API, which was previously mandatory. This means that the data is
     not padded in any way and so the total length much be a multiple
     of the block size, otherwise an error occurs.
     [Steve Henson]

  *) Initial (incomplete) OCSP SSL support.
     [Steve Henson]

  *) New function OCSP_parse_url(). This splits up a URL into its host,
     port and path components: primarily to parse OCSP URLs. New -url
     option to ocsp utility.
     [Steve Henson]

  *) New nonce behavior. The return value of OCSP_check_nonce() now 
     reflects the various checks performed. Applications can decide
     whether to tolerate certain situations such as an absent nonce
     in a response when one was present in a request: the ocsp application
     just prints out a warning. New function OCSP_add1_basic_nonce()
     this is to allow responders to include a nonce in a response even if
     the request is nonce-less.
     [Steve Henson]

  *) Disable stdin buffering in load_cert (apps/apps.c) so that no certs are
     skipped when using openssl x509 multiple times on a single input file,
     e.g. "(openssl x509 -out cert1; openssl x509 -out cert2) <certs".
     [Bodo Moeller]

  *) Make ASN1_UTCTIME_set_string() and ASN1_GENERALIZEDTIME_set_string()
     set string type: to handle setting ASN1_TIME structures. Fix ca
     utility to correctly initialize revocation date of CRLs.
     [Steve Henson]

  *) New option SSL_OP_CIPHER_SERVER_PREFERENCE allows the server to override
     the clients preferred ciphersuites and rather use its own preferences.
     Should help to work around M$ SGC (Server Gated Cryptography) bug in
     Internet Explorer by ensuring unchanged hash method during stepup.
     (Also replaces the broken/deactivated SSL_OP_NON_EXPORT_FIRST option.)
     [Lutz Jaenicke]

  *) Make mkdef.pl recognise all DECLARE_ASN1 macros, change rijndael
     to aes and add a new 'exist' option to print out symbols that don't
     appear to exist.
     [Steve Henson]

  *) Additional options to ocsp utility to allow flags to be set and
     additional certificates supplied.
     [Steve Henson]

  *) Add the option -VAfile to 'openssl ocsp', so the user can give the
     OCSP client a number of certificate to only verify the response
     signature against.
     [Richard Levitte]

  *) Update Rijndael code to version 3.0 and change EVP AES ciphers to
     handle the new API. Currently only ECB, CBC modes supported. Add new
     AES OIDs.

     Add TLS AES ciphersuites as described in RFC3268, "Advanced
     Encryption Standard (AES) Ciphersuites for Transport Layer
     Security (TLS)".  (In beta versions of OpenSSL 0.9.7, these were
     not enabled by default and were not part of the "ALL" ciphersuite
     alias because they were not yet official; they could be
     explicitly requested by specifying the "AESdraft" ciphersuite
     group alias.  In the final release of OpenSSL 0.9.7, the group
     alias is called "AES" and is part of "ALL".)
     [Ben Laurie, Steve  Henson, Bodo Moeller]

  *) New function OCSP_copy_nonce() to copy nonce value (if present) from
     request to response.
     [Steve Henson]

  *) Functions for OCSP responders. OCSP_request_onereq_count(),
     OCSP_request_onereq_get0(), OCSP_onereq_get0_id() and OCSP_id_get0_info()
     extract information from a certificate request. OCSP_response_create()
     creates a response and optionally adds a basic response structure.
     OCSP_basic_add1_status() adds a complete single response to a basic
     response and returns the OCSP_SINGLERESP structure just added (to allow
     extensions to be included for example). OCSP_basic_add1_cert() adds a
     certificate to a basic response and OCSP_basic_sign() signs a basic
     response with various flags. New helper functions ASN1_TIME_check()
     (checks validity of ASN1_TIME structure) and ASN1_TIME_to_generalizedtime()
     (converts ASN1_TIME to GeneralizedTime).
     [Steve Henson]

  *) Various new functions. EVP_Digest() combines EVP_Digest{Init,Update,Final}()
     in a single operation. X509_get0_pubkey_bitstr() extracts the public_key
     structure from a certificate. X509_pubkey_digest() digests the public_key
     contents: this is used in various key identifiers. 
     [Steve Henson]

  *) Make sk_sort() tolerate a NULL argument.
     [Steve Henson reported by Massimiliano Pala <madwolf@comune.modena.it>]

  *) New OCSP verify flag OCSP_TRUSTOTHER. When set the "other" certificates
     passed by the function are trusted implicitly. If any of them signed the
     response then it is assumed to be valid and is not verified.
     [Steve Henson]

  *) In PKCS7_set_type() initialise content_type in PKCS7_ENC_CONTENT
     to data. This was previously part of the PKCS7 ASN1 code. This
     was causing problems with OpenSSL created PKCS#12 and PKCS#7 structures.
     [Steve Henson, reported by Kenneth R. Robinette
				<support@securenetterm.com>]

  *) Add CRYPTO_push_info() and CRYPTO_pop_info() calls to new ASN1
     routines: without these tracing memory leaks is very painful.
     Fix leaks in PKCS12 and PKCS7 routines.
     [Steve Henson]

  *) Make X509_time_adj() cope with the new behaviour of ASN1_TIME_new().
     Previously it initialised the 'type' argument to V_ASN1_UTCTIME which
     effectively meant GeneralizedTime would never be used. Now it
     is initialised to -1 but X509_time_adj() now has to check the value
     and use ASN1_TIME_set() if the value is not V_ASN1_UTCTIME or
     V_ASN1_GENERALIZEDTIME, without this it always uses GeneralizedTime.
     [Steve Henson, reported by Kenneth R. Robinette
				<support@securenetterm.com>]

  *) Fixes to BN_to_ASN1_INTEGER when bn is zero. This would previously
     result in a zero length in the ASN1_INTEGER structure which was
     not consistent with the structure when d2i_ASN1_INTEGER() was used
     and would cause ASN1_INTEGER_cmp() to fail. Enhance s2i_ASN1_INTEGER()
     to cope with hex and negative integers. Fix bug in i2a_ASN1_INTEGER()
     where it did not print out a minus for negative ASN1_INTEGER.
     [Steve Henson]

  *) Add summary printout to ocsp utility. The various functions which
     convert status values to strings have been renamed to:
     OCSP_response_status_str(), OCSP_cert_status_str() and
     OCSP_crl_reason_str() and are no longer static. New options
     to verify nonce values and to disable verification. OCSP response
     printout format cleaned up.
     [Steve Henson]

  *) Add additional OCSP certificate checks. These are those specified
     in RFC2560. This consists of two separate checks: the CA of the
     certificate being checked must either be the OCSP signer certificate
     or the issuer of the OCSP signer certificate. In the latter case the
     OCSP signer certificate must contain the OCSP signing extended key
     usage. This check is performed by attempting to match the OCSP
     signer or the OCSP signer CA to the issuerNameHash and issuerKeyHash
     in the OCSP_CERTID structures of the response.
     [Steve Henson]

  *) Initial OCSP certificate verification added to OCSP_basic_verify()
     and related routines. This uses the standard OpenSSL certificate
     verify routines to perform initial checks (just CA validity) and
     to obtain the certificate chain. Then additional checks will be
     performed on the chain. Currently the root CA is checked to see
     if it is explicitly trusted for OCSP signing. This is used to set
     a root CA as a global signing root: that is any certificate that
     chains to that CA is an acceptable OCSP signing certificate.
     [Steve Henson]

  *) New '-extfile ...' option to 'openssl ca' for reading X.509v3
     extensions from a separate configuration file.
     As when reading extensions from the main configuration file,
     the '-extensions ...' option may be used for specifying the
     section to use.
     [Massimiliano Pala <madwolf@comune.modena.it>]

  *) New OCSP utility. Allows OCSP requests to be generated or
     read. The request can be sent to a responder and the output
     parsed, outputed or printed in text form. Not complete yet:
     still needs to check the OCSP response validity.
     [Steve Henson]

  *) New subcommands for 'openssl ca':
     'openssl ca -status <serial>' prints the status of the cert with
     the given serial number (according to the index file).
     'openssl ca -updatedb' updates the expiry status of certificates
     in the index file.
     [Massimiliano Pala <madwolf@comune.modena.it>]

  *) New '-newreq-nodes' command option to CA.pl.  This is like
     '-newreq', but calls 'openssl req' with the '-nodes' option
     so that the resulting key is not encrypted.
     [Damien Miller <djm@mindrot.org>]

  *) New configuration for the GNU Hurd.
     [Jonathan Bartlett <johnnyb@wolfram.com> via Richard Levitte]

  *) Initial code to implement OCSP basic response verify. This
     is currently incomplete. Currently just finds the signer's
     certificate and verifies the signature on the response.
     [Steve Henson]

  *) New SSLeay_version code SSLEAY_DIR to determine the compiled-in
     value of OPENSSLDIR.  This is available via the new '-d' option
     to 'openssl version', and is also included in 'openssl version -a'.
     [Bodo Moeller]

  *) Allowing defining memory allocation callbacks that will be given
     file name and line number information in additional arguments
     (a const char* and an int).  The basic functionality remains, as
     well as the original possibility to just replace malloc(),
     realloc() and free() by functions that do not know about these
     additional arguments.  To register and find out the current
     settings for extended allocation functions, the following
     functions are provided:

	CRYPTO_set_mem_ex_functions
	CRYPTO_set_locked_mem_ex_functions
	CRYPTO_get_mem_ex_functions
	CRYPTO_get_locked_mem_ex_functions

     These work the same way as CRYPTO_set_mem_functions and friends.
     CRYPTO_get_[locked_]mem_functions now writes 0 where such an
     extended allocation function is enabled.
     Similarly, CRYPTO_get_[locked_]mem_ex_functions writes 0 where
     a conventional allocation function is enabled.
     [Richard Levitte, Bodo Moeller]

  *) Finish off removing the remaining LHASH function pointer casts.
     There should no longer be any prototype-casting required when using
     the LHASH abstraction, and any casts that remain are "bugs". See
     the callback types and macros at the head of lhash.h for details
     (and "OBJ_cleanup" in crypto/objects/obj_dat.c as an example).
     [Geoff Thorpe]

  *) Add automatic query of EGD sockets in RAND_poll() for the unix variant.
     If /dev/[u]random devices are not available or do not return enough
     entropy, EGD style sockets (served by EGD or PRNGD) will automatically
     be queried.
     The locations /var/run/egd-pool, /dev/egd-pool, /etc/egd-pool, and
     /etc/entropy will be queried once each in this sequence, quering stops
     when enough entropy was collected without querying more sockets.
     [Lutz Jaenicke]

  *) Change the Unix RAND_poll() variant to be able to poll several
     random devices, as specified by DEVRANDOM, until a sufficient amount
     of data has been collected.   We spend at most 10 ms on each file
     (select timeout) and read in non-blocking mode.  DEVRANDOM now
     defaults to the list "/dev/urandom", "/dev/random", "/dev/srandom"
     (previously it was just the string "/dev/urandom"), so on typical
     platforms the 10 ms delay will never occur.
     Also separate out the Unix variant to its own file, rand_unix.c.
     For VMS, there's a currently-empty rand_vms.c.
     [Richard Levitte]

  *) Move OCSP client related routines to ocsp_cl.c. These
     provide utility functions which an application needing
     to issue a request to an OCSP responder and analyse the
     response will typically need: as opposed to those which an
     OCSP responder itself would need which will be added later.

     OCSP_request_sign() signs an OCSP request with an API similar
     to PKCS7_sign(). OCSP_response_status() returns status of OCSP
     response. OCSP_response_get1_basic() extracts basic response
     from response. OCSP_resp_find_status(): finds and extracts status
     information from an OCSP_CERTID structure (which will be created
     when the request structure is built). These are built from lower
     level functions which work on OCSP_SINGLERESP structures but
     wont normally be used unless the application wishes to examine
     extensions in the OCSP response for example.

     Replace nonce routines with a pair of functions.
     OCSP_request_add1_nonce() adds a nonce value and optionally
     generates a random value. OCSP_check_nonce() checks the
     validity of the nonce in an OCSP response.
     [Steve Henson]

  *) Change function OCSP_request_add() to OCSP_request_add0_id().
     This doesn't copy the supplied OCSP_CERTID and avoids the
     need to free up the newly created id. Change return type
     to OCSP_ONEREQ to return the internal OCSP_ONEREQ structure.
     This can then be used to add extensions to the request.
     Deleted OCSP_request_new(), since most of its functionality
     is now in OCSP_REQUEST_new() (and the case insensitive name
     clash) apart from the ability to set the request name which
     will be added elsewhere.
     [Steve Henson]

  *) Update OCSP API. Remove obsolete extensions argument from
     various functions. Extensions are now handled using the new
     OCSP extension code. New simple OCSP HTTP function which 
     can be used to send requests and parse the response.
     [Steve Henson]

  *) Fix the PKCS#7 (S/MIME) code to work with new ASN1. Two new
     ASN1_ITEM structures help with sign and verify. PKCS7_ATTR_SIGN
     uses the special reorder version of SET OF to sort the attributes
     and reorder them to match the encoded order. This resolves a long
     standing problem: a verify on a PKCS7 structure just after signing
     it used to fail because the attribute order did not match the
     encoded order. PKCS7_ATTR_VERIFY does not reorder the attributes:
     it uses the received order. This is necessary to tolerate some broken
     software that does not order SET OF. This is handled by encoding
     as a SEQUENCE OF but using implicit tagging (with UNIVERSAL class)
     to produce the required SET OF.
     [Steve Henson]

  *) Have mk1mf.pl generate the macros OPENSSL_BUILD_SHLIBCRYPTO and
     OPENSSL_BUILD_SHLIBSSL and use them appropriately in the header
     files to get correct declarations of the ASN.1 item variables.
     [Richard Levitte]

  *) Rewrite of PKCS#12 code to use new ASN1 functionality. Replace many
     PKCS#12 macros with real functions. Fix two unrelated ASN1 bugs:
     asn1_check_tlen() would sometimes attempt to use 'ctx' when it was
     NULL and ASN1_TYPE was not dereferenced properly in asn1_ex_c2i().
     New ASN1 macro: DECLARE_ASN1_ITEM() which just declares the relevant
     ASN1_ITEM and no wrapper functions.
     [Steve Henson]

  *) New functions or ASN1_item_d2i_fp() and ASN1_item_d2i_bio(). These
     replace the old function pointer based I/O routines. Change most of
     the *_d2i_bio() and *_d2i_fp() functions to use these.
     [Steve Henson]

  *) Enhance mkdef.pl to be more accepting about spacing in C preprocessor
     lines, recognice more "algorithms" that can be deselected, and make
     it complain about algorithm deselection that isn't recognised.
     [Richard Levitte]

  *) New ASN1 functions to handle dup, sign, verify, digest, pack and
     unpack operations in terms of ASN1_ITEM. Modify existing wrappers
     to use new functions. Add NO_ASN1_OLD which can be set to remove
     some old style ASN1 functions: this can be used to determine if old
     code will still work when these eventually go away.
     [Steve Henson]

  *) New extension functions for OCSP structures, these follow the
     same conventions as certificates and CRLs.
     [Steve Henson]

  *) New function X509V3_add1_i2d(). This automatically encodes and
     adds an extension. Its behaviour can be customised with various
     flags to append, replace or delete. Various wrappers added for
     certifcates and CRLs.
     [Steve Henson]

  *) Fix to avoid calling the underlying ASN1 print routine when
     an extension cannot be parsed. Correct a typo in the
     OCSP_SERVICELOC extension. Tidy up print OCSP format.
     [Steve Henson]

  *) Make mkdef.pl parse some of the ASN1 macros and add apropriate
     entries for variables.
     [Steve Henson]

  *) Add functionality to apps/openssl.c for detecting locking
     problems: As the program is single-threaded, all we have
     to do is register a locking callback using an array for
     storing which locks are currently held by the program.
     [Bodo Moeller]

  *) Use a lock around the call to CRYPTO_get_ex_new_index() in
     SSL_get_ex_data_X509_STORE_idx(), which is used in
     ssl_verify_cert_chain() and thus can be called at any time
     during TLS/SSL handshakes so that thread-safety is essential.
     Unfortunately, the ex_data design is not at all suited
     for multi-threaded use, so it probably should be abolished.
     [Bodo Moeller]

  *) Added Broadcom "ubsec" ENGINE to OpenSSL.
     [Broadcom, tweaked and integrated by Geoff Thorpe]

  *) Move common extension printing code to new function
     X509V3_print_extensions(). Reorganise OCSP print routines and
     implement some needed OCSP ASN1 functions. Add OCSP extensions.
     [Steve Henson]

  *) New function X509_signature_print() to remove duplication in some
     print routines.
     [Steve Henson]

  *) Add a special meaning when SET OF and SEQUENCE OF flags are both
     set (this was treated exactly the same as SET OF previously). This
     is used to reorder the STACK representing the structure to match the
     encoding. This will be used to get round a problem where a PKCS7
     structure which was signed could not be verified because the STACK
     order did not reflect the encoded order.
     [Steve Henson]

  *) Reimplement the OCSP ASN1 module using the new code.
     [Steve Henson]

  *) Update the X509V3 code to permit the use of an ASN1_ITEM structure
     for its ASN1 operations. The old style function pointers still exist
     for now but they will eventually go away.
     [Steve Henson]

  *) Merge in replacement ASN1 code from the ASN1 branch. This almost
     completely replaces the old ASN1 functionality with a table driven
     encoder and decoder which interprets an ASN1_ITEM structure describing
     the ASN1 module. Compatibility with the existing ASN1 API (i2d,d2i) is
     largely maintained. Almost all of the old asn1_mac.h macro based ASN1
     has also been converted to the new form.
     [Steve Henson]

  *) Change BN_mod_exp_recp so that negative moduli are tolerated
     (the sign is ignored).  Similarly, ignore the sign in BN_MONT_CTX_set
     so that BN_mod_exp_mont and BN_mod_exp_mont_word work
     for negative moduli.
     [Bodo Moeller]

  *) Fix BN_uadd and BN_usub: Always return non-negative results instead
     of not touching the result's sign bit.
     [Bodo Moeller]

  *) BN_div bugfix: If the result is 0, the sign (res->neg) must not be
     set.
     [Bodo Moeller]

  *) Changed the LHASH code to use prototypes for callbacks, and created
     macros to declare and implement thin (optionally static) functions
     that provide type-safety and avoid function pointer casting for the
     type-specific callbacks.
     [Geoff Thorpe]

  *) Added Kerberos Cipher Suites to be used with TLS, as written in
     RFC 2712.
     [Veers Staats <staatsvr@asc.hpc.mil>,
      Jeffrey Altman <jaltman@columbia.edu>, via Richard Levitte]

  *) Reformat the FAQ so the different questions and answers can be divided
     in sections depending on the subject.
     [Richard Levitte]

  *) Have the zlib compression code load ZLIB.DLL dynamically under
     Windows.
     [Richard Levitte]

  *) New function BN_mod_sqrt for computing square roots modulo a prime
     (using the probabilistic Tonelli-Shanks algorithm unless
     p == 3 (mod 4)  or  p == 5 (mod 8),  which are cases that can
     be handled deterministically).
     [Lenka Fibikova <fibikova@exp-math.uni-essen.de>, Bodo Moeller]

  *) Make BN_mod_inverse faster by explicitly handling small quotients
     in the Euclid loop. (Speed gain about 20% for small moduli [256 or
     512 bits], about 30% for larger ones [1024 or 2048 bits].)
     [Bodo Moeller]

  *) New function BN_kronecker.
     [Bodo Moeller]

  *) Fix BN_gcd so that it works on negative inputs; the result is
     positive unless both parameters are zero.
     Previously something reasonably close to an infinite loop was
     possible because numbers could be growing instead of shrinking
     in the implementation of Euclid's algorithm.
     [Bodo Moeller]

  *) Fix BN_is_word() and BN_is_one() macros to take into account the
     sign of the number in question.

     Fix BN_is_word(a,w) to work correctly for w == 0.

     The old BN_is_word(a,w) macro is now called BN_abs_is_word(a,w)
     because its test if the absolute value of 'a' equals 'w'.
     Note that BN_abs_is_word does *not* handle w == 0 reliably;
     it exists mostly for use in the implementations of BN_is_zero(),
     BN_is_one(), and BN_is_word().
     [Bodo Moeller]

  *) New function BN_swap.
     [Bodo Moeller]

  *) Use BN_nnmod instead of BN_mod in crypto/bn/bn_exp.c so that
     the exponentiation functions are more likely to produce reasonable
     results on negative inputs.
     [Bodo Moeller]

  *) Change BN_mod_mul so that the result is always non-negative.
     Previously, it could be negative if one of the factors was negative;
     I don't think anyone really wanted that behaviour.
     [Bodo Moeller]

  *) Move BN_mod_... functions into new file crypto/bn/bn_mod.c
     (except for exponentiation, which stays in crypto/bn/bn_exp.c,
     and BN_mod_mul_reciprocal, which stays in crypto/bn/bn_recp.c)
     and add new functions:

          BN_nnmod
          BN_mod_sqr
          BN_mod_add
          BN_mod_add_quick
          BN_mod_sub
          BN_mod_sub_quick
          BN_mod_lshift1
          BN_mod_lshift1_quick
          BN_mod_lshift
          BN_mod_lshift_quick

     These functions always generate non-negative results.

     BN_nnmod otherwise is like BN_mod (if BN_mod computes a remainder  r
     such that  |m| < r < 0,  BN_nnmod will output  rem + |m|  instead).

     BN_mod_XXX_quick(r, a, [b,] m) generates the same result as
     BN_mod_XXX(r, a, [b,] m, ctx), but requires that  a  [and  b]
     be reduced modulo  m.
     [Lenka Fibikova <fibikova@exp-math.uni-essen.de>, Bodo Moeller]

#if 0
     The following entry accidentily appeared in the CHANGES file
     distributed with OpenSSL 0.9.7.  The modifications described in
     it do *not* apply to OpenSSL 0.9.7.

  *) Remove a few calls to bn_wexpand() in BN_sqr() (the one in there
     was actually never needed) and in BN_mul().  The removal in BN_mul()
     required a small change in bn_mul_part_recursive() and the addition
     of the functions bn_cmp_part_words(), bn_sub_part_words() and
     bn_add_part_words(), which do the same thing as bn_cmp_words(),
     bn_sub_words() and bn_add_words() except they take arrays with
     differing sizes.
     [Richard Levitte]
#endif

  *) In 'openssl passwd', verify passwords read from the terminal
     unless the '-salt' option is used (which usually means that
     verification would just waste user's time since the resulting
     hash is going to be compared with some given password hash)
     or the new '-noverify' option is used.

     This is an incompatible change, but it does not affect
     non-interactive use of 'openssl passwd' (passwords on the command
     line, '-stdin' option, '-in ...' option) and thus should not
     cause any problems.
     [Bodo Moeller]

  *) Remove all references to RSAref, since there's no more need for it.
     [Richard Levitte]

  *) Make DSO load along a path given through an environment variable
     (SHLIB_PATH) with shl_load().
     [Richard Levitte]

  *) Constify the ENGINE code as a result of BIGNUM constification.
     Also constify the RSA code and most things related to it.  In a
     few places, most notable in the depth of the ASN.1 code, ugly
     casts back to non-const were required (to be solved at a later
     time)
     [Richard Levitte]

  *) Make it so the openssl application has all engines loaded by default.
     [Richard Levitte]

  *) Constify the BIGNUM routines a little more.
     [Richard Levitte]

  *) Add the following functions:

	ENGINE_load_cswift()
	ENGINE_load_chil()
	ENGINE_load_atalla()
	ENGINE_load_nuron()
	ENGINE_load_builtin_engines()

     That way, an application can itself choose if external engines that
     are built-in in OpenSSL shall ever be used or not.  The benefit is
     that applications won't have to be linked with libdl or other dso
     libraries unless it's really needed.

     Changed 'openssl engine' to load all engines on demand.
     Changed the engine header files to avoid the duplication of some
     declarations (they differed!).
     [Richard Levitte]

  *) 'openssl engine' can now list capabilities.
     [Richard Levitte]

  *) Better error reporting in 'openssl engine'.
     [Richard Levitte]

  *) Never call load_dh_param(NULL) in s_server.
     [Bodo Moeller]

  *) Add engine application.  It can currently list engines by name and
     identity, and test if they are actually available.
     [Richard Levitte]

  *) Improve RPM specification file by forcing symbolic linking and making
     sure the installed documentation is also owned by root.root.
     [Damien Miller <djm@mindrot.org>]

  *) Give the OpenSSL applications more possibilities to make use of
     keys (public as well as private) handled by engines.
     [Richard Levitte]

  *) Add OCSP code that comes from CertCo.
     [Richard Levitte]

  *) Add VMS support for the Rijndael code.
     [Richard Levitte]

  *) Added untested support for Nuron crypto accelerator.
     [Ben Laurie]

  *) Add support for external cryptographic devices.  This code was
     previously distributed separately as the "engine" branch.
     [Geoff Thorpe, Richard Levitte]

  *) Rework the filename-translation in the DSO code. It is now possible to
     have far greater control over how a "name" is turned into a filename
     depending on the operating environment and any oddities about the
     different shared library filenames on each system.
     [Geoff Thorpe]

  *) Support threads on FreeBSD-elf in Configure.
     [Richard Levitte]

  *) Fix for SHA1 assembly problem with MASM: it produces
     warnings about corrupt line number information when assembling
     with debugging information. This is caused by the overlapping
     of two sections.
     [Bernd Matthes <mainbug@celocom.de>, Steve Henson]

  *) NCONF changes.
     NCONF_get_number() has no error checking at all.  As a replacement,
     NCONF_get_number_e() is defined (_e for "error checking") and is
     promoted strongly.  The old NCONF_get_number is kept around for
     binary backward compatibility.
     Make it possible for methods to load from something other than a BIO,
     by providing a function pointer that is given a name instead of a BIO.
     For example, this could be used to load configuration data from an
     LDAP server.
     [Richard Levitte]

  *) Fix for non blocking accept BIOs. Added new I/O special reason
     BIO_RR_ACCEPT to cover this case. Previously use of accept BIOs
     with non blocking I/O was not possible because no retry code was
     implemented. Also added new SSL code SSL_WANT_ACCEPT to cover
     this case.
     [Steve Henson]

  *) Added the beginnings of Rijndael support.
     [Ben Laurie]

  *) Fix for bug in DirectoryString mask setting. Add support for
     X509_NAME_print_ex() in 'req' and X509_print_ex() function
     to allow certificate printing to more controllable, additional
     'certopt' option to 'x509' to allow new printing options to be
     set.
     [Steve Henson]

  *) Clean old EAY MD5 hack from e_os.h.
     [Richard Levitte]

 Changes between 0.9.6l and 0.9.6m  [17 Mar 2004]

  *) Fix null-pointer assignment in do_change_cipher_spec() revealed
     by using the Codenomicon TLS Test Tool (CVE-2004-0079)
     [Joe Orton, Steve Henson]

 Changes between 0.9.6k and 0.9.6l  [04 Nov 2003]

  *) Fix additional bug revealed by the NISCC test suite:

     Stop bug triggering large recursion when presented with
     certain ASN.1 tags (CVE-2003-0851)
     [Steve Henson]

 Changes between 0.9.6j and 0.9.6k  [30 Sep 2003]

  *) Fix various bugs revealed by running the NISCC test suite:

     Stop out of bounds reads in the ASN1 code when presented with
     invalid tags (CVE-2003-0543 and CVE-2003-0544).
     
     If verify callback ignores invalid public key errors don't try to check
     certificate signature with the NULL public key.

     [Steve Henson]

  *) In ssl3_accept() (ssl/s3_srvr.c) only accept a client certificate
     if the server requested one: as stated in TLS 1.0 and SSL 3.0
     specifications.
     [Steve Henson]

  *) In ssl3_get_client_hello() (ssl/s3_srvr.c), tolerate additional
     extra data after the compression methods not only for TLS 1.0
     but also for SSL 3.0 (as required by the specification).
     [Bodo Moeller; problem pointed out by Matthias Loepfe]

  *) Change X509_certificate_type() to mark the key as exported/exportable
     when it's 512 *bits* long, not 512 bytes.
     [Richard Levitte]

 Changes between 0.9.6i and 0.9.6j  [10 Apr 2003]

  *) Countermeasure against the Klima-Pokorny-Rosa extension of
     Bleichbacher's attack on PKCS #1 v1.5 padding: treat
     a protocol version number mismatch like a decryption error
     in ssl3_get_client_key_exchange (ssl/s3_srvr.c).
     [Bodo Moeller]

  *) Turn on RSA blinding by default in the default implementation
     to avoid a timing attack. Applications that don't want it can call
     RSA_blinding_off() or use the new flag RSA_FLAG_NO_BLINDING.
     They would be ill-advised to do so in most cases.
     [Ben Laurie, Steve Henson, Geoff Thorpe, Bodo Moeller]

  *) Change RSA blinding code so that it works when the PRNG is not
     seeded (in this case, the secret RSA exponent is abused as
     an unpredictable seed -- if it is not unpredictable, there
     is no point in blinding anyway).  Make RSA blinding thread-safe
     by remembering the creator's thread ID in rsa->blinding and
     having all other threads use local one-time blinding factors
     (this requires more computation than sharing rsa->blinding, but
     avoids excessive locking; and if an RSA object is not shared
     between threads, blinding will still be very fast).
     [Bodo Moeller]

 Changes between 0.9.6h and 0.9.6i  [19 Feb 2003]

  *) In ssl3_get_record (ssl/s3_pkt.c), minimize information leaked
     via timing by performing a MAC computation even if incorrrect
     block cipher padding has been found.  This is a countermeasure
     against active attacks where the attacker has to distinguish
     between bad padding and a MAC verification error. (CVE-2003-0078)

     [Bodo Moeller; problem pointed out by Brice Canvel (EPFL),
     Alain Hiltgen (UBS), Serge Vaudenay (EPFL), and
     Martin Vuagnoux (EPFL, Ilion)]

 Changes between 0.9.6g and 0.9.6h  [5 Dec 2002]

  *) New function OPENSSL_cleanse(), which is used to cleanse a section of
     memory from it's contents.  This is done with a counter that will
     place alternating values in each byte.  This can be used to solve
     two issues: 1) the removal of calls to memset() by highly optimizing
     compilers, and 2) cleansing with other values than 0, since those can
     be read through on certain media, for example a swap space on disk.
     [Geoff Thorpe]

  *) Bugfix: client side session caching did not work with external caching,
     because the session->cipher setting was not restored when reloading
     from the external cache. This problem was masked, when
     SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG (part of SSL_OP_ALL) was set.
     (Found by Steve Haslam <steve@araqnid.ddts.net>.)
     [Lutz Jaenicke]

  *) Fix client_certificate (ssl/s2_clnt.c): The permissible total
     length of the REQUEST-CERTIFICATE message is 18 .. 34, not 17 .. 33.
     [Zeev Lieber <zeev-l@yahoo.com>]

  *) Undo an undocumented change introduced in 0.9.6e which caused
     repeated calls to OpenSSL_add_all_ciphers() and 
     OpenSSL_add_all_digests() to be ignored, even after calling
     EVP_cleanup().
     [Richard Levitte]

  *) Change the default configuration reader to deal with last line not
     being properly terminated.
     [Richard Levitte]

  *) Change X509_NAME_cmp() so it applies the special rules on handling
     DN values that are of type PrintableString, as well as RDNs of type
     emailAddress where the value has the type ia5String.
     [stefank@valicert.com via Richard Levitte]

  *) Add a SSL_SESS_CACHE_NO_INTERNAL_STORE flag to take over half
     the job SSL_SESS_CACHE_NO_INTERNAL_LOOKUP was inconsistently
     doing, define a new flag (SSL_SESS_CACHE_NO_INTERNAL) to be
     the bitwise-OR of the two for use by the majority of applications
     wanting this behaviour, and update the docs. The documented
     behaviour and actual behaviour were inconsistent and had been
     changing anyway, so this is more a bug-fix than a behavioural
     change.
     [Geoff Thorpe, diagnosed by Nadav Har'El]

  *) Don't impose a 16-byte length minimum on session IDs in ssl/s3_clnt.c
     (the SSL 3.0 and TLS 1.0 specifications allow any length up to 32 bytes).
     [Bodo Moeller]

  *) Fix initialization code race conditions in
        SSLv23_method(),  SSLv23_client_method(),   SSLv23_server_method(),
        SSLv2_method(),   SSLv2_client_method(),    SSLv2_server_method(),
        SSLv3_method(),   SSLv3_client_method(),    SSLv3_server_method(),
        TLSv1_method(),   TLSv1_client_method(),    TLSv1_server_method(),
        ssl2_get_cipher_by_char(),
        ssl3_get_cipher_by_char().
     [Patrick McCormick <patrick@tellme.com>, Bodo Moeller]

  *) Reorder cleanup sequence in SSL_CTX_free(): only remove the ex_data after
     the cached sessions are flushed, as the remove_cb() might use ex_data
     contents. Bug found by Sam Varshavchik <mrsam@courier-mta.com>
     (see [openssl.org #212]).
     [Geoff Thorpe, Lutz Jaenicke]

  *) Fix typo in OBJ_txt2obj which incorrectly passed the content
     length, instead of the encoding length to d2i_ASN1_OBJECT.
     [Steve Henson]

 Changes between 0.9.6f and 0.9.6g  [9 Aug 2002]

  *) [In 0.9.6g-engine release:]
     Fix crypto/engine/vendor_defns/cswift.h for WIN32 (use '_stdcall').
     [Lynn Gazis <lgazis@rainbow.com>]

 Changes between 0.9.6e and 0.9.6f  [8 Aug 2002]

  *) Fix ASN1 checks. Check for overflow by comparing with LONG_MAX
     and get fix the header length calculation.
     [Florian Weimer <Weimer@CERT.Uni-Stuttgart.DE>,
	Alon Kantor <alonk@checkpoint.com> (and others),
	Steve Henson]

  *) Use proper error handling instead of 'assertions' in buffer
     overflow checks added in 0.9.6e.  This prevents DoS (the
     assertions could call abort()).
     [Arne Ansper <arne@ats.cyber.ee>, Bodo Moeller]

 Changes between 0.9.6d and 0.9.6e  [30 Jul 2002]

  *) Add various sanity checks to asn1_get_length() to reject
     the ASN1 length bytes if they exceed sizeof(long), will appear
     negative or the content length exceeds the length of the
     supplied buffer.
     [Steve Henson, Adi Stav <stav@mercury.co.il>, James Yonan <jim@ntlp.com>]

  *) Fix cipher selection routines: ciphers without encryption had no flags
     for the cipher strength set and where therefore not handled correctly
     by the selection routines (PR #130).
     [Lutz Jaenicke]

  *) Fix EVP_dsa_sha macro.
     [Nils Larsch]

  *) New option
          SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
     for disabling the SSL 3.0/TLS 1.0 CBC vulnerability countermeasure
     that was added in OpenSSL 0.9.6d.

     As the countermeasure turned out to be incompatible with some
     broken SSL implementations, the new option is part of SSL_OP_ALL.
     SSL_OP_ALL is usually employed when compatibility with weird SSL
     implementations is desired (e.g. '-bugs' option to 's_client' and
     's_server'), so the new option is automatically set in many
     applications.
     [Bodo Moeller]

  *) Changes in security patch:

     Changes marked "(CHATS)" were sponsored by the Defense Advanced
     Research Projects Agency (DARPA) and Air Force Research Laboratory,
     Air Force Materiel Command, USAF, under agreement number
     F30602-01-2-0537.

  *) Add various sanity checks to asn1_get_length() to reject
     the ASN1 length bytes if they exceed sizeof(long), will appear
     negative or the content length exceeds the length of the
     supplied buffer. (CVE-2002-0659)
     [Steve Henson, Adi Stav <stav@mercury.co.il>, James Yonan <jim@ntlp.com>]

  *) Assertions for various potential buffer overflows, not known to
     happen in practice.
     [Ben Laurie (CHATS)]

  *) Various temporary buffers to hold ASCII versions of integers were
     too small for 64 bit platforms. (CVE-2002-0655)
     [Matthew Byng-Maddick <mbm@aldigital.co.uk> and Ben Laurie (CHATS)>

  *) Remote buffer overflow in SSL3 protocol - an attacker could
     supply an oversized session ID to a client. (CVE-2002-0656)
     [Ben Laurie (CHATS)]

  *) Remote buffer overflow in SSL2 protocol - an attacker could
     supply an oversized client master key. (CVE-2002-0656)
     [Ben Laurie (CHATS)]

 Changes between 0.9.6c and 0.9.6d  [9 May 2002]

  *) Fix crypto/asn1/a_sign.c so that 'parameters' is omitted (not
     encoded as NULL) with id-dsa-with-sha1.
     [Nils Larsch <nla@trustcenter.de>; problem pointed out by Bodo Moeller]

  *) Check various X509_...() return values in apps/req.c.
     [Nils Larsch <nla@trustcenter.de>]

  *) Fix BASE64 decode (EVP_DecodeUpdate) for data with CR/LF ended lines:
     an end-of-file condition would erronously be flagged, when the CRLF
     was just at the end of a processed block. The bug was discovered when
     processing data through a buffering memory BIO handing the data to a
     BASE64-decoding BIO. Bug fund and patch submitted by Pavel Tsekov
     <ptsekov@syntrex.com> and Nedelcho Stanev.
     [Lutz Jaenicke]

  *) Implement a countermeasure against a vulnerability recently found
     in CBC ciphersuites in SSL 3.0/TLS 1.0: Send an empty fragment
     before application data chunks to avoid the use of known IVs
     with data potentially chosen by the attacker.
     [Bodo Moeller]

  *) Fix length checks in ssl3_get_client_hello().
     [Bodo Moeller]

  *) TLS/SSL library bugfix: use s->s3->in_read_app_data differently
     to prevent ssl3_read_internal() from incorrectly assuming that
     ssl3_read_bytes() found application data while handshake
     processing was enabled when in fact s->s3->in_read_app_data was
     merely automatically cleared during the initial handshake.
     [Bodo Moeller; problem pointed out by Arne Ansper <arne@ats.cyber.ee>]

  *) Fix object definitions for Private and Enterprise: they were not
     recognized in their shortname (=lowercase) representation. Extend
     obj_dat.pl to issue an error when using undefined keywords instead
     of silently ignoring the problem (Svenning Sorensen
     <sss@sss.dnsalias.net>).
     [Lutz Jaenicke]

  *) Fix DH_generate_parameters() so that it works for 'non-standard'
     generators, i.e. generators other than 2 and 5.  (Previously, the
     code did not properly initialise the 'add' and 'rem' values to
     BN_generate_prime().)

     In the new general case, we do not insist that 'generator' is
     actually a primitive root: This requirement is rather pointless;
     a generator of the order-q subgroup is just as good, if not
     better.
     [Bodo Moeller]
 
  *) Map new X509 verification errors to alerts. Discovered and submitted by
     Tom Wu <tom@arcot.com>.
     [Lutz Jaenicke]

  *) Fix ssl3_pending() (ssl/s3_lib.c) to prevent SSL_pending() from
     returning non-zero before the data has been completely received
     when using non-blocking I/O.
     [Bodo Moeller; problem pointed out by John Hughes]

  *) Some of the ciphers missed the strength entry (SSL_LOW etc).
     [Ben Laurie, Lutz Jaenicke]

  *) Fix bug in SSL_clear(): bad sessions were not removed (found by
     Yoram Zahavi <YoramZ@gilian.com>).
     [Lutz Jaenicke]

  *) Add information about CygWin 1.3 and on, and preserve proper
     configuration for the versions before that.
     [Corinna Vinschen <vinschen@redhat.com> and Richard Levitte]

  *) Make removal from session cache (SSL_CTX_remove_session()) more robust:
     check whether we deal with a copy of a session and do not delete from
     the cache in this case. Problem reported by "Izhar Shoshani Levi"
     <izhar@checkpoint.com>.
     [Lutz Jaenicke]

  *) Do not store session data into the internal session cache, if it
     is never intended to be looked up (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP
     flag is set). Proposed by Aslam <aslam@funk.com>.
     [Lutz Jaenicke]

  *) Have ASN1_BIT_STRING_set_bit() really clear a bit when the requested
     value is 0.
     [Richard Levitte]

  *) [In 0.9.6d-engine release:]
     Fix a crashbug and a logic bug in hwcrhk_load_pubkey().
     [Toomas Kiisk <vix@cyber.ee> via Richard Levitte]

  *) Add the configuration target linux-s390x.
     [Neale Ferguson <Neale.Ferguson@SoftwareAG-USA.com> via Richard Levitte]

  *) The earlier bugfix for the SSL3_ST_SW_HELLO_REQ_C case of
     ssl3_accept (ssl/s3_srvr.c) incorrectly used a local flag
     variable as an indication that a ClientHello message has been
     received.  As the flag value will be lost between multiple
     invocations of ssl3_accept when using non-blocking I/O, the
     function may not be aware that a handshake has actually taken
     place, thus preventing a new session from being added to the
     session cache.

     To avoid this problem, we now set s->new_session to 2 instead of
     using a local variable.
     [Lutz Jaenicke, Bodo Moeller]

  *) Bugfix: Return -1 from ssl3_get_server_done (ssl3/s3_clnt.c)
     if the SSL_R_LENGTH_MISMATCH error is detected.
     [Geoff Thorpe, Bodo Moeller]

  *) New 'shared_ldflag' column in Configure platform table.
     [Richard Levitte]

  *) Fix EVP_CIPHER_mode macro.
     ["Dan S. Camper" <dan@bti.net>]

  *) Fix ssl3_read_bytes (ssl/s3_pkt.c): To ignore messages of unknown
     type, we must throw them away by setting rr->length to 0.
     [D P Chang <dpc@qualys.com>]

 Changes between 0.9.6b and 0.9.6c  [21 dec 2001]

  *) Fix BN_rand_range bug pointed out by Dominikus Scherkl
     <Dominikus.Scherkl@biodata.com>.  (The previous implementation
     worked incorrectly for those cases where  range = 10..._2  and
     3*range  is two bits longer than  range.)
     [Bodo Moeller]

  *) Only add signing time to PKCS7 structures if it is not already
     present.
     [Steve Henson]

  *) Fix crypto/objects/objects.h: "ld-ce" should be "id-ce",
     OBJ_ld_ce should be OBJ_id_ce.
     Also some ip-pda OIDs in crypto/objects/objects.txt were
     incorrect (cf. RFC 3039).
     [Matt Cooper, Frederic Giudicelli, Bodo Moeller]

  *) Release CRYPTO_LOCK_DYNLOCK when CRYPTO_destroy_dynlockid()
     returns early because it has nothing to do.
     [Andy Schneider <andy.schneider@bjss.co.uk>]

  *) [In 0.9.6c-engine release:]
     Fix mutex callback return values in crypto/engine/hw_ncipher.c.
     [Andy Schneider <andy.schneider@bjss.co.uk>]

  *) [In 0.9.6c-engine release:]
     Add support for Cryptographic Appliance's keyserver technology.
     (Use engine 'keyclient')
     [Cryptographic Appliances and Geoff Thorpe]

  *) Add a configuration entry for OS/390 Unix.  The C compiler 'c89'
     is called via tools/c89.sh because arguments have to be
     rearranged (all '-L' options must appear before the first object
     modules).
     [Richard Shapiro <rshapiro@abinitio.com>]

  *) [In 0.9.6c-engine release:]
     Add support for Broadcom crypto accelerator cards, backported
     from 0.9.7.
     [Broadcom, Nalin Dahyabhai <nalin@redhat.com>, Mark Cox]

  *) [In 0.9.6c-engine release:]
     Add support for SureWare crypto accelerator cards from 
     Baltimore Technologies.  (Use engine 'sureware')
     [Baltimore Technologies and Mark Cox]

  *) [In 0.9.6c-engine release:]
     Add support for crypto accelerator cards from Accelerated
     Encryption Processing, www.aep.ie.  (Use engine 'aep')
     [AEP Inc. and Mark Cox]

  *) Add a configuration entry for gcc on UnixWare.
     [Gary Benson <gbenson@redhat.com>]

  *) Change ssl/s2_clnt.c and ssl/s2_srvr.c so that received handshake
     messages are stored in a single piece (fixed-length part and
     variable-length part combined) and fix various bugs found on the way.
     [Bodo Moeller]

  *) Disable caching in BIO_gethostbyname(), directly use gethostbyname()
     instead.  BIO_gethostbyname() does not know what timeouts are
     appropriate, so entries would stay in cache even when they have
     become invalid.
     [Bodo Moeller; problem pointed out by Rich Salz <rsalz@zolera.com>

  *) Change ssl23_get_client_hello (ssl/s23_srvr.c) behaviour when
     faced with a pathologically small ClientHello fragment that does
     not contain client_version: Instead of aborting with an error,
     simply choose the highest available protocol version (i.e.,
     TLS 1.0 unless it is disabled).  In practice, ClientHello
     messages are never sent like this, but this change gives us
     strictly correct behaviour at least for TLS.
     [Bodo Moeller]

  *) Fix SSL handshake functions and SSL_clear() such that SSL_clear()
     never resets s->method to s->ctx->method when called from within
     one of the SSL handshake functions.
     [Bodo Moeller; problem pointed out by Niko Baric]

  *) In ssl3_get_client_hello (ssl/s3_srvr.c), generate a fatal alert
     (sent using the client's version number) if client_version is
     smaller than the protocol version in use.  Also change
     ssl23_get_client_hello (ssl/s23_srvr.c) to select TLS 1.0 if
     the client demanded SSL 3.0 but only TLS 1.0 is enabled; then
     the client will at least see that alert.
     [Bodo Moeller]

  *) Fix ssl3_get_message (ssl/s3_both.c) to handle message fragmentation
     correctly.
     [Bodo Moeller]

  *) Avoid infinite loop in ssl3_get_message (ssl/s3_both.c) if a
     client receives HelloRequest while in a handshake.
     [Bodo Moeller; bug noticed by Andy Schneider <andy.schneider@bjss.co.uk>]

  *) Bugfix in ssl3_accept (ssl/s3_srvr.c): Case SSL3_ST_SW_HELLO_REQ_C
     should end in 'break', not 'goto end' which circuments various
     cleanups done in state SSL_ST_OK.   But session related stuff
     must be disabled for SSL_ST_OK in the case that we just sent a
     HelloRequest.

     Also avoid some overhead by not calling ssl_init_wbio_buffer()
     before just sending a HelloRequest.
     [Bodo Moeller, Eric Rescorla <ekr@rtfm.com>]

  *) Fix ssl/s3_enc.c, ssl/t1_enc.c and ssl/s3_pkt.c so that we don't
     reveal whether illegal block cipher padding was found or a MAC
     verification error occured.  (Neither SSLerr() codes nor alerts
     are directly visible to potential attackers, but the information
     may leak via logfiles.)

     Similar changes are not required for the SSL 2.0 implementation
     because the number of padding bytes is sent in clear for SSL 2.0,
     and the extra bytes are just ignored.  However ssl/s2_pkt.c
     failed to verify that the purported number of padding bytes is in
     the legal range.
     [Bodo Moeller]

  *) Add OpenUNIX-8 support including shared libraries
     (Boyd Lynn Gerber <gerberb@zenez.com>).
     [Lutz Jaenicke]

  *) Improve RSA_padding_check_PKCS1_OAEP() check again to avoid
     'wristwatch attack' using huge encoding parameters (cf.
     James H. Manger's CRYPTO 2001 paper).  Note that the
     RSA_PKCS1_OAEP_PADDING case of RSA_private_decrypt() does not use
     encoding parameters and hence was not vulnerable.
     [Bodo Moeller]

  *) BN_sqr() bug fix.
     [Ulf Möller, reported by Jim Ellis <jim.ellis@cavium.com>]

  *) Rabin-Miller test analyses assume uniformly distributed witnesses,
     so use BN_pseudo_rand_range() instead of using BN_pseudo_rand()
     followed by modular reduction.
     [Bodo Moeller; pointed out by Adam Young <AYoung1@NCSUS.JNJ.COM>]

  *) Add BN_pseudo_rand_range() with obvious functionality: BN_rand_range()
     equivalent based on BN_pseudo_rand() instead of BN_rand().
     [Bodo Moeller]

  *) s3_srvr.c: allow sending of large client certificate lists (> 16 kB).
     This function was broken, as the check for a new client hello message
     to handle SGC did not allow these large messages.
     (Tracked down by "Douglas E. Engert" <deengert@anl.gov>.)
     [Lutz Jaenicke]

  *) Add alert descriptions for TLSv1 to SSL_alert_desc_string[_long]().
     [Lutz Jaenicke]

  *) Fix buggy behaviour of BIO_get_num_renegotiates() and BIO_ctrl()
     for BIO_C_GET_WRITE_BUF_SIZE ("Stephen Hinton" <shinton@netopia.com>).
     [Lutz Jaenicke]

  *) Rework the configuration and shared library support for Tru64 Unix.
     The configuration part makes use of modern compiler features and
     still retains old compiler behavior for those that run older versions
     of the OS.  The shared library support part includes a variant that
     uses the RPATH feature, and is available through the special
     configuration target "alpha-cc-rpath", which will never be selected
     automatically.
     [Tim Mooney <mooney@dogbert.cc.ndsu.NoDak.edu> via Richard Levitte]

  *) In ssl3_get_key_exchange (ssl/s3_clnt.c), call ssl3_get_message()
     with the same message size as in ssl3_get_certificate_request().
     Otherwise, if no ServerKeyExchange message occurs, CertificateRequest
     messages might inadvertently be reject as too long.
     [Petr Lampa <lampa@fee.vutbr.cz>]

  *) Enhanced support for IA-64 Unix platforms (well, Linux and HP-UX).
     [Andy Polyakov]

  *) Modified SSL library such that the verify_callback that has been set
     specificly for an SSL object with SSL_set_verify() is actually being
     used. Before the change, a verify_callback set with this function was
     ignored and the verify_callback() set in the SSL_CTX at the time of
     the call was used. New function X509_STORE_CTX_set_verify_cb() introduced
     to allow the necessary settings.
     [Lutz Jaenicke]

  *) Initialize static variable in crypto/dsa/dsa_lib.c and crypto/dh/dh_lib.c
     explicitly to NULL, as at least on Solaris 8 this seems not always to be
     done automatically (in contradiction to the requirements of the C
     standard). This made problems when used from OpenSSH.
     [Lutz Jaenicke]

  *) In OpenSSL 0.9.6a and 0.9.6b, crypto/dh/dh_key.c ignored
     dh->length and always used

          BN_rand_range(priv_key, dh->p).

     BN_rand_range() is not necessary for Diffie-Hellman, and this
     specific range makes Diffie-Hellman unnecessarily inefficient if
     dh->length (recommended exponent length) is much smaller than the
     length of dh->p.  We could use BN_rand_range() if the order of
     the subgroup was stored in the DH structure, but we only have
     dh->length.

     So switch back to

          BN_rand(priv_key, l, ...)

     where 'l' is dh->length if this is defined, or BN_num_bits(dh->p)-1
     otherwise.
     [Bodo Moeller]

  *) In

          RSA_eay_public_encrypt
          RSA_eay_private_decrypt
          RSA_eay_private_encrypt (signing)
          RSA_eay_public_decrypt (signature verification)

     (default implementations for RSA_public_encrypt,
     RSA_private_decrypt, RSA_private_encrypt, RSA_public_decrypt),
     always reject numbers >= n.
     [Bodo Moeller]

  *) In crypto/rand/md_rand.c, use a new short-time lock CRYPTO_LOCK_RAND2
     to synchronize access to 'locking_thread'.  This is necessary on
     systems where access to 'locking_thread' (an 'unsigned long'
     variable) is not atomic.
     [Bodo Moeller]

  *) In crypto/rand/md_rand.c, set 'locking_thread' to current thread's ID
     *before* setting the 'crypto_lock_rand' flag.  The previous code had
     a race condition if 0 is a valid thread ID.
     [Travis Vitek <vitek@roguewave.com>]

  *) Add support for shared libraries under Irix.
     [Albert Chin-A-Young <china@thewrittenword.com>]

  *) Add configuration option to build on Linux on both big-endian and
     little-endian MIPS.
     [Ralf Baechle <ralf@uni-koblenz.de>]

  *) Add the possibility to create shared libraries on HP-UX.
     [Richard Levitte]

 Changes between 0.9.6a and 0.9.6b  [9 Jul 2001]

  *) Change ssleay_rand_bytes (crypto/rand/md_rand.c)
     to avoid a SSLeay/OpenSSL PRNG weakness pointed out by
     Markku-Juhani O. Saarinen <markku-juhani.saarinen@nokia.com>:
     PRNG state recovery was possible based on the output of
     one PRNG request appropriately sized to gain knowledge on
     'md' followed by enough consecutive 1-byte PRNG requests
     to traverse all of 'state'.

     1. When updating 'md_local' (the current thread's copy of 'md')
        during PRNG output generation, hash all of the previous
        'md_local' value, not just the half used for PRNG output.

     2. Make the number of bytes from 'state' included into the hash
        independent from the number of PRNG bytes requested.

     The first measure alone would be sufficient to avoid
     Markku-Juhani's attack.  (Actually it had never occurred
     to me that the half of 'md_local' used for chaining was the
     half from which PRNG output bytes were taken -- I had always
     assumed that the secret half would be used.)  The second
     measure makes sure that additional data from 'state' is never
     mixed into 'md_local' in small portions; this heuristically
     further strengthens the PRNG.
     [Bodo Moeller]

  *) Fix crypto/bn/asm/mips3.s.
     [Andy Polyakov]

  *) When only the key is given to "enc", the IV is undefined. Print out
     an error message in this case.
     [Lutz Jaenicke]

  *) Handle special case when X509_NAME is empty in X509 printing routines.
     [Steve Henson]

  *) In dsa_do_verify (crypto/dsa/dsa_ossl.c), verify that r and s are
     positive and less than q.
     [Bodo Moeller]

  *) Don't change *pointer in CRYPTO_add_lock() is add_lock_callback is
     used: it isn't thread safe and the add_lock_callback should handle
     that itself.
     [Paul Rose <Paul.Rose@bridge.com>]

  *) Verify that incoming data obeys the block size in
     ssl3_enc (ssl/s3_enc.c) and tls1_enc (ssl/t1_enc.c).
     [Bodo Moeller]

  *) Fix OAEP check.
     [Ulf Möller, Bodo Möller]

  *) The countermeasure against Bleichbacher's attack on PKCS #1 v1.5
     RSA encryption was accidentally removed in s3_srvr.c in OpenSSL 0.9.5
     when fixing the server behaviour for backwards-compatible 'client
     hello' messages.  (Note that the attack is impractical against
     SSL 3.0 and TLS 1.0 anyway because length and version checking
     means that the probability of guessing a valid ciphertext is
     around 2^-40; see section 5 in Bleichenbacher's CRYPTO '98
     paper.)

     Before 0.9.5, the countermeasure (hide the error by generating a
     random 'decryption result') did not work properly because
     ERR_clear_error() was missing, meaning that SSL_get_error() would
     detect the supposedly ignored error.

     Both problems are now fixed.
     [Bodo Moeller]

  *) In crypto/bio/bf_buff.c, increase DEFAULT_BUFFER_SIZE to 4096
     (previously it was 1024).
     [Bodo Moeller]

  *) Fix for compatibility mode trust settings: ignore trust settings
     unless some valid trust or reject settings are present.
     [Steve Henson]

  *) Fix for blowfish EVP: its a variable length cipher.
     [Steve Henson]

  *) Fix various bugs related to DSA S/MIME verification. Handle missing
     parameters in DSA public key structures and return an error in the
     DSA routines if parameters are absent.
     [Steve Henson]

  *) In versions up to 0.9.6, RAND_file_name() resorted to file ".rnd"
     in the current directory if neither $RANDFILE nor $HOME was set.
     RAND_file_name() in 0.9.6a returned NULL in this case.  This has
     caused some confusion to Windows users who haven't defined $HOME.
     Thus RAND_file_name() is changed again: e_os.h can define a
     DEFAULT_HOME, which will be used if $HOME is not set.
     For Windows, we use "C:"; on other platforms, we still require
     environment variables.

  *) Move 'if (!initialized) RAND_poll()' into regions protected by
     CRYPTO_LOCK_RAND.  This is not strictly necessary, but avoids
     having multiple threads call RAND_poll() concurrently.
     [Bodo Moeller]

  *) In crypto/rand/md_rand.c, replace 'add_do_not_lock' flag by a
     combination of a flag and a thread ID variable.
     Otherwise while one thread is in ssleay_rand_bytes (which sets the
     flag), *other* threads can enter ssleay_add_bytes without obeying
     the CRYPTO_LOCK_RAND lock (and may even illegally release the lock
     that they do not hold after the first thread unsets add_do_not_lock).
     [Bodo Moeller]

  *) Change bctest again: '-x' expressions are not available in all
     versions of 'test'.
     [Bodo Moeller]

 Changes between 0.9.6 and 0.9.6a  [5 Apr 2001]

  *) Fix a couple of memory leaks in PKCS7_dataDecode()
     [Steve Henson, reported by Heyun Zheng <hzheng@atdsprint.com>]

  *) Change Configure and Makefiles to provide EXE_EXT, which will contain
     the default extension for executables, if any.  Also, make the perl
     scripts that use symlink() to test if it really exists and use "cp"
     if it doesn't.  All this made OpenSSL compilable and installable in
     CygWin.
     [Richard Levitte]

  *) Fix for asn1_GetSequence() for indefinite length constructed data.
     If SEQUENCE is length is indefinite just set c->slen to the total
     amount of data available.
     [Steve Henson, reported by shige@FreeBSD.org]
     [This change does not apply to 0.9.7.]

  *) Change bctest to avoid here-documents inside command substitution
     (workaround for FreeBSD /bin/sh bug).
     For compatibility with Ultrix, avoid shell functions (introduced
     in the bctest version that searches along $PATH).
     [Bodo Moeller]

  *) Rename 'des_encrypt' to 'des_encrypt1'.  This avoids the clashes
     with des_encrypt() defined on some operating systems, like Solaris
     and UnixWare.
     [Richard Levitte]

  *) Check the result of RSA-CRT (see D. Boneh, R. DeMillo, R. Lipton:
     On the Importance of Eliminating Errors in Cryptographic
     Computations, J. Cryptology 14 (2001) 2, 101-119,
     http://theory.stanford.edu/~dabo/papers/faults.ps.gz).
     [Ulf Moeller]
  
  *) MIPS assembler BIGNUM division bug fix. 
     [Andy Polyakov]

  *) Disabled incorrect Alpha assembler code.
     [Richard Levitte]

  *) Fix PKCS#7 decode routines so they correctly update the length
     after reading an EOC for the EXPLICIT tag.
     [Steve Henson]
     [This change does not apply to 0.9.7.]

  *) Fix bug in PKCS#12 key generation routines. This was triggered
     if a 3DES key was generated with a 0 initial byte. Include
     PKCS12_BROKEN_KEYGEN compilation option to retain the old
     (but broken) behaviour.
     [Steve Henson]

  *) Enhance bctest to search for a working bc along $PATH and print
     it when found.
     [Tim Rice <tim@multitalents.net> via Richard Levitte]

  *) Fix memory leaks in err.c: free err_data string if necessary;
     don't write to the wrong index in ERR_set_error_data.
     [Bodo Moeller]

  *) Implement ssl23_peek (analogous to ssl23_read), which previously
     did not exist.
     [Bodo Moeller]

  *) Replace rdtsc with _emit statements for VC++ version 5.
     [Jeremy Cooper <jeremy@baymoo.org>]

  *) Make it possible to reuse SSLv2 sessions.
     [Richard Levitte]

  *) In copy_email() check for >= 0 as a return value for
     X509_NAME_get_index_by_NID() since 0 is a valid index.
     [Steve Henson reported by Massimiliano Pala <madwolf@opensca.org>]

  *) Avoid coredump with unsupported or invalid public keys by checking if
     X509_get_pubkey() fails in PKCS7_verify(). Fix memory leak when
     PKCS7_verify() fails with non detached data.
     [Steve Henson]

  *) Don't use getenv in library functions when run as setuid/setgid.
     New function OPENSSL_issetugid().
     [Ulf Moeller]

  *) Avoid false positives in memory leak detection code (crypto/mem_dbg.c)
     due to incorrect handling of multi-threading:

     1. Fix timing glitch in the MemCheck_off() portion of CRYPTO_mem_ctrl().

     2. Fix logical glitch in is_MemCheck_on() aka CRYPTO_is_mem_check_on().

     3. Count how many times MemCheck_off() has been called so that
        nested use can be treated correctly.  This also avoids 
        inband-signalling in the previous code (which relied on the
        assumption that thread ID 0 is impossible).
     [Bodo Moeller]

  *) Add "-rand" option also to s_client and s_server.
     [Lutz Jaenicke]

  *) Fix CPU detection on Irix 6.x.
     [Kurt Hockenbury <khockenb@stevens-tech.edu> and
      "Bruce W. Forsberg" <bruce.forsberg@baesystems.com>]

  *) Fix X509_NAME bug which produced incorrect encoding if X509_NAME
     was empty.
     [Steve Henson]
     [This change does not apply to 0.9.7.]

  *) Use the cached encoding of an X509_NAME structure rather than
     copying it. This is apparently the reason for the libsafe "errors"
     but the code is actually correct.
     [Steve Henson]

  *) Add new function BN_rand_range(), and fix DSA_sign_setup() to prevent
     Bleichenbacher's DSA attack.
     Extend BN_[pseudo_]rand: As before, top=1 forces the highest two bits
     to be set and top=0 forces the highest bit to be set; top=-1 is new
     and leaves the highest bit random.
     [Ulf Moeller, Bodo Moeller]

  *) In the NCONF_...-based implementations for CONF_... queries
     (crypto/conf/conf_lib.c), if the input LHASH is NULL, avoid using
     a temporary CONF structure with the data component set to NULL
     (which gives segmentation faults in lh_retrieve).
     Instead, use NULL for the CONF pointer in CONF_get_string and
     CONF_get_number (which may use environment variables) and directly
     return NULL from CONF_get_section.
     [Bodo Moeller]

  *) Fix potential buffer overrun for EBCDIC.
     [Ulf Moeller]

  *) Tolerate nonRepudiation as being valid for S/MIME signing and certSign
     keyUsage if basicConstraints absent for a CA.
     [Steve Henson]

  *) Make SMIME_write_PKCS7() write mail header values with a format that
     is more generally accepted (no spaces before the semicolon), since
     some programs can't parse those values properly otherwise.  Also make
     sure BIO's that break lines after each write do not create invalid
     headers.
     [Richard Levitte]

  *) Make the CRL encoding routines work with empty SEQUENCE OF. The
     macros previously used would not encode an empty SEQUENCE OF
     and break the signature.
     [Steve Henson]
     [This change does not apply to 0.9.7.]

  *) Zero the premaster secret after deriving the master secret in
     DH ciphersuites.
     [Steve Henson]

  *) Add some EVP_add_digest_alias registrations (as found in
     OpenSSL_add_all_digests()) to SSL_library_init()
     aka OpenSSL_add_ssl_algorithms().  This provides improved
     compatibility with peers using X.509 certificates
     with unconventional AlgorithmIdentifier OIDs.
     [Bodo Moeller]

  *) Fix for Irix with NO_ASM.
     ["Bruce W. Forsberg" <bruce.forsberg@baesystems.com>]

  *) ./config script fixes.
     [Ulf Moeller, Richard Levitte]

  *) Fix 'openssl passwd -1'.
     [Bodo Moeller]

  *) Change PKCS12_key_gen_asc() so it can cope with non null
     terminated strings whose length is passed in the passlen
     parameter, for example from PEM callbacks. This was done
     by adding an extra length parameter to asc2uni().
     [Steve Henson, reported by <oddissey@samsung.co.kr>]

  *) Fix C code generated by 'openssl dsaparam -C': If a BN_bin2bn
     call failed, free the DSA structure.
     [Bodo Moeller]

  *) Fix to uni2asc() to cope with zero length Unicode strings.
     These are present in some PKCS#12 files.
     [Steve Henson]

  *) Increase s2->wbuf allocation by one byte in ssl2_new (ssl/s2_lib.c).
     Otherwise do_ssl_write (ssl/s2_pkt.c) will write beyond buffer limits
     when writing a 32767 byte record.
     [Bodo Moeller; problem reported by Eric Day <eday@concentric.net>]

  *) In RSA_eay_public_{en,ed}crypt and RSA_eay_mod_exp (rsa_eay.c),
     obtain lock CRYPTO_LOCK_RSA before setting rsa->_method_mod_{n,p,q}.

     (RSA objects have a reference count access to which is protected
     by CRYPTO_LOCK_RSA [see rsa_lib.c, s3_srvr.c, ssl_cert.c, ssl_rsa.c],
     so they are meant to be shared between threads.)
     [Bodo Moeller, Geoff Thorpe; original patch submitted by
     "Reddie, Steven" <Steven.Reddie@ca.com>]

  *) Fix a deadlock in CRYPTO_mem_leaks().
     [Bodo Moeller]

  *) Use better test patterns in bntest.
     [Ulf Möller]

  *) rand_win.c fix for Borland C.
     [Ulf Möller]
 
  *) BN_rshift bugfix for n == 0.
     [Bodo Moeller]

  *) Add a 'bctest' script that checks for some known 'bc' bugs
     so that 'make test' does not abort just because 'bc' is broken.
     [Bodo Moeller]

  *) Store verify_result within SSL_SESSION also for client side to
     avoid potential security hole. (Re-used sessions on the client side
     always resulted in verify_result==X509_V_OK, not using the original
     result of the server certificate verification.)
     [Lutz Jaenicke]

  *) Fix ssl3_pending: If the record in s->s3->rrec is not of type
     SSL3_RT_APPLICATION_DATA, return 0.
     Similarly, change ssl2_pending to return 0 if SSL_in_init(s) is true.
     [Bodo Moeller]

  *) Fix SSL_peek:
     Both ssl2_peek and ssl3_peek, which were totally broken in earlier
     releases, have been re-implemented by renaming the previous
     implementations of ssl2_read and ssl3_read to ssl2_read_internal
     and ssl3_read_internal, respectively, and adding 'peek' parameters
     to them.  The new ssl[23]_{read,peek} functions are calls to
     ssl[23]_read_internal with the 'peek' flag set appropriately.
     A 'peek' parameter has also been added to ssl3_read_bytes, which
     does the actual work for ssl3_read_internal.
     [Bodo Moeller]

  *) Initialise "ex_data" member of RSA/DSA/DH structures prior to calling
     the method-specific "init()" handler. Also clean up ex_data after
     calling the method-specific "finish()" handler. Previously, this was
     happening the other way round.
     [Geoff Thorpe]

  *) Increase BN_CTX_NUM (the number of BIGNUMs in a BN_CTX) to 16.
     The previous value, 12, was not always sufficient for BN_mod_exp().
     [Bodo Moeller]

  *) Make sure that shared libraries get the internal name engine with
     the full version number and not just 0.  This should mark the
     shared libraries as not backward compatible.  Of course, this should
     be changed again when we can guarantee backward binary compatibility.
     [Richard Levitte]

  *) Fix typo in get_cert_by_subject() in by_dir.c
     [Jean-Marc Desperrier <jean-marc.desperrier@certplus.com>]

  *) Rework the system to generate shared libraries:

     - Make note of the expected extension for the shared libraries and
       if there is a need for symbolic links from for example libcrypto.so.0
       to libcrypto.so.0.9.7.  There is extended info in Configure for
       that.

     - Make as few rebuilds of the shared libraries as possible.

     - Still avoid linking the OpenSSL programs with the shared libraries.

     - When installing, install the shared libraries separately from the
       static ones.
     [Richard Levitte]

  *) Fix SSL_CTX_set_read_ahead macro to actually use its argument.

     Copy SSL_CTX's read_ahead flag to SSL object directly in SSL_new
     and not in SSL_clear because the latter is also used by the
     accept/connect functions; previously, the settings made by
     SSL_set_read_ahead would be lost during the handshake.
     [Bodo Moeller; problems reported by Anders Gertz <gertz@epact.se>]     

  *) Correct util/mkdef.pl to be selective about disabled algorithms.
     Previously, it would create entries for disableed algorithms no
     matter what.
     [Richard Levitte]

  *) Added several new manual pages for SSL_* function.
     [Lutz Jaenicke]

 Changes between 0.9.5a and 0.9.6  [24 Sep 2000]

  *) In ssl23_get_client_hello, generate an error message when faced
     with an initial SSL 3.0/TLS record that is too small to contain the
     first two bytes of the ClientHello message, i.e. client_version.
     (Note that this is a pathologic case that probably has never happened
     in real life.)  The previous approach was to use the version number
     from the record header as a substitute; but our protocol choice
     should not depend on that one because it is not authenticated
     by the Finished messages.
     [Bodo Moeller]

  *) More robust randomness gathering functions for Windows.
     [Jeffrey Altman <jaltman@columbia.edu>]

  *) For compatibility reasons if the flag X509_V_FLAG_ISSUER_CHECK is
     not set then we don't setup the error code for issuer check errors
     to avoid possibly overwriting other errors which the callback does
     handle. If an application does set the flag then we assume it knows
     what it is doing and can handle the new informational codes
     appropriately.
     [Steve Henson]

  *) Fix for a nasty bug in ASN1_TYPE handling. ASN1_TYPE is used for
     a general "ANY" type, as such it should be able to decode anything
     including tagged types. However it didn't check the class so it would
     wrongly interpret tagged types in the same way as their universal
     counterpart and unknown types were just rejected. Changed so that the
     tagged and unknown types are handled in the same way as a SEQUENCE:
     that is the encoding is stored intact. There is also a new type
     "V_ASN1_OTHER" which is used when the class is not universal, in this
     case we have no idea what the actual type is so we just lump them all
     together.
     [Steve Henson]

  *) On VMS, stdout may very well lead to a file that is written to
     in a record-oriented fashion.  That means that every write() will
     write a separate record, which will be read separately by the
     programs trying to read from it.  This can be very confusing.

     The solution is to put a BIO filter in the way that will buffer
     text until a linefeed is reached, and then write everything a
     line at a time, so every record written will be an actual line,
     not chunks of lines and not (usually doesn't happen, but I've
     seen it once) several lines in one record.  BIO_f_linebuffer() is
     the answer.

     Currently, it's a VMS-only method, because that's where it has
     been tested well enough.
     [Richard Levitte]

  *) Remove 'optimized' squaring variant in BN_mod_mul_montgomery,
     it can return incorrect results.
     (Note: The buggy variant was not enabled in OpenSSL 0.9.5a,
     but it was in 0.9.6-beta[12].)
     [Bodo Moeller]

  *) Disable the check for content being present when verifying detached
     signatures in pk7_smime.c. Some versions of Netscape (wrongly)
     include zero length content when signing messages.
     [Steve Henson]

  *) New BIO_shutdown_wr macro, which invokes the BIO_C_SHUTDOWN_WR
     BIO_ctrl (for BIO pairs).
     [Bodo Möller]

  *) Add DSO method for VMS.
     [Richard Levitte]

  *) Bug fix: Montgomery multiplication could produce results with the
     wrong sign.
     [Ulf Möller]

  *) Add RPM specification openssl.spec and modify it to build three
     packages.  The default package contains applications, application
     documentation and run-time libraries.  The devel package contains
     include files, static libraries and function documentation.  The
     doc package contains the contents of the doc directory.  The original
     openssl.spec was provided by Damien Miller <djm@mindrot.org>.
     [Richard Levitte]
     
  *) Add a large number of documentation files for many SSL routines.
     [Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>]

  *) Add a configuration entry for Sony News 4.
     [NAKAJI Hiroyuki <nakaji@tutrp.tut.ac.jp>]

  *) Don't set the two most significant bits to one when generating a
     random number < q in the DSA library.
     [Ulf Möller]

  *) New SSL API mode 'SSL_MODE_AUTO_RETRY'.  This disables the default
     behaviour that SSL_read may result in SSL_ERROR_WANT_READ (even if
     the underlying transport is blocking) if a handshake took place.
     (The default behaviour is needed by applications such as s_client
     and s_server that use select() to determine when to use SSL_read;
     but for applications that know in advance when to expect data, it
     just makes things more complicated.)
     [Bodo Moeller]

  *) Add RAND_egd_bytes(), which gives control over the number of bytes read
     from EGD.
     [Ben Laurie]

  *) Add a few more EBCDIC conditionals that make `req' and `x509'
     work better on such systems.
     [Martin Kraemer <Martin.Kraemer@MchP.Siemens.De>]

  *) Add two demo programs for PKCS12_parse() and PKCS12_create().
     Update PKCS12_parse() so it copies the friendlyName and the
     keyid to the certificates aux info.
     [Steve Henson]

  *) Fix bug in PKCS7_verify() which caused an infinite loop
     if there was more than one signature.
     [Sven Uszpelkat <su@celocom.de>]

  *) Major change in util/mkdef.pl to include extra information
     about each symbol, as well as presentig variables as well
     as functions.  This change means that there's n more need
     to rebuild the .num files when some algorithms are excluded.
     [Richard Levitte]

  *) Allow the verify time to be set by an application,
     rather than always using the current time.
     [Steve Henson]
  
  *) Phase 2 verify code reorganisation. The certificate
     verify code now looks up an issuer certificate by a
     number of criteria: subject name, authority key id
     and key usage. It also verifies self signed certificates
     by the same criteria. The main comparison function is
     X509_check_issued() which performs these checks.
 
     Lot of changes were necessary in order to support this
     without completely rewriting the lookup code.
 
     Authority and subject key identifier are now cached.
 
     The LHASH 'certs' is X509_STORE has now been replaced
     by a STACK_OF(X509_OBJECT). This is mainly because an
     LHASH can't store or retrieve multiple objects with
     the same hash value.

     As a result various functions (which were all internal
     use only) have changed to handle the new X509_STORE
     structure. This will break anything that messed round
     with X509_STORE internally.
 
     The functions X509_STORE_add_cert() now checks for an
     exact match, rather than just subject name.
 
     The X509_STORE API doesn't directly support the retrieval
     of multiple certificates matching a given criteria, however
     this can be worked round by performing a lookup first
     (which will fill the cache with candidate certificates)
     and then examining the cache for matches. This is probably
     the best we can do without throwing out X509_LOOKUP
     entirely (maybe later...).
 
     The X509_VERIFY_CTX structure has been enhanced considerably.
 
     All certificate lookup operations now go via a get_issuer()
     callback. Although this currently uses an X509_STORE it
     can be replaced by custom lookups. This is a simple way
     to bypass the X509_STORE hackery necessary to make this
     work and makes it possible to use more efficient techniques
     in future. A very simple version which uses a simple
     STACK for its trusted certificate store is also provided
     using X509_STORE_CTX_trusted_stack().
 
     The verify_cb() and verify() callbacks now have equivalents
     in the X509_STORE_CTX structure.
 
     X509_STORE_CTX also has a 'flags' field which can be used
     to customise the verify behaviour.
     [Steve Henson]
 
  *) Add new PKCS#7 signing option PKCS7_NOSMIMECAP which 
     excludes S/MIME capabilities.
     [Steve Henson]

  *) When a certificate request is read in keep a copy of the
     original encoding of the signed data and use it when outputing
     again. Signatures then use the original encoding rather than
     a decoded, encoded version which may cause problems if the
     request is improperly encoded.
     [Steve Henson]

  *) For consistency with other BIO_puts implementations, call
     buffer_write(b, ...) directly in buffer_puts instead of calling
     BIO_write(b, ...).

     In BIO_puts, increment b->num_write as in BIO_write.
     [Peter.Sylvester@EdelWeb.fr]

  *) Fix BN_mul_word for the case where the word is 0. (We have to use
     BN_zero, we may not return a BIGNUM with an array consisting of
     words set to zero.)
     [Bodo Moeller]

  *) Avoid calling abort() from within the library when problems are
     detected, except if preprocessor symbols have been defined
     (such as REF_CHECK, BN_DEBUG etc.).
     [Bodo Moeller]

  *) New openssl application 'rsautl'. This utility can be
     used for low level RSA operations. DER public key
     BIO/fp routines also added.
     [Steve Henson]

  *) New Configure entry and patches for compiling on QNX 4.
     [Andreas Schneider <andreas@ds3.etech.fh-hamburg.de>]

  *) A demo state-machine implementation was sponsored by
     Nuron (http://www.nuron.com/) and is now available in
     demos/state_machine.
     [Ben Laurie]

  *) New options added to the 'dgst' utility for signature
     generation and verification.
     [Steve Henson]

  *) Unrecognized PKCS#7 content types are now handled via a
     catch all ASN1_TYPE structure. This allows unsupported
     types to be stored as a "blob" and an application can
     encode and decode it manually.
     [Steve Henson]

  *) Fix various signed/unsigned issues to make a_strex.c
     compile under VC++.
     [Oscar Jacobsson <oscar.jacobsson@celocom.com>]

  *) ASN1 fixes. i2d_ASN1_OBJECT was not returning the correct
     length if passed a buffer. ASN1_INTEGER_to_BN failed
     if passed a NULL BN and its argument was negative.
     [Steve Henson, pointed out by Sven Heiberg <sven@tartu.cyber.ee>]

  *) Modification to PKCS#7 encoding routines to output definite
     length encoding. Since currently the whole structures are in
     memory there's not real point in using indefinite length 
     constructed encoding. However if OpenSSL is compiled with
     the flag PKCS7_INDEFINITE_ENCODING the old form is used.
     [Steve Henson]

  *) Added BIO_vprintf() and BIO_vsnprintf().
     [Richard Levitte]

  *) Added more prefixes to parse for in the the strings written
     through a logging bio, to cover all the levels that are available
     through syslog.  The prefixes are now:

	PANIC, EMERG, EMR	=>	LOG_EMERG
	ALERT, ALR		=>	LOG_ALERT
	CRIT, CRI		=>	LOG_CRIT
	ERROR, ERR		=>	LOG_ERR
	WARNING, WARN, WAR	=>	LOG_WARNING
	NOTICE, NOTE, NOT	=>	LOG_NOTICE
	INFO, INF		=>	LOG_INFO
	DEBUG, DBG		=>	LOG_DEBUG

     and as before, if none of those prefixes are present at the
     beginning of the string, LOG_ERR is chosen.

     On Win32, the LOG_* levels are mapped according to this:

	LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR	=> EVENTLOG_ERROR_TYPE
	LOG_WARNING				=> EVENTLOG_WARNING_TYPE
	LOG_NOTICE, LOG_INFO, LOG_DEBUG		=> EVENTLOG_INFORMATION_TYPE

     [Richard Levitte]

  *) Made it possible to reconfigure with just the configuration
     argument "reconf" or "reconfigure".  The command line arguments
     are stored in Makefile.ssl in the variable CONFIGURE_ARGS,
     and are retrieved from there when reconfiguring.
     [Richard Levitte]

  *) MD4 implemented.
     [Assar Westerlund <assar@sics.se>, Richard Levitte]

  *) Add the arguments -CAfile and -CApath to the pkcs12 utility.
     [Richard Levitte]

  *) The obj_dat.pl script was messing up the sorting of object
     names. The reason was that it compared the quoted version
     of strings as a result "OCSP" > "OCSP Signing" because
     " > SPACE. Changed script to store unquoted versions of
     names and add quotes on output. It was also omitting some
     names from the lookup table if they were given a default
     value (that is if SN is missing it is given the same
     value as LN and vice versa), these are now added on the
     grounds that if an object has a name we should be able to
     look it up. Finally added warning output when duplicate
     short or long names are found.
     [Steve Henson]

  *) Changes needed for Tandem NSK.
     [Scott Uroff <scott@xypro.com>]

  *) Fix SSL 2.0 rollback checking: Due to an off-by-one error in
     RSA_padding_check_SSLv23(), special padding was never detected
     and thus the SSL 3.0/TLS 1.0 countermeasure against protocol
     version rollback attacks was not effective.

     In s23_clnt.c, don't use special rollback-attack detection padding
     (RSA_SSLV23_PADDING) if SSL 2.0 is the only protocol enabled in the
     client; similarly, in s23_srvr.c, don't do the rollback check if
     SSL 2.0 is the only protocol enabled in the server.
     [Bodo Moeller]

  *) Make it possible to get hexdumps of unprintable data with 'openssl
     asn1parse'.  By implication, the functions ASN1_parse_dump() and
     BIO_dump_indent() are added.
     [Richard Levitte]

  *) New functions ASN1_STRING_print_ex() and X509_NAME_print_ex()
     these print out strings and name structures based on various
     flags including RFC2253 support and proper handling of
     multibyte characters. Added options to the 'x509' utility 
     to allow the various flags to be set.
     [Steve Henson]

  *) Various fixes to use ASN1_TIME instead of ASN1_UTCTIME.
     Also change the functions X509_cmp_current_time() and
     X509_gmtime_adj() work with an ASN1_TIME structure,
     this will enable certificates using GeneralizedTime in validity
     dates to be checked.
     [Steve Henson]

  *) Make the NEG_PUBKEY_BUG code (which tolerates invalid
     negative public key encodings) on by default,
     NO_NEG_PUBKEY_BUG can be set to disable it.
     [Steve Henson]

  *) New function c2i_ASN1_OBJECT() which acts on ASN1_OBJECT
     content octets. An i2c_ASN1_OBJECT is unnecessary because
     the encoding can be trivially obtained from the structure.
     [Steve Henson]

  *) crypto/err.c locking bugfix: Use write locks (CRYPTO_w_[un]lock),
     not read locks (CRYPTO_r_[un]lock).
     [Bodo Moeller]

  *) A first attempt at creating official support for shared
     libraries through configuration.  I've kept it so the
     default is static libraries only, and the OpenSSL programs
     are always statically linked for now, but there are
     preparations for dynamic linking in place.
     This has been tested on Linux and Tru64.
     [Richard Levitte]

  *) Randomness polling function for Win9x, as described in:
     Peter Gutmann, Software Generation of Practically Strong
     Random Numbers.
     [Ulf Möller]

  *) Fix so PRNG is seeded in req if using an already existing
     DSA key.
     [Steve Henson]

  *) New options to smime application. -inform and -outform
     allow alternative formats for the S/MIME message including
     PEM and DER. The -content option allows the content to be
     specified separately. This should allow things like Netscape
     form signing output easier to verify.
     [Steve Henson]

  *) Fix the ASN1 encoding of tags using the 'long form'.
     [Steve Henson]

  *) New ASN1 functions, i2c_* and c2i_* for INTEGER and BIT
     STRING types. These convert content octets to and from the
     underlying type. The actual tag and length octets are
     already assumed to have been read in and checked. These
     are needed because all other string types have virtually
     identical handling apart from the tag. By having versions
     of the ASN1 functions that just operate on content octets
     IMPLICIT tagging can be handled properly. It also allows
     the ASN1_ENUMERATED code to be cut down because ASN1_ENUMERATED
     and ASN1_INTEGER are identical apart from the tag.
     [Steve Henson]

  *) Change the handling of OID objects as follows:

     - New object identifiers are inserted in objects.txt, following
       the syntax given in objects.README.
     - objects.pl is used to process obj_mac.num and create a new
       obj_mac.h.
     - obj_dat.pl is used to create a new obj_dat.h, using the data in
       obj_mac.h.

     This is currently kind of a hack, and the perl code in objects.pl
     isn't very elegant, but it works as I intended.  The simplest way
     to check that it worked correctly is to look in obj_dat.h and
     check the array nid_objs and make sure the objects haven't moved
     around (this is important!).  Additions are OK, as well as
     consistent name changes. 
     [Richard Levitte]

  *) Add BSD-style MD5-based passwords to 'openssl passwd' (option '-1').
     [Bodo Moeller]

  *) Addition of the command line parameter '-rand file' to 'openssl req'.
     The given file adds to whatever has already been seeded into the
     random pool through the RANDFILE configuration file option or
     environment variable, or the default random state file.
     [Richard Levitte]

  *) mkstack.pl now sorts each macro group into lexical order.
     Previously the output order depended on the order the files
     appeared in the directory, resulting in needless rewriting
     of safestack.h .
     [Steve Henson]

  *) Patches to make OpenSSL compile under Win32 again. Mostly
     work arounds for the VC++ problem that it treats func() as
     func(void). Also stripped out the parts of mkdef.pl that
     added extra typesafe functions: these no longer exist.
     [Steve Henson]

  *) Reorganisation of the stack code. The macros are now all 
     collected in safestack.h . Each macro is defined in terms of
     a "stack macro" of the form SKM_<name>(type, a, b). The 
     DEBUG_SAFESTACK is now handled in terms of function casts,
     this has the advantage of retaining type safety without the
     use of additional functions. If DEBUG_SAFESTACK is not defined
     then the non typesafe macros are used instead. Also modified the
     mkstack.pl script to handle the new form. Needs testing to see
     if which (if any) compilers it chokes and maybe make DEBUG_SAFESTACK
     the default if no major problems. Similar behaviour for ASN1_SET_OF
     and PKCS12_STACK_OF.
     [Steve Henson]

  *) When some versions of IIS use the 'NET' form of private key the
     key derivation algorithm is different. Normally MD5(password) is
     used as a 128 bit RC4 key. In the modified case
     MD5(MD5(password) + "SGCKEYSALT")  is used insted. Added some
     new functions i2d_RSA_NET(), d2i_RSA_NET() etc which are the same
     as the old Netscape_RSA functions except they have an additional
     'sgckey' parameter which uses the modified algorithm. Also added
     an -sgckey command line option to the rsa utility. Thanks to 
     Adrian Peck <bertie@ncipher.com> for posting details of the modified
     algorithm to openssl-dev.
     [Steve Henson]

  *) The evp_local.h macros were using 'c.##kname' which resulted in
     invalid expansion on some systems (SCO 5.0.5 for example).
     Corrected to 'c.kname'.
     [Phillip Porch <root@theporch.com>]

  *) New X509_get1_email() and X509_REQ_get1_email() functions that return
     a STACK of email addresses from a certificate or request, these look
     in the subject name and the subject alternative name extensions and 
     omit any duplicate addresses.
     [Steve Henson]

  *) Re-implement BN_mod_exp2_mont using independent (and larger) windows.
     This makes DSA verification about 2 % faster.
     [Bodo Moeller]

  *) Increase maximum window size in BN_mod_exp_... to 6 bits instead of 5
     (meaning that now 2^5 values will be precomputed, which is only 4 KB
     plus overhead for 1024 bit moduli).
     This makes exponentiations about 0.5 % faster for 1024 bit
     exponents (as measured by "openssl speed rsa2048").
     [Bodo Moeller]

  *) Rename memory handling macros to avoid conflicts with other
     software:
          Malloc         =>  OPENSSL_malloc
          Malloc_locked  =>  OPENSSL_malloc_locked
          Realloc        =>  OPENSSL_realloc
          Free           =>  OPENSSL_free
     [Richard Levitte]

  *) New function BN_mod_exp_mont_word for small bases (roughly 15%
     faster than BN_mod_exp_mont, i.e. 7% for a full DH exchange).
     [Bodo Moeller]

  *) CygWin32 support.
     [John Jarvie <jjarvie@newsguy.com>]

  *) The type-safe stack code has been rejigged. It is now only compiled
     in when OpenSSL is configured with the DEBUG_SAFESTACK option and
     by default all type-specific stack functions are "#define"d back to
     standard stack functions. This results in more streamlined output
     but retains the type-safety checking possibilities of the original
     approach.
     [Geoff Thorpe]

  *) The STACK code has been cleaned up, and certain type declarations
     that didn't make a lot of sense have been brought in line. This has
     also involved a cleanup of sorts in safestack.h to more correctly
     map type-safe stack functions onto their plain stack counterparts.
     This work has also resulted in a variety of "const"ifications of
     lots of the code, especially "_cmp" operations which should normally
     be prototyped with "const" parameters anyway.
     [Geoff Thorpe]

  *) When generating bytes for the first time in md_rand.c, 'stir the pool'
     by seeding with STATE_SIZE dummy bytes (with zero entropy count).
     (The PRNG state consists of two parts, the large pool 'state' and 'md',
     where all of 'md' is used each time the PRNG is used, but 'state'
     is used only indexed by a cyclic counter. As entropy may not be
     well distributed from the beginning, 'md' is important as a
     chaining variable. However, the output function chains only half
     of 'md', i.e. 80 bits.  ssleay_rand_add, on the other hand, chains
     all of 'md', and seeding with STATE_SIZE dummy bytes will result
     in all of 'state' being rewritten, with the new values depending
     on virtually all of 'md'.  This overcomes the 80 bit limitation.)
     [Bodo Moeller]

  *) In ssl/s2_clnt.c and ssl/s3_clnt.c, call ERR_clear_error() when
     the handshake is continued after ssl_verify_cert_chain();
     otherwise, if SSL_VERIFY_NONE is set, remaining error codes
     can lead to 'unexplainable' connection aborts later.
     [Bodo Moeller; problem tracked down by Lutz Jaenicke]

  *) Major EVP API cipher revision.
     Add hooks for extra EVP features. This allows various cipher
     parameters to be set in the EVP interface. Support added for variable
     key length ciphers via the EVP_CIPHER_CTX_set_key_length() function and
     setting of RC2 and RC5 parameters.

     Modify EVP_OpenInit() and EVP_SealInit() to cope with variable key length
     ciphers.

     Remove lots of duplicated code from the EVP library. For example *every*
     cipher init() function handles the 'iv' in the same way according to the
     cipher mode. They also all do nothing if the 'key' parameter is NULL and
     for CFB and OFB modes they zero ctx->num.

     New functionality allows removal of S/MIME code RC2 hack.

     Most of the routines have the same form and so can be declared in terms
     of macros.

     By shifting this to the top level EVP_CipherInit() it can be removed from
     all individual ciphers. If the cipher wants to handle IVs or keys
     differently it can set the EVP_CIPH_CUSTOM_IV or EVP_CIPH_ALWAYS_CALL_INIT
     flags.

     Change lots of functions like EVP_EncryptUpdate() to now return a
     value: although software versions of the algorithms cannot fail
     any installed hardware versions can.
     [Steve Henson]

  *) Implement SSL_OP_TLS_ROLLBACK_BUG: In ssl3_get_client_key_exchange, if
     this option is set, tolerate broken clients that send the negotiated
     protocol version number instead of the requested protocol version
     number.
     [Bodo Moeller]

  *) Call dh_tmp_cb (set by ..._TMP_DH_CB) with correct 'is_export' flag;
     i.e. non-zero for export ciphersuites, zero otherwise.
     Previous versions had this flag inverted, inconsistent with
     rsa_tmp_cb (..._TMP_RSA_CB).
     [Bodo Moeller; problem reported by Amit Chopra]

  *) Add missing DSA library text string. Work around for some IIS
     key files with invalid SEQUENCE encoding.
     [Steve Henson]

  *) Add a document (doc/standards.txt) that list all kinds of standards
     and so on that are implemented in OpenSSL.
     [Richard Levitte]

  *) Enhance c_rehash script. Old version would mishandle certificates
     with the same subject name hash and wouldn't handle CRLs at all.
     Added -fingerprint option to crl utility, to support new c_rehash
     features.
     [Steve Henson]

  *) Eliminate non-ANSI declarations in crypto.h and stack.h.
     [Ulf Möller]

  *) Fix for SSL server purpose checking. Server checking was
     rejecting certificates which had extended key usage present
     but no ssl client purpose.
     [Steve Henson, reported by Rene Grosser <grosser@hisolutions.com>]

  *) Make PKCS#12 code work with no password. The PKCS#12 spec
     is a little unclear about how a blank password is handled.
     Since the password in encoded as a BMPString with terminating
     double NULL a zero length password would end up as just the
     double NULL. However no password at all is different and is
     handled differently in the PKCS#12 key generation code. NS
     treats a blank password as zero length. MSIE treats it as no
     password on export: but it will try both on import. We now do
     the same: PKCS12_parse() tries zero length and no password if
     the password is set to "" or NULL (NULL is now a valid password:
     it wasn't before) as does the pkcs12 application.
     [Steve Henson]

  *) Bugfixes in apps/x509.c: Avoid a memory leak; and don't use
     perror when PEM_read_bio_X509_REQ fails, the error message must
     be obtained from the error queue.
     [Bodo Moeller]

  *) Avoid 'thread_hash' memory leak in crypto/err/err.c by freeing
     it in ERR_remove_state if appropriate, and change ERR_get_state
     accordingly to avoid race conditions (this is necessary because
     thread_hash is no longer constant once set).
     [Bodo Moeller]

  *) Bugfix for linux-elf makefile.one.
     [Ulf Möller]

  *) RSA_get_default_method() will now cause a default
     RSA_METHOD to be chosen if one doesn't exist already.
     Previously this was only set during a call to RSA_new()
     or RSA_new_method(NULL) meaning it was possible for
     RSA_get_default_method() to return NULL.
     [Geoff Thorpe]

  *) Added native name translation to the existing DSO code
     that will convert (if the flag to do so is set) filenames
     that are sufficiently small and have no path information
     into a canonical native form. Eg. "blah" converted to
     "libblah.so" or "blah.dll" etc.
     [Geoff Thorpe]

  *) New function ERR_error_string_n(e, buf, len) which is like
     ERR_error_string(e, buf), but writes at most 'len' bytes
     including the 0 terminator.  For ERR_error_string_n, 'buf'
     may not be NULL.
     [Damien Miller <djm@mindrot.org>, Bodo Moeller]

  *) CONF library reworked to become more general.  A new CONF
     configuration file reader "class" is implemented as well as a
     new functions (NCONF_*, for "New CONF") to handle it.  The now
     old CONF_* functions are still there, but are reimplemented to
     work in terms of the new functions.  Also, a set of functions
     to handle the internal storage of the configuration data is
     provided to make it easier to write new configuration file
     reader "classes" (I can definitely see something reading a
     configuration file in XML format, for example), called _CONF_*,
     or "the configuration storage API"...

     The new configuration file reading functions are:

        NCONF_new, NCONF_free, NCONF_load, NCONF_load_fp, NCONF_load_bio,
        NCONF_get_section, NCONF_get_string, NCONF_get_numbre

        NCONF_default, NCONF_WIN32

        NCONF_dump_fp, NCONF_dump_bio

     NCONF_default and NCONF_WIN32 are method (or "class") choosers,
     NCONF_new creates a new CONF object.  This works in the same way
     as other interfaces in OpenSSL, like the BIO interface.
     NCONF_dump_* dump the internal storage of the configuration file,
     which is useful for debugging.  All other functions take the same
     arguments as the old CONF_* functions wth the exception of the
     first that must be a `CONF *' instead of a `LHASH *'.

     To make it easer to use the new classes with the old CONF_* functions,
     the function CONF_set_default_method is provided.
     [Richard Levitte]

  *) Add '-tls1' option to 'openssl ciphers', which was already
     mentioned in the documentation but had not been implemented.
     (This option is not yet really useful because even the additional
     experimental TLS 1.0 ciphers are currently treated as SSL 3.0 ciphers.)
     [Bodo Moeller]

  *) Initial DSO code added into libcrypto for letting OpenSSL (and
     OpenSSL-based applications) load shared libraries and bind to
     them in a portable way.
     [Geoff Thorpe, with contributions from Richard Levitte]

 Changes between 0.9.5 and 0.9.5a  [1 Apr 2000]

  *) Make sure _lrotl and _lrotr are only used with MSVC.

  *) Use lock CRYPTO_LOCK_RAND correctly in ssleay_rand_status
     (the default implementation of RAND_status).

  *) Rename openssl x509 option '-crlext', which was added in 0.9.5,
     to '-clrext' (= clear extensions), as intended and documented.
     [Bodo Moeller; inconsistency pointed out by Michael Attili
     <attili@amaxo.com>]

  *) Fix for HMAC. It wasn't zeroing the rest of the block if the key length
     was larger than the MD block size.      
     [Steve Henson, pointed out by Yost William <YostW@tce.com>]

  *) Modernise PKCS12_parse() so it uses STACK_OF(X509) for its ca argument
     fix a leak when the ca argument was passed as NULL. Stop X509_PUBKEY_set()
     using the passed key: if the passed key was a private key the result
     of X509_print(), for example, would be to print out all the private key
     components.
     [Steve Henson]

  *) des_quad_cksum() byte order bug fix.
     [Ulf Möller, using the problem description in krb4-0.9.7, where
      the solution is attributed to Derrick J Brashear <shadow@DEMENTIA.ORG>]

  *) Fix so V_ASN1_APP_CHOOSE works again: however its use is strongly
     discouraged.
     [Steve Henson, pointed out by Brian Korver <briank@cs.stanford.edu>]

  *) For easily testing in shell scripts whether some command
     'openssl XXX' exists, the new pseudo-command 'openssl no-XXX'
     returns with exit code 0 iff no command of the given name is available.
     'no-XXX' is printed in this case, 'XXX' otherwise.  In both cases,
     the output goes to stdout and nothing is printed to stderr.
     Additional arguments are always ignored.

     Since for each cipher there is a command of the same name,
     the 'no-cipher' compilation switches can be tested this way.

     ('openssl no-XXX' is not able to detect pseudo-commands such
     as 'quit', 'list-XXX-commands', or 'no-XXX' itself.)
     [Bodo Moeller]

  *) Update test suite so that 'make test' succeeds in 'no-rsa' configuration.
     [Bodo Moeller]

  *) For SSL_[CTX_]set_tmp_dh, don't create a DH key if SSL_OP_SINGLE_DH_USE
     is set; it will be thrown away anyway because each handshake creates
     its own key.
     ssl_cert_dup, which is used by SSL_new, now copies DH keys in addition
     to parameters -- in previous versions (since OpenSSL 0.9.3) the
     'default key' from SSL_CTX_set_tmp_dh would always be lost, meanining
     you effectivly got SSL_OP_SINGLE_DH_USE when using this macro.
     [Bodo Moeller]

  *) New s_client option -ign_eof: EOF at stdin is ignored, and
     'Q' and 'R' lose their special meanings (quit/renegotiate).
     This is part of what -quiet does; unlike -quiet, -ign_eof
     does not suppress any output.
     [Richard Levitte]

  *) Add compatibility options to the purpose and trust code. The
     purpose X509_PURPOSE_ANY is "any purpose" which automatically
     accepts a certificate or CA, this was the previous behaviour,
     with all the associated security issues.

     X509_TRUST_COMPAT is the old trust behaviour: only and
     automatically trust self signed roots in certificate store. A
     new trust setting X509_TRUST_DEFAULT is used to specify that
     a purpose has no associated trust setting and it should instead
     use the value in the default purpose.
     [Steve Henson]

  *) Fix the PKCS#8 DSA private key code so it decodes keys again
     and fix a memory leak.
     [Steve Henson]

  *) In util/mkerr.pl (which implements 'make errors'), preserve
     reason strings from the previous version of the .c file, as
     the default to have only downcase letters (and digits) in
     automatically generated reasons codes is not always appropriate.
     [Bodo Moeller]

  *) In ERR_load_ERR_strings(), build an ERR_LIB_SYS error reason table
     using strerror.  Previously, ERR_reason_error_string() returned
     library names as reason strings for SYSerr; but SYSerr is a special
     case where small numbers are errno values, not library numbers.
     [Bodo Moeller]

  *) Add '-dsaparam' option to 'openssl dhparam' application.  This
     converts DSA parameters into DH parameters. (When creating parameters,
     DSA_generate_parameters is used.)
     [Bodo Moeller]

  *) Include 'length' (recommended exponent length) in C code generated
     by 'openssl dhparam -C'.
     [Bodo Moeller]

  *) The second argument to set_label in perlasm was already being used
     so couldn't be used as a "file scope" flag. Moved to third argument
     which was free.
     [Steve Henson]

  *) In PEM_ASN1_write_bio and some other functions, use RAND_pseudo_bytes
     instead of RAND_bytes for encryption IVs and salts.
     [Bodo Moeller]

  *) Include RAND_status() into RAND_METHOD instead of implementing
     it only for md_rand.c  Otherwise replacing the PRNG by calling
     RAND_set_rand_method would be impossible.
     [Bodo Moeller]

  *) Don't let DSA_generate_key() enter an infinite loop if the random
     number generation fails.
     [Bodo Moeller]

  *) New 'rand' application for creating pseudo-random output.
     [Bodo Moeller]

  *) Added configuration support for Linux/IA64
     [Rolf Haberrecker <rolf@suse.de>]

  *) Assembler module support for Mingw32.
     [Ulf Möller]

  *) Shared library support for HPUX (in shlib/).
     [Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE> and Anonymous]

  *) Shared library support for Solaris gcc.
     [Lutz Behnke <behnke@trustcenter.de>]

 Changes between 0.9.4 and 0.9.5  [28 Feb 2000]

  *) PKCS7_encrypt() was adding text MIME headers twice because they
     were added manually and by SMIME_crlf_copy().
     [Steve Henson]

  *) In bntest.c don't call BN_rand with zero bits argument.
     [Steve Henson, pointed out by Andrew W. Gray <agray@iconsinc.com>]

  *) BN_mul bugfix: In bn_mul_part_recursion() only the a>a[n] && b>b[n]
     case was implemented. This caused BN_div_recp() to fail occasionally.
     [Ulf Möller]

  *) Add an optional second argument to the set_label() in the perl
     assembly language builder. If this argument exists and is set
     to 1 it signals that the assembler should use a symbol whose 
     scope is the entire file, not just the current function. This
     is needed with MASM which uses the format label:: for this scope.
     [Steve Henson, pointed out by Peter Runestig <peter@runestig.com>]

  *) Change the ASN1 types so they are typedefs by default. Before
     almost all types were #define'd to ASN1_STRING which was causing
     STACK_OF() problems: you couldn't declare STACK_OF(ASN1_UTF8STRING)
     for example.
     [Steve Henson]

  *) Change names of new functions to the new get1/get0 naming
     convention: After 'get1', the caller owns a reference count
     and has to call ..._free; 'get0' returns a pointer to some
     data structure without incrementing reference counters.
     (Some of the existing 'get' functions increment a reference
     counter, some don't.)
     Similarly, 'set1' and 'add1' functions increase reference
     counters or duplicate objects.
     [Steve Henson]

  *) Allow for the possibility of temp RSA key generation failure:
     the code used to assume it always worked and crashed on failure.
     [Steve Henson]

  *) Fix potential buffer overrun problem in BIO_printf().
     [Ulf Möller, using public domain code by Patrick Powell; problem
      pointed out by David Sacerdote <das33@cornell.edu>]

  *) Support EGD <http://www.lothar.com/tech/crypto/>.  New functions
     RAND_egd() and RAND_status().  In the command line application,
     the EGD socket can be specified like a seed file using RANDFILE
     or -rand.
     [Ulf Möller]

  *) Allow the string CERTIFICATE to be tolerated in PKCS#7 structures.
     Some CAs (e.g. Verisign) distribute certificates in this form.
     [Steve Henson]

  *) Remove the SSL_ALLOW_ADH compile option and set the default cipher
     list to exclude them. This means that no special compilation option
     is needed to use anonymous DH: it just needs to be included in the
     cipher list.
     [Steve Henson]

  *) Change the EVP_MD_CTX_type macro so its meaning consistent with
     EVP_MD_type. The old functionality is available in a new macro called
     EVP_MD_md(). Change code that uses it and update docs.
     [Steve Henson]

  *) ..._ctrl functions now have corresponding ..._callback_ctrl functions
     where the 'void *' argument is replaced by a function pointer argument.
     Previously 'void *' was abused to point to functions, which works on
     many platforms, but is not correct.  As these functions are usually
     called by macros defined in OpenSSL header files, most source code
     should work without changes.
     [Richard Levitte]

  *) <openssl/opensslconf.h> (which is created by Configure) now contains
     sections with information on -D... compiler switches used for
     compiling the library so that applications can see them.  To enable
     one of these sections, a pre-processor symbol OPENSSL_..._DEFINES
     must be defined.  E.g.,
        #define OPENSSL_ALGORITHM_DEFINES
        #include <openssl/opensslconf.h>
     defines all pertinent NO_<algo> symbols, such as NO_IDEA, NO_RSA, etc.
     [Richard Levitte, Ulf and Bodo Möller]

  *) Bugfix: Tolerate fragmentation and interleaving in the SSL 3/TLS
     record layer.
     [Bodo Moeller]

  *) Change the 'other' type in certificate aux info to a STACK_OF
     X509_ALGOR. Although not an AlgorithmIdentifier as such it has
     the required ASN1 format: arbitrary types determined by an OID.
     [Steve Henson]

  *) Add some PEM_write_X509_REQ_NEW() functions and a command line
     argument to 'req'. This is not because the function is newer or
     better than others it just uses the work 'NEW' in the certificate
     request header lines. Some software needs this.
     [Steve Henson]

  *) Reorganise password command line arguments: now passwords can be
     obtained from various sources. Delete the PEM_cb function and make
     it the default behaviour: i.e. if the callback is NULL and the
     usrdata argument is not NULL interpret it as a null terminated pass
     phrase. If usrdata and the callback are NULL then the pass phrase
     is prompted for as usual.
     [Steve Henson]

  *) Add support for the Compaq Atalla crypto accelerator. If it is installed,
     the support is automatically enabled. The resulting binaries will
     autodetect the card and use it if present.
     [Ben Laurie and Compaq Inc.]

  *) Work around for Netscape hang bug. This sends certificate request
     and server done in one record. Since this is perfectly legal in the
     SSL/TLS protocol it isn't a "bug" option and is on by default. See
     the bugs/SSLv3 entry for more info.
     [Steve Henson]

  *) HP-UX tune-up: new unified configs, HP C compiler bug workaround.
     [Andy Polyakov]

  *) Add -rand argument to smime and pkcs12 applications and read/write
     of seed file.
     [Steve Henson]

  *) New 'passwd' tool for crypt(3) and apr1 password hashes.
     [Bodo Moeller]

  *) Add command line password options to the remaining applications.
     [Steve Henson]

  *) Bug fix for BN_div_recp() for numerators with an even number of
     bits.
     [Ulf Möller]

  *) More tests in bntest.c, and changed test_bn output.
     [Ulf Möller]

  *) ./config recognizes MacOS X now.
     [Andy Polyakov]

  *) Bug fix for BN_div() when the first words of num and divsor are
     equal (it gave wrong results if (rem=(n1-q*d0)&BN_MASK2) < d0).
     [Ulf Möller]

  *) Add support for various broken PKCS#8 formats, and command line
     options to produce them.
     [Steve Henson]

  *) New functions BN_CTX_start(), BN_CTX_get() and BT_CTX_end() to
     get temporary BIGNUMs from a BN_CTX.
     [Ulf Möller]

  *) Correct return values in BN_mod_exp_mont() and BN_mod_exp2_mont()
     for p == 0.
     [Ulf Möller]

  *) Change the SSLeay_add_all_*() functions to OpenSSL_add_all_*() and
     include a #define from the old name to the new. The original intent
     was that statically linked binaries could for example just call
     SSLeay_add_all_ciphers() to just add ciphers to the table and not
     link with digests. This never worked becayse SSLeay_add_all_digests()
     and SSLeay_add_all_ciphers() were in the same source file so calling
     one would link with the other. They are now in separate source files.
     [Steve Henson]

  *) Add a new -notext option to 'ca' and a -pubkey option to 'spkac'.
     [Steve Henson]

  *) Use a less unusual form of the Miller-Rabin primality test (it used
     a binary algorithm for exponentiation integrated into the Miller-Rabin
     loop, our standard modexp algorithms are faster).
     [Bodo Moeller]

  *) Support for the EBCDIC character set completed.
     [Martin Kraemer <Martin.Kraemer@Mch.SNI.De>]

  *) Source code cleanups: use const where appropriate, eliminate casts,
     use void * instead of char * in lhash.
     [Ulf Möller] 

  *) Bugfix: ssl3_send_server_key_exchange was not restartable
     (the state was not changed to SSL3_ST_SW_KEY_EXCH_B, and because of
     this the server could overwrite ephemeral keys that the client
     has already seen).
     [Bodo Moeller]

  *) Turn DSA_is_prime into a macro that calls BN_is_prime,
     using 50 iterations of the Rabin-Miller test.

     DSA_generate_parameters now uses BN_is_prime_fasttest (with 50
     iterations of the Rabin-Miller test as required by the appendix
     to FIPS PUB 186[-1]) instead of DSA_is_prime.
     As BN_is_prime_fasttest includes trial division, DSA parameter
     generation becomes much faster.

     This implies a change for the callback functions in DSA_is_prime
     and DSA_generate_parameters: The callback function is called once
     for each positive witness in the Rabin-Miller test, not just
     occasionally in the inner loop; and the parameters to the
     callback function now provide an iteration count for the outer
     loop rather than for the current invocation of the inner loop.
     DSA_generate_parameters additionally can call the callback
     function with an 'iteration count' of -1, meaning that a
     candidate has passed the trial division test (when q is generated 
     from an application-provided seed, trial division is skipped).
     [Bodo Moeller]

  *) New function BN_is_prime_fasttest that optionally does trial
     division before starting the Rabin-Miller test and has
     an additional BN_CTX * argument (whereas BN_is_prime always
     has to allocate at least one BN_CTX).
     'callback(1, -1, cb_arg)' is called when a number has passed the
     trial division stage.
     [Bodo Moeller]

  *) Fix for bug in CRL encoding. The validity dates weren't being handled
     as ASN1_TIME.
     [Steve Henson]

  *) New -pkcs12 option to CA.pl script to write out a PKCS#12 file.
     [Steve Henson]

  *) New function BN_pseudo_rand().
     [Ulf Möller]

  *) Clean up BN_mod_mul_montgomery(): replace the broken (and unreadable)
     bignum version of BN_from_montgomery() with the working code from
     SSLeay 0.9.0 (the word based version is faster anyway), and clean up
     the comments.
     [Ulf Möller]

  *) Avoid a race condition in s2_clnt.c (function get_server_hello) that
     made it impossible to use the same SSL_SESSION data structure in
     SSL2 clients in multiple threads.
     [Bodo Moeller]

  *) The return value of RAND_load_file() no longer counts bytes obtained
     by stat().  RAND_load_file(..., -1) is new and uses the complete file
     to seed the PRNG (previously an explicit byte count was required).
     [Ulf Möller, Bodo Möller]

  *) Clean up CRYPTO_EX_DATA functions, some of these didn't have prototypes
     used (char *) instead of (void *) and had casts all over the place.
     [Steve Henson]

  *) Make BN_generate_prime() return NULL on error if ret!=NULL.
     [Ulf Möller]

  *) Retain source code compatibility for BN_prime_checks macro:
     BN_is_prime(..., BN_prime_checks, ...) now uses
     BN_prime_checks_for_size to determine the appropriate number of
     Rabin-Miller iterations.
     [Ulf Möller]

  *) Diffie-Hellman uses "safe" primes: DH_check() return code renamed to
     DH_CHECK_P_NOT_SAFE_PRIME.
     (Check if this is true? OpenPGP calls them "strong".)
     [Ulf Möller]

  *) Merge the functionality of "dh" and "gendh" programs into a new program
     "dhparam". The old programs are retained for now but will handle DH keys
     (instead of parameters) in future.
     [Steve Henson]

  *) Make the ciphers, s_server and s_client programs check the return values
     when a new cipher list is set.
     [Steve Henson]

  *) Enhance the SSL/TLS cipher mechanism to correctly handle the TLS 56bit
     ciphers. Before when the 56bit ciphers were enabled the sorting was
     wrong.

     The syntax for the cipher sorting has been extended to support sorting by
     cipher-strength (using the strength_bits hard coded in the tables).
     The new command is "@STRENGTH" (see also doc/apps/ciphers.pod).

     Fix a bug in the cipher-command parser: when supplying a cipher command
     string with an "undefined" symbol (neither command nor alphanumeric
     [A-Za-z0-9], ssl_set_cipher_list used to hang in an endless loop. Now
     an error is flagged.

     Due to the strength-sorting extension, the code of the
     ssl_create_cipher_list() function was completely rearranged. I hope that
     the readability was also increased :-)
     [Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>]

  *) Minor change to 'x509' utility. The -CAcreateserial option now uses 1
     for the first serial number and places 2 in the serial number file. This
     avoids problems when the root CA is created with serial number zero and
     the first user certificate has the same issuer name and serial number
     as the root CA.
     [Steve Henson]

  *) Fixes to X509_ATTRIBUTE utilities, change the 'req' program so it uses
     the new code. Add documentation for this stuff.
     [Steve Henson]

  *) Changes to X509_ATTRIBUTE utilities. These have been renamed from
     X509_*() to X509at_*() on the grounds that they don't handle X509
     structures and behave in an analagous way to the X509v3 functions:
     they shouldn't be called directly but wrapper functions should be used
     instead.

     So we also now have some wrapper functions that call the X509at functions
     when passed certificate requests. (TO DO: similar things can be done with
     PKCS#7 signed and unsigned attributes, PKCS#12 attributes and a few other
     things. Some of these need some d2i or i2d and print functionality
     because they handle more complex structures.)
     [Steve Henson]

  *) Add missing #ifndefs that caused missing symbols when building libssl
     as a shared library without RSA.  Use #ifndef NO_SSL2 instead of
     NO_RSA in ssl/s2*.c. 
     [Kris Kennaway <kris@hub.freebsd.org>, modified by Ulf Möller]

  *) Precautions against using the PRNG uninitialized: RAND_bytes() now
     has a return value which indicates the quality of the random data
     (1 = ok, 0 = not seeded).  Also an error is recorded on the thread's
     error queue. New function RAND_pseudo_bytes() generates output that is
     guaranteed to be unique but not unpredictable. RAND_add is like
     RAND_seed, but takes an extra argument for an entropy estimate
     (RAND_seed always assumes full entropy).
     [Ulf Möller]

  *) Do more iterations of Rabin-Miller probable prime test (specifically,
     3 for 1024-bit primes, 6 for 512-bit primes, 12 for 256-bit primes
     instead of only 2 for all lengths; see BN_prime_checks_for_size definition
     in crypto/bn/bn_prime.c for the complete table).  This guarantees a
     false-positive rate of at most 2^-80 for random input.
     [Bodo Moeller]

  *) Rewrite ssl3_read_n (ssl/s3_pkt.c) avoiding a couple of bugs.
     [Bodo Moeller]

  *) New function X509_CTX_rget_chain() (renamed to X509_CTX_get1_chain
     in the 0.9.5 release), this returns the chain
     from an X509_CTX structure with a dup of the stack and all
     the X509 reference counts upped: so the stack will exist
     after X509_CTX_cleanup() has been called. Modify pkcs12.c
     to use this.

     Also make SSL_SESSION_print() print out the verify return
     code.
     [Steve Henson]

  *) Add manpage for the pkcs12 command. Also change the default
     behaviour so MAC iteration counts are used unless the new
     -nomaciter option is used. This improves file security and
     only older versions of MSIE (4.0 for example) need it.
     [Steve Henson]

  *) Honor the no-xxx Configure options when creating .DEF files.
     [Ulf Möller]

  *) Add PKCS#10 attributes to field table: challengePassword, 
     unstructuredName and unstructuredAddress. These are taken from
     draft PKCS#9 v2.0 but are compatible with v1.2 provided no 
     international characters are used.

     More changes to X509_ATTRIBUTE code: allow the setting of types
     based on strings. Remove the 'loc' parameter when adding
     attributes because these will be a SET OF encoding which is sorted
     in ASN1 order.
     [Steve Henson]

  *) Initial changes to the 'req' utility to allow request generation
     automation. This will allow an application to just generate a template
     file containing all the field values and have req construct the
     request.

     Initial support for X509_ATTRIBUTE handling. Stacks of these are
     used all over the place including certificate requests and PKCS#7
     structures. They are currently handled manually where necessary with
     some primitive wrappers for PKCS#7. The new functions behave in a
     manner analogous to the X509 extension functions: they allow
     attributes to be looked up by NID and added.

     Later something similar to the X509V3 code would be desirable to
     automatically handle the encoding, decoding and printing of the
     more complex types. The string types like challengePassword can
     be handled by the string table functions.

     Also modified the multi byte string table handling. Now there is
     a 'global mask' which masks out certain types. The table itself
     can use the flag STABLE_NO_MASK to ignore the mask setting: this
     is useful when for example there is only one permissible type
     (as in countryName) and using the mask might result in no valid
     types at all.
     [Steve Henson]

  *) Clean up 'Finished' handling, and add functions SSL_get_finished and
     SSL_get_peer_finished to allow applications to obtain the latest
     Finished messages sent to the peer or expected from the peer,
     respectively.  (SSL_get_peer_finished is usually the Finished message
     actually received from the peer, otherwise the protocol will be aborted.)

     As the Finished message are message digests of the complete handshake
     (with a total of 192 bits for TLS 1.0 and more for SSL 3.0), they can
     be used for external authentication procedures when the authentication
     provided by SSL/TLS is not desired or is not enough.
     [Bodo Moeller]

  *) Enhanced support for Alpha Linux is added. Now ./config checks if
     the host supports BWX extension and if Compaq C is present on the
     $PATH. Just exploiting of the BWX extension results in 20-30%
     performance kick for some algorithms, e.g. DES and RC4 to mention
     a couple. Compaq C in turn generates ~20% faster code for MD5 and
     SHA1.
     [Andy Polyakov]

  *) Add support for MS "fast SGC". This is arguably a violation of the
     SSL3/TLS protocol. Netscape SGC does two handshakes: the first with
     weak crypto and after checking the certificate is SGC a second one
     with strong crypto. MS SGC stops the first handshake after receiving
     the server certificate message and sends a second client hello. Since
     a server will typically do all the time consuming operations before
     expecting any further messages from the client (server key exchange
     is the most expensive) there is little difference between the two.

     To get OpenSSL to support MS SGC we have to permit a second client
     hello message after we have sent server done. In addition we have to
     reset the MAC if we do get this second client hello.
     [Steve Henson]

  *) Add a function 'd2i_AutoPrivateKey()' this will automatically decide
     if a DER encoded private key is RSA or DSA traditional format. Changed
     d2i_PrivateKey_bio() to use it. This is only needed for the "traditional"
     format DER encoded private key. Newer code should use PKCS#8 format which
     has the key type encoded in the ASN1 structure. Added DER private key
     support to pkcs8 application.
     [Steve Henson]

  *) SSL 3/TLS 1 servers now don't request certificates when an anonymous
     ciphersuites has been selected (as required by the SSL 3/TLS 1
     specifications).  Exception: When SSL_VERIFY_FAIL_IF_NO_PEER_CERT
     is set, we interpret this as a request to violate the specification
     (the worst that can happen is a handshake failure, and 'correct'
     behaviour would result in a handshake failure anyway).
     [Bodo Moeller]

  *) In SSL_CTX_add_session, take into account that there might be multiple
     SSL_SESSION structures with the same session ID (e.g. when two threads
     concurrently obtain them from an external cache).
     The internal cache can handle only one SSL_SESSION with a given ID,
     so if there's a conflict, we now throw out the old one to achieve
     consistency.
     [Bodo Moeller]

  *) Add OIDs for idea and blowfish in CBC mode. This will allow both
     to be used in PKCS#5 v2.0 and S/MIME.  Also add checking to
     some routines that use cipher OIDs: some ciphers do not have OIDs
     defined and so they cannot be used for S/MIME and PKCS#5 v2.0 for
     example.
     [Steve Henson]

  *) Simplify the trust setting structure and code. Now we just have
     two sequences of OIDs for trusted and rejected settings. These will
     typically have values the same as the extended key usage extension
     and any application specific purposes.

     The trust checking code now has a default behaviour: it will just
     check for an object with the same NID as the passed id. Functions can
     be provided to override either the default behaviour or the behaviour
     for a given id. SSL client, server and email already have functions
     in place for compatibility: they check the NID and also return "trusted"
     if the certificate is self signed.
     [Steve Henson]

  *) Add d2i,i2d bio/fp functions for PrivateKey: these convert the
     traditional format into an EVP_PKEY structure.
     [Steve Henson]

  *) Add a password callback function PEM_cb() which either prompts for
     a password if usr_data is NULL or otherwise assumes it is a null
     terminated password. Allow passwords to be passed on command line
     environment or config files in a few more utilities.
     [Steve Henson]

  *) Add a bunch of DER and PEM functions to handle PKCS#8 format private
     keys. Add some short names for PKCS#8 PBE algorithms and allow them
     to be specified on the command line for the pkcs8 and pkcs12 utilities.
     Update documentation.
     [Steve Henson]

  *) Support for ASN1 "NULL" type. This could be handled before by using
     ASN1_TYPE but there wasn't any function that would try to read a NULL
     and produce an error if it couldn't. For compatibility we also have
     ASN1_NULL_new() and ASN1_NULL_free() functions but these are faked and
     don't allocate anything because they don't need to.
     [Steve Henson]

  *) Initial support for MacOS is now provided. Examine INSTALL.MacOS
     for details.
     [Andy Polyakov, Roy Woods <roy@centicsystems.ca>]

  *) Rebuild of the memory allocation routines used by OpenSSL code and
     possibly others as well.  The purpose is to make an interface that
     provide hooks so anyone can build a separate set of allocation and
     deallocation routines to be used by OpenSSL, for example memory
     pool implementations, or something else, which was previously hard
     since Malloc(), Realloc() and Free() were defined as macros having
     the values malloc, realloc and free, respectively (except for Win32
     compilations).  The same is provided for memory debugging code.
     OpenSSL already comes with functionality to find memory leaks, but
     this gives people a chance to debug other memory problems.

     With these changes, a new set of functions and macros have appeared:

       CRYPTO_set_mem_debug_functions()	        [F]
       CRYPTO_get_mem_debug_functions()         [F]
       CRYPTO_dbg_set_options()	                [F]
       CRYPTO_dbg_get_options()                 [F]
       CRYPTO_malloc_debug_init()               [M]

     The memory debug functions are NULL by default, unless the library
     is compiled with CRYPTO_MDEBUG or friends is defined.  If someone
     wants to debug memory anyway, CRYPTO_malloc_debug_init() (which
     gives the standard debugging functions that come with OpenSSL) or
     CRYPTO_set_mem_debug_functions() (tells OpenSSL to use functions
     provided by the library user) must be used.  When the standard
     debugging functions are used, CRYPTO_dbg_set_options can be used to
     request additional information:
     CRYPTO_dbg_set_options(V_CYRPTO_MDEBUG_xxx) corresponds to setting
     the CRYPTO_MDEBUG_xxx macro when compiling the library.   

     Also, things like CRYPTO_set_mem_functions will always give the
     expected result (the new set of functions is used for allocation
     and deallocation) at all times, regardless of platform and compiler
     options.

     To finish it up, some functions that were never use in any other
     way than through macros have a new API and new semantic:

       CRYPTO_dbg_malloc()
       CRYPTO_dbg_realloc()
       CRYPTO_dbg_free()

     All macros of value have retained their old syntax.
     [Richard Levitte and Bodo Moeller]

  *) Some S/MIME fixes. The OID for SMIMECapabilities was wrong, the
     ordering of SMIMECapabilities wasn't in "strength order" and there
     was a missing NULL in the AlgorithmIdentifier for the SHA1 signature
     algorithm.
     [Steve Henson]

  *) Some ASN1 types with illegal zero length encoding (INTEGER,
     ENUMERATED and OBJECT IDENTIFIER) choked the ASN1 routines.
     [Frans Heymans <fheymans@isaserver.be>, modified by Steve Henson]

  *) Merge in my S/MIME library for OpenSSL. This provides a simple
     S/MIME API on top of the PKCS#7 code, a MIME parser (with enough
     functionality to handle multipart/signed properly) and a utility
     called 'smime' to call all this stuff. This is based on code I
     originally wrote for Celo who have kindly allowed it to be
     included in OpenSSL.
     [Steve Henson]

  *) Add variants des_set_key_checked and des_set_key_unchecked of
     des_set_key (aka des_key_sched).  Global variable des_check_key
     decides which of these is called by des_set_key; this way
     des_check_key behaves as it always did, but applications and
     the library itself, which was buggy for des_check_key == 1,
     have a cleaner way to pick the version they need.
     [Bodo Moeller]

  *) New function PKCS12_newpass() which changes the password of a
     PKCS12 structure.
     [Steve Henson]

  *) Modify X509_TRUST and X509_PURPOSE so it also uses a static and
     dynamic mix. In both cases the ids can be used as an index into the
     table. Also modified the X509_TRUST_add() and X509_PURPOSE_add()
     functions so they accept a list of the field values and the
     application doesn't need to directly manipulate the X509_TRUST
     structure.
     [Steve Henson]

  *) Modify the ASN1_STRING_TABLE stuff so it also uses bsearch and doesn't
     need initialising.
     [Steve Henson]

  *) Modify the way the V3 extension code looks up extensions. This now
     works in a similar way to the object code: we have some "standard"
     extensions in a static table which is searched with OBJ_bsearch()
     and the application can add dynamic ones if needed. The file
     crypto/x509v3/ext_dat.h now has the info: this file needs to be
     updated whenever a new extension is added to the core code and kept
     in ext_nid order. There is a simple program 'tabtest.c' which checks
     this. New extensions are not added too often so this file can readily
     be maintained manually.

     There are two big advantages in doing things this way. The extensions
     can be looked up immediately and no longer need to be "added" using
     X509V3_add_standard_extensions(): this function now does nothing.
     [Side note: I get *lots* of email saying the extension code doesn't
      work because people forget to call this function]
     Also no dynamic allocation is done unless new extensions are added:
     so if we don't add custom extensions there is no need to call
     X509V3_EXT_cleanup().
     [Steve Henson]

  *) Modify enc utility's salting as follows: make salting the default. Add a
     magic header, so unsalted files fail gracefully instead of just decrypting
     to garbage. This is because not salting is a big security hole, so people
     should be discouraged from doing it.
     [Ben Laurie]

  *) Fixes and enhancements to the 'x509' utility. It allowed a message
     digest to be passed on the command line but it only used this
     parameter when signing a certificate. Modified so all relevant
     operations are affected by the digest parameter including the
     -fingerprint and -x509toreq options. Also -x509toreq choked if a
     DSA key was used because it didn't fix the digest.
     [Steve Henson]

  *) Initial certificate chain verify code. Currently tests the untrusted
     certificates for consistency with the verify purpose (which is set
     when the X509_STORE_CTX structure is set up) and checks the pathlength.

     There is a NO_CHAIN_VERIFY compilation option to keep the old behaviour:
     this is because it will reject chains with invalid extensions whereas
     every previous version of OpenSSL and SSLeay made no checks at all.

     Trust code: checks the root CA for the relevant trust settings. Trust
     settings have an initial value consistent with the verify purpose: e.g.
     if the verify purpose is for SSL client use it expects the CA to be
     trusted for SSL client use. However the default value can be changed to
     permit custom trust settings: one example of this would be to only trust
     certificates from a specific "secure" set of CAs.

     Also added X509_STORE_CTX_new() and X509_STORE_CTX_free() functions
     which should be used for version portability: especially since the
     verify structure is likely to change more often now.

     SSL integration. Add purpose and trust to SSL_CTX and SSL and functions
     to set them. If not set then assume SSL clients will verify SSL servers
     and vice versa.

     Two new options to the verify program: -untrusted allows a set of
     untrusted certificates to be passed in and -purpose which sets the
     intended purpose of the certificate. If a purpose is set then the
     new chain verify code is used to check extension consistency.
     [Steve Henson]

  *) Support for the authority information access extension.
     [Steve Henson]

  *) Modify RSA and DSA PEM read routines to transparently handle
     PKCS#8 format private keys. New *_PUBKEY_* functions that handle
     public keys in a format compatible with certificate
     SubjectPublicKeyInfo structures. Unfortunately there were already
     functions called *_PublicKey_* which used various odd formats so
     these are retained for compatibility: however the DSA variants were
     never in a public release so they have been deleted. Changed dsa/rsa
     utilities to handle the new format: note no releases ever handled public
     keys so we should be OK.

     The primary motivation for this change is to avoid the same fiasco
     that dogs private keys: there are several incompatible private key
     formats some of which are standard and some OpenSSL specific and
     require various evil hacks to allow partial transparent handling and
     even then it doesn't work with DER formats. Given the option anything
     other than PKCS#8 should be dumped: but the other formats have to
     stay in the name of compatibility.

     With public keys and the benefit of hindsight one standard format 
     is used which works with EVP_PKEY, RSA or DSA structures: though
     it clearly returns an error if you try to read the wrong kind of key.

     Added a -pubkey option to the 'x509' utility to output the public key.
     Also rename the EVP_PKEY_get_*() to EVP_PKEY_rget_*()
     (renamed to EVP_PKEY_get1_*() in the OpenSSL 0.9.5 release) and add
     EVP_PKEY_rset_*() functions (renamed to EVP_PKEY_set1_*())
     that do the same as the EVP_PKEY_assign_*() except they up the
     reference count of the added key (they don't "swallow" the
     supplied key).
     [Steve Henson]

  *) Fixes to crypto/x509/by_file.c the code to read in certificates and
     CRLs would fail if the file contained no certificates or no CRLs:
     added a new function to read in both types and return the number
     read: this means that if none are read it will be an error. The
     DER versions of the certificate and CRL reader would always fail
     because it isn't possible to mix certificates and CRLs in DER format
     without choking one or the other routine. Changed this to just read
     a certificate: this is the best we can do. Also modified the code
     in apps/verify.c to take notice of return codes: it was previously
     attempting to read in certificates from NULL pointers and ignoring
     any errors: this is one reason why the cert and CRL reader seemed
     to work. It doesn't check return codes from the default certificate
     routines: these may well fail if the certificates aren't installed.
     [Steve Henson]

  *) Code to support otherName option in GeneralName.
     [Steve Henson]

  *) First update to verify code. Change the verify utility
     so it warns if it is passed a self signed certificate:
     for consistency with the normal behaviour. X509_verify
     has been modified to it will now verify a self signed
     certificate if *exactly* the same certificate appears
     in the store: it was previously impossible to trust a
     single self signed certificate. This means that:
     openssl verify ss.pem
     now gives a warning about a self signed certificate but
     openssl verify -CAfile ss.pem ss.pem
     is OK.
     [Steve Henson]

  *) For servers, store verify_result in SSL_SESSION data structure
     (and add it to external session representation).
     This is needed when client certificate verifications fails,
     but an application-provided verification callback (set by
     SSL_CTX_set_cert_verify_callback) allows accepting the session
     anyway (i.e. leaves x509_store_ctx->error != X509_V_OK
     but returns 1): When the session is reused, we have to set
     ssl->verify_result to the appropriate error code to avoid
     security holes.
     [Bodo Moeller, problem pointed out by Lutz Jaenicke]

  *) Fix a bug in the new PKCS#7 code: it didn't consider the
     case in PKCS7_dataInit() where the signed PKCS7 structure
     didn't contain any existing data because it was being created.
     [Po-Cheng Chen <pocheng@nst.com.tw>, slightly modified by Steve Henson]

  *) Add a salt to the key derivation routines in enc.c. This
     forms the first 8 bytes of the encrypted file. Also add a
     -S option to allow a salt to be input on the command line.
     [Steve Henson]

  *) New function X509_cmp(). Oddly enough there wasn't a function
     to compare two certificates. We do this by working out the SHA1
     hash and comparing that. X509_cmp() will be needed by the trust
     code.
     [Steve Henson]

  *) SSL_get1_session() is like SSL_get_session(), but increments
     the reference count in the SSL_SESSION returned.
     [Geoff Thorpe <geoff@eu.c2.net>]

  *) Fix for 'req': it was adding a null to request attributes.
     Also change the X509_LOOKUP and X509_INFO code to handle
     certificate auxiliary information.
     [Steve Henson]

  *) Add support for 40 and 64 bit RC2 and RC4 algorithms: document
     the 'enc' command.
     [Steve Henson]

  *) Add the possibility to add extra information to the memory leak
     detecting output, to form tracebacks, showing from where each
     allocation was originated: CRYPTO_push_info("constant string") adds
     the string plus current file name and line number to a per-thread
     stack, CRYPTO_pop_info() does the obvious, CRYPTO_remove_all_info()
     is like calling CYRPTO_pop_info() until the stack is empty.
     Also updated memory leak detection code to be multi-thread-safe.
     [Richard Levitte]

  *) Add options -text and -noout to pkcs7 utility and delete the
     encryption options which never did anything. Update docs.
     [Steve Henson]

  *) Add options to some of the utilities to allow the pass phrase
     to be included on either the command line (not recommended on
     OSes like Unix) or read from the environment. Update the
     manpages and fix a few bugs.
     [Steve Henson]

  *) Add a few manpages for some of the openssl commands.
     [Steve Henson]

  *) Fix the -revoke option in ca. It was freeing up memory twice,
     leaking and not finding already revoked certificates.
     [Steve Henson]

  *) Extensive changes to support certificate auxiliary information.
     This involves the use of X509_CERT_AUX structure and X509_AUX
     functions. An X509_AUX function such as PEM_read_X509_AUX()
     can still read in a certificate file in the usual way but it
     will also read in any additional "auxiliary information". By
     doing things this way a fair degree of compatibility can be
     retained: existing certificates can have this information added
     using the new 'x509' options. 

     Current auxiliary information includes an "alias" and some trust
     settings. The trust settings will ultimately be used in enhanced
     certificate chain verification routines: currently a certificate
     can only be trusted if it is self signed and then it is trusted
     for all purposes.
     [Steve Henson]

  *) Fix assembler for Alpha (tested only on DEC OSF not Linux or *BSD).
     The problem was that one of the replacement routines had not been working
     since SSLeay releases.  For now the offending routine has been replaced
     with non-optimised assembler.  Even so, this now gives around 95%
     performance improvement for 1024 bit RSA signs.
     [Mark Cox]

  *) Hack to fix PKCS#7 decryption when used with some unorthodox RC2 
     handling. Most clients have the effective key size in bits equal to
     the key length in bits: so a 40 bit RC2 key uses a 40 bit (5 byte) key.
     A few however don't do this and instead use the size of the decrypted key
     to determine the RC2 key length and the AlgorithmIdentifier to determine
     the effective key length. In this case the effective key length can still
     be 40 bits but the key length can be 168 bits for example. This is fixed
     by manually forcing an RC2 key into the EVP_PKEY structure because the
     EVP code can't currently handle unusual RC2 key sizes: it always assumes
     the key length and effective key length are equal.
     [Steve Henson]

  *) Add a bunch of functions that should simplify the creation of 
     X509_NAME structures. Now you should be able to do:
     X509_NAME_add_entry_by_txt(nm, "CN", MBSTRING_ASC, "Steve", -1, -1, 0);
     and have it automatically work out the correct field type and fill in
     the structures. The more adventurous can try:
     X509_NAME_add_entry_by_txt(nm, field, MBSTRING_UTF8, str, -1, -1, 0);
     and it will (hopefully) work out the correct multibyte encoding.
     [Steve Henson]

  *) Change the 'req' utility to use the new field handling and multibyte
     copy routines. Before the DN field creation was handled in an ad hoc
     way in req, ca, and x509 which was rather broken and didn't support
     BMPStrings or UTF8Strings. Since some software doesn't implement
     BMPStrings or UTF8Strings yet, they can be enabled using the config file
     using the dirstring_type option. See the new comment in the default
     openssl.cnf for more info.
     [Steve Henson]

  *) Make crypto/rand/md_rand.c more robust:
     - Assure unique random numbers after fork().
     - Make sure that concurrent threads access the global counter and
       md serializably so that we never lose entropy in them
       or use exactly the same state in multiple threads.
       Access to the large state is not always serializable because
       the additional locking could be a performance killer, and
       md should be large enough anyway.
     [Bodo Moeller]

  *) New file apps/app_rand.c with commonly needed functionality
     for handling the random seed file.

     Use the random seed file in some applications that previously did not:
          ca,
          dsaparam -genkey (which also ignored its '-rand' option), 
          s_client,
          s_server,
          x509 (when signing).
     Except on systems with /dev/urandom, it is crucial to have a random
     seed file at least for key creation, DSA signing, and for DH exchanges;
     for RSA signatures we could do without one.

     gendh and gendsa (unlike genrsa) used to read only the first byte
     of each file listed in the '-rand' option.  The function as previously
     found in genrsa is now in app_rand.c and is used by all programs
     that support '-rand'.
     [Bodo Moeller]

  *) In RAND_write_file, use mode 0600 for creating files;
     don't just chmod when it may be too late.
     [Bodo Moeller]

  *) Report an error from X509_STORE_load_locations
     when X509_LOOKUP_load_file or X509_LOOKUP_add_dir failed.
     [Bill Perry]

  *) New function ASN1_mbstring_copy() this copies a string in either
     ASCII, Unicode, Universal (4 bytes per character) or UTF8 format
     into an ASN1_STRING type. A mask of permissible types is passed
     and it chooses the "minimal" type to use or an error if not type
     is suitable.
     [Steve Henson]

  *) Add function equivalents to the various macros in asn1.h. The old
     macros are retained with an M_ prefix. Code inside the library can
     use the M_ macros. External code (including the openssl utility)
     should *NOT* in order to be "shared library friendly".
     [Steve Henson]

  *) Add various functions that can check a certificate's extensions
     to see if it usable for various purposes such as SSL client,
     server or S/MIME and CAs of these types. This is currently 
     VERY EXPERIMENTAL but will ultimately be used for certificate chain
     verification. Also added a -purpose flag to x509 utility to
     print out all the purposes.
     [Steve Henson]

  *) Add a CRYPTO_EX_DATA to X509 certificate structure and associated
     functions.
     [Steve Henson]

  *) New X509V3_{X509,CRL,REVOKED}_get_d2i() functions. These will search
     for, obtain and decode and extension and obtain its critical flag.
     This allows all the necessary extension code to be handled in a
     single function call.
     [Steve Henson]

  *) RC4 tune-up featuring 30-40% performance improvement on most RISC
     platforms. See crypto/rc4/rc4_enc.c for further details.
     [Andy Polyakov]

  *) New -noout option to asn1parse. This causes no output to be produced
     its main use is when combined with -strparse and -out to extract data
     from a file (which may not be in ASN.1 format).
     [Steve Henson]

  *) Fix for pkcs12 program. It was hashing an invalid certificate pointer
     when producing the local key id.
     [Richard Levitte <levitte@stacken.kth.se>]

  *) New option -dhparam in s_server. This allows a DH parameter file to be
     stated explicitly. If it is not stated then it tries the first server
     certificate file. The previous behaviour hard coded the filename
     "server.pem".
     [Steve Henson]

  *) Add -pubin and -pubout options to the rsa and dsa commands. These allow
     a public key to be input or output. For example:
     openssl rsa -in key.pem -pubout -out pubkey.pem
     Also added necessary DSA public key functions to handle this.
     [Steve Henson]

  *) Fix so PKCS7_dataVerify() doesn't crash if no certificates are contained
     in the message. This was handled by allowing
     X509_find_by_issuer_and_serial() to tolerate a NULL passed to it.
     [Steve Henson, reported by Sampo Kellomaki <sampo@mail.neuronio.pt>]

  *) Fix for bug in d2i_ASN1_bytes(): other ASN1 functions add an extra null
     to the end of the strings whereas this didn't. This would cause problems
     if strings read with d2i_ASN1_bytes() were later modified.
     [Steve Henson, reported by Arne Ansper <arne@ats.cyber.ee>]

  *) Fix for base64 decode bug. When a base64 bio reads only one line of
     data and it contains EOF it will end up returning an error. This is
     caused by input 46 bytes long. The cause is due to the way base64
     BIOs find the start of base64 encoded data. They do this by trying a
     trial decode on each line until they find one that works. When they
     do a flag is set and it starts again knowing it can pass all the
     data directly through the decoder. Unfortunately it doesn't reset
     the context it uses. This means that if EOF is reached an attempt
     is made to pass two EOFs through the context and this causes the
     resulting error. This can also cause other problems as well. As is
     usual with these problems it takes *ages* to find and the fix is
     trivial: move one line.
     [Steve Henson, reported by ian@uns.ns.ac.yu (Ivan Nejgebauer) ]

  *) Ugly workaround to get s_client and s_server working under Windows. The
     old code wouldn't work because it needed to select() on sockets and the
     tty (for keypresses and to see if data could be written). Win32 only
     supports select() on sockets so we select() with a 1s timeout on the
     sockets and then see if any characters are waiting to be read, if none
     are present then we retry, we also assume we can always write data to
     the tty. This isn't nice because the code then blocks until we've
     received a complete line of data and it is effectively polling the
     keyboard at 1s intervals: however it's quite a bit better than not
     working at all :-) A dedicated Windows application might handle this
     with an event loop for example.
     [Steve Henson]

  *) Enhance RSA_METHOD structure. Now there are two extra methods, rsa_sign
     and rsa_verify. When the RSA_FLAGS_SIGN_VER option is set these functions
     will be called when RSA_sign() and RSA_verify() are used. This is useful
     if rsa_pub_dec() and rsa_priv_enc() equivalents are not available.
     For this to work properly RSA_public_decrypt() and RSA_private_encrypt()
     should *not* be used: RSA_sign() and RSA_verify() must be used instead.
     This necessitated the support of an extra signature type NID_md5_sha1
     for SSL signatures and modifications to the SSL library to use it instead
     of calling RSA_public_decrypt() and RSA_private_encrypt().
     [Steve Henson]

  *) Add new -verify -CAfile and -CApath options to the crl program, these
     will lookup a CRL issuers certificate and verify the signature in a
     similar way to the verify program. Tidy up the crl program so it
     no longer accesses structures directly. Make the ASN1 CRL parsing a bit
     less strict. It will now permit CRL extensions even if it is not
     a V2 CRL: this will allow it to tolerate some broken CRLs.
     [Steve Henson]

  *) Initialize all non-automatic variables each time one of the openssl
     sub-programs is started (this is necessary as they may be started
     multiple times from the "OpenSSL>" prompt).
     [Lennart Bang, Bodo Moeller]

  *) Preliminary compilation option RSA_NULL which disables RSA crypto without
     removing all other RSA functionality (this is what NO_RSA does). This
     is so (for example) those in the US can disable those operations covered
     by the RSA patent while allowing storage and parsing of RSA keys and RSA
     key generation.
     [Steve Henson]

  *) Non-copying interface to BIO pairs.
     (still largely untested)
     [Bodo Moeller]

  *) New function ANS1_tag2str() to convert an ASN1 tag to a descriptive
     ASCII string. This was handled independently in various places before.
     [Steve Henson]

  *) New functions UTF8_getc() and UTF8_putc() that parse and generate
     UTF8 strings a character at a time.
     [Steve Henson]

  *) Use client_version from client hello to select the protocol
     (s23_srvr.c) and for RSA client key exchange verification
     (s3_srvr.c), as required by the SSL 3.0/TLS 1.0 specifications.
     [Bodo Moeller]

  *) Add various utility functions to handle SPKACs, these were previously
     handled by poking round in the structure internals. Added new function
     NETSCAPE_SPKI_print() to print out SPKAC and a new utility 'spkac' to
     print, verify and generate SPKACs. Based on an original idea from
     Massimiliano Pala <madwolf@comune.modena.it> but extensively modified.
     [Steve Henson]

  *) RIPEMD160 is operational on all platforms and is back in 'make test'.
     [Andy Polyakov]

  *) Allow the config file extension section to be overwritten on the
     command line. Based on an original idea from Massimiliano Pala
     <madwolf@comune.modena.it>. The new option is called -extensions
     and can be applied to ca, req and x509. Also -reqexts to override
     the request extensions in req and -crlexts to override the crl extensions
     in ca.
     [Steve Henson]

  *) Add new feature to the SPKAC handling in ca.  Now you can include
     the same field multiple times by preceding it by "XXXX." for example:
     1.OU="Unit name 1"
     2.OU="Unit name 2"
     this is the same syntax as used in the req config file.
     [Steve Henson]

  *) Allow certificate extensions to be added to certificate requests. These
     are specified in a 'req_extensions' option of the req section of the
     config file. They can be printed out with the -text option to req but
     are otherwise ignored at present.
     [Steve Henson]

  *) Fix a horrible bug in enc_read() in crypto/evp/bio_enc.c: if the first
     data read consists of only the final block it would not decrypted because
     EVP_CipherUpdate() would correctly report zero bytes had been decrypted.
     A misplaced 'break' also meant the decrypted final block might not be
     copied until the next read.
     [Steve Henson]

  *) Initial support for DH_METHOD. Again based on RSA_METHOD. Also added
     a few extra parameters to the DH structure: these will be useful if
     for example we want the value of 'q' or implement X9.42 DH.
     [Steve Henson]

  *) Initial support for DSA_METHOD. This is based on the RSA_METHOD and
     provides hooks that allow the default DSA functions or functions on a
     "per key" basis to be replaced. This allows hardware acceleration and
     hardware key storage to be handled without major modification to the
     library. Also added low level modexp hooks and CRYPTO_EX structure and 
     associated functions.
     [Steve Henson]

  *) Add a new flag to memory BIOs, BIO_FLAG_MEM_RDONLY. This marks the BIO
     as "read only": it can't be written to and the buffer it points to will
     not be freed. Reading from a read only BIO is much more efficient than
     a normal memory BIO. This was added because there are several times when
     an area of memory needs to be read from a BIO. The previous method was
     to create a memory BIO and write the data to it, this results in two
     copies of the data and an O(n^2) reading algorithm. There is a new
     function BIO_new_mem_buf() which creates a read only memory BIO from
     an area of memory. Also modified the PKCS#7 routines to use read only
     memory BIOs.
     [Steve Henson]

  *) Bugfix: ssl23_get_client_hello did not work properly when called in
     state SSL23_ST_SR_CLNT_HELLO_B, i.e. when the first 7 bytes of
     a SSLv2-compatible client hello for SSLv3 or TLSv1 could be read,
     but a retry condition occured while trying to read the rest.
     [Bodo Moeller]

  *) The PKCS7_ENC_CONTENT_new() function was setting the content type as
     NID_pkcs7_encrypted by default: this was wrong since this should almost
     always be NID_pkcs7_data. Also modified the PKCS7_set_type() to handle
     the encrypted data type: this is a more sensible place to put it and it
     allows the PKCS#12 code to be tidied up that duplicated this
     functionality.
     [Steve Henson]

  *) Changed obj_dat.pl script so it takes its input and output files on
     the command line. This should avoid shell escape redirection problems
     under Win32.
     [Steve Henson]

  *) Initial support for certificate extension requests, these are included
     in things like Xenroll certificate requests. Included functions to allow
     extensions to be obtained and added.
     [Steve Henson]

  *) -crlf option to s_client and s_server for sending newlines as
     CRLF (as required by many protocols).
     [Bodo Moeller]

 Changes between 0.9.3a and 0.9.4  [09 Aug 1999]
  
  *) Install libRSAglue.a when OpenSSL is built with RSAref.
     [Ralf S. Engelschall]

  *) A few more ``#ifndef NO_FP_API / #endif'' pairs for consistency.
     [Andrija Antonijevic <TheAntony2@bigfoot.com>]

  *) Fix -startdate and -enddate (which was missing) arguments to 'ca'
     program.
     [Steve Henson]

  *) New function DSA_dup_DH, which duplicates DSA parameters/keys as
     DH parameters/keys (q is lost during that conversion, but the resulting
     DH parameters contain its length).

     For 1024-bit p, DSA_generate_parameters followed by DSA_dup_DH is
     much faster than DH_generate_parameters (which creates parameters
     where p = 2*q + 1), and also the smaller q makes DH computations
     much more efficient (160-bit exponentiation instead of 1024-bit
     exponentiation); so this provides a convenient way to support DHE
     ciphersuites in SSL/TLS servers (see ssl/ssltest.c).  It is of
     utter importance to use
         SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_DH_USE);
     or
         SSL_set_options(s_ctx, SSL_OP_SINGLE_DH_USE);
     when such DH parameters are used, because otherwise small subgroup
     attacks may become possible!
     [Bodo Moeller]

  *) Avoid memory leak in i2d_DHparams.
     [Bodo Moeller]

  *) Allow the -k option to be used more than once in the enc program:
     this allows the same encrypted message to be read by multiple recipients.
     [Steve Henson]

  *) New function OBJ_obj2txt(buf, buf_len, a, no_name), this converts
     an ASN1_OBJECT to a text string. If the "no_name" parameter is set then
     it will always use the numerical form of the OID, even if it has a short
     or long name.
     [Steve Henson]

  *) Added an extra RSA flag: RSA_FLAG_EXT_PKEY. Previously the rsa_mod_exp
     method only got called if p,q,dmp1,dmq1,iqmp components were present,
     otherwise bn_mod_exp was called. In the case of hardware keys for example
     no private key components need be present and it might store extra data
     in the RSA structure, which cannot be accessed from bn_mod_exp.
     By setting RSA_FLAG_EXT_PKEY rsa_mod_exp will always be called for
     private key operations.
     [Steve Henson]

  *) Added support for SPARC Linux.
     [Andy Polyakov]

  *) pem_password_cb function type incompatibly changed from
          typedef int pem_password_cb(char *buf, int size, int rwflag);
     to
          ....(char *buf, int size, int rwflag, void *userdata);
     so that applications can pass data to their callbacks:
     The PEM[_ASN1]_{read,write}... functions and macros now take an
     additional void * argument, which is just handed through whenever
     the password callback is called.
     [Damien Miller <dmiller@ilogic.com.au>; tiny changes by Bodo Moeller]

     New function SSL_CTX_set_default_passwd_cb_userdata.

     Compatibility note: As many C implementations push function arguments
     onto the stack in reverse order, the new library version is likely to
     interoperate with programs that have been compiled with the old
     pem_password_cb definition (PEM_whatever takes some data that
     happens to be on the stack as its last argument, and the callback
     just ignores this garbage); but there is no guarantee whatsoever that
     this will work.

  *) The -DPLATFORM="\"$(PLATFORM)\"" definition and the similar -DCFLAGS=...
     (both in crypto/Makefile.ssl for use by crypto/cversion.c) caused
     problems not only on Windows, but also on some Unix platforms.
     To avoid problematic command lines, these definitions are now in an
     auto-generated file crypto/buildinf.h (created by crypto/Makefile.ssl
     for standard "make" builds, by util/mk1mf.pl for "mk1mf" builds).
     [Bodo Moeller]

  *) MIPS III/IV assembler module is reimplemented.
     [Andy Polyakov]

  *) More DES library cleanups: remove references to srand/rand and
     delete an unused file.
     [Ulf Möller]

  *) Add support for the the free Netwide assembler (NASM) under Win32,
     since not many people have MASM (ml) and it can be hard to obtain.
     This is currently experimental but it seems to work OK and pass all
     the tests. Check out INSTALL.W32 for info.
     [Steve Henson]

  *) Fix memory leaks in s3_clnt.c: All non-anonymous SSL3/TLS1 connections
     without temporary keys kept an extra copy of the server key,
     and connections with temporary keys did not free everything in case
     of an error.
     [Bodo Moeller]

  *) New function RSA_check_key and new openssl rsa option -check
     for verifying the consistency of RSA keys.
     [Ulf Moeller, Bodo Moeller]

  *) Various changes to make Win32 compile work: 
     1. Casts to avoid "loss of data" warnings in p5_crpt2.c
     2. Change unsigned int to int in b_dump.c to avoid "signed/unsigned
        comparison" warnings.
     3. Add sk_<TYPE>_sort to DEF file generator and do make update.
     [Steve Henson]

  *) Add a debugging option to PKCS#5 v2 key generation function: when
     you #define DEBUG_PKCS5V2 passwords, salts, iteration counts and
     derived keys are printed to stderr.
     [Steve Henson]

  *) Copy the flags in ASN1_STRING_dup().
     [Roman E. Pavlov <pre@mo.msk.ru>]

  *) The x509 application mishandled signing requests containing DSA
     keys when the signing key was also DSA and the parameters didn't match.

     It was supposed to omit the parameters when they matched the signing key:
     the verifying software was then supposed to automatically use the CA's
     parameters if they were absent from the end user certificate.

     Omitting parameters is no longer recommended. The test was also
     the wrong way round! This was probably due to unusual behaviour in
     EVP_cmp_parameters() which returns 1 if the parameters match. 
     This meant that parameters were omitted when they *didn't* match and
     the certificate was useless. Certificates signed with 'ca' didn't have
     this bug.
     [Steve Henson, reported by Doug Erickson <Doug.Erickson@Part.NET>]

  *) Memory leak checking (-DCRYPTO_MDEBUG) had some problems.
     The interface is as follows:
     Applications can use
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON) aka MemCheck_start(),
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF) aka MemCheck_stop();
     "off" is now the default.
     The library internally uses
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE) aka MemCheck_off(),
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE) aka MemCheck_on()
     to disable memory-checking temporarily.

     Some inconsistent states that previously were possible (and were
     even the default) are now avoided.

     -DCRYPTO_MDEBUG_TIME is new and additionally stores the current time
     with each memory chunk allocated; this is occasionally more helpful
     than just having a counter.

     -DCRYPTO_MDEBUG_THREAD is also new and adds the thread ID.

     -DCRYPTO_MDEBUG_ALL enables all of the above, plus any future
     extensions.
     [Bodo Moeller]

  *) Introduce "mode" for SSL structures (with defaults in SSL_CTX),
     which largely parallels "options", but is for changing API behaviour,
     whereas "options" are about protocol behaviour.
     Initial "mode" flags are:

     SSL_MODE_ENABLE_PARTIAL_WRITE   Allow SSL_write to report success when
                                     a single record has been written.
     SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER  Don't insist that SSL_write
                                     retries use the same buffer location.
                                     (But all of the contents must be
                                     copied!)
     [Bodo Moeller]

  *) Bugfix: SSL_set_options ignored its parameter, only SSL_CTX_set_options
     worked.

  *) Fix problems with no-hmac etc.
     [Ulf Möller, pointed out by Brian Wellington <bwelling@tislabs.com>]

  *) New functions RSA_get_default_method(), RSA_set_method() and
     RSA_get_method(). These allows replacement of RSA_METHODs without having
     to mess around with the internals of an RSA structure.
     [Steve Henson]

  *) Fix memory leaks in DSA_do_sign and DSA_is_prime.
     Also really enable memory leak checks in openssl.c and in some
     test programs.
     [Chad C. Mulligan, Bodo Moeller]

  *) Fix a bug in d2i_ASN1_INTEGER() and i2d_ASN1_INTEGER() which can mess
     up the length of negative integers. This has now been simplified to just
     store the length when it is first determined and use it later, rather
     than trying to keep track of where data is copied and updating it to
     point to the end.
     [Steve Henson, reported by Brien Wheeler
      <bwheeler@authentica-security.com>]

  *) Add a new function PKCS7_signatureVerify. This allows the verification
     of a PKCS#7 signature but with the signing certificate passed to the
     function itself. This contrasts with PKCS7_dataVerify which assumes the
     certificate is present in the PKCS#7 structure. This isn't always the
     case: certificates can be omitted from a PKCS#7 structure and be
     distributed by "out of band" means (such as a certificate database).
     [Steve Henson]

  *) Complete the PEM_* macros with DECLARE_PEM versions to replace the
     function prototypes in pem.h, also change util/mkdef.pl to add the
     necessary function names. 
     [Steve Henson]

  *) mk1mf.pl (used by Windows builds) did not properly read the
     options set by Configure in the top level Makefile, and Configure
     was not even able to write more than one option correctly.
     Fixed, now "no-idea no-rc5 -DCRYPTO_MDEBUG" etc. works as intended.
     [Bodo Moeller]

  *) New functions CONF_load_bio() and CONF_load_fp() to allow a config
     file to be loaded from a BIO or FILE pointer. The BIO version will
     for example allow memory BIOs to contain config info.
     [Steve Henson]

  *) New function "CRYPTO_num_locks" that returns CRYPTO_NUM_LOCKS.
     Whoever hopes to achieve shared-library compatibility across versions
     must use this, not the compile-time macro.
     (Exercise 0.9.4: Which is the minimum library version required by
     such programs?)
     Note: All this applies only to multi-threaded programs, others don't
     need locks.
     [Bodo Moeller]

  *) Add missing case to s3_clnt.c state machine -- one of the new SSL tests
     through a BIO pair triggered the default case, i.e.
     SSLerr(...,SSL_R_UNKNOWN_STATE).
     [Bodo Moeller]

  *) New "BIO pair" concept (crypto/bio/bss_bio.c) so that applications
     can use the SSL library even if none of the specific BIOs is
     appropriate.
     [Bodo Moeller]

  *) Fix a bug in i2d_DSAPublicKey() which meant it returned the wrong value
     for the encoded length.
     [Jeon KyoungHo <khjeon@sds.samsung.co.kr>]

  *) Add initial documentation of the X509V3 functions.
     [Steve Henson]

  *) Add a new pair of functions PEM_write_PKCS8PrivateKey() and 
     PEM_write_bio_PKCS8PrivateKey() that are equivalent to
     PEM_write_PrivateKey() and PEM_write_bio_PrivateKey() but use the more
     secure PKCS#8 private key format with a high iteration count.
     [Steve Henson]

  *) Fix determination of Perl interpreter: A perl or perl5
     _directory_ in $PATH was also accepted as the interpreter.
     [Ralf S. Engelschall]

  *) Fix demos/sign/sign.c: well there wasn't anything strictly speaking
     wrong with it but it was very old and did things like calling
     PEM_ASN1_read() directly and used MD5 for the hash not to mention some
     unusual formatting.
     [Steve Henson]

  *) Fix demos/selfsign.c: it used obsolete and deleted functions, changed
     to use the new extension code.
     [Steve Henson]

  *) Implement the PEM_read/PEM_write functions in crypto/pem/pem_all.c
     with macros. This should make it easier to change their form, add extra
     arguments etc. Fix a few PEM prototypes which didn't have cipher as a
     constant.
     [Steve Henson]

  *) Add to configuration table a new entry that can specify an alternative
     name for unistd.h (for pre-POSIX systems); we need this for NeXTstep,
     according to Mark Crispin <MRC@Panda.COM>.
     [Bodo Moeller]

#if 0
  *) DES CBC did not update the IV. Weird.
     [Ben Laurie]
#else
     des_cbc_encrypt does not update the IV, but des_ncbc_encrypt does.
     Changing the behaviour of the former might break existing programs --
     where IV updating is needed, des_ncbc_encrypt can be used.
#endif

  *) When bntest is run from "make test" it drives bc to check its
     calculations, as well as internally checking them. If an internal check
     fails, it needs to cause bc to give a non-zero result or make test carries
     on without noticing the failure. Fixed.
     [Ben Laurie]

  *) DES library cleanups.
     [Ulf Möller]

  *) Add support for PKCS#5 v2.0 PBE algorithms. This will permit PKCS#8 to be
     used with any cipher unlike PKCS#5 v1.5 which can at most handle 64 bit
     ciphers. NOTE: although the key derivation function has been verified
     against some published test vectors it has not been extensively tested
     yet. Added a -v2 "cipher" option to pkcs8 application to allow the use
     of v2.0.
     [Steve Henson]

  *) Instead of "mkdir -p", which is not fully portable, use new
     Perl script "util/mkdir-p.pl".
     [Bodo Moeller]

  *) Rewrite the way password based encryption (PBE) is handled. It used to
     assume that the ASN1 AlgorithmIdentifier parameter was a PBEParameter
     structure. This was true for the PKCS#5 v1.5 and PKCS#12 PBE algorithms
     but doesn't apply to PKCS#5 v2.0 where it can be something else. Now
     the 'parameter' field of the AlgorithmIdentifier is passed to the
     underlying key generation function so it must do its own ASN1 parsing.
     This has also changed the EVP_PBE_CipherInit() function which now has a
     'parameter' argument instead of literal salt and iteration count values
     and the function EVP_PBE_ALGOR_CipherInit() has been deleted.
     [Steve Henson]

  *) Support for PKCS#5 v1.5 compatible password based encryption algorithms
     and PKCS#8 functionality. New 'pkcs8' application linked to openssl.
     Needed to change the PEM_STRING_EVP_PKEY value which was just "PRIVATE
     KEY" because this clashed with PKCS#8 unencrypted string. Since this
     value was just used as a "magic string" and not used directly its
     value doesn't matter.
     [Steve Henson]

  *) Introduce some semblance of const correctness to BN. Shame C doesn't
     support mutable.
     [Ben Laurie]

  *) "linux-sparc64" configuration (ultrapenguin).
     [Ray Miller <ray.miller@oucs.ox.ac.uk>]
     "linux-sparc" configuration.
     [Christian Forster <fo@hawo.stw.uni-erlangen.de>]

  *) config now generates no-xxx options for missing ciphers.
     [Ulf Möller]

  *) Support the EBCDIC character set (work in progress).
     File ebcdic.c not yet included because it has a different license.
     [Martin Kraemer <Martin.Kraemer@MchP.Siemens.De>]

  *) Support BS2000/OSD-POSIX.
     [Martin Kraemer <Martin.Kraemer@MchP.Siemens.De>]

  *) Make callbacks for key generation use void * instead of char *.
     [Ben Laurie]

  *) Make S/MIME samples compile (not yet tested).
     [Ben Laurie]

  *) Additional typesafe stacks.
     [Ben Laurie]

  *) New configuration variants "bsdi-elf-gcc" (BSD/OS 4.x).
     [Bodo Moeller]


 Changes between 0.9.3 and 0.9.3a  [29 May 1999]

  *) New configuration variant "sco5-gcc".

  *) Updated some demos.
     [Sean O Riordain, Wade Scholine]

  *) Add missing BIO_free at exit of pkcs12 application.
     [Wu Zhigang]

  *) Fix memory leak in conf.c.
     [Steve Henson]

  *) Updates for Win32 to assembler version of MD5.
     [Steve Henson]

  *) Set #! path to perl in apps/der_chop to where we found it
     instead of using a fixed path.
     [Bodo Moeller]

  *) SHA library changes for irix64-mips4-cc.
     [Andy Polyakov]

  *) Improvements for VMS support.
     [Richard Levitte]


 Changes between 0.9.2b and 0.9.3  [24 May 1999]

  *) Bignum library bug fix. IRIX 6 passes "make test" now!
     This also avoids the problems with SC4.2 and unpatched SC5.  
     [Andy Polyakov <appro@fy.chalmers.se>]

  *) New functions sk_num, sk_value and sk_set to replace the previous macros.
     These are required because of the typesafe stack would otherwise break 
     existing code. If old code used a structure member which used to be STACK
     and is now STACK_OF (for example cert in a PKCS7_SIGNED structure) with
     sk_num or sk_value it would produce an error because the num, data members
     are not present in STACK_OF. Now it just produces a warning. sk_set
     replaces the old method of assigning a value to sk_value
     (e.g. sk_value(x, i) = y) which the library used in a few cases. Any code
     that does this will no longer work (and should use sk_set instead) but
     this could be regarded as a "questionable" behaviour anyway.
     [Steve Henson]

  *) Fix most of the other PKCS#7 bugs. The "experimental" code can now
     correctly handle encrypted S/MIME data.
     [Steve Henson]

  *) Change type of various DES function arguments from des_cblock
     (which means, in function argument declarations, pointer to char)
     to des_cblock * (meaning pointer to array with 8 char elements),
     which allows the compiler to do more typechecking; it was like
     that back in SSLeay, but with lots of ugly casts.

     Introduce new type const_des_cblock.
     [Bodo Moeller]

  *) Reorganise the PKCS#7 library and get rid of some of the more obvious
     problems: find RecipientInfo structure that matches recipient certificate
     and initialise the ASN1 structures properly based on passed cipher.
     [Steve Henson]

  *) Belatedly make the BN tests actually check the results.
     [Ben Laurie]

  *) Fix the encoding and decoding of negative ASN1 INTEGERS and conversion
     to and from BNs: it was completely broken. New compilation option
     NEG_PUBKEY_BUG to allow for some broken certificates that encode public
     key elements as negative integers.
     [Steve Henson]

  *) Reorganize and speed up MD5.
     [Andy Polyakov <appro@fy.chalmers.se>]

  *) VMS support.
     [Richard Levitte <richard@levitte.org>]

  *) New option -out to asn1parse to allow the parsed structure to be
     output to a file. This is most useful when combined with the -strparse
     option to examine the output of things like OCTET STRINGS.
     [Steve Henson]

  *) Make SSL library a little more fool-proof by not requiring any longer
     that SSL_set_{accept,connect}_state be called before
     SSL_{accept,connect} may be used (SSL_set_..._state is omitted
     in many applications because usually everything *appeared* to work as
     intended anyway -- now it really works as intended).
     [Bodo Moeller]

  *) Move openssl.cnf out of lib/.
     [Ulf Möller]

  *) Fix various things to let OpenSSL even pass ``egcc -pipe -O2 -Wall
     -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes
     -Wmissing-declarations -Wnested-externs -Winline'' with EGCS 1.1.2+ 
     [Ralf S. Engelschall]

  *) Various fixes to the EVP and PKCS#7 code. It may now be able to
     handle PKCS#7 enveloped data properly.
     [Sebastian Akerman <sak@parallelconsulting.com>, modified by Steve]

  *) Create a duplicate of the SSL_CTX's CERT in SSL_new instead of
     copying pointers.  The cert_st handling is changed by this in
     various ways (and thus what used to be known as ctx->default_cert
     is now called ctx->cert, since we don't resort to s->ctx->[default_]cert
     any longer when s->cert does not give us what we need).
     ssl_cert_instantiate becomes obsolete by this change.
     As soon as we've got the new code right (possibly it already is?),
     we have solved a couple of bugs of the earlier code where s->cert
     was used as if it could not have been shared with other SSL structures.

     Note that using the SSL API in certain dirty ways now will result
     in different behaviour than observed with earlier library versions:
     Changing settings for an SSL_CTX *ctx after having done s = SSL_new(ctx)
     does not influence s as it used to.
     
     In order to clean up things more thoroughly, inside SSL_SESSION
     we don't use CERT any longer, but a new structure SESS_CERT
     that holds per-session data (if available); currently, this is
     the peer's certificate chain and, for clients, the server's certificate
     and temporary key.  CERT holds only those values that can have
     meaningful defaults in an SSL_CTX.
     [Bodo Moeller]

  *) New function X509V3_EXT_i2d() to create an X509_EXTENSION structure
     from the internal representation. Various PKCS#7 fixes: remove some
     evil casts and set the enc_dig_alg field properly based on the signing
     key type.
     [Steve Henson]

  *) Allow PKCS#12 password to be set from the command line or the
     environment. Let 'ca' get its config file name from the environment
     variables "OPENSSL_CONF" or "SSLEAY_CONF" (for consistency with 'req'
     and 'x509').
     [Steve Henson]

  *) Allow certificate policies extension to use an IA5STRING for the
     organization field. This is contrary to the PKIX definition but
     VeriSign uses it and IE5 only recognises this form. Document 'x509'
     extension option.
     [Steve Henson]

  *) Add PEDANTIC compiler flag to allow compilation with gcc -pedantic,
     without disallowing inline assembler and the like for non-pedantic builds.
     [Ben Laurie]

  *) Support Borland C++ builder.
     [Janez Jere <jj@void.si>, modified by Ulf Möller]

  *) Support Mingw32.
     [Ulf Möller]

  *) SHA-1 cleanups and performance enhancements.
     [Andy Polyakov <appro@fy.chalmers.se>]

  *) Sparc v8plus assembler for the bignum library.
     [Andy Polyakov <appro@fy.chalmers.se>]

  *) Accept any -xxx and +xxx compiler options in Configure.
     [Ulf Möller]

  *) Update HPUX configuration.
     [Anonymous]
  
  *) Add missing sk_<type>_unshift() function to safestack.h
     [Ralf S. Engelschall]

  *) New function SSL_CTX_use_certificate_chain_file that sets the
     "extra_cert"s in addition to the certificate.  (This makes sense
     only for "PEM" format files, as chains as a whole are not
     DER-encoded.)
     [Bodo Moeller]

  *) Support verify_depth from the SSL API.
     x509_vfy.c had what can be considered an off-by-one-error:
     Its depth (which was not part of the external interface)
     was actually counting the number of certificates in a chain;
     now it really counts the depth.
     [Bodo Moeller]

  *) Bugfix in crypto/x509/x509_cmp.c: The SSLerr macro was used
     instead of X509err, which often resulted in confusing error
     messages since the error codes are not globally unique
     (e.g. an alleged error in ssl3_accept when a certificate
     didn't match the private key).

  *) New function SSL_CTX_set_session_id_context that allows to set a default
     value (so that you don't need SSL_set_session_id_context for each
     connection using the SSL_CTX).
     [Bodo Moeller]

  *) OAEP decoding bug fix.
     [Ulf Möller]

  *) Support INSTALL_PREFIX for package builders, as proposed by
     David Harris.
     [Bodo Moeller]

  *) New Configure options "threads" and "no-threads".  For systems
     where the proper compiler options are known (currently Solaris
     and Linux), "threads" is the default.
     [Bodo Moeller]

  *) New script util/mklink.pl as a faster substitute for util/mklink.sh.
     [Bodo Moeller]

  *) Install various scripts to $(OPENSSLDIR)/misc, not to
     $(INSTALLTOP)/bin -- they shouldn't clutter directories
     such as /usr/local/bin.
     [Bodo Moeller]

  *) "make linux-shared" to build shared libraries.
     [Niels Poppe <niels@netbox.org>]

  *) New Configure option no-<cipher> (rsa, idea, rc5, ...).
     [Ulf Möller]

  *) Add the PKCS#12 API documentation to openssl.txt. Preliminary support for
     extension adding in x509 utility.
     [Steve Henson]

  *) Remove NOPROTO sections and error code comments.
     [Ulf Möller]

  *) Partial rewrite of the DEF file generator to now parse the ANSI
     prototypes.
     [Steve Henson]

  *) New Configure options --prefix=DIR and --openssldir=DIR.
     [Ulf Möller]

  *) Complete rewrite of the error code script(s). It is all now handled
     by one script at the top level which handles error code gathering,
     header rewriting and C source file generation. It should be much better
     than the old method: it now uses a modified version of Ulf's parser to
     read the ANSI prototypes in all header files (thus the old K&R definitions
     aren't needed for error creation any more) and do a better job of
     translating function codes into names. The old 'ASN1 error code imbedded
     in a comment' is no longer necessary and it doesn't use .err files which
     have now been deleted. Also the error code call doesn't have to appear all
     on one line (which resulted in some large lines...).
     [Steve Henson]

  *) Change #include filenames from <foo.h> to <openssl/foo.h>.
     [Bodo Moeller]

  *) Change behaviour of ssl2_read when facing length-0 packets: Don't return
     0 (which usually indicates a closed connection), but continue reading.
     [Bodo Moeller]

  *) Fix some race conditions.
     [Bodo Moeller]

  *) Add support for CRL distribution points extension. Add Certificate
     Policies and CRL distribution points documentation.
     [Steve Henson]

  *) Move the autogenerated header file parts to crypto/opensslconf.h.
     [Ulf Möller]

  *) Fix new 56-bit DES export ciphersuites: they were using 7 bytes instead of
     8 of keying material. Merlin has also confirmed interop with this fix
     between OpenSSL and Baltimore C/SSL 2.0 and J/SSL 2.0.
     [Merlin Hughes <merlin@baltimore.ie>]

  *) Fix lots of warnings.
     [Richard Levitte <levitte@stacken.kth.se>]
 
  *) In add_cert_dir() in crypto/x509/by_dir.c, break out of the loop if
     the directory spec didn't end with a LIST_SEPARATOR_CHAR.
     [Richard Levitte <levitte@stacken.kth.se>]
 
  *) Fix problems with sizeof(long) == 8.
     [Andy Polyakov <appro@fy.chalmers.se>]

  *) Change functions to ANSI C.
     [Ulf Möller]

  *) Fix typos in error codes.
     [Martin Kraemer <Martin.Kraemer@MchP.Siemens.De>, Ulf Möller]

  *) Remove defunct assembler files from Configure.
     [Ulf Möller]

  *) SPARC v8 assembler BIGNUM implementation.
     [Andy Polyakov <appro@fy.chalmers.se>]

  *) Support for Certificate Policies extension: both print and set.
     Various additions to support the r2i method this uses.
     [Steve Henson]

  *) A lot of constification, and fix a bug in X509_NAME_oneline() that could
     return a const string when you are expecting an allocated buffer.
     [Ben Laurie]

  *) Add support for ASN1 types UTF8String and VISIBLESTRING, also the CHOICE
     types DirectoryString and DisplayText.
     [Steve Henson]

  *) Add code to allow r2i extensions to access the configuration database,
     add an LHASH database driver and add several ctx helper functions.
     [Steve Henson]

  *) Fix an evil bug in bn_expand2() which caused various BN functions to
     fail when they extended the size of a BIGNUM.
     [Steve Henson]

  *) Various utility functions to handle SXNet extension. Modify mkdef.pl to
     support typesafe stack.
     [Steve Henson]

  *) Fix typo in SSL_[gs]et_options().
     [Nils Frostberg <nils@medcom.se>]

  *) Delete various functions and files that belonged to the (now obsolete)
     old X509V3 handling code.
     [Steve Henson]

  *) New Configure option "rsaref".
     [Ulf Möller]

  *) Don't auto-generate pem.h.
     [Bodo Moeller]

  *) Introduce type-safe ASN.1 SETs.
     [Ben Laurie]

  *) Convert various additional casted stacks to type-safe STACK_OF() variants.
     [Ben Laurie, Ralf S. Engelschall, Steve Henson]

  *) Introduce type-safe STACKs. This will almost certainly break lots of code
     that links with OpenSSL (well at least cause lots of warnings), but fear
     not: the conversion is trivial, and it eliminates loads of evil casts. A
     few STACKed things have been converted already. Feel free to convert more.
     In the fullness of time, I'll do away with the STACK type altogether.
     [Ben Laurie]

  *) Add `openssl ca -revoke <certfile>' facility which revokes a certificate
     specified in <certfile> by updating the entry in the index.txt file.
     This way one no longer has to edit the index.txt file manually for
     revoking a certificate. The -revoke option does the gory details now.
     [Massimiliano Pala <madwolf@openca.org>, Ralf S. Engelschall]

  *) Fix `openssl crl -noout -text' combination where `-noout' killed the
     `-text' option at all and this way the `-noout -text' combination was
     inconsistent in `openssl crl' with the friends in `openssl x509|rsa|dsa'.
     [Ralf S. Engelschall]

  *) Make sure a corresponding plain text error message exists for the
     X509_V_ERR_CERT_REVOKED/23 error number which can occur when a
     verify callback function determined that a certificate was revoked.
     [Ralf S. Engelschall]

  *) Bugfix: In test/testenc, don't test "openssl <cipher>" for
     ciphers that were excluded, e.g. by -DNO_IDEA.  Also, test
     all available cipers including rc5, which was forgotten until now.
     In order to let the testing shell script know which algorithms
     are available, a new (up to now undocumented) command
     "openssl list-cipher-commands" is used.
     [Bodo Moeller]

  *) Bugfix: s_client occasionally would sleep in select() when
     it should have checked SSL_pending() first.
     [Bodo Moeller]

  *) New functions DSA_do_sign and DSA_do_verify to provide access to
     the raw DSA values prior to ASN.1 encoding.
     [Ulf Möller]

  *) Tweaks to Configure
     [Niels Poppe <niels@netbox.org>]

  *) Add support for PKCS#5 v2.0 ASN1 PBES2 structures. No other support,
     yet...
     [Steve Henson]

  *) New variables $(RANLIB) and $(PERL) in the Makefiles.
     [Ulf Möller]

  *) New config option to avoid instructions that are illegal on the 80386.
     The default code is faster, but requires at least a 486.
     [Ulf Möller]
  
  *) Got rid of old SSL2_CLIENT_VERSION (inconsistently used) and
     SSL2_SERVER_VERSION (not used at all) macros, which are now the
     same as SSL2_VERSION anyway.
     [Bodo Moeller]

  *) New "-showcerts" option for s_client.
     [Bodo Moeller]

  *) Still more PKCS#12 integration. Add pkcs12 application to openssl
     application. Various cleanups and fixes.
     [Steve Henson]

  *) More PKCS#12 integration. Add new pkcs12 directory with Makefile.ssl and
     modify error routines to work internally. Add error codes and PBE init
     to library startup routines.
     [Steve Henson]

  *) Further PKCS#12 integration. Added password based encryption, PKCS#8 and
     packing functions to asn1 and evp. Changed function names and error
     codes along the way.
     [Steve Henson]

  *) PKCS12 integration: and so it begins... First of several patches to
     slowly integrate PKCS#12 functionality into OpenSSL. Add PKCS#12
     objects to objects.h
     [Steve Henson]

  *) Add a new 'indent' option to some X509V3 extension code. Initial ASN1
     and display support for Thawte strong extranet extension.
     [Steve Henson]

  *) Add LinuxPPC support.
     [Jeff Dubrule <igor@pobox.org>]

  *) Get rid of redundant BN file bn_mulw.c, and rename bn_div64 to
     bn_div_words in alpha.s.
     [Hannes Reinecke <H.Reinecke@hw.ac.uk> and Ben Laurie]

  *) Make sure the RSA OAEP test is skipped under -DRSAref because
     OAEP isn't supported when OpenSSL is built with RSAref.
     [Ulf Moeller <ulf@fitug.de>]

  *) Move definitions of IS_SET/IS_SEQUENCE inside crypto/asn1/asn1.h 
     so they no longer are missing under -DNOPROTO. 
     [Soren S. Jorvang <soren@t.dk>]


 Changes between 0.9.1c and 0.9.2b  [22 Mar 1999]

  *) Make SSL_get_peer_cert_chain() work in servers. Unfortunately, it still
     doesn't work when the session is reused. Coming soon!
     [Ben Laurie]

  *) Fix a security hole, that allows sessions to be reused in the wrong
     context thus bypassing client cert protection! All software that uses
     client certs and session caches in multiple contexts NEEDS PATCHING to
     allow session reuse! A fuller solution is in the works.
     [Ben Laurie, problem pointed out by Holger Reif, Bodo Moeller (and ???)]

  *) Some more source tree cleanups (removed obsolete files
     crypto/bf/asm/bf586.pl, test/test.txt and crypto/sha/asm/f.s; changed
     permission on "config" script to be executable) and a fix for the INSTALL
     document.
     [Ulf Moeller <ulf@fitug.de>]

  *) Remove some legacy and erroneous uses of malloc, free instead of
     Malloc, Free.
     [Lennart Bang <lob@netstream.se>, with minor changes by Steve]

  *) Make rsa_oaep_test return non-zero on error.
     [Ulf Moeller <ulf@fitug.de>]

  *) Add support for native Solaris shared libraries. Configure
     solaris-sparc-sc4-pic, make, then run shlib/solaris-sc4.sh. It'd be nice
     if someone would make that last step automatic.
     [Matthias Loepfe <Matthias.Loepfe@AdNovum.CH>]

  *) ctx_size was not built with the right compiler during "make links". Fixed.
     [Ben Laurie]

  *) Change the meaning of 'ALL' in the cipher list. It now means "everything
     except NULL ciphers". This means the default cipher list will no longer
     enable NULL ciphers. They need to be specifically enabled e.g. with
     the string "DEFAULT:eNULL".
     [Steve Henson]

  *) Fix to RSA private encryption routines: if p < q then it would
     occasionally produce an invalid result. This will only happen with
     externally generated keys because OpenSSL (and SSLeay) ensure p > q.
     [Steve Henson]

  *) Be less restrictive and allow also `perl util/perlpath.pl
     /path/to/bin/perl' in addition to `perl util/perlpath.pl /path/to/bin',
     because this way one can also use an interpreter named `perl5' (which is
     usually the name of Perl 5.xxx on platforms where an Perl 4.x is still
     installed as `perl').
     [Matthias Loepfe <Matthias.Loepfe@adnovum.ch>]

  *) Let util/clean-depend.pl work also with older Perl 5.00x versions.
     [Matthias Loepfe <Matthias.Loepfe@adnovum.ch>]

  *) Fix Makefile.org so CC,CFLAG etc are passed to 'make links' add
     advapi32.lib to Win32 build and change the pem test comparision
     to fc.exe (thanks to Ulrich Kroener <kroneru@yahoo.com> for the
     suggestion). Fix misplaced ASNI prototypes and declarations in evp.h
     and crypto/des/ede_cbcm_enc.c.
     [Steve Henson]

  *) DES quad checksum was broken on big-endian architectures. Fixed.
     [Ben Laurie]

  *) Comment out two functions in bio.h that aren't implemented. Fix up the
     Win32 test batch file so it (might) work again. The Win32 test batch file
     is horrible: I feel ill....
     [Steve Henson]

  *) Move various #ifdefs around so NO_SYSLOG, NO_DIRENT etc are now selected
     in e_os.h. Audit of header files to check ANSI and non ANSI
     sections: 10 functions were absent from non ANSI section and not exported
     from Windows DLLs. Fixed up libeay.num for new functions.
     [Steve Henson]

  *) Make `openssl version' output lines consistent.
     [Ralf S. Engelschall]

  *) Fix Win32 symbol export lists for BIO functions: Added
     BIO_get_ex_new_index, BIO_get_ex_num, BIO_get_ex_data and BIO_set_ex_data
     to ms/libeay{16,32}.def.
     [Ralf S. Engelschall]

  *) Second round of fixing the OpenSSL perl/ stuff. It now at least compiled
     fine under Unix and passes some trivial tests I've now added. But the
     whole stuff is horribly incomplete, so a README.1ST with a disclaimer was
     added to make sure no one expects that this stuff really works in the
     OpenSSL 0.9.2 release.  Additionally I've started to clean the XS sources
     up and fixed a few little bugs and inconsistencies in OpenSSL.{pm,xs} and
     openssl_bio.xs.
     [Ralf S. Engelschall]

  *) Fix the generation of two part addresses in perl.
     [Kenji Miyake <kenji@miyake.org>, integrated by Ben Laurie]

  *) Add config entry for Linux on MIPS.
     [John Tobey <jtobey@channel1.com>]

  *) Make links whenever Configure is run, unless we are on Windoze.
     [Ben Laurie]

  *) Permit extensions to be added to CRLs using crl_section in openssl.cnf.
     Currently only issuerAltName and AuthorityKeyIdentifier make any sense
     in CRLs.
     [Steve Henson]

  *) Add a useful kludge to allow package maintainers to specify compiler and
     other platforms details on the command line without having to patch the
     Configure script everytime: One now can use ``perl Configure
     <id>:<details>'', i.e. platform ids are allowed to have details appended
     to them (seperated by colons). This is treated as there would be a static
     pre-configured entry in Configure's %table under key <id> with value
     <details> and ``perl Configure <id>'' is called.  So, when you want to
     perform a quick test-compile under FreeBSD 3.1 with pgcc and without
     assembler stuff you can use ``perl Configure "FreeBSD-elf:pgcc:-O6:::"''
     now, which overrides the FreeBSD-elf entry on-the-fly.
     [Ralf S. Engelschall]

  *) Disable new TLS1 ciphersuites by default: they aren't official yet.
     [Ben Laurie]

  *) Allow DSO flags like -fpic, -fPIC, -KPIC etc. to be specified
     on the `perl Configure ...' command line. This way one can compile
     OpenSSL libraries with Position Independent Code (PIC) which is needed
     for linking it into DSOs.
     [Ralf S. Engelschall]

  *) Remarkably, export ciphers were totally broken and no-one had noticed!
     Fixed.
     [Ben Laurie]

  *) Cleaned up the LICENSE document: The official contact for any license
     questions now is the OpenSSL core team under openssl-core@openssl.org.
     And add a paragraph about the dual-license situation to make sure people
     recognize that _BOTH_ the OpenSSL license _AND_ the SSLeay license apply
     to the OpenSSL toolkit.
     [Ralf S. Engelschall]

  *) General source tree makefile cleanups: Made `making xxx in yyy...'
     display consistent in the source tree and replaced `/bin/rm' by `rm'.
     Additonally cleaned up the `make links' target: Remove unnecessary
     semicolons, subsequent redundant removes, inline point.sh into mklink.sh
     to speed processing and no longer clutter the display with confusing
     stuff. Instead only the actually done links are displayed.
     [Ralf S. Engelschall]

  *) Permit null encryption ciphersuites, used for authentication only. It used
     to be necessary to set the preprocessor define SSL_ALLOW_ENULL to do this.
     It is now necessary to set SSL_FORBID_ENULL to prevent the use of null
     encryption.
     [Ben Laurie]

  *) Add a bunch of fixes to the PKCS#7 stuff. It used to sometimes reorder
     signed attributes when verifying signatures (this would break them), 
     the detached data encoding was wrong and public keys obtained using
     X509_get_pubkey() weren't freed.
     [Steve Henson]

  *) Add text documentation for the BUFFER functions. Also added a work around
     to a Win95 console bug. This was triggered by the password read stuff: the
     last character typed gets carried over to the next fread(). If you were 
     generating a new cert request using 'req' for example then the last
     character of the passphrase would be CR which would then enter the first
     field as blank.
     [Steve Henson]

  *) Added the new `Includes OpenSSL Cryptography Software' button as
     doc/openssl_button.{gif,html} which is similar in style to the old SSLeay
     button and can be used by applications based on OpenSSL to show the
     relationship to the OpenSSL project.  
     [Ralf S. Engelschall]

  *) Remove confusing variables in function signatures in files
     ssl/ssl_lib.c and ssl/ssl.h.
     [Lennart Bong <lob@kulthea.stacken.kth.se>]

  *) Don't install bss_file.c under PREFIX/include/
     [Lennart Bong <lob@kulthea.stacken.kth.se>]

  *) Get the Win32 compile working again. Modify mkdef.pl so it can handle
     functions that return function pointers and has support for NT specific
     stuff. Fix mk1mf.pl and VC-32.pl to support NT differences also. Various
     #ifdef WIN32 and WINNTs sprinkled about the place and some changes from
     unsigned to signed types: this was killing the Win32 compile.
     [Steve Henson]

  *) Add new certificate file to stack functions,
     SSL_add_dir_cert_subjects_to_stack() and
     SSL_add_file_cert_subjects_to_stack().  These largely supplant
     SSL_load_client_CA_file(), and can be used to add multiple certs easily
     to a stack (usually this is then handed to SSL_CTX_set_client_CA_list()).
     This means that Apache-SSL and similar packages don't have to mess around
     to add as many CAs as they want to the preferred list.
     [Ben Laurie]

  *) Experiment with doxygen documentation. Currently only partially applied to
     ssl/ssl_lib.c.
     See http://www.stack.nl/~dimitri/doxygen/index.html, and run doxygen with
     openssl.doxy as the configuration file.
     [Ben Laurie]
  
  *) Get rid of remaining C++-style comments which strict C compilers hate.
     [Ralf S. Engelschall, pointed out by Carlos Amengual]

  *) Changed BN_RECURSION in bn_mont.c to BN_RECURSION_MONT so it is not
     compiled in by default: it has problems with large keys.
     [Steve Henson]

  *) Add a bunch of SSL_xxx() functions for configuring the temporary RSA and
     DH private keys and/or callback functions which directly correspond to
     their SSL_CTX_xxx() counterparts but work on a per-connection basis. This
     is needed for applications which have to configure certificates on a
     per-connection basis (e.g. Apache+mod_ssl) instead of a per-context basis
     (e.g. s_server). 
        For the RSA certificate situation is makes no difference, but
     for the DSA certificate situation this fixes the "no shared cipher"
     problem where the OpenSSL cipher selection procedure failed because the
     temporary keys were not overtaken from the context and the API provided
     no way to reconfigure them. 
        The new functions now let applications reconfigure the stuff and they
     are in detail: SSL_need_tmp_RSA, SSL_set_tmp_rsa, SSL_set_tmp_dh,
     SSL_set_tmp_rsa_callback and SSL_set_tmp_dh_callback.  Additionally a new
     non-public-API function ssl_cert_instantiate() is used as a helper
     function and also to reduce code redundancy inside ssl_rsa.c.
     [Ralf S. Engelschall]

  *) Move s_server -dcert and -dkey options out of the undocumented feature
     area because they are useful for the DSA situation and should be
     recognized by the users.
     [Ralf S. Engelschall]

  *) Fix the cipher decision scheme for export ciphers: the export bits are
     *not* within SSL_MKEY_MASK or SSL_AUTH_MASK, they are within
     SSL_EXP_MASK.  So, the original variable has to be used instead of the
     already masked variable.
     [Richard Levitte <levitte@stacken.kth.se>]

  *) Fix 'port' variable from `int' to `unsigned int' in crypto/bio/b_sock.c
     [Richard Levitte <levitte@stacken.kth.se>]

  *) Change type of another md_len variable in pk7_doit.c:PKCS7_dataFinal()
     from `int' to `unsigned int' because it's a length and initialized by
     EVP_DigestFinal() which expects an `unsigned int *'.
     [Richard Levitte <levitte@stacken.kth.se>]

  *) Don't hard-code path to Perl interpreter on shebang line of Configure
     script. Instead use the usual Shell->Perl transition trick.
     [Ralf S. Engelschall]

  *) Make `openssl x509 -noout -modulus' functional also for DSA certificates
     (in addition to RSA certificates) to match the behaviour of `openssl dsa
     -noout -modulus' as it's already the case for `openssl rsa -noout
     -modulus'.  For RSA the -modulus is the real "modulus" while for DSA
     currently the public key is printed (a decision which was already done by
     `openssl dsa -modulus' in the past) which serves a similar purpose.
     Additionally the NO_RSA no longer completely removes the whole -modulus
     option; it now only avoids using the RSA stuff. Same applies to NO_DSA
     now, too.
     [Ralf S.  Engelschall]

  *) Add Arne Ansper's reliable BIO - this is an encrypted, block-digested
     BIO. See the source (crypto/evp/bio_ok.c) for more info.
     [Arne Ansper <arne@ats.cyber.ee>]

  *) Dump the old yucky req code that tried (and failed) to allow raw OIDs
     to be added. Now both 'req' and 'ca' can use new objects defined in the
     config file.
     [Steve Henson]

  *) Add cool BIO that does syslog (or event log on NT).
     [Arne Ansper <arne@ats.cyber.ee>, integrated by Ben Laurie]

  *) Add support for new TLS ciphersuites, TLS_RSA_EXPORT56_WITH_RC4_56_MD5,
     TLS_RSA_EXPORT56_WITH_RC2_CBC_56_MD5 and
     TLS_RSA_EXPORT56_WITH_DES_CBC_SHA, as specified in "56-bit Export Cipher
     Suites For TLS", draft-ietf-tls-56-bit-ciphersuites-00.txt.
     [Ben Laurie]

  *) Add preliminary config info for new extension code.
     [Steve Henson]

  *) Make RSA_NO_PADDING really use no padding.
     [Ulf Moeller <ulf@fitug.de>]

  *) Generate errors when private/public key check is done.
     [Ben Laurie]

  *) Overhaul for 'crl' utility. New function X509_CRL_print. Partial support
     for some CRL extensions and new objects added.
     [Steve Henson]

  *) Really fix the ASN1 IMPLICIT bug this time... Partial support for private
     key usage extension and fuller support for authority key id.
     [Steve Henson]

  *) Add OAEP encryption for the OpenSSL crypto library. OAEP is the improved
     padding method for RSA, which is recommended for new applications in PKCS
     #1 v2.0 (RFC 2437, October 1998).
     OAEP (Optimal Asymmetric Encryption Padding) has better theoretical
     foundations than the ad-hoc padding used in PKCS #1 v1.5. It is secure
     against Bleichbacher's attack on RSA.
     [Ulf Moeller <ulf@fitug.de>, reformatted, corrected and integrated by
      Ben Laurie]

  *) Updates to the new SSL compression code
     [Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)]

  *) Fix so that the version number in the master secret, when passed
     via RSA, checks that if TLS was proposed, but we roll back to SSLv3
     (because the server will not accept higher), that the version number
     is 0x03,0x01, not 0x03,0x00
     [Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)]

  *) Run extensive memory leak checks on SSL apps. Fixed *lots* of memory
     leaks in ssl/ relating to new X509_get_pubkey() behaviour. Also fixes
     in apps/ and an unrelated leak in crypto/dsa/dsa_vrf.c
     [Steve Henson]

  *) Support for RAW extensions where an arbitrary extension can be
     created by including its DER encoding. See apps/openssl.cnf for
     an example.
     [Steve Henson]

  *) Make sure latest Perl versions don't interpret some generated C array
     code as Perl array code in the crypto/err/err_genc.pl script.
     [Lars Weber <3weber@informatik.uni-hamburg.de>]

  *) Modify ms/do_ms.bat to not generate assembly language makefiles since
     not many people have the assembler. Various Win32 compilation fixes and
     update to the INSTALL.W32 file with (hopefully) more accurate Win32
     build instructions.
     [Steve Henson]

  *) Modify configure script 'Configure' to automatically create crypto/date.h
     file under Win32 and also build pem.h from pem.org. New script
     util/mkfiles.pl to create the MINFO file on environments that can't do a
     'make files': perl util/mkfiles.pl >MINFO should work.
     [Steve Henson]

  *) Major rework of DES function declarations, in the pursuit of correctness
     and purity. As a result, many evil casts evaporated, and some weirdness,
     too. You may find this causes warnings in your code. Zapping your evil
     casts will probably fix them. Mostly.
     [Ben Laurie]

  *) Fix for a typo in asn1.h. Bug fix to object creation script
     obj_dat.pl. It considered a zero in an object definition to mean
     "end of object": none of the objects in objects.h have any zeros
     so it wasn't spotted.
     [Steve Henson, reported by Erwann ABALEA <eabalea@certplus.com>]

  *) Add support for Triple DES Cipher Block Chaining with Output Feedback
     Masking (CBCM). In the absence of test vectors, the best I have been able
     to do is check that the decrypt undoes the encrypt, so far. Send me test
     vectors if you have them.
     [Ben Laurie]

  *) Correct calculation of key length for export ciphers (too much space was
     allocated for null ciphers). This has not been tested!
     [Ben Laurie]

  *) Modifications to the mkdef.pl for Win32 DEF file creation. The usage
     message is now correct (it understands "crypto" and "ssl" on its
     command line). There is also now an "update" option. This will update
     the util/ssleay.num and util/libeay.num files with any new functions.
     If you do a: 
     perl util/mkdef.pl crypto ssl update
     it will update them.
     [Steve Henson]

  *) Overhauled the Perl interface (perl/*):
     - ported BN stuff to OpenSSL's different BN library
     - made the perl/ source tree CVS-aware
     - renamed the package from SSLeay to OpenSSL (the files still contain
       their history because I've copied them in the repository)
     - removed obsolete files (the test scripts will be replaced
       by better Test::Harness variants in the future)
     [Ralf S. Engelschall]

  *) First cut for a very conservative source tree cleanup:
     1. merge various obsolete readme texts into doc/ssleay.txt
     where we collect the old documents and readme texts.
     2. remove the first part of files where I'm already sure that we no
     longer need them because of three reasons: either they are just temporary
     files which were left by Eric or they are preserved original files where
     I've verified that the diff is also available in the CVS via "cvs diff
     -rSSLeay_0_8_1b" or they were renamed (as it was definitely the case for
     the crypto/md/ stuff).
     [Ralf S. Engelschall]

  *) More extension code. Incomplete support for subject and issuer alt
     name, issuer and authority key id. Change the i2v function parameters
     and add an extra 'crl' parameter in the X509V3_CTX structure: guess
     what that's for :-) Fix to ASN1 macro which messed up
     IMPLICIT tag and add f_enum.c which adds a2i, i2a for ENUMERATED.
     [Steve Henson]

  *) Preliminary support for ENUMERATED type. This is largely copied from the
     INTEGER code.
     [Steve Henson]

  *) Add new function, EVP_MD_CTX_copy() to replace frequent use of memcpy.
     [Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)]

  *) Make sure `make rehash' target really finds the `openssl' program.
     [Ralf S. Engelschall, Matthias Loepfe <Matthias.Loepfe@adnovum.ch>]

  *) Squeeze another 7% of speed out of MD5 assembler, at least on a P2. I'd
     like to hear about it if this slows down other processors.
     [Ben Laurie]

  *) Add CygWin32 platform information to Configure script.
     [Alan Batie <batie@aahz.jf.intel.com>]

  *) Fixed ms/32all.bat script: `no_asm' -> `no-asm'
     [Rainer W. Gerling <gerling@mpg-gv.mpg.de>]
  
  *) New program nseq to manipulate netscape certificate sequences
     [Steve Henson]

  *) Modify crl2pkcs7 so it supports multiple -certfile arguments. Fix a
     few typos.
     [Steve Henson]

  *) Fixes to BN code.  Previously the default was to define BN_RECURSION
     but the BN code had some problems that would cause failures when
     doing certificate verification and some other functions.
     [Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)]

  *) Add ASN1 and PEM code to support netscape certificate sequences.
     [Steve Henson]

  *) Add ASN1 and PEM code to support netscape certificate sequences.
     [Steve Henson]

  *) Add several PKIX and private extended key usage OIDs.
     [Steve Henson]

  *) Modify the 'ca' program to handle the new extension code. Modify
     openssl.cnf for new extension format, add comments.
     [Steve Henson]

  *) More X509 V3 changes. Fix typo in v3_bitstr.c. Add support to 'req'
     and add a sample to openssl.cnf so req -x509 now adds appropriate
     CA extensions.
     [Steve Henson]

  *) Continued X509 V3 changes. Add to other makefiles, integrate with the
     error code, add initial support to X509_print() and x509 application.
     [Steve Henson]

  *) Takes a deep breath and start addding X509 V3 extension support code. Add
     files in crypto/x509v3. Move original stuff to crypto/x509v3/old. All this
     stuff is currently isolated and isn't even compiled yet.
     [Steve Henson]

  *) Continuing patches for GeneralizedTime. Fix up certificate and CRL
     ASN1 to use ASN1_TIME and modify print routines to use ASN1_TIME_print.
     Removed the versions check from X509 routines when loading extensions:
     this allows certain broken certificates that don't set the version
     properly to be processed.
     [Steve Henson]

  *) Deal with irritating shit to do with dependencies, in YAAHW (Yet Another
     Ad Hoc Way) - Makefile.ssls now all contain local dependencies, which
     can still be regenerated with "make depend".
     [Ben Laurie]

  *) Spelling mistake in C version of CAST-128.
     [Ben Laurie, reported by Jeremy Hylton <jeremy@cnri.reston.va.us>]

  *) Changes to the error generation code. The perl script err-code.pl 
     now reads in the old error codes and retains the old numbers, only
     adding new ones if necessary. It also only changes the .err files if new
     codes are added. The makefiles have been modified to only insert errors
     when needed (to avoid needlessly modifying header files). This is done
     by only inserting errors if the .err file is newer than the auto generated
     C file. To rebuild all the error codes from scratch (the old behaviour)
     either modify crypto/Makefile.ssl to pass the -regen flag to err_code.pl
     or delete all the .err files.
     [Steve Henson]

  *) CAST-128 was incorrectly implemented for short keys. The C version has
     been fixed, but is untested. The assembler versions are also fixed, but
     new assembler HAS NOT BEEN GENERATED FOR WIN32 - the Makefile needs fixing
     to regenerate it if needed.
     [Ben Laurie, reported (with fix for C version) by Jun-ichiro itojun
      Hagino <itojun@kame.net>]

  *) File was opened incorrectly in randfile.c.
     [Ulf Möller <ulf@fitug.de>]

  *) Beginning of support for GeneralizedTime. d2i, i2d, check and print
     functions. Also ASN1_TIME suite which is a CHOICE of UTCTime or
     GeneralizedTime. ASN1_TIME is the proper type used in certificates et
     al: it's just almost always a UTCTime. Note this patch adds new error
     codes so do a "make errors" if there are problems.
     [Steve Henson]

  *) Correct Linux 1 recognition in config.
     [Ulf Möller <ulf@fitug.de>]

  *) Remove pointless MD5 hash when using DSA keys in ca.
     [Anonymous <nobody@replay.com>]

  *) Generate an error if given an empty string as a cert directory. Also
     generate an error if handed NULL (previously returned 0 to indicate an
     error, but didn't set one).
     [Ben Laurie, reported by Anonymous <nobody@replay.com>]

  *) Add prototypes to SSL methods. Make SSL_write's buffer const, at last.
     [Ben Laurie]

  *) Fix the dummy function BN_ref_mod_exp() in rsaref.c to have the correct
     parameters. This was causing a warning which killed off the Win32 compile.
     [Steve Henson]

  *) Remove C++ style comments from crypto/bn/bn_local.h.
     [Neil Costigan <neil.costigan@celocom.com>]

  *) The function OBJ_txt2nid was broken. It was supposed to return a nid
     based on a text string, looking up short and long names and finally
     "dot" format. The "dot" format stuff didn't work. Added new function
     OBJ_txt2obj to do the same but return an ASN1_OBJECT and rewrote 
     OBJ_txt2nid to use it. OBJ_txt2obj can also return objects even if the
     OID is not part of the table.
     [Steve Henson]

  *) Add prototypes to X509 lookup/verify methods, fixing a bug in
     X509_LOOKUP_by_alias().
     [Ben Laurie]

  *) Sort openssl functions by name.
     [Ben Laurie]

  *) Get the gendsa program working (hopefully) and add it to app list. Remove
     encryption from sample DSA keys (in case anyone is interested the password
     was "1234").
     [Steve Henson]

  *) Make _all_ *_free functions accept a NULL pointer.
     [Frans Heymans <fheymans@isaserver.be>]

  *) If a DH key is generated in s3_srvr.c, don't blow it by trying to use
     NULL pointers.
     [Anonymous <nobody@replay.com>]

  *) s_server should send the CAfile as acceptable CAs, not its own cert.
     [Bodo Moeller <3moeller@informatik.uni-hamburg.de>]

  *) Don't blow it for numeric -newkey arguments to apps/req.
     [Bodo Moeller <3moeller@informatik.uni-hamburg.de>]

  *) Temp key "for export" tests were wrong in s3_srvr.c.
     [Anonymous <nobody@replay.com>]

  *) Add prototype for temp key callback functions
     SSL_CTX_set_tmp_{rsa,dh}_callback().
     [Ben Laurie]

  *) Make DH_free() tolerate being passed a NULL pointer (like RSA_free() and
     DSA_free()). Make X509_PUBKEY_set() check for errors in d2i_PublicKey().
     [Steve Henson]

  *) X509_name_add_entry() freed the wrong thing after an error.
     [Arne Ansper <arne@ats.cyber.ee>]

  *) rsa_eay.c would attempt to free a NULL context.
     [Arne Ansper <arne@ats.cyber.ee>]

  *) BIO_s_socket() had a broken should_retry() on Windoze.
     [Arne Ansper <arne@ats.cyber.ee>]

  *) BIO_f_buffer() didn't pass on BIO_CTRL_FLUSH.
     [Arne Ansper <arne@ats.cyber.ee>]

  *) Make sure the already existing X509_STORE->depth variable is initialized
     in X509_STORE_new(), but document the fact that this variable is still
     unused in the certificate verification process.
     [Ralf S. Engelschall]

  *) Fix the various library and apps files to free up pkeys obtained from
     X509_PUBKEY_get() et al. Also allow x509.c to handle netscape extensions.
     [Steve Henson]

  *) Fix reference counting in X509_PUBKEY_get(). This makes
     demos/maurice/example2.c work, amongst others, probably.
     [Steve Henson and Ben Laurie]

  *) First cut of a cleanup for apps/. First the `ssleay' program is now named
     `openssl' and second, the shortcut symlinks for the `openssl <command>'
     are no longer created. This way we have a single and consistent command
     line interface `openssl <command>', similar to `cvs <command>'.
     [Ralf S. Engelschall, Paul Sutton and Ben Laurie]

  *) ca.c: move test for DSA keys inside #ifndef NO_DSA. Make pubkey
     BIT STRING wrapper always have zero unused bits.
     [Steve Henson]

  *) Add CA.pl, perl version of CA.sh, add extended key usage OID.
     [Steve Henson]

  *) Make the top-level INSTALL documentation easier to understand.
     [Paul Sutton]

  *) Makefiles updated to exit if an error occurs in a sub-directory
     make (including if user presses ^C) [Paul Sutton]

  *) Make Montgomery context stuff explicit in RSA data structure.
     [Ben Laurie]

  *) Fix build order of pem and err to allow for generated pem.h.
     [Ben Laurie]

  *) Fix renumbering bug in X509_NAME_delete_entry().
     [Ben Laurie]

  *) Enhanced the err-ins.pl script so it makes the error library number 
     global and can add a library name. This is needed for external ASN1 and
     other error libraries.
     [Steve Henson]

  *) Fixed sk_insert which never worked properly.
     [Steve Henson]

  *) Fix ASN1 macros so they can handle indefinite length construted 
     EXPLICIT tags. Some non standard certificates use these: they can now
     be read in.
     [Steve Henson]

  *) Merged the various old/obsolete SSLeay documentation files (doc/xxx.doc)
     into a single doc/ssleay.txt bundle. This way the information is still
     preserved but no longer messes up this directory. Now it's new room for
     the new set of documenation files.
     [Ralf S. Engelschall]

  *) SETs were incorrectly DER encoded. This was a major pain, because they
     shared code with SEQUENCEs, which aren't coded the same. This means that
     almost everything to do with SETs or SEQUENCEs has either changed name or
     number of arguments.
     [Ben Laurie, based on a partial fix by GP Jayan <gp@nsj.co.jp>]

  *) Fix test data to work with the above.
     [Ben Laurie]

  *) Fix the RSA header declarations that hid a bug I fixed in 0.9.0b but
     was already fixed by Eric for 0.9.1 it seems.
     [Ben Laurie - pointed out by Ulf Möller <ulf@fitug.de>]

  *) Autodetect FreeBSD3.
     [Ben Laurie]

  *) Fix various bugs in Configure. This affects the following platforms:
     nextstep
     ncr-scde
     unixware-2.0
     unixware-2.0-pentium
     sco5-cc.
     [Ben Laurie]

  *) Eliminate generated files from CVS. Reorder tests to regenerate files
     before they are needed.
     [Ben Laurie]

  *) Generate Makefile.ssl from Makefile.org (to keep CVS happy).
     [Ben Laurie]


 Changes between 0.9.1b and 0.9.1c  [23-Dec-1998]

  *) Added OPENSSL_VERSION_NUMBER to crypto/crypto.h and 
     changed SSLeay to OpenSSL in version strings.
     [Ralf S. Engelschall]
  
  *) Some fixups to the top-level documents.
     [Paul Sutton]

  *) Fixed the nasty bug where rsaref.h was not found under compile-time
     because the symlink to include/ was missing.
     [Ralf S. Engelschall]

  *) Incorporated the popular no-RSA/DSA-only patches 
     which allow to compile a RSA-free SSLeay.
     [Andrew Cooke / Interrader Ldt., Ralf S. Engelschall]

  *) Fixed nasty rehash problem under `make -f Makefile.ssl links'
     when "ssleay" is still not found.
     [Ralf S. Engelschall]

  *) Added more platforms to Configure: Cray T3E, HPUX 11, 
     [Ralf S. Engelschall, Beckmann <beckman@acl.lanl.gov>]

  *) Updated the README file.
     [Ralf S. Engelschall]

  *) Added various .cvsignore files in the CVS repository subdirs
     to make a "cvs update" really silent.
     [Ralf S. Engelschall]

  *) Recompiled the error-definition header files and added
     missing symbols to the Win32 linker tables.
     [Ralf S. Engelschall]

  *) Cleaned up the top-level documents;
     o new files: CHANGES and LICENSE
     o merged VERSION, HISTORY* and README* files a CHANGES.SSLeay 
     o merged COPYRIGHT into LICENSE
     o removed obsolete TODO file
     o renamed MICROSOFT to INSTALL.W32
     [Ralf S. Engelschall]

  *) Removed dummy files from the 0.9.1b source tree: 
     crypto/asn1/x crypto/bio/cd crypto/bio/fg crypto/bio/grep crypto/bio/vi
     crypto/bn/asm/......add.c crypto/bn/asm/a.out crypto/dsa/f crypto/md5/f
     crypto/pem/gmon.out crypto/perlasm/f crypto/pkcs7/build crypto/rsa/f
     crypto/sha/asm/f crypto/threads/f ms/zzz ssl/f ssl/f.mak test/f
     util/f.mak util/pl/f util/pl/f.mak crypto/bf/bf_locl.old apps/f
     [Ralf S. Engelschall]

  *) Added various platform portability fixes.
     [Mark J. Cox]

  *) The Genesis of the OpenSSL rpject:
     We start with the latest (unreleased) SSLeay version 0.9.1b which Eric A.
     Young and Tim J. Hudson created while they were working for C2Net until
     summer 1998.
     [The OpenSSL Project]
 

 Changes between 0.9.0b and 0.9.1b  [not released]

  *) Updated a few CA certificates under certs/
     [Eric A. Young]

  *) Changed some BIGNUM api stuff.
     [Eric A. Young]

  *) Various platform ports: OpenBSD, Ultrix, IRIX 64bit, NetBSD, 
     DGUX x86, Linux Alpha, etc.
     [Eric A. Young]

  *) New COMP library [crypto/comp/] for SSL Record Layer Compression: 
     RLE (dummy implemented) and ZLIB (really implemented when ZLIB is
     available).
     [Eric A. Young]

  *) Add -strparse option to asn1pars program which parses nested 
     binary structures 
     [Dr Stephen Henson <shenson@bigfoot.com>]

  *) Added "oid_file" to ssleay.cnf for "ca" and "req" programs.
     [Eric A. Young]

  *) DSA fix for "ca" program.
     [Eric A. Young]

  *) Added "-genkey" option to "dsaparam" program.
     [Eric A. Young]

  *) Added RIPE MD160 (rmd160) message digest.
     [Eric A. Young]

  *) Added -a (all) option to "ssleay version" command.
     [Eric A. Young]

  *) Added PLATFORM define which is the id given to Configure.
     [Eric A. Young]

  *) Added MemCheck_XXXX functions to crypto/mem.c for memory checking.
     [Eric A. Young]

  *) Extended the ASN.1 parser routines.
     [Eric A. Young]

  *) Extended BIO routines to support REUSEADDR, seek, tell, etc.
     [Eric A. Young]

  *) Added a BN_CTX to the BN library.
     [Eric A. Young]

  *) Fixed the weak key values in DES library
     [Eric A. Young]

  *) Changed API in EVP library for cipher aliases.
     [Eric A. Young]

  *) Added support for RC2/64bit cipher.
     [Eric A. Young]

  *) Converted the lhash library to the crypto/mem.c functions.
     [Eric A. Young]

  *) Added more recognized ASN.1 object ids.
     [Eric A. Young]

  *) Added more RSA padding checks for SSL/TLS.
     [Eric A. Young]

  *) Added BIO proxy/filter functionality.
     [Eric A. Young]

  *) Added extra_certs to SSL_CTX which can be used
     send extra CA certificates to the client in the CA cert chain sending
     process. It can be configured with SSL_CTX_add_extra_chain_cert().
     [Eric A. Young]

  *) Now Fortezza is denied in the authentication phase because
     this is key exchange mechanism is not supported by SSLeay at all.
     [Eric A. Young]

  *) Additional PKCS1 checks.
     [Eric A. Young]

  *) Support the string "TLSv1" for all TLS v1 ciphers.
     [Eric A. Young]

  *) Added function SSL_get_ex_data_X509_STORE_CTX_idx() which gives the
     ex_data index of the SSL context in the X509_STORE_CTX ex_data.
     [Eric A. Young]

  *) Fixed a few memory leaks.
     [Eric A. Young]

  *) Fixed various code and comment typos.
     [Eric A. Young]

  *) A minor bug in ssl/s3_clnt.c where there would always be 4 0 
     bytes sent in the client random.
     [Edward Bishop <ebishop@spyglass.com>]

alt-openssl/README000064400000012546150415544700007702 0ustar00
 OpenSSL 1.0.2u 20 Dec 2019

 Copyright (c) 1998-2019 The OpenSSL Project
 Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson
 All rights reserved.

 WARNING
 -------

 This version of OpenSSL is built in a way that supports operation in
 the so called FIPS mode. Note though that the library as we build it
 is not FIPS 140-2 validated and the FIPS mode is present for testing
 purposes only.

 This version also contains a few differences from the upstream code
 some of which are:
   * The FIPS validation support is significantly different from the
     upstream FIPS support. For example the FIPS integrity verification
     check is implemented differently as the FIPS module is built inside
     the shared library. The HMAC-SHA256 checksums of the whole shared
     libraries are verified. Also note that the FIPS integrity
     verification check requires that the libcrypto and libssl shared
     library files are unmodified which means that it will fail if these
     files are changed for example by prelink.
   * If the file /etc/system-fips is present the integrity verification
     and selftests of the crypto algorithms are run inside the library
     constructor code.
   * With the /etc/system-fips present the module respects the kernel
     FIPS flag /proc/sys/crypto/fips and tries to initialize the FIPS mode
     if it is set to 1 aborting if the FIPS mode could not be initialized.
     With the /etc/system-fips present it is also possible to force the
     OpenSSL library to FIPS mode especially for debugging purposes by
     setting the environment variable OPENSSL_FORCE_FIPS_MODE.
   * If the environment variable OPENSSL_NO_DEFAULT_ZLIB is set the module
     will not automatically load the built in compression method ZLIB
     when initialized. Applications can still explicitely ask for ZLIB
     compression method.
   * The library was patched so the certificates, CRLs and other objects
     signed with use of MD5 fail verification as the MD5 is too insecure
     to be used for signatures. If the environment variable
     OPENSSL_ENABLE_MD5_VERIFY is set, the verification can proceed
     normally.
   * If the OPENSSL_ENFORCE_MODULUS_BITS environment variable is set,
     the library will not allow generation of DSA and RSA keys with
     other lengths than specified in the FIPS 186-4 standard.

 DESCRIPTION
 -----------

 The OpenSSL Project is a collaborative effort to develop a robust,
 commercial-grade, fully featured, and Open Source toolkit implementing the
 Secure Sockets Layer (SSLv3) and Transport Layer Security (TLS) protocols as
 well as a full-strength general purpose cryptograpic library. The project is
 managed by a worldwide community of volunteers that use the Internet to
 communicate, plan, and develop the OpenSSL toolkit and its related
 documentation.

 OpenSSL is descended from the SSLeay library developed by Eric A. Young
 and Tim J. Hudson.  The OpenSSL toolkit is licensed under a dual-license (the
 OpenSSL license plus the SSLeay license), which means that you are free to
 get and use it for commercial and non-commercial purposes as long as you
 fulfill the conditions of both licenses.

 OVERVIEW
 --------

 The OpenSSL toolkit includes:

 libssl.a:
     Provides the client and server-side implementations for SSLv3 and TLS.

 libcrypto.a:
     Provides general cryptographic and X.509 support needed by SSL/TLS but
     not logically part of it.

 openssl:
     A command line tool that can be used for:
        Creation of key parameters
        Creation of X.509 certificates, CSRs and CRLs
        Calculation of message digests
        Encryption and decryption
        SSL/TLS client and server tests
        Handling of S/MIME signed or encrypted mail
        And more...

 INSTALLATION
 ------------

 See the appropriate file:
        INSTALL         Linux, Unix, etc.
        INSTALL.DJGPP   DOS platform with DJGPP
        INSTALL.NW      Netware
        INSTALL.OS2     OS/2
        INSTALL.VMS     VMS
        INSTALL.W32     Windows (32bit)
        INSTALL.W64     Windows (64bit)
        INSTALL.WCE     Windows CE

 SUPPORT
 -------

 See the OpenSSL website www.openssl.org for details on how to obtain
 commercial technical support.

 If you have any problems with OpenSSL then please take the following steps
 first:

    - Download the latest version from the repository
      to see if the problem has already been addressed
    - Configure with no-asm
    - Remove compiler optimisation flags

 If you wish to report a bug then please include the following information
 and create an issue on GitHub:

    - On Unix systems:
        Self-test report generated by 'make report'
    - On other systems:
        OpenSSL version: output of 'openssl version -a'
        OS Name, Version, Hardware platform
        Compiler Details (name, version)
    - Application Details (name, version)
    - Problem Description (steps that will reproduce the problem, if known)
    - Stack Traceback (if the application dumps core)

 Just because something doesn't work the way you expect does not mean it
 is necessarily a bug in OpenSSL.

 HOW TO CONTRIBUTE TO OpenSSL
 ----------------------------

 See CONTRIBUTING

 LEGALITIES
 ----------

 A number of nations restrict the use or export of cryptography. If you
 are potentially subject to such restrictions you should seek competent
 professional legal advice before attempting to develop or distribute
 cryptographic code.
alt-openssl/FAQ000064400000000124150415544700007341 0ustar00The FAQ is now maintained on the web:
        https://www.openssl.org/docs/faq.html
alt-php52-ioncube-loader/USER-GUIDE.txt000064400000026060150431076070013327 0ustar00ionCube Loader 14.4 User Guide
=====================================

This document describes the available php.ini configuration options of the
ionCube Loader that relate to processing of PHP encoded files, and also the
ionCube24 service. It also describes which encoded files can be run by each
ionCube Loader.

PERFORMANCE OF ENCODED FILES
----------------------------

We recommend that the encoded paths feature (see below) is used 
with encoded files in order to maximise performance.

ENCODED FILES  
-------------

INI entry: ioncube.loader.encoded_paths

Purpose:   Specify the locations of encoded files

  The ionCube Loader will normally examine a PHP file before processing
  to test whether it is encoded, and will run the file itself if necessary.
  Although this checking is very efficient, restricting which files the
  Loader tests for being encoded may give extra performance. If set to 
  a series of paths or files, only files in those locations are tested.

  Entries should be separated by a : on Unix and ; on Windows. 
  A path may be prefixed with + or - to add or remove that path from
  the possible locations. + is assumed if no character is given.


Examples: (... means ioncube.loader.encoded_paths)

  * Site with a single encoded module in /var/www/html/modules/RSS

... = "/var/www/html/modules/RSS"


  * As above, with a site configuration file encoded too.

... = "/var/www/html/modules/RSS:/var/www/html/config/config.php"


  * Encoded files may be anywhere except for /var/www/html/framework

... = "/:-/var/www/html/framework"


  * Site with most modules encoded except for one

... = "/var/www/html/modules:-/var/www/html/modules/plain"


  * As above, with an encoded config file in the plain directory

... = "/site/modules:-/site/modules/plain:/site/modules/plain/config.php"


Locations:

  The ioncube.loader.encoded_paths property can be set in a php.ini
  file, in a .htaccess file (when using Apache), in a .user.ini file
  (when using CGI PHP 5.3+) or using ini_set within a PHP script. In ini
  files only the last value will be used for the encoded_paths property. If
  you wish to build up the value in several lines then, for PHP 5.1+, you
  can use the following syntax:

ioncube.loader.encoded_paths = "/path1"  
ioncube.loader.encoded_paths = ${ioncube.loader.encoded_paths}":/path2"  
; etc...

LIMITATIONS OF LOADERS AND ENCODED FILES
----------------------------------------

Encoded files can, in general, run on versions of PHP equal to
or greater than the source language of the Encoder used to
produce them. So a file produced by the Encoder for PHP 7.2
can be run by the Loaders for PHP 7.2, 7.3 and 7.4, but 7.1. This 
means that the Loaders offer good backwards compatibility, 
however there are the following limitations:

  * The Loader for PHP 8.3 can run files produced by the PHP 8.2 and
    8.3 Encoders.

  * The Loader for PHP 8.2 can only run files produced for
    PHP 8.2. Updates for files produced for PHP 8.1 should
    be obtained to use them with PHP 8.2.

  * The Loader for PHP 8.1 can only run files produced for
    PHP 8.1.

  * The Loaders for PHP 7.1 through 7.4 can only run files 
    produced by the Encoders for PHP 7. 

  * The Loader for PHP 7.0 can only run files produced by the
    Encoder for PHP 5.6.

  * The Loaders for PHP 5.5 and PHP 5.6 cannot run files 
    produced by the PHP 4 Encoder.


IONCUBE24 : real-time intrusion protection and PHP error reporting
---------
### (Available for Linux 32 and 64 bit x86 servers using PHP 7)

ionCube24 (https://ioncube24.com) is an ionCube service that uses the
ionCube Loader to provide both real-time protection against the exploit of
website vulnerabilities and alerting of website errors.

Vulnerabilities in PHP applications are common, particularly in sites using 
Wordpress and other plugin based systems. Exploits result in website
defacement or customer data being compromised, and ionCube24 provides a 
uniquely powerful defense. 

PHP errors can cause intermittent or even persistent blank pages or errors for
visitors until discovered, and without active monitoring this could go
undetected indefinitely. ionCube24 active monitoring ensures you are always
aware of problems in your website code.

ionCube24 is free to try, with the server side support built into the Linux
Loaders as standard. With the Loader installed, ionCube24 can be activated
at any time to give active intrusion protection and error reporting.

## php.ini settings

ionCube24 has a powerful real-time web interface to configure, monitor and
manage things, and there are also settings that can be used in a php.ini
file as summarised below.

The setup process at https://ioncube24.com automatically gives the settings
that you need to get started, but you may wish to make changes yourself
once setup. The default values are given with each example.

### Global settings

INI entry: ic24.enable ; default 0

Purpose: Enable or disable all ionCube24 features. 

This defaults to 0 (off), and in this case no ionCube24 behaviour is
activated.

Example:

  ic24.enable = 1

----------

INI entry: ic24.api_access_key ; provided during setup

Purpose: An authentication key for adminstration requests. 

  This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.api_check_ip ; default 1

Purpose: Specify whether the IP for admin requests should be validated

  If set, ionCube24 refuses access to API functions unless the calling IP
  is a known ionCube IP address. This option should be left with the
  default setting unless web requests pass through a proxy and your site
  appears to be accessed from the IP of the proxy instead of ionCube. Note
  that access to API functions will still be authenticated by access key.

----------

INI entry: ic24.api_max_timeout ; default 7

Purpose: Maximum timeout period when sending notifications to ionCube24.

  The actual period is adaptive so that a brief increase in typical latency
  will favour a timeout followed by a retry rather than a longer than usual
  timeout.

----------

INI entry: ic24.home_dir ; no default

Purpose: The home directory for ionCube24 related system files. 

  A location outside of the web root is recommended.  It should be writable
  by the web server during startup.

Example:

ic24.home_dir = /var/www/ic24_home

----------

INI entry: ic24.update_domains_retry_interval ; default 30

Purpose: The number of seconds to wait before retrying a fetch of the set
of domains being managed.


### Security related settings

INI entry: ic24.sec.enable ; default "auto"

Purpose: Enable the intrusion protection feature of ionCube24.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

INI entry: ic24.sec.initial_state ; default 1

Purpose: The default for whether security should be enabled or
disabled. The default is to enable protection. Any files on a protected
domain will become blocked if they are changed, so setting this to 0 will
avoid accidental blocking when using ionCube24 for the first time.
Protection may be enabled and disabled using the ionCube24 control panel and
also via the User API.

Accepted values:

   * 1 : protection will be active when ionCube24 initialises.
   * 0 : protection will be disabled.

----------

INI entry: ic24.sec.initial_action ; default "block"

Purpose: The initial setting for how new and modified files should be
treated when about to execute. The default is to block. The action is taken
only if protection is enabled, and the setting may be changed via the
ionCube24 control panel.

Accepted values:

   * "block" : prevent execution of new or modified files
   * "allow" : allow execution of new or modified files

Note that depending on the notification settings, a notification may still
be generated when a new or modified file is about to execute even if it is
not blocked.

----------

INI entry: ic24.sec.initial_notify ; default "always"

Purpose: The initial setting for whether a notification is generated the 
first time an unacknowledged new or modified file is attempted to be
executed. This setting can be changed via the ionCube24 control panel.

Accepted values:

   * "always" : always notify of a new modification 
   * "once"   : only the first detected modification is reported
   * "never"  : never notify of new and modified files

----------

INI entry: ic24.sec.exclusion_key ; provided during setup

Purpose: A key that if present at the start of a file, will identify the
file as trusted. This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.sec.trusted_include_paths ; no default

Purpose: List paths from where files can be included and automatically
trusted.

Example:

ic24.sec.trusted_include_paths = "/var/cache:/var/cache2"

Directories can be excluded from the list by prefixing with a minus
character -. e.g.

"/var/cache:-/var/cache/subdir"

This is useful if your site creates and/or modifies files by itself from
time to time, e.g. in a cache directory. Requests that *directly* access
files on a trusted include path will be blocked but the file itself will
not be blocked, so requests that use the file as intended will still work.
See ioncube24.com for more details once signed up.  As an alternative, if
possible we recommend producing files that include the exclusion key.

----------

INI entry: ic24.sec.block_uploaded_files ; default 1

Purpose: If set, block any uploaded files in ionCube24 that are processed
using the standard PHP mechanism for uploaded files. This applies even if
the file is subsequently included and where included files being
automatically approved with the previous setting.

----------

INI entry: ic24.sec.block_stdin ; default 1

Purpose: Refuse code that PHP sees via stdin.  If disabled, code via
stdin will run without security checking as there is no filepath. This
setting should be left on as PHP would normally never receive a script via
stdin.

### PHP Error reporting settings

INI entry: ic24.phperr.enable ; default "auto"

Purpose: Enable reporting of PHP errors to ionCube24.  When enabled, any
non-ignored errors are reported to ionCube24 in realtime, triggering
alerting so errors can be investigated as necessary.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

### Deprecated settings

Deprecated settings are subject to removal in a future
release.

INI entry: ic24.phperr.ignore ; default 0

Purpose: Specify default error levels to always ignore for all domains.

Note that default and per-domain errors to ignore can also be set via the
web interface, and are combined with this setting. Leaving this unset and
using the web interface is recommended for maximum flexibility.

Example: 

ic24.phperr.ignore = E_NOTICE | E_DEPRECATED

(c) ionCube Ltd. 2025
alt-php52-ioncube-loader/USER-GUIDE.pdf000064400000115466150431076100013264 0ustar00%PDF-1.4
1 0 obj
<<
/Title (��Markdown To PDF)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20250130155421Z)
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 33  
813.500000  0]
endobj
9 0 obj
[0 /XYZ 33  
749.750000  0]
endobj
10 0 obj
[0 /XYZ 33  
700.250000  0]
endobj
11 0 obj
[0 /XYZ 33  
131.750000  0]
endobj
12 0 obj
[0 /XYZ 33  
296  0]
endobj
13 0 obj
[0 /XYZ 33  
97.2500000  0]
endobj
14 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [71.2500000  66.5000000  144.750000  75.5000000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 15 0 R
/Resources 17 0 R
/Annots 18 0 R
/MediaBox [0 0 595 842]
>>
endobj
17 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
18 0 obj
[ 14 0 R ]
endobj
15 0 obj
<<
/Length 16 0 R
/Filter /FlateDecode
>>
stream
x��][��8v~�_��FI���@w� �0l A�l���8;��Ϗ.TU�򱪾�(���H�\lR���_�ۗo��#y����|�r�RSd�I���ej�'�P�{��Ï�����s�����~�n�|���{ޡ������/�ɿ��{�_�]��.���#L�,/������Sd�Nu%���=������O�o�>���2)�T������魞�eZ	�s�e�]y��J7ߕ�5X��}�I.����/�ߟ���ㄪ�>Oʰ�WVEXx
=��12����E��?�fy���C���}�5eH��5�^���k���N��%y����׿tjJ!����َ�"�t��ӈ�Gre�s�n�L��)�s��ӈ�GL��=�FL7���,�#��u5yNկ�������|�[�k��ҎTi�=�]<>g<�
G>�#&UE���w ���D�o*D����
aϧ�����Ont)�}���o��ɻ�����/_���ɇ��Ǘ���xy��y�������sf}��6��&-��.#�wV�-�Ϡ��7��t�w�i5����Av
u٣�N5����}�i9>wQ�9�z�v-�-�Ң{��y�TM�K�պ9j
�M�0D0�p?O�|Lg��Y�����a`�9�
�����SL�I7�H˞]��
B�a�X���x�ρ��s,�WSJ�*xs�`����q���-��}���;�ۈqS7���i/ƪ@���~��S1���[^o&�'�^�/8ާ�s�B�+y�����q��6s�1��1w&8�co�����&��:���b�"��eBѷ��R�)g#�fW���x�c׌��H��s0�������ɮ�EVv�:�a�Y
�|��>2��ءӜ�ַ֊��El��|�_w�{�N��A<����v�V)a��-�ë��lr
�E
��Z��-e�`�->S��Y��xݵT�^k�;�
�1M�{�v��w��:I#�(@�(Yw\-t�9]�����4b�Tr:��9cG�<:�&� ^�CQ�j�t�U��	S|�3A�8g��M�^���c�@8Vðf���c��5;�s��@�9�>!�ٽ�5{�����%)�&ěpW7aMW�g7c�R��<����&M��o�ףO��{�Y��Ms���|�tFs�Z-��`�b|����~��z�?��^���{��G~�����o���bN�ҝ[�V���5t��8�q�f5*؈p�:H��a��K�u���–n_��99��F���] p�9��\rSݟ�LfG��Օ�6��` 1|���=ę0 <dz���#��ص�.�#��1J���*K�|�ɔU��T}���=��(��DT��?6��3��)Z���1��xG69Qp$�#�p���T�<��gbo/Į�j��2��|�#��?����������8*I�d�.6��u4r��Y&iRqC�
c���
��PF\Ƥń�<N"H�����,�U�щ�d�>L��N���L����4�шy��w�!�5a<t��k���2���g?�W�g��e�-镫��� @'-��~�7�?�$�h0W�.��-��m@$
�XL�^�3�
��ǁ��L�T(A����e�n����v�W��7����U��\KL�q,����j�^Y!��D���a�M����`p	n��$N&$0�J5��?",�~}�����3��d츮�M���rb�#�($fR��>m��~��E�ofw(n�K�ox,��ŰƄ�H�Z�)&�X�c�n�
3L]0�|�5���x� �b�X�Zڈ��׏��r�_��TK�WL$�W��p���,�9�&F�Q6ܾ����*u��կ9���?���{Z�ߙ���5� �u�_�9��L�O�!h��IH�˴{UN=K�$���ue��B&Bm?ץ��9���b$k�<Я��l���t�!:98"�D�Ah��� ���i㣗4J�r
�v�<b�x�U���9ۊ����E*��__�_ߚ�Y�a�T��[�b{h�l	������"���/MV
��L�/Y����1��1�s~�1�
��Ռ"�׿�Pu�ٰQΫ�p5ח/0oe2J�.�)�^��i�9�TM�&��cE�JkY�?��~��2/Êaeq��r4n).c<C��fD�P�L���ע��φʋc<8�½0�p��Y�k���7�х�k �Ţ7s֍�ni��;�%�҉���vF�c���ե����t��Y��oZ�Se�f��L'r18�X�.��s��K�)Y
8�\�`��v+�i+�$�RɯݗZ���BW��[^��(i���RiY�ʺ��T�V�W�a�2��Z����gԿ��$c���OA����cp�TG�_ ����7N�k����I�a��ğ�-�v)� P�H��\�0;�d��"h�2�W�� �x1��Ȓl�fpıF�âO�s�
(T;�⁀��#�L�I^�l��֯�hT�߮K��J(;�@A9ҒHKV�%Gߪ�T��<���y*��)��<��j0I�ku:OY��<eծUu��w3�d�ZK�<U�k�<��|�5�ɡ{�˯�JiCX�b��dži����~�,�җ��6<rf� �"Kr�7R#��,�(�F�7����aq4�R�.�7p��*�j��vPL��jx�ձ�M�:y9�:��Q��������T�V�:y1�:m|d�1P���`��k-�:���L���
2�g�C�w��߮T�6��5��cr3����-gtR4�7�r�J�4�9ጲZ8Y�!��(,�3Z�m���&E�KV&�n�������)�;����L�2o�2�iP�Vm~��
Jg��z������T�V�A�L�hP�M�o?T��L2v��5�ZH��i��¶8�8
��n�q)p����e!R�<i�B��*�iE�����Y���U��
;�p���� ��U~�m#���ԺS4�(b��]
&�v�Ni)�"�_۵�Q�`��L2v���#O#�MT�ՇQ6���r��֧r@��0p`/~Sj���B(��pձ��0�}�����9b��`�8/�M(��j�S�?Մ��xpx�6���|�v�E3R���.��,�Bԇ4y_�ƶ�03��؝yqY��f�Njj��豤��XǒZ^RK6U�Ϯ�ߖ�a�m�Y	�ӓ`f�ud��s�k߳�hޚ*�
�k�qo�����z�5$�����W��3�k���L*m��|�75/:QT��QS�i����T��bANx��(,~��VLW	'�;�l%�Z8��fn1WGe*^�v�3�s��ֶ�l�Uc�1�cKR��vC�u9��ܤ�;��~��M
[&��g��%_Y8P������IM5V�;��Sk�pT�3]��ϱxw6�j�SL��F��
|� S=`�=��k��T*GsT��b��i�V2T7��j&��G�	#�ln2�R�s�@�i<z����ʉ~����d�0�bB�O��m��"pC0�bN���K=���$���"m���F�{�|��C�P�	�8*��W6
����u��C�����W�2��gn����׳B�
��2_��a�*B\칺 k�@Fv�2FpL���g̼��L�C�1ta��3�Y�H���-�Ӊ��"!�*O>�9�.�[�J��c�p@���K��:u�%�ʑ]�E.j�4�WaY�W�R(�j����׃O�q)��1WF:����i*��=�ƛ��X�-��g1f޽����ύ��J
'V�%����ȓ��UO)���"�0R�s$<�O!ެx���fI3����A0	�?��^뵽�f��i��'�}���a�&lM�42,��
]ji��2�>t���ˠ��`�j�S�c)����;���&U�ݑ�2U���c�慜T���B����֡��ӉM��Y��ϱ���Y�XA�st�bނ6����s ��s?b]Gc�^?����)zLF���S��v<�|�����ݦ0��2�qc�w��왎(û/��-y�>y��~�����#y�!��!y��r0in-���D
)H� ��?�\_�سtY�b����1@ԭ_��)����($����Y3�`���D29K^˕1p�5�b����Mo����7��I~����`�ôue
�1��op��0�`�!�n3QA�V
���P!%��fxp(:�6-Æ��+E{��~���{~�W�v4 d�'pSI�o3ɳ��"�)�1I0�"pN�ΰ*�WRw!�}4�
!����9wV�4�a+d�6�u���S�x�w�1�1;���(��F�}3�s��Q&#�)�@�)LUbc���e�oQ��D���y����lQ�7"�
fQw0<�B3�yaX3�>C6�Ҭ��[fF%`�lw0D�z�fb܁��o]�G
�c� 
�a�"_��gS���`��d^����7#m^z��f��X|1}�sa�HP���,㛹W�욹W��i�^�YӀ��4soW�I�]�m�^=�̽��]��4so7�IƮ�p3��T�`��l;��~s��������n:�0��6m����f�.�,��h�>��J1�vw�x$���G�7+���G���j�ρ�ԍ��<խ��H�7���p��멡�ԍ��<ӯ���T?�/�((�'���ի}GQ�D�H��q^fv�f��
c>9����� ҃M�G0�-��gxැ�ߐ9�>�9�e�o��c�YX���*|��T��;�7�
��M�F?c*Py��ן#SA3��T��5�l�T�2�^66t>��y�_oqS��+'FSA�� �
�j�h��.��E�l�Ekѱ�sĢ�5����,�.��.�w�0c݌��<ӯ�8��}٭Ȣ7n��pBżm�!��84F����z\UjD�F��g��݅`D��Mp-u/��fNp-�N�,˱�ڌ��<խg�2�\Kk�*��ڌ��<ӯ���Z)
��z9�,��D1��Ĭ��-Eq(�8�@T�h��^.�y��$�������$D�
6��PPjG�`�������A��Ϯ'F�R;b�L��҂�&
Joc�欞�i�a"J��#8{��)�pb��:=��Q<ݴx�6:�/ة�|���jѲ��~[�&26N���ĝ>�#CnԒ�#�<;�F��&�rA1���d}5����w0���~$���
�t5�ڟ�$����r�PI��(�2U5�f��9�V7
{̰�c���q�1�v ����r�M�j��p��	�~�t�X:)�v��f1�:��=�#�3ŧp�!R�`�h��x|K�ix��"9����o�R���_ds��E6�\ds��m��{N��0
�Fy,�!{J�O��������I���ޜr�gK�Z�p���jڎ��~s�;g�;UZ���0XLM-Y�g�s�i5D��s�9ֽQ���s��Kp&����gT��nE�k�f���=���33#�7�g�����z�x�w���J�����	JR����zB�v�)�ka���
Ʒⵃ0�����X��Y����Ǟ�NL�G���9ܩ�O��e!�E�Fd�aD��X��\0�$�����S�kk�qo�"��Ҋ��q��|�5�������Yϭ��T59(j�p仼��W���=��A;�Nw<.=�A5�]�<���kF<�j��+��y�*�GT�'e���w�����7bo[&�L�.*���SN[����k#/���53c����.l9H:T96�a�=����#Bm�"T&L�`ج��T��M�p�f����)�
�L�VA���h��@����[Y�9֬SLu
�VC4ᢚVy��{��$�5.U��!�������Sl�)����ɫ��t��k��$��RzQ����x��{ʤ���3΂��������'��H�@����EaJ�%0F6c�JnJ�H�]~=���z$�K��o�=	�R�4�yp`<�k��i�R�@�u�[�ނ�@���< ��p�g��XL���Nل��ݴ>���׮�pc���_j�1�g|`LQ�L�)�Ѷ�>rS0��e�E)��*F�,�^���Y�ê����2X��j��wai�EU]�!�1~T�4^�E"�n���4��ӳ���W�1��r"�Fg&��2��oh�>#.<kU˗��ŀwP�ptk��]�s0l�Zk�����	�F��+����S�>��K~8�|z;�*�~N>�I�˙
endstream
endobj
16 0 obj
6379
endobj
20 0 obj
[1 /XYZ 33  
760.250000  0]
endobj
21 0 obj
[1 /XYZ 33  
672.500000  0]
endobj
22 0 obj
[1 /XYZ 33  
158.750000  0]
endobj
23 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [102  696.500000  175.500000  705.500000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
19 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 24 0 R
/Resources 26 0 R
/Annots 27 0 R
/MediaBox [0 0 595 842]
>>
endobj
26 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
27 0 obj
[ 23 0 R ]
endobj
24 0 obj
<<
/Length 25 0 R
/Filter /FlateDecode
>>
stream
x��][k�H~�_��Ȫ*�.`�maaL���C�dv���d��+�JmK꯺��QIrk㶫���:��\��o>F��#����-zr?o>l�8�I�_T�{������P�}���l�G�7����7���x���h��4�p���"�����_��~�����e��<�_�l��痿�$��TeQ�=�Z���?��V�H�"I�6ڨf,��߽x��=��K�gi�آ��mZ&����&o~���JuE5�迟6�V�?w]�X]���\�؎��:)�Ĕ��]�&�vm�w]X=Q�:Iҩ�V:��k3ݬm�w�~� ���c[׏���,R:z�5j���X��2���KtYq�۫��M�L[�C]�ݶ�b�iV�5:�LRl[t\6��hɷ-YlR�k�ٶ�q���Ӣ�ۊ�ߦ�{F5C;f�ʺgt�t����Ūf�[�kɒ�tG-ۏE�xf�w�j[��768S��c�<CЁʶ-*iሱ�Pccf�W��^�d��;�z�L=���h�N��z�n�gf��ZU“Ep�RU�7�����#P7��6�{C��Y˟k�6�	c���Sg��ʡVKM���ⳍ�vݞ���·u
�֔�􆟁3U�n��h(�.�����u+�d����pl�,`���L��Cڡ�CU�Wam���@��Ң��ū����[��k�G��YQ<6QY�5֞�:�������aLT��W�je�~Ō��%xl��q�4sd���{��p>�}��ӆ��q^�9 >-�B«������lY%�IBʾ��S/��2r�s�	�Jiӌ�Ϝ9��߆׍�q?�؄W�uX�1���0(>?��Q{��P�@s<���
�,���9Ƣ �A�=���fzռ��!Y����2��68��#��`��,����5�ش,�ʌs�72#���-<Z�!��y�(���&��H��1)�3�5�H�㑍p�L��i�׎
�(���(�Ö#�_�������LM߶�I�&��X��Ԝ�Y棢t��=,�O]�`��Lg�c��~��||�Dc<c��]����+F�y����L���M���*y,+S��<�V'T���і��1��P���o������"�yZK𹓃r���;u�Z+ĩS�wwF����윪�o��g܊�=�C�������i^w�3-������-o���
��ma�s�=-�|��[k7��V]|���kty]�����Ϗ���]^EWW��Me��Ԭ[:�-�����@z�x
Yj��$�S����x%�Q��Pnj,T��	.U��9%A�itzSQ6�`֩���qf9J�ך�����!v�Ѐ���=Ϻ1#M=�*�h�ŒӠ�]K��J�^��b''�U���@/Lo�N��:�dD00�h`��]�i�c��P�t!*��IE��|1�I���a*Ɣ���Hr	v�^�ƊNmՎ�9i��lL(�:D�d0�a�ztZ�дCr��H��uW}N�_]��.f�"�=���i�zi]iӥv,�-�#'���̽��AP%n�Ex=�;=���dG���lt��ӬC���Ɣ�8�'Iq
O%,&�
%#�F(�u���u�Y���%Ťp�"_�!r�* �	k	�L��̙�i�H*�S�h�u��u�OMYf�2�5��L��Z0e����u
_�ܨ�I �F�Dcӈ��Ri���U����х���"!���S�J�T#F�I��c��>ƶ��ƒ�k���-�u��Ze7}խ���q�Ͳ
eh��E�'��QO?E{
�	����`7�8z����6`�;���f\?.�w����:�昬7��M m�z���k�۽�た��'Z��^:~z�5����6*���06{�-0��S6/+ΚD�[�vL�'SJZM��RԢ3ؒ÷�?c`�{�Ƕ+Yp�v���
?��CN�=��X���~q��cv��Q�������>;�={C{����-����kf�:�EA�2\�c�(�py� �\}E^G���̉�t\&f'��e| ��Ӣ�ZZhDiaܢ�( %Q�2XQ�h�Y_��2��s�*︨_&N���.����?ӗ
UR+�n���Ƕ͜��"�! �TD*+�H%��0&UcLy�bLnj��1ݞ���0�|��б�ɔtn�H�zI�a@?��>�w��ZO?p���P��p���h��u�?�
����׀���3�����mx>pv�){J�vDxfzD�;��8"J7Ӂ�\8��Ԧ�eo{f��ɫ�2!�TBR�[̙��P�P5��LgL;�[ô���
=�`� �G��n�w�L<
�N�g�O�^��ee�,f��w�2�eW��:���F>���QO�u<gY.N+��
N��Q��xu���g�����5�s�5�iM�2E�y�!���!ѬvFV�t��)X���9'���5�i����j%VPa����%�.����z•���4��D&
��у��PQ��WӔ�K�	D��S�%�S��7f�Dtc(z���c(8���R��#�C�YSl"��S���)�CY��n"���N�}��1o����A�pd���%IJp���T���N�(:ĈR�2��Rr���o���[Ӭ_q��8N�_!��zb��I��b.\�\W5gj��AK�� 2��P9���R�����:5]~��2֣	�)U{}r4P��9㫢!�]�	N���Q:a��H2��ZF�Jx`8c��R�B�<�������L֑��ߕ3k���
ߜߐ��D�R"��rԱ��|��	��Ռ�]�����хSC$�褲�I�59f��]�*�jq�1/�|�cN��#�xl8����*4D�,\�œ�B����6�R���I�3��'զiQI||�OQD��a8���"56,v���f`{�1f�"��)Мq��
 ������E��dZ&\;��:)�:��.�-����I�zc�#X(7��&�J�Ya�sm������5)���r���6�U
�	˘v0T��|�:Õ�3�p4AUA�QSz��l����}���PWN0�o�f&
=P��$p-ҁ$�N-꘠�F��YWa�zeyqJ(�䭭5S@`r�D$�w�eʛ ��ں��k�K��]�ʚH��s-?��eO�C|����`�ū�]��NZ|�^�%�|�f�e{���oCA�L�;%���b\p�q�@�D��Y__q>.+Y�6��dwA��REsj�p�-�Fvi�+���75���g2���t"C��@������iA/L]&&�;ZTa4/J'c¢�u(Cp��"�ra�!,Z��|*Hyx���g�|�!�K��Ҥ���Ɋe^��9��[8P0*e0�D� :ZF�O�+Yu{�4�	�Ǻ7��8,��k�

��֙���%!�F�u�"�{8�؈;N4����\���p��sL�'%�]�G��f��n`竩�ʗ$
��W3���CwӟƼ1�NDY�
<j�?ؕKd=c!�Y��8C�s% vM3��%#v�L�j�|4n��
�3̮���!Z&����C���'�u�>��a`��_E�d��dM�*Ü���C��'�)ܽHת��J�b�	#8��%g��3�e���C�ݭ��$���t��s�;���?����i��fH�MUv�4�2N�~�Y�bE[dg���y�[��u�dE
�pL\���x��5p��_����G�gZ��%-��'�~�q?��i:p>�G{�;<86Ϩ�Z�)E{�Z����Ňo�F�����~������Utu]�����I�Ļ���{��MO(l���>H"=�������.��gڿ�tJ�/~�ǯ�߆Qc�~b&�^`�`�36<S쩹{f1#��<k�;�1��(���*�mN�]*�?�5���P	@�_\!�dR�2LX��%g�$H�&�@#|��
L�B�DR�T-���e��1��r�<Ӄ�#mu}q��O*��d͇2��ZD��S�|ژʒ.mj�c:ϙ�}���Oi��T�ޗ����T����}�m����-q�vY�b0�e�e3!��*u�2bh,�m}ߎ��s�ަ,�)���Z ���w���]�g�z�
S��p"e�0.L��>w$!�S�
�T�����Ϟ�ߊ��s�y����'�Mټ����uK�y.o�7��Ow	0��7�v0����bJcȂ��0��<��Q�;���Ս�Ӎ�@7�N7����tc�W7�N7���:��vtcD7�vd�u�<�=+r��E߽;2��d�=l��S
endstream
endobj
25 0 obj
4362
endobj
29 0 obj
[2 /XYZ 33  
122.750000  0]
endobj
28 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 30 0 R
/Resources 32 0 R
/Annots 33 0 R
/MediaBox [0 0 595 842]
>>
endobj
32 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
33 0 obj
[ ]
endobj
30 0 obj
<<
/Length 31 0 R
/Filter /FlateDecode
>>
stream
x��]߯۶~�_��QDR% ����A�a�C��+��h�
۟?ɢl�G��=�$�-��k]Q$ux~~����}��?��O�>��O7E�l��u��:�B׹�������/����͇͇�߯�a��?>��y�?k�����f:�s��/����������S.�V�����_UQVyը�n�/����߾�~k�Q�uQhm�Q�\F���EcrS��u�'}�޼����)U����\U��sS4ua�F�8�:Ӯ6Y]����������L�6j�U�v��z�-˹]٣G��4�i
�w�6���L���OY?�W��Oݤ_�J�٧�7�����/�k�cd�ʷ�+-+��ck�+��^�y��rp�m�T�)���T����NSTz|��J�'s�G�y���Q��NF�g���}{�iZb)lKC�g�m���>��c��P�mYE�������.�~��J��P����Ŗ芮�G���g�G�s��	���<�|�4��wľ���{�[PO�
�Q|O��RK�����liBQ`�0��R\n{�xf�',3b5����h�>;��\#>.��3��S�˕=�G�p�X�a�7P���]1�z�w�dn{�Tǣ����;�
�
�SL!�9��8^)�~�J��M���k5�S]���&NcO	��J1+
�5���g��A9�U̩'T�نs���;�g;0L���̿o�����$��E!�-�`�_��{��4|����w��s�Ѱ·�~�	֍?����ϡ�)>��,œj��h�,���Jg|^i�]T1l�5o�9�mc
���ŋ�|���kF�3r�
����R/~�hS{?��x^������#�1��+�s���O�!��7�K5Bã�xLU�v��5���`���ю
�C�d���L��L;w�s�<�Hfn�aC�Q
"�,��)d���u�=��D�ak��Q���X�c�/���r����X�a_�����a�8�!4�
a<�8��d�\���!�nʒH�����̬3ұJ��1��v���q4·&�!�:����坨�)�	{K�g�mh|�HD,����vCx�(l�|a�/~��i�*/Ϟ�h�S	O��P��/�DL�c��o���:M&1.Ӯ��T�(m����ДݷMfl���Ƙ�nli
��1��L?^�w�'�q6���l�w�'�W��>7�����7�v�%�R
�b��� v)��:î�����e�?�	̸(0�"f��eR�9�Ue����b�sZs���DZ=�AkΉA[�b��y$�+ft����b��Ġ-�xű쮸�}nor1��ދ4"��`�F�7o^˫��&%��f=G�i��.'~u��{J��$��D�hxw�Y��-����=
����'�m?����+)=Vڙ�R��q��@=Djh����F�ר�D
��$��0f��
f,8
*�<��v�̕#��=&U�EgM�W��:�D���R�wJ���hIK��H�C�T�X�w�J�dV�@� ]SPeF�L!�i�zj_JU���g�0)��l�X�{�q�2%c�)܏�M؟�%���?NȾ1=$��Uy�X���X��-���9F�m���}��G�5�<�k���G(��7��
�M�k��-9��5�I��6L���a��t%�2�0%u���l@1Ʀ	��X5!��	�V�l�F��HuW��>ӏ煐n�	!�gu?��Pwō�s�x��vJ=�:I�'|Xc	��W�J(I��'P�a�[N[���d.��=1Hٸ06>q&��u���O�sc�W���C��J1�2����Ʀ%ƣ�H(��*S�����4Ʉ`��.�:x � 6+�l��`� R"r��k�uJdu�%ci��Ho�Ա�t�3$қ���\۵%�PJ�? �u%��Y��jb�8%]�Y�D���Dz�B�x8Z��͛bo�ԁ��JJ��;��)���Q;����N�Kn�i��o�$x�#��G�:�DG�K��D��z�R�R�BZ���C(=�x�B�����l`bс�K����K��f'�����ޛ]��\OJqN)�aJL)α��M3�CJq��g��o��~:���v����9�.믘�}�o�]�~:���֏w����F��a����ڧUvd��F+�S�İ伳X{�d'6U�F6�l���%;Vdx1�����4�k�mz�|���bF��~<���5����cF�7�;��
�M��w��,��C	��"ӞR���͠d��u��o[p���Od\�L�FYe<I�E����7�(p�xJ|�t�;3�\?��[oF�쯘�}��K�s��o�x'f��f��Q1�	e�0�����dV�;�&J�ξ��Ғ~?�c�#�����0:���=r��VE��\]��~�6�p4�4d�0�"�R|�h�3fp������q�9!��;
��"��Ce��<�յ����N�s�s��J�d��ld����P���'[l��+D�8Z-aѽ��=ӆ�rO-8�("�q��XE�0�%��i��$Yr�E{����ej����A0ώ׊��'۴���2��ފ���_��������HA�̖�hG�
5�&7t1��wZ�zO@��.1��c\�9�33P��)*%�V�ܶx=Li"\	;Zq�!Y�:Q$kՅ��z��x��n�Kkԕ*�p�
"�qkPvk0�d�2���N���iķ���)����1���$�� *���s�E��f�p��:�W�4�Z�p�^��>q��f�w�/!x�a�jD����ڬ�V�\W�Q�Np�&zΚ)6��	�������%�X���v'�a��.��4G�]^۫�Ԉ�d�����i���D���ɋ�i���d!���(`E
�S05��d���0�	�<Z�;���l>�%�Clk�T63�j��U�˥�C�-M��z�D8�8Z�=�B1uK/e�i�*�A�_�C��d��=/i�B{��B؏�W�=<�9�<"Sۮ��
���a�����|�sD�����@t����x���M�E���h��D��<�=8��R�i���X
Y�e=3�G������b5�����Z��8�mw�u�xkd=I҄��0>t&Qg��%hG[��{�|�J��?M�-�N���rs�Ө�M��ȾZ2�_D�Mh�VM1�'&1X����{�e뙊�~Y4���p�q1���l���7�
Y�-07l�0�3eO��=?z`�����pNe+�&~jsK��e�zu��H���$|?�Q7�\S�e�R6��e�D�[`w?X@b0~��9.W7�`٬M٦DK)>s�M4�� ���yͮ���,���5b�p¨�!:FP�.ք������I�{Sp��)pS{��u��|kY�1�@ٜs�$u�U��������&�Z@c�h�jA�{�h��0o�;)�e���'�-b�2�#��E#���/���~I*:gAP�T�]��t�mA�==P9��K��Pxw�zp)�K]z�f��uD{2��T�}�+�	C��~.�P�M������R�C�q�{b�K�L�����`���h�
�>A��ݡ�'�*2�*���K6�R��H&�(T9VP�1�e_� !LX_�l.C�'��OW?�2hiLЖI|`����Zp�<�!��U�uHgL!�DJ��FHe�Dʞ{��%�����e�#tsʏ 
Hf\�E�W�[p˄%�y����C6%���~��@���jx�=p�O`�5�ҿ��0>O�r����lS�/
ܣj��d�s�=�Ze�rmp�=%�G���K��LJ"��Aհ����y��~�`рl����d�쌚|�nRluE�23N�Y����sƸ�rB��+3ZٜY��jFs���Q5�9�'K6�K������qn�\��ŝr�RUc.��JL�A&�ɸ�M�q�1u2���x=Tg5�
��y�@L���ك�Tp��)��0�?��*�P+
50�UYY�)Q�n(��2��F
��s��3����>T�X��H�e�
�@D%*�π�ek��j�8��L�,�Ra,�{�Ehk���u+�Eh[����"t�G+;c�iBUu�]�qY�y��������*+(�w��dmelj�륱RyY�x�?I�Y�fl��r��'�ɟ��<�]d�?�W����y��@��m7���@���u��'�M�gpZy�	�
�?�P�8�X��>&������͛�����������y��}����S#��t�Q����/OGKX-yu'qzO��9q�uQfz]j�W�'��q��PR��8.��g�Qp�
�5~���q�#�F0��v���BLj���ui���#��u� �<Ǫ<L�Lj�x���B��$eG�}S~R��1~s�Q`����]��g�F��A\����2�|&�Ō�JL`��tL�
�c�f��I���!�Ʌ���*��h�B6�?�5�r������9S�N1�_89�-�G;2Z���ឪ���LQ��\�S{b�Q�]�u���T�T�I5,�T�J����N�z(��_�����2�'Y-�WF����6�kO��C����T�}�T���V���M�}�3c���7��ucKS�o��g��k?u���订��k�w������~޼�f�l���U�m-w�c�UG+0�,?�
�i*v�2{@(��y���.���DTIej��Տ�"����s�T��T1,���i{̘ژv���D:����y��נ�;���C�a��l��
endstream
endobj
31 0 obj
4897
endobj
35 0 obj
[3 /XYZ 33  
765.500000  0]
endobj
36 0 obj
<<
/__WKANCHOR_2 8 0 R
/__WKANCHOR_4 9 0 R
/__WKANCHOR_6 10 0 R
/__WKANCHOR_a 11 0 R
/__WKANCHOR_8 12 0 R
/__WKANCHOR_c 13 0 R
/__WKANCHOR_e 20 0 R
/__WKANCHOR_g 21 0 R
/__WKANCHOR_i 22 0 R
/__WKANCHOR_k 29 0 R
/__WKANCHOR_m 35 0 R
>>
endobj
39 0 obj
<</Title (��PERFORMANCE OF ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_4
  /Count 0
  /Next 40 0 R
>>
endobj
40 0 obj
<</Title (��ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_6
  /Count 0
  /Next 41 0 R
  /Prev 39 0 R
>>
endobj
41 0 obj
<</Title (��LIMITATIONS OF LOADERS AND ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_8
  /Count 0
  /Next 42 0 R
  /Prev 40 0 R
>>
endobj
44 0 obj
<</Title (��\(Available for Linux 32 and 64 bit x86 servers using PHP 7\))
  /Parent 42 0 R
  /Dest /__WKANCHOR_c
  /Count 0
>>
endobj
42 0 obj
<</Title (��IONCUBE24 : real-time intrusion protection and PHP error reporting)
  /Parent 38 0 R
  /Dest /__WKANCHOR_a
  /Count 0
  /Next 43 0 R
  /Prev 41 0 R
  /First 44 0 R
  /Last 44 0 R
>>
endobj
45 0 obj
<</Title (��Global settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_g
  /Count 0
  /Next 46 0 R
>>
endobj
46 0 obj
<</Title (��Security related settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_i
  /Count 0
  /Next 47 0 R
  /Prev 45 0 R
>>
endobj
47 0 obj
<</Title (��PHP Error reporting settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_k
  /Count 0
  /Next 48 0 R
  /Prev 46 0 R
>>
endobj
48 0 obj
<</Title (��Deprecated settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_m
  /Count 0
  /Prev 47 0 R
>>
endobj
43 0 obj
<</Title (��php.ini settings)
  /Parent 38 0 R
  /Dest /__WKANCHOR_e
  /Count 0
  /Prev 42 0 R
  /First 45 0 R
  /Last 48 0 R
>>
endobj
38 0 obj
<</Title (��ionCube Loader 14.4 User Guide)
  /Parent 37 0 R
  /Dest /__WKANCHOR_2
  /Count 0
  /First 39 0 R
  /Last 43 0 R
>>
endobj
37 0 obj
<</Type /Outlines /First 38 0 R
/Last 38 0 R>>
endobj
49 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/Outlines 37 0 R
/PageMode /UseOutlines
/Dests 36 0 R
>>
endobj
34 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 50 0 R
/Resources 52 0 R
/Annots 53 0 R
/MediaBox [0 0 595 842]
>>
endobj
52 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
53 0 obj
[ ]
endobj
50 0 obj
<<
/Length 51 0 R
/Filter /FlateDecode
>>
stream
x��[mk�8��_��u�jIP
M��AI�>��d�X�e�����?9gc'��L��^wj'�F�g4�������MLf�/bI�ټ��w��'�g�_�Pҽ�нX��ⱸ-n��Ǣm���|(&M_E��|�{��Gh�k��I��W��%�����+_�M+�>~�����*�����~�c����e�Rk��jl�|>3��Rz]=���-C���hU}�.�W֧�(c�&j�ixO�0��F|}W��=v�a��a�:7:�Lsg��xW	S57��ߦ?��.��H��I���3M{�s��l]-I���NOI�;z�m�c1}�c���:]��J(-�E�γ沸/lHތ����<���B,>U�5u��O5����2Va;k�Q�DV�#�:�qʭ��QkZ�$��}ܚ6+�++�Bg<J�N�0�=�s6$�$��=�A�d�Z���>�X0m[���ܬ$׋Y�	��*6�
h�k/Tj��虦=
�v��uԞ�J-�=߶w�Pq����H��'���i±TU���N�X<�����i�j86���e����
+��=J۟guI�m�h����Zs$1Dt��Op�.����}�~h�w-�
�M]�E��w
�-c�"–�t��6C�@V�'~2�r� ����r���ϋw�~���BL�f�o���	�����f�s�i�9�E�/��3�h�69l�B�-%9~Hk�$��A�Ϸ�%���I�x<ж��8�C�Hە�9�'|Ɯ�<��H1尚���o����:��	ýÊ���4u,P��:r��������kF�Lɣ�2o�9�5JX8��o<ی�o��0w�5;j��V��-7q}�a�q�����U�'7�+�wr��^�t}ﵳ1A��o�qi{����"�� �LSZ�����T� ق��dž[-��
J<l-@�5�(�����l5��V(���H�Q���&��Xpu.��AI����X.�D+[K�h{A�y�4��T���8�7=����T���l�p5R�XX�Dl5&[��a	
��g�8&[X��=�$�A�2�A9[Ƒ�>/�U�F�=�l}8��l�q���kΜ���x��yo��Z�)�`Te���/m�(�%N���b(c�S|=Y
[�WN!��a�a�i�:��x‘|�����̄���.Y��3?��>r��b$�f�8�9ebNfb�-�Xqkx�F-��r=^�Y3�U74�}��GʚG{����ɚo��9��L��É�qW
�	���Ki�������i�G?X��8��3��N������돶*��)#�<��������aX�*N�{<��-2��sh�Q�aU?�T/�T2���F��a���F����g�.����13�ގS������ [�'�Y�����B֬�^:�� ��F�_�U�o��u��|˾V���-W��h�#�D���D��~3���
[�Gj�8�18��<���Lk�o�6��L?��K��]bT[^����'_0��ls��K��[��Y{XE�얞�]�^u�����H��Ȍ��d��}����jz�
endstream
endobj
51 0 obj
1581
endobj
54 0 obj
<< /Type /FontDescriptor
/FontName /QCCAAA+Roboto-Regular
/Flags 4 
/FontBBox [-736.816406 -270.996093 1148.43750 1056.15234 ]
/ItalicAngle 0 
/Ascent 927.734375 
/Descent -244.140625 
/CapHeight 927.734375 
/StemV 48.8281250 
/FontFile2 55 0 R
>>
endobj
55 0 obj
<<
/Length1 6976 
/Length 58 0 R
/Filter /FlateDecode
>>
stream
x�}X	\G����{�F�1+Ȍ�`�P`&�7�)ry" �9ܠ� ry+(*�&��&Fr�I0�$���[s=�xd�M6	0��g0׾���ꪯ���5B�
�L8B����j�=���bI��_�y=�����Н����q!l!���';Ư������삲*���`�B`l�1-���#d~&��UE$�,�v#�U����7�	Bh;��`:Rp����$��V,�-BGb�j���!K�������eD$$S�A�e�x?�4�C��Hm�9"'���B�j��S{5�A�M3ϥ����a����F9QG�5��S��rs���R�*Z9�%M1�_��$���Wq
{��Q�87���K��0Q.�LպA��t�'�蝝���>��y?p��rqQ�r����j���G�J�����J��˴HF���t4x�o��v�\�j��b��͍s�Kv�����}{\,�'�4��Sm��MAA;��Vo���m�����3�((D���'�.�J��^�Q�Y�˱
���˰�3Q�޸* ���5k�z�f����6�~�R��]�}��ȲF�uS��F7�� U
R�)u��Ͽ�c�}��q�C�O}��2��_b��LY9ik�=��W���h:�ցCq�[�x::��ip���V=��m���@��Z��)&���p�
�>�r���ө�͐��O��A����.I�C��dg����i�D���Q�Т�5(	�c^UR�w�h�m*�����x~I™��aT�s��=52b~������Y�%���,\'	���y2�� C.���
(����*����z�����<����zy�Yï\ޒ�]�$~X��Sl�&ž]�O=�ych0���b���4�>m���Ҹ=�GG2u�_8������
��g��_<r�9%���7ȝ+�Dv��4ȡ���	�P���*�����R�t�)lk�9��
[6}s�Ͽ(- z��7-��7/GpZ��->	����W��HNJH�O]pLTĬ�����8~�r�������Ӌq�9��~�-���e�B��ՙ�%�J�ʊ/Mݶ�K/TT� *��'6�(�ˁ�Z�=Hʚu�,7eew�wsr�^@�q��!�-@�,����<��t�[�w�3�Of�05�a���Y�L�{A画�-t�3���kȽ��"C�#e��	����B�5�shk�y�;�����[�}7�K�1�v���*�-�ta@#Q�$u�����;�	�i����s����E�1g�
@5E��c7��
N���7��7�aD�w�M[n�ݱ^Z��c�@85<��k���͟s���:���e�:���d���(%���z�r栱
�o�me�Ĝɀ�Q0��l���N�b�se%��f���[�fN(-?_��a�5�!A%ً�KČi.SfL���ٺz���}zf��5ST3f��Oܓ�`��ؔ$�Gf�`��C	���e�����S��7����h�Qy��j�Fx}CϳM�Qh&����fU�A���P\t!�R��C�.����:���g�C�����R��=0i�/�f�7��96Ԓ��|�8���g
�:Gc0���:���l�ε�!��j�C����_�!Ӻ���@lx�e�@L秅���榦ܬ�C�,���*���М��Q�us�L�O��{�ȎTo��q2_�}��3��-�Ȫpu��Ip)�y�f4��xk-i�O�x�8�e	��&7��Ouv@И��g0�T���� 6�gҁR�y��^��@��7�lc;r�&
��Y7s��R p���Wh�:l�<y��ox`����Bqp�9u��zl�Ĉ�fzt'HrS��{�,6\�75X���/���Ū��C�,k2�&� Β�Y^�I9DL���-9Ē�-�	�Aa�O��⋗�L]�E���	ډ�ا�c�-Y����!�`�^q�?����C�򲑃��܀́�Z���8�\��ҁ��O&%u/\0��{%��m�ɝƧ��ص�z����N@����{�y
�i��J����t��K�4L�Yf�)�e/_2�vU�\+/*�K�8�a�PV�|DĶ����Eb�5��h��um�z��\n܋Ѹ9i�:��s�w�^*e�>�M��8Z���U�8`XG
9}�M���-v���q��q;����|I8�ֿ���28����6:���;��>$i�y��:��yj_��"=nNN�w��,~��#b���bRӱ�r���<�ďCk[��;�b㫑[F'�#��caP�5��%�����f�6GF��n���}q=�h+���X�r��:7��{�{�
������*��l��H��F8-ԞY(3R{{��I�o!m�����.q��o�~��r3p����¹vH�R�V�W��`@;�?|I�ʸ�	�Z��i���an搋�=7��ws�,�g[�C�E����
w��Do�q{��e:�x�S��zE�Ͽ�3��Xc��Ajd�a��^�/�g?6ԇE�B�s!hw$�Ò�v�Ce~V8UT�NSz���m,�&<�f[h��4W��/q�H�`��i��\ø�ܔ��lQo�0I��ѰȲ����AK����	�	����[{N�7�F��5ԟ�i�z���?���A^��73��]�u���ĸ��Wr�?�,!>���w(������w삦ъ�d��9���
{�'��pn��_�&�S��{T��j��j��C��Q��Ć(8K�e�?������2w6]��NP�~s|�3T��x����]��[fa ��_h.^��\��u��,�o��!����Z��r"�s
ӡ��.8�Ҟ�K�钘��_�>p�fK�©���C�'�w���x&�47�$����1)� �.A�X�eV5<@�Q$!��H��$ǣ�?��o�,_��b|����1q�Lv��gs��ں���kSo�]I��s�<U\�矑��.*�-0��7_��7?6��tn�?����>2j���ܹR̟����2�����Ar@�\��;M�_�i.�]����P*��{�c}�F�I��a�S�r_��F��GLs@��t�,�L��Y	��e��Ξr-�
��VUmqۓ�l������%�^}��+d}�#~� ֈ_v���@<��
HqҨm�1����-M������_��N{09���Y�1����y~4��W�:V\��Oࡺz���K�û�z�
R���nc�C��

���?�;������@�|��@��k�M�/�Q
U2m@�Z����������{<�?����v�ֱ��1F���L]���2�)
�~*��w?�׉�22�\	��\s3�ف���ѠF�1�p���a4�bW�IH~%�~c~vVn�k���6|��
v=va!�[�Ö�ԯ��w�K@��O>�Ry�/�,X�b���+���4\��k~A�b��G�$���߁|T>SG���z��@CKmd�Ⱥ�Pl��[����V-^�i�[W6m鍈ظ����{[8/(�EO��^LY�r����1k�g�� $�nS`���d�͟��z+jU�h'����b.��r�zDox�XD�Gr8�'8�;0���koG��y5A��G`�_-�A�5�^�K�������~I��\���a`���Po�,���}F�nS�����1Q
O,[q�aIuٿoK�����mz1�v@n�,
-�킁D\����x���˽/��&`�6���G]��W
��5 �Y�ꖳ�{�5�ؑ�A�kX���.޴��k7â�%k
�Be��}�����O'�au��a ~S�8�ޅ�s���+^,*����k��$&���k����H���P\�
*-


(*	F���yi�C�<�,'&Noga[±Z]��1����3��19��;.������-{�t�)�'Xt�p��qw�s�����]�0/�\��uN���c�s��J���l����G���d���ؗ\~	q4��~�*`��w-eI��Ҙ��a�.�>"l��U[�]�t۶�G����u����/!��ի�ڒV�&�FF�F)�;�S�NB��Q_d���;W���4�.�q�����*��o�����K"A�L샩5Q�!;�/����ˌ��1u՚M��b�]� $h=Ƞc����G}��R:��eŌ��'�Wԥ�}�0R��Y���4��F�_�f��ZO1��]3�m���z0Ƃ�	T��x	9q{���0��0�=�*��7��� F�
��qęat;�T��b�?�����s�ϛ���<Y?��s2�7&^���4�8�yp����P��m��'?<�G�����1CvO�<S�����E����8�PvO���+�k%�����"��\�*�I%��r�!��<�C(�h�ů$|I��a�FҍEO'�]��U$Y(%�Kē�ƶY-�H=Bl�[D��3z�52�)�X�%�!]��8#�$�N��82�{�8��=r���1�I�lߏ'6^X��.��#d}�l������$
�x��Fҁe
�D��Ä��d:�Kƾ(,EXJ���C���+I&J�Dw�F�z��Ë$���,��x�O�D:�.��t#�;�rq\%w�����Z^�g�����`/L��B���p_��"d�&�Q��Z./���$����M�M��36l�ٺ��l�m���4f՘�1c��<6�IKd�#i�/;r�A��b�3�wZ���s�:��oX�<�oY�����u����d�
g�^@�HX?��)�z�Z�Ek��5k] n䶵.#N���Ǔx��IYGJH�"٤��P��o	��F��'�
#�$����"���w�Y�R+�H���8��֕�de���<<=U!FcV~�*�0m�jQ~�*�}*U�f�f�Td��X\o-�2,$ָ�X��H.��㒩H��fd�秖����Cg��V)�k�M�-��
��?�0���c��k�����x6�����x�p��EJ�-b����8�K~��'f��|d'
{
%��bO$�8�!‰ç�Ħ-++�3���rvjQjZv�lcI֜�����Ҍ�9�aA�qA�^�q��G+�
endstream
endobj
58 0 obj
5244
endobj
56 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Roboto-Regular
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 54 0 R
/CIDToGIDMap /Identity
/W [0 [440 241 566 547 646 547 557 526 246 534 540 559 336 557 557 261 643 512 676 592 546 519 869 324 481 241 557 344 557 626 707 195 557 270 745 469 564 611 548 682 866 647 707 651 589 880 339 345 492 240 503 557 557 562 448 210 564 557 557 557 557 618 274 409 631 317 237 ]
]
>>
endobj
57 0 obj
<< /Length 826 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0042> [<0069> <006F> <006E> <0043> <0075> <0062> <0065> <0020> <004C> <0061> <0064> <0072> <0031> <0034> <002E> <0055> <0073> <0047> <0054> <0068> <0063> <006D> <0074> <0076> <006C> <0070> <0066> <0067> <0050> <0048> <002C> <0032> <0049> <0077> <0079> <0045> <0052> <0046> <004F> <004D> <0041> <004E> <0044> <0053> <0057> <0028> <0029> <0078> <003A> <006B> <0035> <0033> <002B> <005F> <003B> <0071> <0037> <0038> <0030> <0036> <0042> <002D> <002F> <0056> <0022> <006A> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
6 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Roboto-Regular
/Encoding /Identity-H
/DescendantFonts [56 0 R]
/ToUnicode 57 0 R>>
endobj
59 0 obj
<< /Type /FontDescriptor
/FontName /QHCAAA+Consolas
/Flags 4 
/FontBBox [-432.128906 -302.246093 677.246093 1011.23046 ]
/ItalicAngle 0 
/Ascent 742.675781 
/Descent -257.324218 
/CapHeight 742.675781 
/StemV 70.3125000 
/FontFile2 60 0 R
>>
endobj
60 0 obj
<<
/Length1 11900 
/Length 63 0 R
/Filter /FlateDecode
>>
stream
x��yytǙgW7�� �H$��M���/�%ID @�hZ�%��x��-;vd[����$���x2Il����;M6;���y��y����Yٱw=~�l�W�
�e�X�+tuu�W���jR����8�P�������`����%Vf�Ux�o������c�hde��e��X�<�L�=<�����}���u<�<�6�����ߚ(ʌ�/.��[�ڨ'(ʢ�g6^��ێ��\MQ�a�͢�(1E��(
�;�kj��

i����E-�J�7��՛@��c�R]TwS���'hZ:E�)�o���bލ2S"j��D��̀�
8EJ�7;��J��:\��`��_G0P���K���f�$��Pe�_���!frMD��*U��@p@���h����.�;�c{��~Ra�K
d�R���D)SH*�*d����5��n��g���x�mv����5FCqQ�`�r����`tnZZ�T�*�R��^�����A6{��*'CN�r��`�>��{�#�3j7��2�L&/S�f���T��j��L=���S�ĔL�R���Xƿ,3�-f�N���(�c��"�Q6����*�uא����w���4j~<��+���wN�[L�M���X���}�d:1>��b���TZgecS��PsyE�R�r9C�};�B�e��[
��8]�a��
<��90��r"�����L
���Zde���[�o��k���}��:u4�&��Rt��k�e�R��ܳR����rW�<32|y�'X+˖;]����
�r��P���ڽ���!T(��ܭk�x��n~¼���sb�
`}h�?�(��üпep���@�}�����������7���V�3�N������4*�щ��	��W:�Ln�hW��~�ď�M!�,e1���NY(��pI6,R��I�y󌤦ʍ�yvx�|��Zv����ݡ�J�ԾW���x��Z���~|�������LTӆo`i]���.~!U�9s�,�o�޽���s�`���XOW�W�}�c���^�pT�ܾ@������Se������� n�x�;�j�[�*�]�������g6�r�F���3hd
�V�x�
b�΂f>O��:���
~B���yv�I�(�IN�cD����oyk�g\Nvpr���[������D|d�)d1��⨫�i�Ֆ;�Z��5ώ�AbF")�>��:��g��Ӄ[����clr����]��ju.w�	�3����_�V��h*l5�kg�:MqQQ�Fge��U�+*F��H��ZQkQ�����q��Vi���7�xt��壍�G�P�:���1?'�F�<�`����(�
�+ǝ��q����o�t+����;���yi|dϤB����~���@����;=�Z�����P���j�vn�xh���.g0������PR�˟S(d�B�!�����1��])*�����`Vi
T�؅�I���9�n�(U>恟���p�Q=�*�#�b�Q��9�/�ռxF24:>3������!�3�u�r��;w���b��^g9�H���G~z�>PQ�ӵ��/�xr_k��*�0[�
d?)hؐ�2�+RG�-(v�y�����3#���*�pEy������\�Ku~������(6Z<�mkG�.�͊f��p
��,���x�}k�7�܀=�T0/�hw(y@�k���PwV�������.?+���X��5L|5���Ţ"nJ����y����~:���k�6X��6�W)��\i���z}�~�}d��~���֦{����%�4>�Z�8R�p?{��$�L��bdU6���|fh�7/{�G�=�.W��eI���$�'��OdZ��3��$7w��Cj)������5�Ȇ��6���F���]��Lks�ɿ����ll��W[W��=911��BPf xO_s�ۣ׫U���ᕖ��;�5�xkL�B.���{&;�+���˂��\�+)�R"��Qc�F�F��hL*��Q�u{�몽����Y��P&/Ui�&�V�Ҫ4P�X�+�5���������OT<�"�V�Y�.V(����ʚ,j�m�B���ػ�c���Xs��-���%��������Kp��r��q��Ľ��V:tZTTR�**)���A��6�����֎�S˨�.r����t���
:�����j�]Q��ZSӾg�Ζ�r�x�"j�j��hJ���W@i�q�/p��k/����p���i�$wg��w�4�ɡ3�v�Gw�T榛�~��ysm�E����]���ij@5S�O�����ןC���;�7�����o���\'�큹e�8�~�5�G��[�,��u��h����Ք�d���х�7��O�(�=��"���)��]�ʆM�_���Fy�-�^j*�L�K
eE��R�J�5؞��EQiY��t�����Qo4����G�Ӛ
v��u��>���N	
����Z;B���aW�H�4��lY;�\�Y��e�C�@
�T��e1�Kp�9�/�&8/9�z�ZL0�r�|N��rhR�ĥ���/tZ��dc]�/��{����2UyECco��t�D]����Xg��Y�Q��~֊�Ck��McuMg���`��g���}�aZ2l�v�Y͞*����5��1xȫV�E�N�$T�	�6�h�p�
�!����`&X�=�����:�\NU)Bf���������3[����2}�	(��.��|��OZ�u���v��jF3�1C��"\��^��(�x2\���jƶd�������:�ƈDi���hktVZ�0�hc��M�`����\e	�\��ru�3���'8���4�%#��
�k�`�g�҉��v��)J3A7:
΂$d���^'2}-r��p�?�^G�}k��wf��K��B�S�cHI���M��Խ�zh3P�]�U'�t�[Q���v��5(WF��)�Ѩ$<�ug�}LƤ,1[�C㝡&���@Ն
��;jk�d��uLM�l<Ԥ7�45`T��
��u���D�I,�`���
G�%֘��'w��)�����q7���H$���bv���X+U�-.wm��6Y�J�i���qgW��Vo,.R��Zi0"SZf����}�m5�F�Z��c�`S(�(S�4z��+�^�5�f����Z0n�W��6{I�Q����Huj�F��i���
6-V��R�����b���#��k	�x�G?"u

 ��\�e�|��ܴq�=���3�\�LJ����v�{���xg�������B�A�W/}㟿8�}#uS�\�M5C����`d6e9��ʅ�NU�q6 ��ñ�R5�8�SƆ`CMS������'�`��r������G�5vn�:����YWoc���ͪ�6�"��@@�PG{Q���t5���DZ({�H.s�F+[�in�ꮩ1�D}$Q�J.�JD�
���q55�h�h���6�S
_��-�'Z^5���&*,f�s�4v��1'�ߥ� =�^G��;��z@�@TK�ԣ�Co�?���5Y�k���Alt�
���P��߼��͢�����:��l�{X!7�+��G�z�>���W?�W�f����6�5��9R�rt�X�w獡S�sTB��ǵ��:0
�������
F�NKꚚ�C�Cm�͵6�w�M���zg��\T��B�7:+��>X�hߧV�ڵk��'�M>���BB^懰+�4��x�v���o�ݻ�
�\VTl4y�[G{��n�9x|bp~�U���!}�ڵ��
�
�j8��U�ʖ��ZBc]����m]�ݽ}#��J��Q�QF�.ɈAP����}y�a��ƻ\�kFo";�.�?̈́W��_Y�~?q�CQ1He�s�P�wɝ�9!A�u�pb�G��M�b��깕/��ї�#���:���XG��B��v�N[n�V5�6�\.�f�d�]����U�@_�	�ҏ<u���^=B��=#Ǐ]~��N�]�=ǎ���ag�X�[
ٹ�n��9p\�ZY3z:�q�Ve)��w���vl��Zf�%U�D
!�ڲp�Cͽ}û"F�ƀ1�頻he��_s���
��_�D:�-Vi�1�Ev[}� .�Μ��{n�aO9�/��0����>�>��Nr��&�6�:Ɲ@��O�Пq�v	���W�ז8�~���7��&+Z��!��y,�8�
�ܕW��o+�{�vÁ��3��T��x�j�@��ׇ�;۷�����P(��궎�'��R��%]W���-��.g��嬘�5l0��[#�z��ҨG��o�j�����\")+-��ڂ�*����Q�,���=�q���\^P {<mm��ݶ��@�wV���K��S�E�o�Kk���_Ҷ��tPlz�;���I��p��
%�"H�T���=��x
z�"S�$kܴش����K��k��%1�y{uwˑ��t�[�ET��<[������juW
���=�������J�\����Ѷ�J�J���\Ύ��=m�J��~��N��r�ښ�G��|���nO��vt�ȑ�dNo��U��S旦ý[�pb��O�!����ƩGT��!w�yU��GE�����k��&������b�-T��P���SO��N�S7���N�\�{�C�Tn>Ư+c�����~���'�tW�؞H|���;��ػ붆�ɂ��ߌ��>X׍��m�w���~���|����g��
w�W�Y��d������������������� �z ~�q��"**������‘/s�G#���S�!���qxW���u�́���Cm�j�^lz�,������
hU���}���~��2��"mX?�0�[��]�p�e��;���ze��o���sc�ûv�j�t�8�ؤ�������]{�����F4E�H*"\<`1�h�{���+��O��yY�߁#�'���~��)ķط�ׅ%m����v��ȳ�K��F��5���D�Ǐ�YB)�/c��^��s��
wܖD�����]�F	�;���`�3p�m�p�@�愶�%h)a-�B�П��S	��C��	h^��Vh[x~��К��o�
<bd�����D����>A���oL#s��>�D�!J�>��.�'��şK�%A�i���NH�)}��t�
�>Q�O�JY�짲��Z�G~^���mE�bX1���⇊�ElQ+�n�z��۟%��멜=�B���B���ӧB_D ��S
�.�%0>%�TzW�PzP�R��q�/��'�&��W���WPy��/Bۋ� �ƒK�	�F	W���R�i�Oì
}������Q��@�)=r}	�	})u�	��C��~!���B_&�M��rj\���WP�J�ѧ�cB��J��Q߃J�j�:*�T��Pi*Ee��RY�^|��a$�$ԉ,�M%�b��06G�ûy��=��oW��c�uvG<�NeR�Y�7�^L���x*�c�	vw|n>�aw�2���X��m0	�6�d&�C�0�~�����R"�۹o����:-�ͻl7N����PJ�@YxKg@6��Ja�+h��0�,Qk�X ��1�<~3�w6�y^��fG��a�)NL��`��g�0�M����p���e��<�̥SK�x8�ZX'㱌�N��c�@�Ѵ�X�PUDh7�������/E��7���T*{7]�A>�P,���g�x���,�s��������~�҄�y�
4��^J�u��ό���%s"D�,Y���`�B��=��]�(�������2�[�'4Ä���=�%c��>9/��b��8���𔀧Cdk,JV����V|�f5�7ssz��ě�9�7)b�X��X�0�:��bLk(#�a��(C�����=*�'ފmrX�����eBiC�Q��E�+dw�;<�_\+C�()�k(����ܕ�3A,�[=}��2M�� c1�>���#���uZ�ܻ{B�;���M_H��$��9�2y�_ ��z��
҄A�	���狷-�	<�1�՘�9�x,ː��9��ab�$p��!F}I�)mX{KB8���;-ț\K�x��%�J+ٛ��y�[5�!���Uy��*�*)�Fn~�{zR���B�`��s��s4#؟�WΧp��lI�ov=��=8A�&�s���2#D���躟�OY�_�̟!=LPae]�9��3dn>�-�q{�/Ģ�l*�.ebl<�.�Ss���B<9�ƒ���Tr!��\NF�d�4��#K�l8�e�e�A6YH%S��p��Kf1��b,��C�&I=2N�#YȒ�|�p���Lx!�.ǣ�j6?cS�(�]Y�-��xf5�>�y�ga��T*
dR�H��3R�p�07���'c��t:�YL%��C;
��@0�$؉x2�Z��<F��Dx�
'�ex�ē��%���<V�.���f"��M��Tzv���˂�$I�q<F7)!��ԛZJ�ci�	V9�,C�_H�� �B?�I����i!��X2
��NPVd"�X���Xr4�����%��I,A�n���4�Ľ��B,NdZ�|>�f��l�
D�?�������$dk0Of>��cB3 ?�5����[�,6��D*�����e����6�
g�1vf�=N�`�lО	�yG[��%�<��E(�j�Z&����[����B���E���8�n�/5��.���.//�r���P���q~�6�%��C��,A�4A���9�x�lx&?��R�^��|�]ɫS��8����G��Wr���@.�1(���P,���pQRje׫�e�W��;���o ���ǕE����r<-���ȸYn���OU��M2�]�?�U�6�~mP�Ȅ|���#�T��r�f��3
���%K�˕˜>/+_�$I~�QIy=�o�i�ߍ�k{�P
�H=|*Erp�[�����_W�g16T���'8��c�l{7���]�dq�X��G�����ш�:�BL/��0!� ����ީ$�^U���������w�L'`	�M�#<P����i��V�]��|I�aWH�D*��)��9ň�2^j)���"vg�3K,n�XmU-1.��%R���/BY��0`���lx)���3���;�	
endstream
endobj
63 0 obj
7274
endobj
61 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Consolas
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 59 0 R
/CIDToGIDMap /Identity
/DW 545 >>
endobj
62 0 obj
<< /Length 742 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0036> [<0069> <006F> <006E> <0063> <0075> <0062> <0065> <002E> <006C> <0061> <0064> <0072> <005F> <0070> <0074> <0068> <0073> <003A> <003B> <002B> <002D> <002F> <0076> <0077> <006D> <0052> <0053> <0020> <003D> <0022> <0066> <0067> <006B> <0031> <0024> <007B> <007D> <0032> <0034> <0030> <0079> <0078> <0037> <0033> <0045> <004E> <004F> <0054> <0049> <0043> <007C> <0044> <0050> <0041> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Consolas
/Encoding /Identity-H
/DescendantFonts [61 0 R]
/ToUnicode 62 0 R>>
endobj
2 0 obj
<<
/Type /Pages
/Kids 
[
5 0 R
19 0 R
28 0 R
34 0 R
]
/Count 4
/ProcSet [/PDF /Text /ImageB /ImageC]
>>
endobj
xref
0 64
0000000000 65535 f 
0000000009 00000 n 
0000038255 00000 n 
0000000187 00000 n 
0000000282 00000 n 
0000000756 00000 n 
0000029337 00000 n 
0000038121 00000 n 
0000000319 00000 n 
0000000362 00000 n 
0000000405 00000 n 
0000000449 00000 n 
0000000493 00000 n 
0000000530 00000 n 
0000000574 00000 n 
0000001080 00000 n 
0000007535 00000 n 
0000000877 00000 n 
0000001053 00000 n 
0000007863 00000 n 
0000007556 00000 n 
0000007600 00000 n 
0000007644 00000 n 
0000007688 00000 n 
0000008188 00000 n 
0000012626 00000 n 
0000007985 00000 n 
0000008161 00000 n 
0000012691 00000 n 
0000012647 00000 n 
0000013009 00000 n 
0000017982 00000 n 
0000012813 00000 n 
0000012989 00000 n 
0000020361 00000 n 
0000018003 00000 n 
0000018047 00000 n 
0000020194 00000 n 
0000020020 00000 n 
0000018298 00000 n 
0000018452 00000 n 
0000018591 00000 n 
0000018987 00000 n 
0000019859 00000 n 
0000018784 00000 n 
0000019263 00000 n 
0000019391 00000 n 
0000019554 00000 n 
0000019723 00000 n 
0000020257 00000 n 
0000020679 00000 n 
0000022336 00000 n 
0000020483 00000 n 
0000020659 00000 n 
0000022357 00000 n 
0000022621 00000 n 
0000027977 00000 n 
0000028459 00000 n 
0000027956 00000 n 
0000029477 00000 n 
0000029735 00000 n 
0000037122 00000 n 
0000037327 00000 n 
0000037101 00000 n 
trailer
<<
/Size 64
/Info 1 0 R
/Root 49 0 R
>>
startxref
38374
%%EOF
alt-php52-ioncube-loader/LICENSE.txt000064400000025020150431076110012766 0ustar00LICENCE AGREEMENT FOR THE IONCUBE PHP LOADER, PROVIDED TO ENABLE THE USE
OF IONCUBE ENCODED FILES AND AS PART OF THE IONCUBE24 SERVICE (ioncube24.com)

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING THE
LOADER SOFTWARE. THE INSTALLATION AND/OR USE OR COPYING OF THE IONCUBE PHP
LOADER SOFTWARE INDICATES YOUR ACCEPTANCE OF THIS LICENCE AGREEMENT.  IF YOU
DO NOT ACCEPT THE TERMS OF THIS LICENCE AGREEMENT, DO NOT INSTALL, COPY
AND/OR USE THE LOADER SOFTWARE.

DEFINITIONS

The following definitions shall apply in this document:

LOADER shall mean the ionCube PHP Loader software package or collection 
of Loaders, including any modifications or upgrades to the software, used for
executing PHP scripts previously encoded with the ionCube PHP Encoder
software to render them non-humanly readable, and any associated
documentation or electronic or online materials relating to the software.

ENCODER shall mean any ionCube PHP Encoder software or service used for the
purpose of producing non-humanly readable encoded files from PHP scripts.

ENCODED FILE shall mean a non-humanly readable file produced by the 
Encoder and being derived from humanly readable PHP script source.

PROVIDER shall mean ionCube Ltd.

USER/YOU shall mean any entity who has downloaded or obtained through any
other means a version of the Loader software.


1 LICENSE ENTITLEMENT 

1.1 The Loader is provided without charge.  Title to the Loader does not pass
to the user in any circumstances.  The Loader is supplied as object code.

1.2 The provider grants a personal, non-transferable, non-exclusive licence to
use the Loader in accordance with the terms and conditions of this Licence
Agreement.

1.3 The installation or downloading and use of the Loader entitles the user
to install and use the Loader for its own internal lawful purposes.


2 DISTRIBUTION 

2.1 The Loader may be freely distributed to third parties alone or as 
part of a distribution containing other items provided that this license
is also included. 

2.2 The Loader may under no circumstances be branded as another product, 
whether distributed or not. 

2.3 Distribution as part of a commercial product is permitted provided such
distribution is in accordance with clauses 2.1 and 2.2 with respect to the 
Loader.


3 ANALYSIS / REVERSE ENGINEERING / MODIFICATION 

Except insofar as the user is permitted to do so in accordance with applicable
law:

3.1 Any analysis of the Loader and embedded data by any means and by
any entity whether human or otherwise and including but without limitation to
discover details of internal operation, to reverse engineer, to de-compile
object code, or to modify for the purposes of modifying behaviour is
forbidden.

3.2 Any analysis of encoded files by any means and by any entity whether human
or otherwise and including but without limitation to discover details of file
format or for the purposes of modifying behaviour or scope of their usage is
forbidden.


4 WARRANTY

THE LOADER SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
WARRANTIES INCLUDING BUT WITHOUT LIMITATION THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE ARE
DISCLAIMED. THE PROVIDER DOES NOT WARRANT THAT THE LOADER IS UNINTERRUPTED
OR ERROR FREE, NOR THAT THE OPERATION OF THE LOADER WILL FUNCTION IN
CONJUNCTION WITH ANY OTHER PRODUCT.  


5 LIMITATION OF LIABILITY 

5.1 IN NO EVENT WILL THE PROVIDER OF THE LOADER BE LIABLE TO THE USER OR ANY
PARTY FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR OTHER
CONSEQUENTIAL DAMAGES ARISING DIRECTLY OR INDIRECTLY FROM THIS LICENCE
AGREEMENT OR ANY USE OF THE LOADER OR ENCODED FILES, EVEN IF THE PROVIDER IS
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

5.2 THE LOADER IS PROVIDED ON AN "AS IS" BASIS.  THE PROVIDER EXCLUDES ALL
WARRANTIES, CONDITIONS, TERMS, UNDERTAKINGS AND REPRESENTATIONS (EXCLUDING
FRAUDULENT MISREPRESENTATION) OF ANY KIND, EXPRESS OR IMPLIED, STATUTORY OR
OTHERWISE IN CONNECTION WITH THE LOADER TO THE FULLEST EXTENT PERMITTED BY
LAW.

5.3 DOWNLOADING THE LOADER IS AT YOUR OWN RISK AND THE PROVIDER DOES NOT
ACCEPT LIABILITY FOR ANY DIRECT OR INDIRECT LOSS OR DAMAGE HOWSOEVER CAUSED AS
A RESULT OF ANY COMPUTER VIRUSES, BUGS, TROJAN HORSES, WORMS, SOFTWARE BOMBS
OR OTHER SIMILAR PROGRAMS ARISING FROM YOUR USE OF THE LOADER.  WHILST THE
PROVIDER WILL DO ITS BEST TO ENSURE THAT THE LOADER IS FREE FROM SUCH
DESTRUCTIVE PROGRAMS, IT IS YOUR RESPONSIBILITY TO TAKE REASONABLE PRECAUTIONS
TO SCAN FOR SUCH DESTRUCTIVE PROGRAMS DOWNLOADED FROM THE INTERNET.

5.4 THE PROVIDER'S MAXIMUM LIABILITY FOR ANY LOSS OR DAMAGE ARISING FROM THIS
LICENCE AGREEMENT SHALL IN ANY EVENT BE LIMITED IN THE SOLE DISCRETION OF THE
PROVIDER TO THE REPLACEMENT OF THE LOADER PRODUCT.

5.5 DUE TO THE NATURE OF THE INTERNET, THE PROVIDER CANNOT GUARANTEE THAT ANY
E-MAILS OR OTHER ELECTRONIC TRANSMISSIONS WILL BE SENT TO YOU OR RECEIVED BY
THE PROVIDER OR THAT THE CONTENT OF SUCH TRANSMISSIONS WILL BE SECURE DURING
TRANSMISSION.


6 BUG FIXING AND PRODUCT SUPPORT 

6.1 The provider will use reasonable endeavours to provide support to users.
The provider will at their discretion only provide support for the latest
release.

6.2 Support comprises of fault reporting via tickets and fault diagnosis,
recommendations on workarounds, and where reasonably possible a timely
resolution.

6.3 The user accepts that on occasion the ability of the provider to meet
anticipated or published support schedules may be impaired due to, but without
limitation, Internet service provider failures or software failures that
affect the ability to communicate for an indeterminate period.

6.4 The provider reserves the right to refuse to provide support at any time.

6.5 The provider wishes to maintain and offer a product of the highest
possible quality, and accordingly may from time to time and at its discretion
make product changes for the purpose of correcting behaviour in variance to
the published specification or the user's reasonable expectations. 

6.6 The provider reserves the right to charge for support where the user does
not have a valid support plan in place, or where the support offered exceeds
the scope of the active support plan.


7 PRODUCT UPGRADES

7.1 The provider may from time to time release product upgrades. These will
be provided free of charge and attempts made to provide a timely notification
to customers of the existence of any new release.


8 ERRORS AND OMISSIONS

Whilst reasonable endeavours are made to ensure the accuracy of documentation
concerning the details of the Loader, the user accepts the possibility of
inaccuracies in information presented in any format, including email
communications and online services. The provider shall under no circumstances
be liable for any events that arise as a result of unintentional inaccuracies
or omissions.


9 USER INDEMNITY

You agree to fully indemnify, defend and hold the provider harmless
immediately upon demand from and against all actions, liability, claims,
losses, damages, costs and expenses (including legal/attorney fees) incurred
by the provider arising directly or indirectly as a result of your breach of
this Licence Agreement.


10 INTELLECTUAL PROPERTY RIGHTS

10.1 The user acknowledges that the Loader and associated documentation and
materials contain proprietary information of the provider and are and shall
remain the exclusive property of the provider and/or its licensors and all
title, copyright, trade marks, trade names, patents and other intellectual
property rights therein of whatever nature shall remain the sole property of
the provider and/or its licensors.

10.2 No title to or rights of ownership, copyright or other intellectual
property in the Loader is transferred to the user (other than the licence
rights expressly granted in this Licence Agreement).


11 TERMINATION

11.1 The provider reserves the right to terminate this Licence Agreement
immediately by notice in writing against the user if the user is in breach of
any terms and conditions of this Licence Agreement.

11.2 Termination of this Licence Agreement for any reason shall be without
prejudice to any other rights or remedies of the provider which may have
arisen on or before the date of termination under this Licence Agreement or in
law.

11.3 The provisions of the following clauses shall survive any termination of
this agreement; clause 3, 5, 10 and 13.


12 GENERAL

12.1 The provider reserves the right to transfer or assign all or any of its
rights and duties and responsibilities set out in this Licence Agreement to
another party.

12.2 Headings have been included for convenience only and will not be used in
construing any provision of this Licence Agreement.

12.3 No delay or failure by the provider to exercise any powers, rights or
remedies under this Licence Agreement will operate as a waiver of them nor
will any single or partial exercise of any such powers, rights or remedies
include any other or further exercise of them.

12.4 If any part of this Licence Agreement is found by a court of competent
jurisdiction or other competent authority to be invalid, unlawful or
unenforceable then such part shall be severed from the remainder of this
Licence Agreement which will continue to be valid and enforceable to the
fullest extent permitted by applicable law.

12.5 This Licence Agreement including the documents or other sources referred
to herein supersede all prior representations, understandings and agreements
between the user and the provider relating to the Loader and sets forth the
entire agreement and understanding between the user and the provider relating
to the Loader.

12.6 Nothing in this Licence Agreement shall be deemed to constitute a
partnership between you and the provider nor constitute either party being an
agent of the other party.

12.7 This Agreement does not create any rights or benefits enforceable by any
person not a party to it (within the meaning of the U.K.Contracts (Rights of
Third Parties) Act 1999) except that a person who under clause 12.1 is a
permitted successor or assignee of the rights or benefits of the provider may
enforce such rights or benefits.


13 GOVERNING LAW AND JURISDICTION

This License Agreement and any issues relating thereto shall be construed and
interpreted in accordance with the laws of England and subject to the
exclusive jurisdiction of the English courts.

Copyright (c) 2002-2024 ionCube Ltd.          Last revised 23-April-2015
alt-php52-ioncube-loader/loader-wizard.php000064400000541746150431076120014443 0ustar00<?php // -*- c++ -*-

/** 
 * ionCube Loader install Wizard
 *
 * ionCube is a registered trademark of ionCube Ltd. 
 *
 * Copyright (c) ionCube Ltd. 2002-2022
 */


 

define ('ERROR_UNKNOWN_OS',1);
define ('ERROR_UNSUPPORTED_OS',2);
define ('ERROR_UNKNOWN_ARCH',3);
define ('ERROR_UNSUPPORTED_ARCH',4);
define ('ERROR_UNSUPPORTED_ARCH_OS',5);
define ('ERROR_WINDOWS_64_BIT',6);
define ('ERROR_PHP_UNSUPPORTED',7);
define ('ERROR_PHP_DEBUG_BUILD',8);
define ('ERROR_RUNTIME_EXT_DIR_NOT_FOUND',101);
define ('ERROR_RUNTIME_LOADER_FILE_NOT_FOUND',102);
define ('ERROR_INI_NOT_FIRST_ZE',201);
define ('ERROR_INI_WRONG_ZE_START',202);
define ('ERROR_INI_ZE_LINE_NOT_FOUND',203);
define ('ERROR_INI_LOADER_FILE_NOT_FOUND',204);
define ('ERROR_INI_NOT_FULL_PATH',205);
define ('ERROR_INI_NO_PATH',206);
define ('ERROR_INI_NOT_FOUND',207);
define ('ERROR_INI_NOT_READABLE',208);
define ('ERROR_INI_MULTIPLE_IC_LOADER_LINES',209);
define ('ERROR_INI_USER_INI_NOT_FOUND',210);
define ('ERROR_INI_USER_CANNOT_CREATE',211);
define ('ERROR_LOADER_UNEXPECTED_NAME',301);
define ('ERROR_LOADER_NOT_READABLE',302);
define ('ERROR_LOADER_PHP_MISMATCH',303);
define ('ERROR_LOADER_NONTS_PHP_TS',304);
define ('ERROR_LOADER_TS_PHP_NONTS',305);
define ('ERROR_LOADER_WRONG_OS',306);
define ('ERROR_LOADER_WRONG_ARCH',307);
define ('ERROR_LOADER_WRONG_GENERAL',308);
define ('ERROR_LOADER_WIN_SERVER_NONWIN',321);
define ('ERROR_LOADER_WIN_NONTS_PHP_TS',322);
define ('ERROR_LOADER_WIN_TS_PHP_NONTS',323);
define ('ERROR_LOADER_WIN_PHP_MISMATCH',324);
define ('ERROR_LOADER_WIN_COMPILER_MISMATCH',325);
define ('ERROR_LOADER_NOT_FOUND',380);
define ('ERROR_LOADER_PHP_VERSION_UNKNOWN',390);


define ('SERVER_UNKNOWN',0);
define ('HAS_PHP_INI',1);
define ('SERVER_SHARED',2); 
define ('SERVER_VPS',5); 
define ('SERVER_DEDICATED',7); 
define ('SERVER_LOCAL',9);

define ('IONCUBE_IP_ADDRESS',
			'94.101.154.134');
define  ('IONCUBE_ACCESS_ADDRESS',
			'lwaccess.ioncube.com');
define ('LOADERS_PAGE',
            'https://loaders.ioncube.com/'); 
define ('SUPPORT_SITE',
            'https://support.ioncube.com/');                                 
define ('WIZARD_SUPPORT_TICKET_DEPARTMENT',
			'3');
define ('LOADER_FORUM_URL',
            'https://forum.ioncube.com/viewforum.php?f=4');                  
define ('LOADERS_FAQ_URL',
            'https://www.ioncube.com/faqs/loaders.php');                     
define ('UNIX_ERRORS_URL',
            'https://www.ioncube.com/loaders/unix_startup_errors.php');      
define ('LOADER_WIZARD_URL',
            LOADERS_PAGE);                                                  
define ('ENCODER_URL',
            'https://www.ioncube.com/sa_encoder.php');                       
define ('LOADER_VERSION_URL',
            'https://www.ioncube.com/feeds/product_info/versions.php');    
define ('WIZARD_LATEST_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-wizard'); 
define ('PHP_COMPILERS_URL',
            LOADER_VERSION_URL . '?item=php-compilers');
define ('LOADER_PLATFORM_URL',
            LOADER_VERSION_URL . '?item=loader-platforms-all');   
define ('LOADER_LATEST_VERSIONS_URL',
            LOADER_VERSION_URL . '?item=loader-versions'); 
define ('LOADER_PHP_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-php-support'); 
define ('WIZARD_STATS_URL',
            'https://www.ioncube.com/feeds/stats/wizard.php');    
define ('IONCUBE_DOWNLOADS_SERVER',
            'https://downloads.ioncube.com/loader_downloads');          
define ('IONCUBE24_URL',
			'https://ioncube24.com');
define ('IONCUBE_CONNECT_TIMEOUT',4);

define ('DEFAULT_SELF','/ioncube/loader-wizard.php');
define ('LOADER_NAME_CHECK',true);
define ('LOADER_EXTENSION_NAME','ionCube Loader');
define ('LOADER_SUBDIR','ioncube');
define ('WINDOWS_IIS_LOADER_DIR', 'system32');
define ('ADDITIONAL_INI_FILE_NAME','00-ioncube.ini');
define ('UNIX_SYSTEM_LOADER_DIR','/usr/local/ioncube');
define ('RECENT_LOADER_VERSION','4.0.7');
define ('LATEST_LOADER_MAJOR_VERSION',12);
define ('LOADERS_PACKAGE_PREFIX','ioncube_loaders_');
define ('SESSION_LIFETIME_MINUTES',360);
define ('WIZARD_EXPIRY_MINUTES',2880);
define ('IONCUBE_WIZARD_EXPIRY_MINUTES',10080);
define ('MIN_INITIALISE_TIME',4);
define ('IC24_ENABLED_INI_PROPERTY',"ic24.enable");

    run();


function php4_http_build_query($formdata, $numeric_prefix = null, $key = null ) {
    $res = array();
    foreach ((array)$formdata as $k=>$v) {
        $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
        if ($key) $tmp_key = $key.'['.$tmp_key.']';
        if ( is_array($v) || is_object($v) ) {
            $res[] = php4_http_build_query($v, null , $tmp_key);
        } else {
            $res[] = $tmp_key."=".urlencode($v);
        }
   }
   $separator = ini_get('arg_separator.output');
   return implode($separator, $res);
}


function script_version()
{
    return "2.73";
}

function retrieve_latest_wizard_version()
{
    $v = false;

    $s = trim(remote_file_contents(WIZARD_LATEST_VERSION_URL));
    if (preg_match('/^\d+([.]\d+)*$/', $s)) {
        $v = $s;
    }

    return $v;
}

function latest_wizard_version()
{
    if (!isset($_SESSION['latest_wizard_version'])) {
        $_SESSION['latest_wizard_version'] = retrieve_latest_wizard_version();
    } 
    return $_SESSION['latest_wizard_version'];
}

function update_is_available($lv)
{
    if (is_numeric($lv)) {
        $lv_parts = explode('.',$lv);
        $script_parts = explode('.',script_version());
        return ($lv_parts[0] > $script_parts[0] || ($lv_parts[0] == $script_parts[0] && $lv_parts[1] > $script_parts[1]));
    } else {
        return null;
    }
}

function check_for_wizard_update($echo_message = false)
{
    $latest_version = latest_wizard_version();
    $update_available = update_is_available($latest_version);

    if ($update_available) {
        if ($echo_message) {
            echo '<p class="alert">An updated version of this Wizard script is available <a href="' . LOADER_WIZARD_URL . '">here</a>.</p>';
        }
        return $latest_version;
    } else {
        return $update_available;
    }
}


function remote_file_contents($url)
{
    $remote_file_opening = ini_get('allow_url_fopen');
    $contents = false;
    if (isset($_SESSION['timing_out']) && $_SESSION['timing_out']) {
        return false;
    }
    @session_write_close();
    $timing_out = 0;
    if ($remote_file_opening) {
        $fh = @fopen($url,'rb');
        if ($fh) {
            stream_set_blocking($fh,0);
            stream_set_timeout($fh,IONCUBE_CONNECT_TIMEOUT);
            while (!feof($fh)) {
                $result = fread($fh, 8192);
                $info = stream_get_meta_data($fh);
                $timing_out = $info['timed_out']?1:0;
                if ($timing_out) {
                    break;
                }
                if ($result !== false) {
                    $contents .= $result;
                } else {
                    break;
                }
            }
            fclose($fh);
        } else {
            $timing_out = 1;
        }
    } elseif (extension_loaded('curl')) {
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,IONCUBE_CONNECT_TIMEOUT);
            $output = curl_exec($ch);
            $info = curl_getinfo($ch);
            $timing_out = ($info['http_code'] >= 400)?1:0;
            curl_close($ch);

            if (is_string($output)) {
                $contents = $output;
            }
    } else {
        $timing_out = 1;
    }
    @session_start();
    $_SESSION['timing_out'] = $timing_out;
    return $contents;
}

function php_version()
{
    $v = explode('.',PHP_VERSION);

    return array(
           'major'      =>  $v[0],
           'minor'      =>  $v[1],
           'release'    =>  $v[2]);
}

function php_version_maj_min()
{
    $vprts = php_version();
    return ($vprts['major'] . '.' . $vprts['minor']);
}

function is_supported_php_version()
{
    $v = php_version(); 

    return ((($v['major'] == 4) && ($v['minor'] >= 1)) ||
      (($v['major'] == 5) && (($v['minor'] >= 1) || ($v['release'] >= 3))) ||
	  $v['major'] == 7 || ($v['major'] == 8 && $v['minor'] >= 1));
}

function is_php_version_or_greater($major,$minor,$release = 0)
{
    $version = php_version();
    return ($version['major'] > $major || 
            ($version['major'] == $major && $version['minor'] > $minor) ||
            ($version['major'] == $major && $version['minor'] == $minor && $version['release'] >= $release));
}

function ini_file_name()
{
    $sysinfo = get_sysinfo();
    return (!empty($sysinfo['PHP_INI'])?$sysinfo['PHP_INI_BASENAME']:'php.ini');
}

function get_remote_session_value($session_var,$remote_url,$default_function)
{
    if (!isset($_SESSION[$session_var])) {
        $serialised_res = remote_file_contents($remote_url);
        $unserialised_res = @unserialize($serialised_res);
        if (empty($unserialised_res)) {
            $unserialised_res = call_user_func($default_function);
        } else {
			$_SESSION['remote_access_successful'] = 1;
		}
        if (false === $unserialised_res) {
            $unserialised_res = '';
        }
        $_SESSION[$session_var] = $unserialised_res;
    }
    return $_SESSION[$session_var];
}

function get_file_contents($file)
{
    if (function_exists('file_get_contents')) {
        $strs = @file_get_contents($file);
    } else {
        $lines = @file($file);
        $strs = join(' ',$lines);
    }
    return $strs;
}

function default_platform_list()
{
    $platforms = array();


    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6', 'is_legacy' => 1,       'os_mod' => '_vc6',     'arch'=>'x86',  'dirname'=>'win32', 'us1-dir'=>'windows_vc6/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6 (Non-TS)',   'is_legacy' => 1,  'os_mod' => '_nonts_vc6',   'arch'=>'x86',  'dirname'=>'win32-nonts', 'us1-dir'=>'windows_vc6/x86-nonts' );

    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9',        'os_mod' => '_vc9',     'arch'=>'x86',  'dirname'=>'win32_vc9', 'us1-dir'=>'windows_vc9/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9 (Non-TS)',   'os_mod' => '_nonts_vc9',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc9', 'us1-dir'=>'windows_vc9/x86-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86',  'dirname'=>'win32_vc11', 'us1-dir'=>'windows_vc11/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc11', 'us1-dir'=>'windows_vc11/x86-nonts' );
	
	$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86-64',  'dirname'=>'win64_vc11', 'us1-dir'=>'windows_vc11/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc11', 'us1-dir'=>'windows_vc11/amd64-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86',  'dirname'=>'win32_vc14', 'us1-dir'=>'windows_vc14/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc14', 'us1-dir'=>'windows_vc14/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86-64',  'dirname'=>'win64_vc14', 'us1-dir'=>'windows_vc14/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc14', 'us1-dir'=>'windows_vc14/amd64-nonts' );
	
		 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86',  'dirname'=>'win32_vc15', 'us1-dir'=>'windows_vc15/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc15', 'us1-dir'=>'windows_vc15/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86-64',  'dirname'=>'win64_vc15', 'us1-dir'=>'windows_vc15/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc15', 'us1-dir'=>'windows_vc15/amd64-nonts' );

    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86',      'dirname'=>'linux_i686-glibc2.3.4', 'us1-dir'=>'linux/x86');
    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86-64',   'dirname'=>'linux_x86_64-glibc2.3.4', 'us1-dir'=>'linux/x86_64');
$platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc',      'dirname'=>'linux_ppc-glibc2.3.4','us1-dir'=>'linux/ppc');
            $platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc64',    'dirname'=>'linux_ppc64-glibc2.5','us1-dir'=>'linux/ppc64');
    

$platforms[] = array('os'=>'dra', 'os_human'=>'DragonFly', 'arch'=>'x86',      'dirname'=>'dragonfly_i386-1.7', 'us1-dir'=>'Dragonfly/x86');

$platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 4', 'os_mod'=>'_4',  'arch'=>'x86',      'dirname'=>'freebsd_i386-4.8', 'us1-dir'=>'FreeBSD/v4');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86',      'dirname'=>'freebsd_i386-6.2', 'us1-dir'=>'FreeBSD/v6/x86');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-6.2', 'us1-dir'=>'FreeBSD/v6/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86',      'dirname'=>'freebsd_i386-7.3', 'us1-dir'=>'FreeBSD/v7/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-7.3', 'us1-dir'=>'FreeBSD/v7/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86',      'dirname'=>'freebsd_i386-8.0', 'us1-dir'=>'FreeBSD/v8/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-8.0', 'us1-dir'=>'FreeBSD/v8/AMD64');
    
    $platforms[] = array('os'=>'bsd', 'os_human'=>'BSDi',     'is_legacy' => 1,           'arch'=>'x86',      'dirname'=>'bsdi_i386-4.3.1');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86',      'dirname'=>'netbsd_i386-2.1','us1-dir'=>'NetBSD/x86');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86-64',   'dirname'=>'netbsd_amd64-2.0','us1-dir'=>'NetBSD/x86_64');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.2', 'os_mod'=>'_4.2',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.2', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.5', 'os_mod'=>'_4.5',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.5', 'us1-dir'=>'OpenBSD/x86');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.6', 'os_mod'=>'_4.6',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.6', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.7', 'os_mod'=>'_4.7',  'arch'=>'x86-64', 'dirname'=>'openbsd_amd64-4.7', 'us1-dir' => 'OpenBSD/x86_64');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',    'is_legacy' => 1, 'arch'=>'ppc',      'dirname'=>'osx_powerpc-8.5','us1-dir'=>'OSX/ppc');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86',      'dirname'=>'osx_i386-8.11','us1-dir'=>'OSX/x86');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86-64',       'dirname'=>'osx_x86-64-10.2','us1-dir'=>'OSX/x86_64');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',  'is_legacy' => 1,          'arch'=>'sparc',    'dirname'=>'solaris_sparc-5.9', 'us1-dir'=>'Solaris/sparc');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',            'arch'=>'x86',      'dirname'=>'solaris_i386-5.10','us1-dir'=>'Solaris/x86');

    return $platforms;
}

function get_loader_platforms()
{
    return get_remote_session_value('loader_platform_info',LOADER_PLATFORM_URL,'default_platform_list');
}

function get_platforminfo()
{
    static $platforminfo;

    if (empty($platforminfo)) {
        $platforminfo = get_loader_platforms();
    }
    return $platforminfo;
}

function default_php_versions()
{
	return array();
}

function get_php_versions()
{
	return get_remote_session_value('php_version_info',LOADER_PHP_VERSION_URL,'default_php_versions');
}


function get_max_php_version_supported()
{
	static $max_php_version;
	
	if (empty($max_php_version)) {
		$php_versions = get_php_versions();
		
		$dirname = calc_dirname();
		
		if (array_key_exists($dirname,$php_versions)) {
			$max_php_version = $php_versions[$dirname];
		} else {
			$max_php_version = NULL;
		}
	}
	
	return $max_php_version;
}

function is_after_max_php_version_supported()
{
	$is_too_recent_php = false;
	
	$supported_php_version = get_max_php_version_supported();
	
	if (!is_null($supported_php_version)) {
		$pversion = php_version();
		
		$supported_parts = explode('.',$supported_php_version);
		$is_too_recent_php = ($supported_parts[0] < $pversion['major'] || ($supported_parts[0] == $pversion['major'] && $supported_parts[1] < $pversion['minor']));
	}
	
	if ($is_too_recent_php) {
		return $supported_php_version;
	} else {
		return false;
	}
}

function supported_os_variants($os_code,$arch_code)
{
    if (empty($os_code)) {
        return ERROR_UNKNOWN_OS;
    }
    if (empty($arch_code)) {
        return ERROR_UNKNOWN_ARCH;
    }

    $os_found = false;
    $arch_found = false;
    $os_arch_matches = array();
    $pinfo = get_platforminfo();

    foreach ($pinfo as $p) {
        if ($p['os'] == $os_code && $p['arch'] == $arch_code) {
            $os_arch_matches[$p['os_human']] = (isset($p['os_mod']))?(0 + (int) str_replace('_','',$p['os_mod'])):'';
        } 
        if ($p['os'] == $os_code) {
            $os_found = true;
        } elseif ($p['arch'] == $arch_code) {
            $arch_found = true;
        }
    }
    if (!empty($os_arch_matches)) {
        asort($os_arch_matches);
        return $os_arch_matches;
    } elseif (!$os_found) {
        return ERROR_UNSUPPORTED_OS;
    } elseif (!$arch_found) {
        return ERROR_UNSUPPORTED_ARCH;
    } else {
        return ERROR_UNSUPPORTED_ARCH_OS;
    }
}

function default_win_compilers()
{
    return array('VC6','VC9','VC11','VC14','VC15', 'VC16');
}

function supported_win_compilers()
{
    static $win_compilers;

    if (empty($win_compilers)) {
        $win_compilers = find_win_compilers();
    }
    return $win_compilers;
}

function find_win_compilers()
{
    return get_remote_session_value('php_compilers_info',PHP_COMPILERS_URL,'default_win_compilers');
}

function server_software_info()
{
    $ss = array('full' => '','short' => '');
    $ss['full'] = $_SERVER['SERVER_SOFTWARE'];

    if (preg_match('/apache/i', $ss['full'])) {
        $ss['short'] = 'Apache';
    } else if (preg_match('/IIS/',$ss['full'])) {
        $ss['short'] = 'IIS';
    } else {
        $ss['short'] = '';
    }
    return $ss;
}

function match_arch_pattern($str)
{
    $arch = null;
    $arch_patterns = array(
             'i.?86'        => 'x86',
             'x86[-_]64'    => 'x86',
             'x86'          => 'x86',
             'amd64'        => 'x86',
             'SMP Tue Jan 01 00:00:00 CEST 2000 all GNU\/Linux' => 'x86',
             'ppc64'        => 'ppc',
             'ppc'          => 'ppc',
             'powerpc'      => 'ppc',
             'sparc'        => 'sparc',
             'sun'          => 'sparc',
			 'armv7l'       => 'armv7l',
             'aarch64'      => 'aarch64'
         );

    foreach ($arch_patterns as $token => $a) {
        if (preg_match("/$token/i", $str)) {
          $arch = $a;
          break;
        }
    }
    return $arch;
}

function required_loader_arch($mach_info,$os_code,$wordsize)
{
    if ($os_code == 'win') {
        $arch = ($wordsize == 32)?'x86':'x86-64';
    } elseif (!empty($os_code)) {
        $arch = match_arch_pattern($mach_info);
        if ($wordsize == 64) {
            if ($arch == 'x86') {
                $arch = 'x86-64';
            } elseif ($arch == 'ppc') {
                $arch = 'ppc64';
            }
        }
    } else {
        $arch = ERROR_UNKNOWN_ARCH;
    }
    return $arch;
}

function uname($part = 'a')
{
    $result = '';
    if (!function_is_disabled('php_uname')) {
        $result = @php_uname($part);
    } elseif (function_exists('posix_uname') && !function_is_disabled('posix_uname')) {
        $posix_equivs = array(
                     'm' => 'machine',
                     'n' => 'nodename',
                     'r' => 'release',
                     's' => 'sysname'
                 );
        $puname = @posix_uname();
        if ($part == 'a' || !array_key_exists($part,$posix_equivs)) {
           $result = join(' ',$puname);
        } else {
           $result = $puname[$posix_equivs[$part]];
        }
    } else {
        if (!function_is_disabled('phpinfo')) {
            ob_start();
            phpinfo(INFO_GENERAL);
            $pinfo = ob_get_contents();
            ob_end_clean();
            if (preg_match('~System.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$match)) {
                $uname = $match[2];
                if ($part == 'r') {
                    if (!empty($uname) && preg_match('/\S+\s+\S+\s+([0-9.]+)/',$uname,$matchver)) {
                        $result = $matchver[1];
                    } else {
                        $result = '';
                    }
                } else {
                    $result = $uname;
                }
            }
        } else {
            $result = '';
        }
    }
    return $result;
}

function calc_word_size($os_code)
{
    $wordsize = null;
    if ('win' === $os_code) {
        ob_start();
        phpinfo(INFO_GENERAL);
        $pinfo = ob_get_contents();
        ob_end_clean();
        if (preg_match('~Compiler.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$compmatch)) {
            if (preg_match("/(VC[0-9]+)/i",$compmatch[2],$vcmatch)) {
                $compiler = strtoupper($vcmatch[1]);
            } elseif (stripos(trim($compmatch[2]),"Visual C++ 2019") === 0) {
                $compiler = 'VC16';
            } else {
                $compiler = 'VC6';
            }
        } else {
            $compiler = 'VC6';
        }
        if ($compiler === 'VC9' || $compiler === 'VC11' || $compiler === 'VC14' 
                || $compiler === 'VC15' || $compiler === 'VC16') {
			if (preg_match('~Architecture.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$archmatch)) {
				if (preg_match("/x64/i",$archmatch[2])) {
					$wordsize = 64;
				} else {
					$wordsize = 32;
				}
            } elseif (isset($_ENV['PROCESSOR_ARCHITECTURE']) && preg_match('~(amd64|x86-64|x86_64)~i',$_ENV['PROCESSOR_ARCHITECTURE'])) {
                if (preg_match('~Configure Command.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$confmatch)) {
                    if (preg_match('~(x64|lib64|system64)~i',$confmatch[2])) {
                        $wordsize = 64;
                    }
                }
            } else {
				$wordsize = 32;
			}
        }
    }
    if (empty($wordsize)) {
        $wordsize = ((-1^0xffffffff)?64:32);
    }
    return $wordsize;
}

function required_loader($unamestr = '')
{
    $un = empty($unamestr)?uname():$unamestr;

    $php_major_version = substr(PHP_VERSION,0,3);

    $os_name = substr($un,0,strpos($un,' '));
    $os_code = empty($os_name)?'':strtolower(substr($os_name,0,3));

    $wordsize = calc_word_size($os_code);

	if ($os_code == 'win' && $wordsize == 64 && $php_major_version < '5.5') {
        $arch = ERROR_WINDOWS_64_BIT;
	} else {
		$arch = required_loader_arch($un,$os_code,$wordsize);
	}
    if (!is_string($arch)) {
        return $arch;
    }
    $os_variants = supported_os_variants($os_code,$arch);
    if (!is_array($os_variants)) {
        return $os_variants;
    }

    $os_ver = '';
    if (preg_match('/([0-9.]+)/',uname('r'),$match)) {
        $os_ver = $match[1];
    }
    $os_ver_parts = preg_split('@\.@',$os_ver);

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $loader_sfix = (($os_code == 'win') ? 'dll' : 'so');
    $file = "ioncube_loader_{$os_code_h}_{$php_major_version}.{$loader_sfix}";

    if ($os_code == 'win') {
        $os_name = 'Windows';
        $file_ts = $file;
        $os_name_qual = 'Windows';
    } else {
        $os_names = array_keys($os_variants);
        if (count($os_variants) > 1) {
            $parts = explode(" ",$os_names[0]); 
            $os_name = $parts[0];
            $os_name_qual = $os_name . ' ' . $os_ver_parts[0] . '.' . $os_ver_parts[1];
        } else {
            $os_name = $os_names[0];
            $os_name_qual = $os_name;
        }
        $file_ts = "ioncube_loader_{$os_code_h}_{$php_major_version}_ts.{$loader_sfix}";
    }

    return array(
           'uname'      =>  $un,
           'arch'       =>  $arch,
           'oscode'     =>  $os_code,
           'oscode_h'   =>  $os_code_h,
           'osname'     =>  $os_name,
           'osnamequal' =>  $os_name_qual,
           'osvariants' =>  $os_variants,
           'osver'      =>  $os_ver,
           'osver2'     =>  $os_ver_parts,
           'file'       =>  $file,
           'file_ts'    =>  $file_ts,
           'wordsize'   =>  $wordsize
       );
}

function ic_system_info()
{
    $thread_safe = null;
    $debug_build = null;
    $cgi_cli = false;
	$is_fpm = false;
    $is_cgi = false;
    $is_cli = false;
    $php_ini_path = '';
    $php_ini_dir = '';
    $php_ini_add = '';
    $is_supported_compiler = true;
    $php_compiler = is_ms_windows()?'VC6':'';

    ob_start();
    phpinfo(INFO_GENERAL);
    $php_info = ob_get_contents();
    ob_end_clean();

    $breaker = (php_sapi_name() == 'cli')?"\n":'</tr>';
    $lines = explode($breaker,$php_info);
    foreach ($lines as $line) {
        if (preg_match('/command/i',$line)) {
          continue;
        }

        if (preg_match('/thread safety/i', $line)) {
          $thread_safe = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('/debug build/i', $line)) {
          $debug_build = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('~configuration file.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
          $php_ini_path = $match[2];

          if (!@file_exists($php_ini_path)) {
                $php_ini_path = '';
          }
        }
        if (preg_match('~dir for additional \.ini files.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_dir = $match[2];
            if (!@file_exists($php_ini_dir)) {
                $php_ini_dir = '';
            }
        }
        if (preg_match('~additional \.ini files parsed.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_add = $match[2];
        }
        if (preg_match('/compiler/i',$line)) {
            $supported_match = join('|',supported_win_compilers());
            $is_supported_compiler = preg_match("/($supported_match)/i",$line);
            if (preg_match("/(VC[0-9]+)/i",$line,$match)) {
                $php_compiler = strtoupper($match[1]);
            } elseif (preg_match("/Visual C\+\+ 2017/i",$line)) {
				$php_compiler = "VC15";
				$is_supported_compiler = true;
            } elseif (preg_match("/Visual C\+\+ 2019/i",$line)) {
				$php_compiler = "VC16";
				$is_supported_compiler = true;
			} else {
                $php_compiler = '';
            }
        }
    }
    $is_cgi = strpos(php_sapi_name(),'cgi') !== false;
    $is_cli = strpos(php_sapi_name(),'cli') !== false;
	$is_fpm = strpos(php_sapi_name(),'fpm-fcgi') !== false;
    $cgi_cli = $is_cgi || $is_cli;

    $ss = server_software_info();
	
	if ($is_fpm) {
		$ss['short'] = 'PHP-FPM';
		$ss['full'] = 'PHP-FPM ' . $ss['full'];
	}

    if (!$php_ini_path && function_exists('php_ini_loaded_file')) {
        $php_ini_path = php_ini_loaded_file();
        if ($php_ini_path === false) {
            $php_ini_path = '';
        }
    }
    if (!empty($php_ini_path)) {
        $real_path = @realpath($php_ini_path);
        if (false !== $real_path) {
            $php_ini_path = $real_path;
        }
    }

    $php_ini_basename = basename($php_ini_path);

    return array(
           'THREAD_SAFE'        => $thread_safe,
           'DEBUG_BUILD'        => $debug_build,
           'PHP_INI'            => $php_ini_path,
           'PHP_INI_BASENAME'   => $php_ini_basename,
           'PHP_INI_DIR'        => $php_ini_dir,
           'PHP_INI_ADDITIONAL' => $php_ini_add,
           'PHPRC'              => getenv('PHPRC'),
           'CGI_CLI'            => $cgi_cli,
           'IS_CGI'             => $is_cgi,
           'IS_CLI'             => $is_cli,
		   'IS_FPM'				=> $is_fpm,
           'PHP_COMPILER'       => $php_compiler,
           'SUPPORTED_COMPILER' => $is_supported_compiler,
           'FULL_SS'            => $ss['full'],
           'SS'                 => $ss['short']);
}

function is_possibly_dedicated_or_local()
{
    $sys = get_sysinfo();

    return (empty($sys['PHP_INI']) || !@file_exists($sys['PHP_INI']) || (is_readable($sys['PHP_INI']) && (0 !== strpos($sys['PHP_INI'],$_SERVER['DOCUMENT_ROOT']))));
}

function is_local()
{
    $ret = false;
    if ($_SERVER["SERVER_NAME"] == 'localhost') {
        $ret = true;
    } else {
        $ip_address = strtolower($_SERVER["REMOTE_ADDR"]);
        if (strpos(':',$ip_address) === false) {
            $ip_parts = explode('.',$ip_address);
            $ret = (($ip_parts[0] == 10) || 
                    ($ip_parts[0] == 172 && $ip_parts[1] >= 16 &&  $ip_parts[1] <= 31) ||
                    ($ip_parts[0] == 192 && $ip_parts[1] == 168));
        } else {
            $ret = ($ip_address == '::1') || (($ip_address[0] == 'f') && ($ip_address[1] >= 'c' && $ip_address[1] <= 'f'));
        }
    }
    return $ret;
}

function is_shared()
{
    return !is_local() && !is_possibly_dedicated_or_local();
}

function find_server_type($chosen_type = '',$type_must_be_chosen = false,$set_session = false)
{
    $server_type = SERVER_UNKNOWN;
    if (empty($chosen_type)) {
        if ($type_must_be_chosen) {
            $server_type = SERVER_UNKNOWN;
        } else {
            if (isset($_SESSION['server_type']) && $_SESSION['server_type'] != SERVER_UNKNOWN) {
                $server_type = $_SESSION['server_type'];
            } elseif (is_local()) {
                $server_type = SERVER_LOCAL;
            } elseif (!is_possibly_dedicated_or_local()) {
                $server_type = SERVER_SHARED;
            } else {
                $server_type = SERVER_UNKNOWN;
            } 
        }
    } else {
        switch ($chosen_type)  {
            case 's':
                $server_type = SERVER_SHARED;
                break;
            case 'd':
                $server_type = SERVER_DEDICATED;
                break;
            case 'l':
                $server_type = SERVER_LOCAL;
                break;
            default:
                $server_type = SERVER_UNKNOWN;
                break;
        }
    }
    if ($set_session) {
        $_SESSION['server_type'] = $server_type;
    }
    return $server_type;
}

function server_type_string()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_string = 'SHARED';
            break;
        case SERVER_LOCAL:
            $server_string = 'LOCAL';
            break;
        case SERVER_DEDICATED:
            $server_string = 'DEDICATED';
            break;
        default:
            $server_string = 'UNKNOWN';
            break;
    }
    return $server_string;
}

function server_type_code()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_char = 's';
            break;
        case SERVER_LOCAL:
            $server_char = 'l';
            break;
        case SERVER_DEDICATED:
            $server_char = 'd';
            break;
        default:
            $server_char = '';
            break;
    }
    return $server_char;
}

function get_sysinfo()
{
    static $sysinfo;

    if (empty($sysinfo)) {
        $sysinfo = ic_system_info();
    }
    return $sysinfo;
}

function get_loaderinfo()
{
    static $loader;

    if (empty($loader)) {
        $loader = required_loader();
    }
    return $loader;
}

function is_ms_windows()
{
    $loader_info = get_loaderinfo();
    return ($loader_info['oscode'] == 'win');
}

function function_is_disabled($fn_name)
{
    $disabled_functions=explode(',',ini_get('disable_functions'));
    return in_array($fn_name, $disabled_functions);
}

function selinux_is_enabled()
{
    $se_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('sestatus');
        $se_enabled = preg_match('/enabled/i',$cmd);
    }

    return $se_enabled;
}

function grsecurity_is_enabled()
{
    $gr_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('gradm -S');
        $gr_enabled = preg_match('/enabled/i',$cmd);
    }

    return $gr_enabled;
}

function threaded_and_not_cgi()
{
    $sys = get_sysinfo();
    return($sys['THREAD_SAFE'] && !$sys['IS_CGI']);
}

function is_restricted_server($only_safe_mode = false)
{
    $disable_functions = ini_get('disable_functions');
    $open_basedir = ini_get('open_basedir');
    $php_restrictions = !empty($disable_functions) || !empty($open_basedir);
    $system_restrictions = selinux_is_enabled() || grsecurity_is_enabled();
    $non_safe_mode_restrictions = $php_restrictions || $system_restrictions;
    return (ini_get('safe_mode') || (!$only_safe_mode && $non_safe_mode_restrictions));
}

function server_restriction_warnings()
{
    $warnings = array();

    if (find_server_type() == SERVER_SHARED) {
        if (is_restricted_server()) {
            $warnings[] = "Server restrictions are in place which might affect the operation of this Loader Wizard or prevent the installation of the Loader.";
        }
    } else {
        $warning_suffix = "This may affect the operation of this Loader Wizard.";
        if (ini_get('safe_mode')) {
            $warnings[] = "Safe mode is in effect on the server. " . $warning_suffix;
        } 
        $disabled_functions = ini_get('disable_functions');
        if (!empty($disabled_functions)) {
            $warnings[] = "Some functions are disabled through disable_functions. " . $warning_suffix;
        }
        $open_basedir = ini_get('open_basedir');
        if (!empty($open_basedir)) {
            $warnings[] = "Open basedir restrictions are in effect. " . $warning_suffix;
        }
    }
    return $warnings;
}

function own_php_ini_possible($only_safe_mode = false)
{
    $sysinfo = get_sysinfo();
    return ($sysinfo['CGI_CLI'] && !is_ms_windows() && !is_restricted_server($only_safe_mode));
}

function extension_dir()
{
    $extdir = ini_get('extension_dir');
    if ($extdir == './' || ($extdir == '.\\' && is_ms_windows())) {
        $extdir = '.';
    }
    return $extdir;
}

function possibly_selinux()
{
    $loaderinfo = get_loaderinfo();
    $se_env = (getenv("SELINUX_INIT"));
    return (strtolower($loaderinfo['osname']) == 'linux' && $se_env && ($se_env == 'Yes' || $se_env == '1'));
}

function ini_same_dir_as_wizard()
{
    $sys = get_sysinfo();
    return dirname($sys['PHP_INI']) == dirname(__FILE__); 
}

function extension_dir_path()
{
    $ext_dir = extension_dir();
    if ($ext_dir == '.' || (dirname($ext_dir) == '.')) {
        $ext_dir_path = @realpath($ext_dir);
    } else {
        $ext_dir_path = $ext_dir;
    }
    return $ext_dir_path;
}

function get_loader_name()
{
    $u = uname();
    $sys = get_sysinfo();
    $os = substr($u,0,strpos($u,' '));
    $os_code = strtolower(substr($u,0,3));

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $php_version = phpversion();
    $php_family = substr($php_version,0,3);

    $loader_sfix = (($os_code == 'win') ? '.dll' : (($sys['THREAD_SAFE'])?'_ts.so':'.so'));
    $loader_name="ioncube_loader_{$os_code_h}_{$php_family}{$loader_sfix}";

    return $loader_name;
}

function get_reqd_version($variants)
{
    $exact_match = false;
    $nearest_version = 0;
    $loader_info = get_loaderinfo();
    $os_version = $loader_info['osver2'][0] . '.' . $loader_info['osver2'][1];
    $os_version_major = $loader_info['osver2'][0];
    foreach ($variants as $v) {
        if ($v == $os_version || (is_int($v) && $v == $os_version_major)) {
            $exact_match = true;
            $nearest_version = $v;
            break;
        } elseif ($v > $os_version) {
            break;
        } else {
            $nearest_version = $v;
        }
    }
    return (array($nearest_version,$exact_match));
}

function get_default_loader_dir_webspace()
{
    return ($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . LOADER_SUBDIR);
}

function get_loader_location($loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = get_default_loader_dir_webspace();
    }
    $loader_name = get_loader_name(); 
    return ($loader_dir . DIRECTORY_SEPARATOR . $loader_name);
}

function get_loader_location_from_ini($php_ini = '')
{
    $errors = array();
    if (empty($php_ini)) {
        $sysinfo = get_sysinfo();
        $php_ini = $sysinfo['PHP_INI'];
    }
    if (!@file_exists($php_ini)) {
        if (empty($php_ini)) {
            $errors[ERROR_INI_NOT_FOUND] = "The configuration file could not be found.";
        } else {
            $errors[ERROR_INI_NOT_FOUND] = "The $php_ini file could not be found.";
        }
    } elseif (!is_readable($php_ini)) {
        $errors[ERROR_INI_NOT_READABLE] = "The $php_ini file could not be read.";
    }
    if (!empty($errors)) {
        return array('location' => '', 'errors' => $errors);
    } 
    $lines = file($php_ini);
    $ext_start = zend_extension_line_start();
    $wrong_ext_start = ($ext_start == 'zend_extension')?'zend_extension_ts':'zend_extension';
    $loader_path = '';
    $loader_name_match = "ioncube_loader";
    foreach ($lines as $l) {
        if (preg_match("/^\s*$ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$corr_matches)) {
            if (preg_match("/$loader_name_match/i",$corr_matches[1])) {
                if (!empty($loader_path)) {
                    $errors[ERROR_INI_MULTIPLE_IC_LOADER_LINES] = "It appears that multiple $ext_start lines for the ionCube Loader have been included in the configuration file, $php_ini.";
                }
                $loader_path = $corr_matches[1];
            } else {
                if (empty($loader_path)) {
                    $errors[ERROR_INI_NOT_FIRST_ZE] = "The ionCube Loader must be the first Zend extension listed in the configuration file, $php_ini.";
                }
            }
        }
        if (empty($loader_path)) {
            if (preg_match("/^\s*$wrong_ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$bad_start_matches)) {
                if (preg_match("/$loader_name_match/i",$bad_start_matches[1])) {
                    $bad_zend_ext_msg = "The line for the ionCube Loader in the configuration file, $php_ini, should start with $ext_start and <b>not</b> $wrong_ext_start.";
                    $errors[ERROR_INI_WRONG_ZE_START] = $bad_zend_ext_msg;
                    $loader_path = $bad_start_matches[1];
                }
            }
        }
    }
    $loader_path = trim($loader_path);
    if ($loader_path === '') {
        $errors[ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration file, $php_ini.";
    } elseif (!@file_exists($loader_path)) {
        $errors[ERROR_INI_LOADER_FILE_NOT_FOUND] = "The loader file  $loader_path, listed in the configuration file, $php_ini, does not exist or is not accessible.";
    } elseif (basename($loader_path) == $loader_path) {
        $errors[ERROR_INI_NOT_FULL_PATH] = "A full path must be specified for the loader file in the configuration file, $php_ini.";
    }
    return array('location' => $loader_path, 'errors' => $errors);
}

function zend_extension_line_missing($ini_path)
{
    $loader_loc = get_loader_location_from_ini($ini_path);
    return (!empty($loader_loc['errors']) && array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$loader_loc['errors']));
}

function find_additional_ioncube_ini()
{
    $sys = get_sysinfo();
    $ioncube_ini = '';

    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
        foreach ($ini_files as $f) {
            $fn = trim($f);
            $bfn = basename($fn);
            if (preg_match('/ioncube/i',$bfn)) {
                $ioncube_ini = $fn;
                break;
            }
        }
    }
    return $ioncube_ini;
}

function get_additional_ini_files()
{
    $sys = get_sysinfo();
    $ini_files = array();
    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
    }
    return (array_map('trim',$ini_files));
}

function all_ini_contents()
{
    $sys = get_sysinfo();
    $output = '';

    $output .= ";;; *MAIN INI FILE AT ${sys['PHP_INI']}* ;;;" . PHP_EOL;
    $output .= get_file_contents($sys['PHP_INI']);
    $other_inis = get_additional_ini_files();
    foreach ($other_inis as $inif) {
        $output .= ";;; *Additional ini file at $inif* ;;;" . PHP_EOL;
        $output .= get_file_contents($inif);
    }
    $here = unix_path_dir();
    $unrec_ini_files = unrecognised_inis_webspace($here);
    foreach ($unrec_ini_files as $urinif) {
        $output .= ";;; *UNRECOGNISED INI FILE at $urinif* ;;;" . PHP_EOL;
        $output .= get_file_contents($urinif);
    }
    return $output;
}

function scan_inis_for_loader()
{
    $ldloc = array('location' => '', 'errors' => array());
    $sysinfo = get_sysinfo();
    if (empty($sysinfo['PHP_INI'])) {
        $ini_files_not_found = array("Main ini file");
        $ini_file_list = get_additional_ini_files();
    } else {
        $ini_files_not_found = array();
        $ini_file_list = array_merge(array($sysinfo['PHP_INI']),get_additional_ini_files());
    }
    $server_type = find_server_type();
    $shared_server = SERVER_SHARED == $server_type;
    foreach ($ini_file_list as $f) {
        $ldloc = get_loader_location_from_ini($f);
        if (array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$ldloc['errors'])) {
            unset($ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND]);
        } 
        if ($shared_server && array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            if (false == user_ini_space_path($f)) {
                $ldloc['errors'][ERROR_INI_NOT_FOUND] = "A system ini file cannot be found or read by the Wizard - you cannot do anything about this on your shared server.";
            } else {
                $ldloc['errors'][ERROR_INI_USER_INI_NOT_FOUND] = $ldloc['errors'][ERROR_INI_NOT_FOUND];
            }
        } elseif (array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            $ini_files_not_found[] = $f;
        }
        if (!empty($ldloc['location'])) {
            break;
        }
    }
    if (!empty($ini_files_not_found)) {
        $plural = (count($ini_files_not_found) > 1)?"s":"";
        $ldloc['errors'][ERROR_INI_NOT_FOUND] = "The following ini file$plural could not be found by the Wizard: " . join(',',$ini_files_not_found);
        if (is_restricted_server()) {
            $ldloc['errors'][ERROR_INI_NOT_FOUND] .= "<br> This may be due to server restrictions in place.";
        }
    }
    if (empty($ldloc['location'])) {
        $ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration.";
    }
    return $ldloc;
}

function find_loader_filesystem()
{
    $ld_inst_dir = loader_install_dir(find_server_type());
    $loader_name = get_loader_name();
    $suggested_loader_path = $ld_inst_dir . DIRECTORY_SEPARATOR . $loader_name;
    if (@file_exists($suggested_loader_path)) {
        $location = $suggested_loader_path;
    } elseif (@file_exists($loader_name)) {
        $location = @realpath($loader_name);
    } else {
        $ld_loc = get_loader_location();
        if (@file_exists($ld_loc)) {
            $location = $ld_loc;
        } else {
            $location = '';
        }
    }
    return $location;
}

function find_loader($search_directories_if_not_ini = false)
{
    $sysinfo = get_sysinfo();
    $php_ini = $sysinfo['PHP_INI'];
    $rtl_path = get_runtime_loading_path_if_applicable();
    $location = '';
    $errors = array();

    if (!empty($rtl_path)) {
        $location = $rtl_path;
    } else {
        $loader_ini = scan_inis_for_loader();
        $location = $loader_ini['location'];
        $errors = $loader_ini['errors'];
    }
    if (empty($location) && (empty($errors) || $search_directories_if_not_ini)) {
        $errors = array(); 
        $location = find_loader_filesystem();
        if (empty($location)) {
            $errors[ERROR_LOADER_NOT_FOUND] = 'The loader file could not be found in standard locations.';
        }
    }
    if (!empty($errors)) {
        return $errors;
    } else {
        return $location;
    }
}

function zend_extension_line_start()
{
    $sysinfo = get_sysinfo();
    $is_53_or_later = is_php_version_or_greater(5,3);
    return (is_bool($sysinfo['THREAD_SAFE']) && $sysinfo['THREAD_SAFE'] && !$is_53_or_later ? 'zend_extension_ts' : 'zend_extension');
}

function ioncube_loader_version_information()
{
    $old_version = true;
    $liv = "";
    $lv = "";
    $mv = 0;
    if (function_exists('ioncube_loader_iversion')) {
        $liv = ioncube_loader_iversion();
        $lv = sprintf("%d.%d.%d", $liv / 10000, ($liv / 100) % 100, $liv % 100);

        $latest_version =  get_latestversion();

        $lat_parts = explode('.',$latest_version);
        $cur_parts = explode('.',$lv);

        if (($cur_parts[0] > $lat_parts[0]) || 
            ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] > $lat_parts[1]) ||
             ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] == $lat_parts[1] && $cur_parts[2] >= $lat_parts[2])) {
            $old_version = false;
        } else {
            $old_version = $latest_version;
        }
        $mv = $cur_parts[0];
    }
    return array($lv,$mv,$old_version);
}

function default_loader_version_info()
{
    return array();
}

function get_loader_version_info()
{
    return get_remote_session_value('loader_version_info',LOADER_LATEST_VERSIONS_URL,'default_loader_version_info');
}

function calc_platform()
{
    $platform = array();
    $platform_info = get_platforminfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($osvar,$exact_match) = get_reqd_version($loader['osvariants']);
    } else {
        $osvar = null;
        if (is_ms_windows()) {
            $sys = get_sysinfo();
            $phpc = (empty($sys['PHP_COMPILER']))?'vc6':strtolower($sys['PHP_COMPILER']); 
            $osvar = ($sys['THREAD_SAFE']?'':'nonts_') . $phpc;
        }
    }
    foreach ($platform_info as $p) {
        if ($p['os'] == $loader['oscode'] && $p['arch'] == $loader['arch'] && (empty($osvar) || $p['os_mod'] == "_" . $osvar)) {
            $platform = $p;
            break;
        }
    }
    return $platform;
}

function get_platform()
{
    static $this_platform;

    if (!isset($this_platform)) {
        $this_platform = calc_platform();
    }

    return $this_platform;
}

function is_legacy_platform()
{
    $platform = get_platform();
    return array_key_exists('is_legacy',$platform);
}

function calc_dirname()
{
    $dirname = '';
    $platform = get_platform();
    if (!empty($platform)) {
        $dirname = $platform['dirname'];
    }
    return $dirname;
}

function calc_loader_latest_version()
{
    $lv_info = get_loader_version_info();
    $latest_version = RECENT_LOADER_VERSION;
    if (!empty($lv_info)) {
        $dirname = calc_dirname();
      
        if (!empty($dirname)) {
            $compiler_specific_version = false;
            if (is_ms_windows()) {
                $sys = get_sysinfo();
                $phpc = strtolower($sys['PHP_COMPILER']);
                if (!empty($phpc)) {
                    $dirname_comp = $dirname . "_" . $phpc;
                    if (array_key_exists($dirname_comp,$lv_info)) {
                        $latest_version = $lv_info[$dirname_comp];
                        $compiler_specific_version = true;
                    }
                }
            }
            if (!$compiler_specific_version && array_key_exists($dirname,$lv_info)) {
                $latest_version = $lv_info[$dirname];
            }
        } 
    }
    return $latest_version;
}

function get_latestversion()
{
    static $latest_version;

    if (empty($latest_version)) {
        $latest_version = calc_loader_latest_version();
    }
    return $latest_version;
}


function runtime_loader_location()
{
    $loader_path = false;
    $ext_path = extension_dir_path();
    if ($ext_path !== false) {
        $id = $ext_path;
        $here = dirname(__FILE__);
        if (isset($id[1]) && $id[1] == ':') {
            $id = str_replace('\\','/',substr($id,2));
            $here = str_replace('\\','/',substr($here,2));
        }
        $rd=str_repeat('/..',substr_count($id,'/')).$here.'/';
        $i=strlen($rd);

        $loader_loc = DIRECTORY_SEPARATOR . basename($here) . DIRECTORY_SEPARATOR . get_loader_name();
        while($i--) {
            if($rd[$i]=='/') {
                $loader_path = runtime_location_exists($ext_path,$rd,$i,$loader_loc);
                if ($loader_path !== false) {
                    break;
                }
            }
        }

        if (!$loader_path && !empty($loader_loc) && @file_exists($loader_loc)) {
            $loader_path = basename($loader_loc);
        }
    }
    return $loader_path;
}

function runtime_location_exists($ext_dir,$path_str,$sep_pos,$loc_name)
{
    $sub_path = substr($path_str,0,$sep_pos);
    $lp = $sub_path . $loc_name;
    $fqlp = $ext_dir.$lp;

    if(@file_exists($fqlp)) {
        return $lp;
    } else {
        return false;
    }
}

function runtime_loading_is_possible() {
    return !((is_php_version_or_greater(5,2,5)) || is_restricted_server() || !ini_get('enable_dl') || !function_exists('dl') || function_is_disabled('dl') || threaded_and_not_cgi());
}

function shared_and_runtime_loading()
{
    return (find_server_type() == SERVER_SHARED && empty($_SESSION['use_ini_method']) && runtime_loading_is_possible());
}

function get_valid_runtime_loading_path($ignore_loading_check = false)
{
    if ($ignore_loading_check || runtime_loading_is_possible()) {
        return runtime_loader_location();
    } else {
        return false;
    }
}

function runtime_loading($rtl_path = null)
{
    if (empty($rtl_path)) {
        $rtl_path = get_valid_runtime_loading_path();
    }
    if (!empty($rtl_path) && @dl($rtl_path)) {
        return $rtl_path;
    } else {
        return false;
    }
}

function get_runtime_loading_path_if_applicable()
{
    $rtl = null;
    if (shared_and_runtime_loading()) {
        $rtl = get_valid_runtime_loading_path();
    }
    return $rtl;
}

function try_runtime_loading_if_applicable()
{
    $rtl_path = get_runtime_loading_path_if_applicable();
    if (!empty($rtl_path)) {
        return runtime_loading($rtl_path);
    } else {
        return $rtl_path;
    }
}

function runtime_loading_instructions()
{
    $default = get_default_address();
    echo '<h4>Runtime Loading Instructions</h4>';
    echo '<div class=panel>';
    echo '<p>On your shared server the Loader can be installed using the runtime loading method.';
    echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";

    if ('.' == extension_dir()) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        echo "Please note that on your system the Loader <em>must</em> be present in the same " . $dirphrase . " as the first encoded file accessed.";
    }
    echo '<ol>';
    loader_download_instructions(); 
    $loader_dir = loader_install_instructions(SERVER_SHARED,dirname(__FILE__));
    shared_test_instructions();
    echo '</ol>';
    echo '</div>';
}

function runtime_loading_errors()
{
    $errors = array();
    $ext_path = extension_dir_path();
    if (false === $ext_path) {
        $errors[ERROR_RUNTIME_EXT_DIR_NOT_FOUND] = "Extensions directory cannot be found.";
    } else {
        $expected_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . get_loader_name();
        if (!@file_exists($expected_file)) {
            $errors[ERROR_RUNTIME_LOADER_FILE_NOT_FOUND] = "The Loader file was expected to be at $expected_file but could not be found.";
        } else {
            $errors = loader_compatibility_test($expected_file);
        }
    }
    return $errors;
}


function windows_package_name()
{
    $sys = get_sysinfo();
	$loader = get_loaderinfo();
    return (LOADERS_PACKAGE_PREFIX . 'win' . '_' . ($sys['THREAD_SAFE']?'':'nonts_') . strtolower($sys['PHP_COMPILER']) .  '_' . $loader['arch']);
}

function unix_package_name()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($reqd_version,$exact_match) = get_reqd_version($loader['osvariants']);
        if ($reqd_version) {
            $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $reqd_version . '_' . $loader['arch'];
        } else {
            $basename = "";
        }
    } else {
        $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $loader['arch'];
    }
    return array($basename,$multiple_os_versions);
}

function loader_download_instructions()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;

    if (is_ms_windows()) {
        if (is_bool($sysinfo['THREAD_SAFE'])) {
            $download_str = '<li>Download the following archive of Windows ' . $sysinfo['PHP_COMPILER'];
            if (!$sysinfo['THREAD_SAFE']) {
                $download_str .= ' non-TS';
            }
            $download_str .= ' ' . $loader['arch'] . ' Loaders:';
            echo $download_str;
            $basename = windows_package_name();
            echo make_archive_list($basename,array('zip'));
            echo 'A Loaders archive can also be downloaded from <a href="' . LOADERS_PAGE . '" target="loaders">' . LOADERS_PAGE . '</a>.';
        } else {
            echo '<li>Download a Windows Loaders archive from <a href="' . LOADERS_PAGE  . '" target=loaders>here</a>. If PHP is built with thread safety disabled, use the Windows non-TS Loaders.';
        }
    } else {
        list($basename,$multiple_os_versions) = unix_package_name(); 
        if ($basename == "") {
            echo '<li>Download a ' . $loader['osname'] . ' ' . $loader['arch'] . ' Loaders archive from <a href="' . LOADERS_PAGE . '" target="loaders">here</a>.';
            echo "<br>Your system appears to be ${loader['osnamequal']} for ${loader['wordsize']} bit. If Loaders are not available for that exact release of ${loader['osname']}, Loaders built for an earlier release should work. Note that you may need to install back compatibility libraries for the operating system.";
            echo '<br>If you cannot find a suitable loader then please raise a ticket at <a href="'. SUPPORT_SITE . '">our support helpdesk</a>.';
        } else {
            echo '<li>Download one of the following archives of Loaders for ' . $loader['osnamequal'] . ' ' . $loader['arch'] . ':'; 
            if (SERVER_SHARED == find_server_type()) {
                $archives = array('zip','tar.gz');
            } else {
                $archives = array('tar.gz','zip');
            }
            echo make_archive_list($basename,$archives);
            echo "</p>";
            if ($multiple_os_versions && !$exact_match) {
                echo "<p>Note that you may need to install back compatibility libraries for  ${loader['osname']}.</p>";
            }
        }
    }

    echo '</li>';
}

function ini_dir()
{
    $sysinfo = get_sysinfo();
    $parent_dir = '';
    if (!empty($sysinfo['PHP_INI'])) {
        $parent_dir = dirname($sysinfo['PHP_INI']);
    } else {
        $parent_dir = $_SERVER["PHPRC"];
        if (@is_file($parent_dir)) {
            $parent_dir = dirname($parent_dir);
        }
    }
    return $parent_dir;
}

function unix_install_dir()
{
    $ext_dir = extension_dir_path();
    $cur_dir = @realpath('.');
    if (empty($ext_dir) || $ext_dir == $cur_dir) {
        $loader_dir = UNIX_SYSTEM_LOADER_DIR;
    } else {
        $loader_dir = $ext_dir;
    }
    return $loader_dir;
}

function windows_install_dir()
{
    $sysinfo = get_sysinfo();
    if ($sysinfo['SS'] == 'IIS') {
        if (false === ($ext_dir = extension_dir_path())) {
            $parent_dir = ini_dir();
            $ext_dir = $parent_dir . '\\ext';
            if (!empty($parent_dir) && @file_exists($ext_dir)) {
                $loader_dir = $ext_dir;
            } else {
                $loader_dir = $_SERVER['windir'] . '\\' . WINDOWS_IIS_LOADER_DIR;
            }
        } else {
            $loader_dir = $ext_dir;
        }
    } else {
        if (false === ($ext_dir = extension_dir_path())) {
			$parent_dir = ini_dir();
			$loader_dir = $parent_dir . '\\' . 'ioncube';
		} else {
			$loader_dir = $ext_dir;
		}
    }
    return $loader_dir;
}

function loader_install_dir($server_type)
{
    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $loader_dir = get_default_loader_dir_webspace();
    } elseif (is_ms_windows()) {
        $loader_dir = windows_install_dir();
    } else {
        $loader_dir = unix_install_dir();
    }
    return $loader_dir;
}

function writeable_directories()
{
    $root_path = @realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    $root_path_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
    $above_root_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/../cgi-bin");

    $paths = array();
    foreach (array($root_path,$above_root_path,$root_path_cgi_bin,$above_root_cgi_bin) as $p) {
        if (@is_writeable($p)) {
            $paths[] = $p;
        }
    }
    return $paths;
}

function loader_install_instructions($server_type,$loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = loader_install_dir($server_type);
    }
    if (SERVER_LOCAL == $server_type) {
        echo "<li>Put the Loader files in <code>$loader_dir</code></li>";
    } else {
        echo "<li>Transfer the Loaders to your web server and install in <code>$loader_dir</code></li>";
    }
    return $loader_dir;
}

function zend_extension_lines($loader_dir)
{
    $zend_extension_lines = array();
    $sysinfo = get_sysinfo();
    $qt = (is_ms_windows()?'"':'');
    $loader = get_loaderinfo();

    if (!is_bool($sysinfo['THREAD_SAFE']) || !$sysinfo['THREAD_SAFE']) {
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file'] . $qt;
        $zend_extension_lines[] = "zend_extension = " . $path;
    }
    if ((!is_bool($sysinfo['THREAD_SAFE']) && !is_php_version_or_greater(5,3)) || $sysinfo['THREAD_SAFE']) {
        $line_start = is_php_version_or_greater(5,3)?'zend_extension':'zend_extension_ts';
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file_ts'] . $qt;
        $zend_extension_lines[] = $line_start . " = " . $path;
    }
    return $zend_extension_lines;
}

function user_ini_base()
{
    $doc_root_path = realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    if (!empty($above_root_path) && @is_writeable($above_root_path)) {
        $start_path = $above_root_path;
    } else {
        $start_path = $doc_root_path;
    }
    return $start_path;
}

function user_ini_space_path($file)
{
    $user_base = user_ini_base();
    $fpath = @realpath($file);
    if (!empty($fpath) && (0 === strpos($fpath,$user_base))) {
        return $fpath;
    } else {
        return false;
    }
}

function default_ini_path()
{
    return (realpath($_SERVER['DOCUMENT_ROOT']));
}

function shared_ini_location()
{
    $phprc = getenv('PHPRC');
    if (!empty($phprc)) {
        $phprc_path = user_ini_space_path($phprc);
        if (false !== $phprc_path) {
            return $phprc_path;
        } else {
            return default_ini_path();
        }
    } else {
        return default_ini_path();
    }
}


function zend_extension_instructions($server_type,$loader_dir)
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();
    $editing_ini = true;

    $php_ini_name = ini_file_name();

    if (isset($sysinfo['PHP_INI']) && @file_exists($sysinfo['PHP_INI'])) {
        $php_ini_path = $sysinfo['PHP_INI'];
    } else {
        $php_ini_path = '';
    }

    if (is_bool($sysinfo['THREAD_SAFE'])) {
        $kwd = zend_extension_line_start();
    } else {
        $kwd = 'zend_extension/zend_extension_ts';
    }

    $server_type_code = server_type_code();

    $zend_extension_lines = zend_extension_lines($loader_dir);

    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $ini_dir = shared_ini_location();
        $php_ini_path = $ini_dir . DIRECTORY_SEPARATOR . $php_ini_name;
        if (@file_exists($php_ini_path)) {
            $edit_line = "<li>Edit the <code>$php_ini_name</code> in the <code>$ini_dir</code> directory";
            if (zend_extension_line_missing($php_ini_path) && @is_writeable($php_ini_path) && @is_writeable($ini_dir)) {
                if (function_exists('file_get_contents')) {
                    $ini_strs = @file_get_contents($php_ini_path);
                } else {
                    $lines = @file($php_ini_path);
                    $ini_strs = join(' ',$lines);
                }
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                        fwrite($fh,$zl . PHP_EOL);
                    }
                    fwrite($fh,$ini_strs);
                    fclose($fh);
                    $editing_ini = false;
                    echo "<li>Your php.ini file at $php_ini_path has been modified to include the necessary line for the ionCube Loader.";
                } else {
                    echo $edit_line;
                }
            } else {
               echo $edit_line;
            }
        } else {
            $download_ini_file = "<li><a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">Save this  <code>$php_ini_name</code> file</a> and upload it to <code>$ini_dir</code> (full path on your server).";
            if (@is_writeable($ini_dir)) {
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                       fwrite($fh,$zl . PHP_EOL);
                    }
                    if (!empty($sysinfo['PHP_INI']) && is_readable($sysinfo['PHP_INI'])) {
                        if (function_exists('file_get_contents')) {
                           $ini_strs = @file_get_contents($sysinfo['PHP_INI']);
                        } else {
                           $lines = @file($sysinfo['PHP_INI']);
                           $ini_strs = join(' ',$lines);
                        }
                        fwrite($fh,$ini_strs);
                    }
                    fclose($fh); 
                    echo "<li>A <code>$php_ini_name</code> file has been created for you in <code>$ini_dir</code>.";
                } else {
                    echo $download_ini_file;
                }
            } else {
                echo $download_ini_file;
            }
            $editing_ini = false;
        }
    } elseif (!empty($sysinfo['PHP_INI'])) {
        if (empty($sysinfo['PHP_INI_DIR'])) {
            echo "<li>Edit the file <code>${sysinfo['PHP_INI']}</code>";
        } else {
            $php_ini_path = find_additional_ioncube_ini();
            if (empty($php_ini_path)) {
                $php_ini_name = ADDITIONAL_INI_FILE_NAME;
                echo "<li><a href=\"$base&amp;page=phpconfig&amp;download=1&amp;newlinesonly=1&amp;ininame=$php_ini_name&amp;stype=$server_type_code\">Save this $php_ini_name file</a> and put it in your ini files directory, <code>${sysinfo['PHP_INI_DIR']}</code>";
                $editing_ini = false;
            } else {
                $php_ini_name = basename($php_ini_path);
                echo "<li>Edit the file <code>$php_ini_path</code>";
            }
        }
    } else {
        echo "<li>Edit the system <code>$php_ini_name</code> file";
    }
    if ($editing_ini) {
        echo " and <b>before</b> any other $kwd lines ensure that the following is included:<br>";
        foreach ($zend_extension_lines as $zl) {
            echo "<code>$zl</code><br>";
        }
        if (!empty($php_ini_path)) {
            if (zend_extension_line_missing($php_ini_path)) {
                echo "<a>Alternatively, replace your current <code>$php_ini_path</code> file with <a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">this new $php_ini_name file</a>."; 
            }
        }
    }
    echo '</li>';
}

function server_restart_instructions()
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();

    if ($sysinfo['SS']) {
		if ($sysinfo['SS'] == 'PHP-FPM') {
			echo "<li>Restart PHP-FPM.</li>";
		} else {
			echo "<li>Restart the ${sysinfo['SS']} server software.</li>";
		}
    } else {
        echo "<li>Restart the server software.</li>";
    }

    echo "<li>When the server software has restarted, <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the Loader</a>.</li>";

	if ($sysinfo['SS'] && $sysinfo['SS'] == 'PHP-FPM') {
		echo '<li>If the Loader installation failed, check the PHP-FPM error log file for errors.</li>';
    } elseif ($sysinfo['SS'] == 'Apache' && !is_ms_windows()) {
        echo '<li>If the Loader installation failed, check the Apache error log file for errors and see our guide to <a target="unix_errors" href="'. UNIX_ERRORS_URL . '">Unix related errors</a>.</li>';
    }
}

function shared_test_instructions()
{
    $base = get_base_address();
    echo "<li><a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">Click here to test the Loader</a>.</li>";
}

function link_to_php_ini_instructions()
{
    $default = get_default_address();
    echo "<p><a href=\"{$default}&amp;stype=s&amp;ini=1\">Please click here for instructions on using the php.ini method instead</a>.</p>";
}

function php_ini_instruction_list($server_type)
{
    echo '<h4>Installation Instructions</h4>';
    echo '<div class=panel>';
    echo '<ol>';

    loader_download_instructions(); 
    $loader_dir = loader_install_instructions($server_type);
    zend_extension_instructions($server_type,$loader_dir);
    if ($server_type != SERVER_SHARED || !own_php_ini_possible()) {
        server_restart_instructions();
    } else {
        shared_test_instructions();
    } 
    echo '</ol>';
    echo '</div>';
}

function php_ini_install_shared($give_preamble = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();
    if ($give_preamble) {
        echo "<p>On your <strong>shared</strong> server, the Loader should be installed using a <code>$php_ini_name</code> configuration file.";
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";
    }

    if (own_php_ini_possible()) {
        echo '<p>With your hosting account, you may be able to use your own PHP configuration file.</p>';
    } else {
        echo "<p>It appears that you cannot install the ionCube Loader using the <code>$php_ini_name</code> file. Your server provider or system administrator should be able to perform the installation for you. Please refer them to the following instructions.</p>";
    }

    php_ini_instruction_list(SERVER_SHARED);
}

function php_ini_install($server_type_desc = null, $server_type = SERVER_DEDICATED, $required = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();

    echo '<p>';
    if ($server_type_desc) {
        echo "For a <strong>$server_type_desc</strong> server ";
    } else {
        echo "For this server ";
    }

    if ($required) {
        echo "you should install the ionCube Loader using the <code>$php_ini_name</code> configuration file.";
    } else {
        echo "installing the ionCube Loader using the <code>$php_ini_name</code> file is recommended.";
    }
    if ($server_type_desc) {
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a $server_type_desc server</a>.)";
    }
    echo '</p>';
      
    php_ini_instruction_list($server_type);
}



function help_resources($error_list = array())
{
	$self = get_self();
    $base = get_base_address();
    $server_type_code = server_type_code();
    $server_type = find_server_type();
    $sysinfo = get_sysinfo();
    $resources = array(
            '<a target="_blank" href="' . LOADERS_FAQ_URL . '">ionCube Loaders FAQ</a>',
            '<a target="_blank" href="' . LOADER_FORUM_URL . '">ionCube Loader Forum</a>'
        );
    if (SERVER_SHARED != $server_type || own_php_ini_possible(true)) {
		$support_info = array ( 
			'department' 		=> WIZARD_SUPPORT_TICKET_DEPARTMENT,
			'subject' 			=> "ionCube Loader installation problem",
			'message' 			=> support_ticket_information()
		   );
		if (SERVER_LOCAL == $server_type && !info_should_be_disabled()) {
			$temp_files = system_info_temporary_files();
		} else {
			$temp_files = NULL;
		}
		if (!empty($temp_files)) {
			$support_info['ini'] = base64_encode(file_get_contents($temp_files['ini']));
			$support_info['phpinfo'] = base64_encode(file_get_contents($temp_files['phpinfo']));
			$support_info['additional'] = base64_encode(file_get_contents($temp_files['additional']));
			
			$loader_path = find_loader(true);
			if (is_string($loader_path)) {		
				$support_info['loader'] = base64_encode(file_get_contents($loader_path));
				$support_info['loader_name'] = basename($loader_path);
			} else {
				$support_info['loader'] = '';
				$support_info['loader_name'] = '';
			}
		} else {
			$support_info['ini'] = '';
			$support_info['phpinfo'] = '';
			$support_info['additional'] = '';
			$support_info['loader'] = '';
			$support_info['loader_name'] = '';
		}
		 
        $resources[2] = '<form action="' . SUPPORT_SITE . 'lw_index.php' .'" method="POST" id="support-ticket"><a href="" onclick="document.getElementById(\'support-ticket\').submit(); return false;">Raise a support ticket through our helpdesk</a>';
		$resources[2] .= '<input type="hidden" name="department" value="' . $support_info['department'] . '"/>';
		$resources[2] .= '<input type="hidden" name="subject" value="' . $support_info['subject'] . '"/>';
		$resources[2] .= '<input type="hidden" name="message" value="' . $support_info['message'] . '"/>';
		if (!empty($temp_files)) {
			$resources[2] .= '<input type="hidden" name="phpinfo" value="' . $support_info['phpinfo'] . '"/>';
			$resources[2] .= '<input type="hidden" name="ini" value="' . $support_info['ini'] . '"/>';
			$resources[2] .= '<input type="hidden" name="additional" value="' . $support_info['additional'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader" value="' . $support_info['loader'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader_name" value="' . $support_info['loader_name'] . '"/>';
		}
		$resources[2] .= '</form>';
    } 
	
    if (SERVER_SHARED == $server_type && own_php_ini_possible(true) && !user_ini_space_path($sysinfo['PHP_INI'])) {
        $resources[3] = '<strong>Please check with your host that you can create php.ini files that will override the system one.</strong>';
    }
    return $resources;
}

function system_info_temporary_files()
{
    $tmpfname_ini = get_tempnam("/tmp", "INI");
    $tmpfname_ini .= ".ini";
    $fh_ini = @fopen($tmpfname_ini,'wb');
    if ($fh_ini) {
        $config = all_ini_contents();
        fwrite($fh_ini,$config);
        fclose($fh_ini);
    } else {
        $tmpfname_ini = '';
    }

    $tmpfname_pinf = get_tempnam("/tmp", "PIN");
    $tmpfname_pinf .= ".html";
    $fh_pinfo = @fopen($tmpfname_pinf,'wb');
    if ($fh_pinfo) {
        ob_start();
        @phpinfo();
        $pinfo = ob_get_contents();
        ob_end_clean();
        fwrite($fh_pinfo,$pinfo);
        fclose($fh_pinfo);
    } else {
        $tmpfname_pinf = '';
    }

    $tmpfname_add = get_tempnam("/tmp", "ADD");
    $tmpfname_add .= ".html";
    $fh_add = @fopen($tmpfname_add,'wb');
    if ($fh_add) {
        ob_start();
        extra_page(false);
        $extra = ob_get_contents();
        ob_end_clean();
        fwrite($fh_add,$extra);
        fclose($fh_add);
    } else {
        $tmpfname_add = '';
    }

    if (empty($tmpfname_ini) || empty($tmpfname_pinf) || empty($tmpfname_add)) {
        return (array());
    } else {
        return (array('ini'           =>   $tmpfname_ini,
                      'phpinfo'       =>   $tmpfname_pinf,
                      'additional'    =>   $tmpfname_add));
    }
}

function get_tempnam($default_tmp_dir = '', $prefix = '')
{
	if (function_exists('sys_get_temp_dir')) {
		return tempnam(sys_get_temp_dir(),$prefix);
	} else {
		return @tempnam($default_tmp_dir, $prefix);
	}
}
function system_info_archive_page()
{
    info_disabled_check();
	$server_type = find_server_type();
	if (SERVER_LOCAL != $server_type) {
		exit;
	}
    $loader = find_loader(true);
    if (is_string($loader)) {
        $loader_file = $loader;
    } else {
        $loader_file = '';
    }
    $all_files = system_info_temporary_files();
    if (!empty($all_files)) {
        if (!empty($loader_file)) {
            $all_files['loader'] = $loader_file;
        }
        $archive_name =  get_tempnam('/tmp',"ARC");
        if (extension_loaded('zip')) {
            $archive_name .= '.zip';
            $zip = @new ZipArchive();
            $mode = @constant("ZIPARCHIVE::OVERWRITE");
            if (!$zip || $zip->open($archive_name, $mode)!==TRUE) {
                $archive_name = '';
            } else {
                foreach($all_files as $f) {
                    $zip->addFile($f,basename($f));
                }
                $zip->close();
            }
        } elseif (extension_loaded('zlib') && !is_ms_windows()) {
            $tar_name = $archive_name . ".tar";
            $all_files_str = join(' ',$all_files);
            $script = "tar -chf $tar_name $all_files_str";
            $result = @system($script,$retval);
            if ($result !== false) {
                $archive_name = $tar_name . '.gz';
                $zp = gzopen($archive_name,"w9");
                $tar_contents = get_file_contents($tar_name);
                gzwrite($zp,$tar_contents);
                gzclose($zp);
            } else {
                $archive_name = '';
            }
        } else {
            $archive_name = '';
        }
    } else {
        $archive_name = '';
    }
    if ($archive_name) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. $archive_name);
        @readfile($archive_name);
    } else {
        $self = get_self();
        $base = get_base_address();
        $server_type_code = server_type_code();
        heading();
        echo "<p>A downloadable archive of system information could not be created.<br> 
            <strong>Please save each of the following and then attach those files to the support ticket:</strong></p>"; 
        echo "<ul>";
        echo "<li><a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo()</a></li>";
        echo "<li><a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a></li>";
        echo "<li><a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional information</a></li>";
        echo "<li><a href=\"$self?page=loaderbin\">loader file</a></li>";
        echo "</ul>";
        footer(true);
    }
}

function support_ticket_information($error_list = array())
{
    $sys = get_sysinfo();
    $ld = get_loaderinfo();

    $ticket_strs = array();
    $ticket_strs[] = "PLEASE DO NOT REMOVE THE FOLLOWING INFORMATION\r\n";
    $ticket_strs[] = "==============\r\n";
    if (!empty($error_list)) {
        $ticket_strs[] = "[hr]";
        $ticket_strs[] = "ERRORS";
        $ticket_strs[] = "[table]";
        $ticket_strs[] = '[tr][td]' . join('[/td][/tr][tr][td]',$error_list) . '[/td][/tr]';
        $ticket_strs[] = "[/table]";
    }
    $ticket_strs[] = "[hr]";
    $ticket_strs[] = "SYSTEM INFORMATION";
    $info_lines = array();
    $info_lines["Wizard version"] = script_version();
    $info_lines["PHP uname"] = $ld['uname'];
    $info_lines["Machine architecture"] = $ld['arch'];
    $info_lines["Word size"] = $ld['wordsize'];
    $info_lines["Operating system"] = $ld['osname'] . ' ' . $ld['osver'];
    if (selinux_is_enabled() || possibly_selinux()) {
        $info_lines["Security enhancements"] = "SELinux";
    } elseif (grsecurity_is_enabled()) {
        $info_lines["Security enhancements"] = "Grsecurity";
    } else {
        $info_lines["Security enhancements"] = "None";
    }
    $info_lines["PHP version"] = PHP_VERSION; 
    if ($sys['DEBUG_BUILD']) {
        $info_lines["DEBUG BUILD"] = "DEBUG BUILD OF PHP";
    }
    if (!$sys['SUPPORTED_COMPILER']) {
        $info_lines["SUPPORTED PHP COMPILER"] = "FALSE";
        $info_lines["PHP COMPILER"] = $sys['PHP_COMPILER'];
    }
    $info_lines["Is CLI?"] = ($sys['IS_CLI']?"Yes":"No");
    $info_lines["Is CGI?"] = ($sys['IS_CGI']?"Yes":"No");
    $info_lines["Is thread-safe?"] = ($sys['THREAD_SAFE']?"Yes":"No");
    $info_lines["Web server"] = $sys['FULL_SS'];
    $info_lines["Server type"] = server_type_string();
    $info_lines["PHP ini file"] = $sys['PHP_INI'];
    if (!@file_exists($sys['PHP_INI'])) {
        $info_lines["Ini file found"] = "INI FILE NOT FOUND";
    } else {
        if (is_readable($sys['PHP_INI'])) {
            $info_lines["Ini file found"] = "INI FILE READABLE";
        } else {
            $fh = @fopen($sys['PHP_INI'],"rb");
            if ($fh === false) {
                $info_lines["Ini file found"] = "INI FILE FOUND BUT POSSIBLY NOT READABLE";
            } else {
                $info_lines["Ini file found"] = "INI FILE READABLE";
            }
        }
    }
    $info_lines["PHPRC"] = $sys['PHPRC'];
    $loader_path = find_loader();
    if (is_string($loader_path)) {
        $info_lines["Loader path"] =  $loader_path;
        $info_lines["Loader file size"] = filesize($loader_path) . " bytes.";
        $info_lines["Loader MD5 sum"] =  md5_file($loader_path);
    } else {
        $info_lines["Loader path"] =  "LOADER PATH NOT FOUND";
    }
    $server_type_code = server_type_code();
    if (!empty($_SESSION['hostprovider'])) {
      $info_lines['Hosting provider'] = $_SESSION['hostprovider'];
      $info_lines['Provider URL'] = $_SESSION['hosturl'];
    }
    $info_lines["Wizard script path"] = '[url]http://' . $_SERVER["HTTP_HOST"] . get_self() . '?stype='. $server_type_code . '[/url]';
    $ticket_strs[] = "[table]";
    foreach ($info_lines as $h => $i) {
        $value = (empty($i))?'EMPTY':$i;
        $ticket_strs[] = '[tr][td]' . $h . '[/td]' . '[td]' . $value . '[/td][/tr]';
    }
    $ticket_strs[] = '[/table]';
    $ticket_strs[] = '[hr]';
    $ticket_strs[] = "\r\n==============\r\n";
    $ticket_strs[] = "PLEASE ENTER ANY ADDITIONAL INFORMATION BELOW\r\n";

    $support_ticket_str = join('',$ticket_strs);
    return urlencode($support_ticket_str);
}

function wizard_stats_data($page_id)
{
    $data = array();

    try_runtime_loading_if_applicable();
    $sysinfo = get_sysinfo();
    $ldinfo = get_loaderinfo();

    $data['sessionid'] = session_id();
    $data['wizard_version'] = script_version();
    $data['server_type'] = server_type_code();
    $data['hostprovider'] = (isset($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $data['hosturl'] = (isset($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $data['page_id'] = $page_id;
    $data['loader_state'] = (extension_loaded(LOADER_EXTENSION_NAME))?'installed':'failure';
    $data['ini_location'] = $sysinfo['PHP_INI'];
    $data['is_cgi'] = ($sysinfo['IS_CGI'])?"yes":"no";
    $data['is_ts'] = ($sysinfo['THREAD_SAFE'])?"yes":"no";
    $data['arch'] = $ldinfo['arch'];
    $data['php_version'] = PHP_VERSION;
    $data['os'] = $ldinfo['osname'];
    $data['word_size'] = $ldinfo['wordsize'];
    $data['referrer'] =  $_SERVER["HTTP_HOST"] . get_self();

    return $data;
}

function send_stats($page_id = 'default')
{
    $server_type = find_server_type();
    $res = false;

    if (SERVER_LOCAL != $server_type) {
        $stats_data = wizard_stats_data($page_id);

        if (!isset($_SESSION['stats_sent'][$page_id][$stats_data['loader_state']])) {
            $url = WIZARD_STATS_URL;

            if (!empty($stats_data)) {
                if(function_exists('http_build_query')) {
                    $qparams = http_build_query($stats_data);
                } else {
                    $qparams = php4_http_build_query($stats_data);
                }
                $url .= '?' . $qparams;
                $res = remote_file_contents($url);
            }
            $_SESSION['stats_sent'][$page_id][$stats_data['loader_state']] = 1;
        } else {
            $res = true;
        }
    } else {
        $res = 'LOCAL';
    }
    return $res;
}

function os_arch_string_check($loader_str)
{
    $errors = array();
    if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_str,$os_matches)) {
        $loader_info = get_loaderinfo();
        $dirname = calc_dirname();
        $packed_osname = preg_replace('/\s/','',strtolower($loader_info['osname']));
        if (strtolower($dirname) != $os_matches[1] && $packed_osname != $os_matches[2]) {
            $errors[ERROR_LOADER_WRONG_OS] = "You have the wrong loader for your operating system, ". $loader_info['osname'] . ".";
        } else {
            $loader_wordsize = (strpos($os_matches[3],'64') === false)?32:64;
            if ($loader_info['arch'] != ($ap = required_loader_arch($os_matches[3],$loader_info['oscode'],$loader_wordsize))) {
                $err_str = "You have the wrong loader for your machine architecture.";
                $err_str .= " Your system is " . $loader_info['arch'];
                $err_str .= " but the loader you are using is for " . $ap . ".";
                $errors[ERROR_LOADER_WRONG_ARCH] = $err_str;
            }
        }
    }
    return $errors;
}

function get_loader_strings($loader_location)
{
    if (function_exists('file_get_contents')) {
        $loader_strs = @file_get_contents($loader_location);
    } else {
        $lines = @file($loader_location);
        $loader_strs = join(' ',$lines);
    }
    return $loader_strs;
}

function loader_system($loader_location)
{
    $loader_system = array();
    $loader_strs = get_loader_strings($loader_location);

    if (!empty($loader_strs)) {

        if (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
            $loader_system['oscode'] = 'win';
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '_nonts')?0:1;
			if (preg_match("/_localtime([0-9][0-9])/i",$loader_strs,$size_matches)) {
				$loader_system['wordsize'] = ($size_matches[1] == '64')?64:32;
			} else {
				$loader_system['wordsize'] = 32;
			}
            $loader_system['arch'] = ($loader_system['wordsize'] == 64)?'x86-64':'x86';
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
			if ($loader_system['php_version_major'] == 8 && $loader_system['php_version_minor'] >= 1) {
				$loader_system['compiler'] = 'VC16';
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] >= 2) {
				$loader_system['compiler'] = 'VC15'; 
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] < 2) {
				$loader_system['compiler'] = 'VC14'; 
			} elseif ($loader_system['php_version_major'] == 5 && $loader_system['php_version_minor'] >= 5) {
				$loader_system['compiler'] = 'VC11'; 
			} elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_system['compiler'] = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_system['compiler'] = 'VC6';
            }
        } elseif (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '-ts')?1:0;
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
            if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_strs,$os_matches)) {
                $loader_system['oscode'] = strtolower(substr($os_matches[2],0,3));
                $loader_system['wordsize'] = (strpos($os_matches[3],'64') === false)?32:64;
                $loader_system['arch'] = required_loader_arch($os_matches[3],$loader_system['oscode'],$loader_system['wordsize']);
                $loader_system['compiler'] = $os_matches[4];
            }
        }
        if (preg_match("/ionCube Loader Version\s+(\S+)/",$loader_strs,$loader_version)) {
            $loader_system['loader_version'] = $loader_version[1];
		} elseif (preg_match("/ioncube_loader_(\d{1,2}\.\d\.\d{1,2})\./",$loader_strs,$loader_version)){
			$loader_system['loader_version'] = $loader_version[1];
        } else {
            $loader_system['loader_version'] = 'UNKNOWN';
        }
        if (isset($loader_system['php_version_major'])) {
            $loader_system['php_version'] = $loader_system['php_version_major'] . '.' . $loader_system['php_version_minor'];
        }
    }
    return $loader_system;
}

function loader_compatibility_test($loader_location)
{
    $errors = array();

    $sysinfo = get_sysinfo();
    if (LOADER_NAME_CHECK) {
        $installed_loader_name = basename($loader_location);
        $expected_loader_name = get_loader_name();
        if ($installed_loader_name != $expected_loader_name) {
            $errors[ERROR_LOADER_UNEXPECTED_NAME] = "The installed loader (<code>$installed_loader_name</code>) does not have the name expected (<code>$expected_loader_name</code>) for your system. Please check that you have the correct loader for your system.";
        }
    }
    if (empty($errors) && !is_readable($loader_location)) {
        $execute_error = "The loader at $loader_location does not appear to be readable.";
        $execute_error .= "<br>Please check that it exists and is readable.";
        $execute_error .= "<br>Please also check the permissions of the containing ";
        $execute_error .= (is_ms_windows()?'folder':'directory') . '.';
		if ($sysinfo['SS'] == 'PHP-FPM') {
			$execute_error .= "<br>Please also check that PHP-FPM has been restarted.";
        } elseif (($sysinfo['SS'] == 'IIS') || !($sysinfo['IS_CGI'] || $sysinfo['IS_CLI'])) {
            $execute_error .= "<br>Please also check that the web server has been restarted.";
        }
        $execute_error .= ".";
        $errors[ERROR_LOADER_NOT_READABLE] = $execute_error;
    }
    $loader_strs = get_loader_strings($loader_location);
    $phpv = php_version(); 
    if (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
        if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
            $loader_php = $version_matches[1] . "." . $version_matches[2];
            $server_php =  $phpv['major'] . "." .  $phpv['minor'];
            $errors[ERROR_LOADER_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
        }
        if (is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'] && !is_ms_windows() && !(isset($version_matches[4]) && $version_matches[4] == '-ts')) {
            $errors[ERROR_LOADER_NONTS_PHP_TS] = "Your server is running a thread-safe version of PHP but the loader is not a thread-safe version.";
        } elseif (isset($version_matches[4]) && $version_matches[4] == '-ts' && !(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'])) {
            $errors[ERROR_LOADER_TS_PHP_NONTS] = "Your server is running a non-thread-safe version of PHP but the loader is a thread-safe version.";
        }
    } elseif (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
        if (!is_ms_windows()) {
            $errors[ERROR_LOADER_WIN_SERVER_NONWIN] = "You have a Windows loader but your server does not appear to be running Windows.";
        } else {
            if (isset($version_matches[4]) && $version_matches[4] == '_nonts' && is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) {
                $errors[ERROR_LOADER_WIN_NONTS_PHP_TS] = "You have the non-thread-safe version of the Windows loader but you need the thread-safe one.";
            } elseif (!(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) && !(isset($version_matches[4]) && $version_matches[4] == '_nonts')) {
                $errors[ERROR_LOADER_WIN_TS_PHP_NONTS] = "You have the thread-safe version of the Windows loader but you need the non-thread-safe one."; 
            }
            if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
                $loader_php = $version_matches[1] . "." . $version_matches[2];
                $server_php =  $phpv['major'] . "." .  $phpv['minor'];
                $errors[ERROR_LOADER_WIN_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
            }
                        
            if ($version_matches[1] == 8 && $version_matches[2] >= 1) {
                $loader_compiler = 'VC16';
            } elseif ($version_matches[1] == 7 && $version_matches[2] >= 2) {
                $loader_compiler = 'VC15'; 
            } elseif ($version_matches[1] == 7) {
                $loader_compiler = 'VC14'; 
            } elseif ($version_matches[1] == 5 && $version_matches[2] >= 5) {
                $loader_compiler = 'VC11'; 
            } elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_compiler = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_compiler = 'VC6';
            }
            if ($loader_compiler != $sysinfo['PHP_COMPILER']) {
                $errors[ERROR_LOADER_WIN_COMPILER_MISMATCH] = "Your loader was built using $loader_compiler but you need the loader built using ${sysinfo['PHP_COMPILER']}.";
            }
        }
    } else {
            $errors[ERROR_LOADER_PHP_VERSION_UNKNOWN] = "The PHP version for the loader cannot be determined - please check that you have a valid ionCube Loader.";
    } 
    $errors += os_arch_string_check($loader_strs);

    return $errors;
}


function shared_server()
{
    if (!$rtl_path = runtime_loading()) {
        if (empty($_SESSION['use_ini_method']) && runtime_loading_is_possible()) {
            runtime_loading_instructions();
        } else {
            php_ini_install_shared();
        }
    } else {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        echo "<p>The ionCube Loader $lv for PHP $phpv has been successfully installed.</p>";
        $is_legacy_loader = loader_major_version_instructions($mv);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,$newer_version);
        }
        successful_install_end_instructions($rtl_path);
    }
}

function dedicated_server()
{
    php_ini_install('dedicated or VPS', SERVER_DEDICATED, true);
}

function local_install()
{
    php_ini_install('local',SERVER_LOCAL, true);
}


function unregister_globals()
{
    if (!ini_get('register_globals')) {
        return;
    }

    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

function clear_session($persist = array())
{
    $persist['not_go_daddy'] = empty($_SESSION['not_go_daddy'])?0:1;
    $persist['use_ini_method'] = empty($_SESSION['use_ini_method'])?0:1;
    $persist['server_type'] = empty($_SESSION['server_type'])?SERVER_UNKNOWN:$_SESSION['server_type'];
    @session_destroy();
    $_SESSION = array();
    $_SESSION['CREATED'] = time();
    $_SESSION = $persist;
}

function can_archive()
{
	return (extension_loaded('zip') || (extension_loaded('zlib') && !is_ms_windows()));
}

function is_ioncube()
{
        return (($_SERVER["REMOTE_ADDR"] == IONCUBE_IP_ADDRESS) || ($_SERVER["REMOTE_ADDR"] == gethostbyname(IONCUBE_ACCESS_ADDRESS)));
}

function can_reach_ioncube()
{
	return (isset($_SESSION['remote_access_successful']));
}

function info_should_be_disabled($only_allow_ioncube = false)
{
    $elapsed = time() - max(filemtime(__FILE__),filectime(__FILE__));
	
	if (is_ioncube()) {
		$cutoff_time = IONCUBE_WIZARD_EXPIRY_MINUTES * 60;
	} else {
		if (!$only_allow_ioncube && !extension_loaded(LOADER_EXTENSION_NAME)) {
			$cutoff_time = WIZARD_EXPIRY_MINUTES * 60;
		} else {
			return true;
		}
	}
	
    return ($elapsed > $cutoff_time);
}

function info_disabled_text()
{
    return "The information you have tried to access has been disabled for security reasons. Please re-install this Loader Wizard script and try again.";
}

function info_disabled_check()
{
    if (info_should_be_disabled()) {
        heading();
        echo info_disabled_text();
        footer(true);
        exit;
    }
}

function run()
{

	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (preg_match('/googlebot/i',$user_agent)) {
		exit;
	}
    unregister_globals();
    if (is_php_version_or_greater(4,3,0)) {
        ini_set('session.use_only_cookies',1);
    }
    $session_ok = @session_start();

    if (!defined('PHP_EOL')) {
        if (is_ms_windows()) {
            define('PHP_EOL',"\r\n");
        } else {
            define('PHP_EOL',"\n");
        }
    }

    if (!isset($_SESSION['CREATED'])) {
        $_SESSION['CREATED'] = time();
    } elseif (time() - $_SESSION['CREATED'] > SESSION_LIFETIME_MINUTES * 60 ) {
        clear_session(); 
    }
    if (!isset($_SERVER)) $_SERVER =& $HTTP_SERVER_VARS;

    (php_sapi_name() == 'cli') && die("This script should only be run by a web server.\n");

    $page = get_request_parameter('page');
    $host = get_request_parameter('host');
    $clear = get_request_parameter('clear');
    $ini = get_request_parameter('ini');
    $timeout = get_request_parameter('timeout');

    if ($timeout) {
        $_SESSION['timing_out'] = 1;
        $_SESSION['initial_run'] = 0;
    }

    if (!empty($host)) {
        if ($host == 'ngd') {
            $_SESSION['not_go_daddy'] = 1;
        }
    }
    if (!empty($ini)) {
        $_SESSION['use_ini_method'] = 1;
    }

    if (!empty($clear)) {
        clear_session();
        unset($_SESSION['not_go_daddy']);
        unset($_SESSION['use_ini_method']);
        unset($_SESSION['server_type']);
    } else {
        $stype = get_request_parameter('stype');
        $hostprovider = get_request_parameter('hostprovider');
        $hosturl = get_request_parameter('hosturl');
        if (!empty($hostprovider)) {
            $_SESSION['hostprovider'] = $hostprovider;
            $_SESSION['hosturl'] = $hosturl;
        }
        $server_type = find_server_type($stype,false,true);
    }
    if ($session_ok && !$timeout && !isset($_SESSION['initial_run']) && empty($page)) {
        $_SESSION['initial_run'] = 1;
        initial_page();
        @session_write_close();
        exit;
    } else {
        $_SESSION['initial_run'] = 0;
    }

    if (empty($_SESSION['server_type'])) {
        $_SESSION['server_type'] = SERVER_UNKNOWN;
    }

    if (empty($page) || !function_exists($page . "_page")) {
        $page = get_default_page();
    } 

    $fn = "{$page}_page";
    $fn();

    @session_write_close();
    exit(0);
}

function wizardversion_page()
{
    $start_time = time();
    $wizard_version_only = get_request_parameter('wizard_only');
    $clear_session_info = get_request_parameter('clear_info');
    if ($clear_session_info) {
        unset($_SESSION['timing_out']);
        unset($_SESSION['latest_wizard_version']);
    }
    $wizard_version = latest_wizard_version();
    $message = '';
    if (false === $wizard_version) {
        $message = "0";
    } elseif (update_is_available($wizard_version)) {
        $message = "$wizard_version";
    } else {
        $message = "1";
    }
    echo $message;
    @session_write_close();
    exit(0);
}

function platforminfo_page()
{
    $message = '';
    $platforms = get_loader_platforms();
    $message = empty($platforms)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function loaderversion_page()
{
    $message = '';
    $loader_versions = get_loader_version_info();
    $message = empty($loader_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function compilerversion_page()
{
    $message = '';
    $compiler_versions = find_win_compilers();
    $message = empty($compiler_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function initial_page()
{
    $self = get_self();
    $start_page = get_default_address(false);
    $stage_timeout = 7000;
    $step_lag = 500;

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <style type="text/css">
        body {
            height: 100%;
            width: 100%;
        }
        </style>
        <script type="text/javascript">
        var timingOut = 0;
        var xmlHttpTimeout;
        var ajax;
        var statusPar;
        var stage_timeout = $stage_timeout;
        var step_lag = $step_lag;

        function checkNextStep(ajax,expected,continuation) {
            if (ajax.readyState==4 && ajax.status==200)
            {
                clearTimeout(xmlHttpTimeout);
                if (ajax.responseText == expected) {
                   setTimeout('',step_lag);
                   continuation();
                } else {
                   statusPar.innerHTML = 'Unable to check for update<br>script continuing';
                   setTimeout("window.location.href = '$start_page&timeout=1'",1000);
                }
            }
        }

        function getXmlHttp() {
            if (window.XMLHttpRequest) {
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xmlhttp;
        }
        var startMainLoaderWizard = function() {
            window.location.href = '$start_page';
        }
        var loaderVersionCheck = function() {
            statusPar.innerHTML = 'Stage 4/4: Getting latest loader versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",startMainLoaderWizard);
            }
            xmlHttp.open("GET","$self?page=loaderversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var platformCheck = function() {
            statusPar.innerHTML = 'Stage 3/4: Getting platform information';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",loaderVersionCheck);
            }
            xmlHttp.open("GET","$self?page=platforminfo",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var compilerVersionCheck = function() {
            statusPar.innerHTML = 'Stage 2/4: Getting compiler versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",platformCheck);
            }
            xmlHttp.open("GET","$self?page=compilerversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var startChecks = function() {
            statusPar = document.getElementById('status');
            statusPar.innerHTML = 'Stage 1/4: Getting Loader Wizard version';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",compilerVersionCheck);
            }
            xmlHttp.open("GET","$self?page=wizardversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        function ajaxTimeout(){
           ajax.abort();
           statusPar.innerHTML = 'Cannot reach server<br>script continuing';
           setTimeout("window.location.href = '$start_page&timeout=1'",1000);
        }
        </script>
    </head>
    <body>

    <div id="loading"><script type="text/javascript">document.write('<p>Initialising<br>ionCube Loader Wizard<br><span id="status"></span></p>');</script><p id="noscript">Your browser does not support JavaScript so the ionCube Loader Wizard initialisation cannot be made now. This script can get the latest loader version information from the ionCube server when you go to the next page.<br>Please choose one of the following. <br>If the script appears to hang please restart the script and choose the "NO" option.<br><br><br><a href="$start_page">YES - my server DOES have internet access</a><br><br><a href="$start_page&timeout=1">NO - my server does NOT have internet access</a></p></div>
    <script type="text/javascript">
        document.getElementById('noscript').style.display = 'none';
        window.onload = startChecks;
    </script>
    </body>
    </html>
EOT;
}

function default_page($loader_extension = LOADER_EXTENSION_NAME)
{
    $self = get_self();
    foreach (array('self') as $vn) {
        if (empty($$vn)) {
			$server_data = print_r($_SERVER,true);
            error("Unable to initialise ($vn)". ' $_SERVER is: ' . $server_data);
        }
    }

    heading();

    $wizard_update = check_for_wizard_update(true);

    $rtl = try_runtime_loading_if_applicable();

    $server_type = find_server_type();

    if (extension_loaded($loader_extension) && $server_type != SERVER_UNKNOWN) {
        loader_already_installed($rtl);
    } else {
        loader_not_installed();
    }
    send_stats('default');

    footer($wizard_update);
}

function uninstall_wizard_instructions()
{
    echo '<p><strong>For security reasons we advise that you remove this Wizard script from your server now that the ionCube Loader is installed.</strong></p>';
}

function contact_script_provider_instructions()
{
    echo '<p>Please contact the script provider if you do experience any problems running encoded files.</p>';
}

function may_need_to_copy_ini()
{
    $sys = get_sysinfo();
    if (ini_same_dir_as_wizard() && $sys['IS_CGI']) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        $ini = ini_file_name();
        echo "<p>Please note that if encoded files in a different $dirphrase from the Wizard fail then you should attempt to copy the $ini file to each $dirphrase in which you have encoded files.</p>";
    }
}

function ioncube_24_is_available()
{
	$loaderinfo = get_loaderinfo();
	$php_ver = php_version();
   
	return ($loaderinfo['oscode'] == 'lin' && (($php_ver['major'] == 5 && $php_ver['minor'] >= 3) || $php_ver['major'] > 5) );
}

function ioncube_24_is_enabled()
{
	$ic24_enabled = ini_get(IC24_ENABLED_INI_PROPERTY);
	return $ic24_enabled;
}

function ioncube_24_information()
{
    if (ioncube_24_is_available() && !ioncube_24_is_enabled()) {
        $self = get_self();
        echo '<div class="ic24">';
        echo '<div class="ic24graphic">';
        echo '<a target="_blank" href="' . IONCUBE24_URL . '"><img id="ic24logo" src="' . $self . '?page=ic24logo" alt="ionCube24 logo"></a>';
        echo '</div>';
        echo '<div id="ic24info">';
        echo '<p><strong>Bonus Features!</strong> The ionCube Loader can also give ';
        echo '<strong>real-time intrusion protection</strong> to protect against malware and <strong>PHP error reporting</strong> ';
        echo 'to alert when things go wrong on your website.</p>';
        echo '<p>These features are disabled by default but easily activated. ';
        echo '<strong><a target="_blank" href="' . IONCUBE24_URL . '">visit ioncube24.com</a></strong> to find out more.</p>';
        echo '</div>';
        echo '</div>';
    }
}

function cli_install_instructions()
{

	if (is_php_version_or_greater(5,3)) {
		$cli_loader_installed = shell_exec('php -r "echo extension_loaded(\"' . LOADER_EXTENSION_NAME . '\");"');
		
		if (!$cli_loader_installed) {
			$cli_php_ini_output = shell_exec("php --ini");
			
			$ini_loader_loc = scan_inis_for_loader();
		
			if (!is_null($cli_php_ini_output)) {
				echo '<div class="panel">';
				echo '<h4>Loader Installation for Command-Line (CLI) PHP</h4>';
				echo "<p>At present it does not look like the ionCube Loader is installed for command-line (CLI) PHP.</p>";
				echo "<p>Please note that if you need to run the CLI PHP, such as for <strong>cron jobs</strong>, then please ensure the zend_extension line for the ionCube Loader is included in your CLI PHP configuration.</p>";
				
				if (!empty($ini_loader_loc['location'])) {
					echo "<p>The zend_extension line that needs to be copied is:</p>";
					echo "<p><kbd>zend_extension = " . $ini_loader_loc['location'] . "</kbd></p>";
				}
				
				echo "<p>Your CLI PHP Configuration is:</p>";
				echo '<div class="terminal">';
				echo "<pre>";
				echo $cli_php_ini_output;
				echo "</pre>";
				echo '</div>';
				echo '</div>';
			}
		}
	}
}

function successful_install_end_instructions($rtl_path = null)
{
    if (empty($rtl_path)) {
        may_need_to_copy_ini();
    } elseif (is_string($rtl_path)) {
        echo "<p>The runtime loading method of installation was used with path <code>$rtl_path</code></p>";
    }
    contact_script_provider_instructions();
    if (is_legacy_platform()) {
        legacy_platform_instructions();
    }
	
	if (!is_ms_windows() && is_php_version_or_greater(5,3)) {
		cli_install_instructions();
	}
	
    uninstall_wizard_instructions();
	
	ioncube_24_information();
}

function loader_major_version_instructions($mv)
{
    if ($mv < LATEST_LOADER_MAJOR_VERSION) {
        echo "<p><strong>The installed version of the Loader cannot run files produced by the most recent ionCube Encoder.</strong>";
        echo " You will need a version " . LATEST_LOADER_MAJOR_VERSION . " ionCube Loader to run such files.</p>";
    }
    return ($mv < LATEST_LOADER_MAJOR_VERSION);
}

function loader_already_installed($rtl = null)
{
    list($lv,$mv,$newer_version) = ioncube_loader_version_information();
    $phpv = php_version_maj_min();
    $php_str = ' for PHP ' . $phpv;
    echo '<div class="success">';
    echo '<h4>Loader Installed</h4>';
    if ($newer_version) {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is <strong>already installed</strong> but it is an old version.';
        echo ' It is recommended that the Loader be upgraded to the latest version if possible.</p>';
        $know_latest_version = is_string($newer_version);
        $is_legacy_loader = loader_major_version_instructions($mv);
        echo '</div>';
        loader_upgrade_instructions($lv,$newer_version);
    } else {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is already installed and encoded files should run without problems.</p>'; 
        echo '</div>';
        $is_legacy_loader = loader_major_version_instructions($mv,true);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,true);
        }
    }

    successful_install_end_instructions($rtl);
}

function loader_upgrade_instructions($installed_version,$newer_version)
{
    if ($newer_version) {
        echo '<div class="panel">';
        echo '<h4>Loader Upgrade Instructions</h4>';
        $restart_needed = true;
        $server_type = find_server_type();
        if ($server_type == SERVER_SHARED || $server_type == SERVER_UNKNOWN) {
            $loader_path = find_loader(true);
            if (!is_string($loader_path) || false === user_ini_space_path($loader_path)) {
                $verb_case = ($server_type == SERVER_UNKNOWN)?"may":"will";
                echo "<p>Please note that you $verb_case need your system administrator to do the following to upgrade. The web server will need to be restarted after the loader file is changed.</p>";
            }
            $restart_needed = false;
        }
        if (is_string($newer_version)) {
            $version_str = "version $newer_version";
        } else {
            $version_str = "a newer version";
        }
        $loader_name =  get_loader_name();
        echo "<p>To upgrade from version $installed_version to $version_str of the ionCube Loader, please replace your existing loader file, $loader_name, with
            the file of the same name from one of the following packages:</p>";
        if (is_ms_windows()) {
            $basename = windows_package_name();
        } else {
            list($basename,$multiple_os_versions) = unix_package_name();
        }
        echo make_archive_list($basename,array('zip','tar.gz'));
        if ($restart_needed) {
            echo "<p>Once you have replaced the loader file please restart your web server.</p>";
        }
        echo '</div>';
    }
}

function legacy_platform_warning()
{
    $leg_warn = '<p><strong>You are on a platform on which ionCube Loaders are no longer being developed. ';
    $leg_warn .= 'Loaders on your platform may not be able to run files produced by the latest ionCube Encoder. ';
    $leg_warn .= 'Please switch, if possible, to a platform on which loaders are currently supported. ';
    $leg_warn .= 'A list of currently supported platforms is shown on our <a href="' . LOADERS_PAGE . '" target="loaders">loaders page</a>.</strong></p>';

    return $leg_warn;
}

function legacy_platform_instructions()
{
    echo legacy_platform_warning();
}

function loader_not_installed()
{
    $loader = get_loaderinfo();
    $sysinfo = get_sysinfo();

    $stype = get_request_parameter('stype');
    $manual_select = get_request_parameter('manual');
    $host_type = find_server_type($stype,$manual_select,true);

    if ($host_type != SERVER_UNKNOWN && is_array($loader) && !$sysinfo['DEBUG_BUILD']) {
        $warnings = server_restriction_warnings();
        if (is_legacy_platform()) {
            $warnings[] = legacy_platform_warning();
        }
        if (empty($_SESSION['use_ini_method']) && $host_type == SERVER_SHARED && runtime_loading_is_possible()) {
            $errors = runtime_loading_errors();
        } else {
            $errors = ini_loader_errors();
            $warnings = array_merge($warnings,ini_loader_warnings());
        }
        if (!empty($errors)) {
            if (count($errors) > 1) {
                $problem_str = "Please note that the following problems currently exist";
            } else {
                $problem_str = "Please note that the following problem currently exists";
            }
            echo '<div class="alert">' .$problem_str . ' with the ionCube Loader installation:';
            echo make_list($errors,"ul"); 
            echo '</div>';
        }
        if (!empty($warnings)) {
            $addword = empty($errors)?'':'also';
            $plural = (count($warnings)>1)?'s':'';
            echo '<div class="warning">';
            echo "Please note $addword the following issue$plural:";
            echo make_list($warnings,"ul"); 
            echo '</div>';
        }
    }
    if (!isset($stype)) {
        echo '<p>To use files that have been protected by the <a href="' . ENCODER_URL . '" target=encoder>ionCube PHP Encoder</a>, a component called the ionCube Loader must be installed.</p>';
    }

    if (!is_supported_php_version()) {
        echo '<p>Your server is running PHP version ' . PHP_VERSION . ' and is
                unsupported by ionCube Loaders.  Recommended PHP 4 versions are PHP 4.2 or higher, 
                PHP 5.1 or higher for PHP 5, PHP 7.1 or higher for PHP 7 and PHP 8.1 or higher for PHP 8. Please note that there is not an ionCube Loader for PHP 8.0.</p>';
	} elseif ($latest_supported_php_version = is_after_max_php_version_supported()) {
		echo '<strong>Your server is running PHP version ' . PHP_VERSION . ' and is
                currently unsupported by any ionCube Loaders. <br/>This may change in the future if a Loader is produced for your PHP platform.<br/>In the meantime please downgrade PHP to version ' . $latest_supported_php_version . '.</strong>';
    } elseif ($sysinfo['DEBUG_BUILD']) {
         echo '<p>Your server is currently running a debug build of PHP. The Loader cannot be installed with a debug build of PHP. Please ensure that PHP is reconfigured with debug disabled. Note that debug builds of PHP cannot help in debugging PHP scripts.</p>'; 
    } elseif (!is_array($loader)) {
        if ($loader == ERROR_WINDOWS_64_BIT) {
            echo '<p>Loaders for 64-bit PHP on Windows are not currently available. However, if you <b>install and run 32-bit PHP</b> the corresponding 32-bit loader for Windows should work.</p>';
            if ($sysinfo['THREAD_SAFE']) {
                echo '<li>Download one of the following archives of 32-bit Windows x86 loaders:';
            } else {
                echo '<li>Download one of the following archives of 32-bit Windows non-TS x86 loaders:';
            }
            echo make_archive_list(windows_package_name());
        } else {
            echo '<p>There may not be an ionCube Loader available for your type of system at the moment. However, if you create a <a href="'  . SUPPORT_SITE . '">support ticket</a> more advice and information may be available to assist. Please include the URL for this Wizard in your ticket.</p>';
        }
    } elseif (!$sysinfo['SUPPORTED_COMPILER']) {
        $supported_compilers = supported_win_compilers();
        $supported_compiler_string = join('/',$supported_compilers);
        echo '<p>At the current time the ionCube Loader requires PHP to be built with ' . $supported_compiler_string . '. Your PHP software has been built using ' . $sysinfo['PHP_COMPILER'] . '. Supported builds of PHP are available from <a href="https://windows.php.net/download/">PHP.net</a>.';
    } else {
        switch ($host_type) {
            case SERVER_SHARED:
                shared_server();
                break;
            case SERVER_DEDICATED:
                dedicated_server();
                break;
            case SERVER_LOCAL:
                local_install();
                break;
            default:
                echo server_selection_form();
                break;
        }
    }
}

function server_selection_form()
{
    $self = get_self();
    $timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?1:0;
    $hostprovider = (!empty($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $hostprovider = htmlspecialchars($hostprovider, ENT_QUOTES, 'UTF-8');
    $hosturl = (!empty($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $hosturl =  htmlspecialchars($hosturl, ENT_QUOTES, 'UTF-8');
    $form = <<<EOT
    <p>This Wizard will give you information on how to install the ionCube Loader.</p>
    <p>Please select the type of web server that you have and then click Next.</p>
    <script type=text/javascript>
        function trim(s) {
            return s.replace(/^\s+|\s+$/g,"");
        }
        function input_ok() {
            var l = document.getElementById('local');
            if (l.checked) {
                return true;
            } 

            var s = document.getElementById('shared');
            var d = document.getElementById('dedi');

            if (!s.checked && !d.checked) {
                alert("Please select one of the server types.");
                return false;
            } else {
                var hn = document.getElementById('hostprovider');
                var hu = document.getElementById('hosturl');
                var hostprovider = trim(hn.value);
                var hosturl = trim(hu.value);

                if (!hostprovider || !hosturl) {
                    alert("Please enter both a hosting provider name and their URL.");
                    return false;
                }
                if (hostprovider.length < 1) {
                    alert("The hosting provider name should be at least 1 character in length.");
                    return false;
                }
                if (!hosturl.match(/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+/)) {
                    alert("The hosting provider URL is invalid.");
                    return false;
                }
                if (hosturl.length < 4) {
                    alert("The hosting provider URL should be at least 4 characters in length.");
                    return false;
                }
            }
            return true;
        }
    </script>
    <form method=GET action=$self>
        <input type="hidden" name="page" value="default">
        <input type="hidden" name="timeout" value="$timeout">
        <input type=radio id=shared name=stype value=s onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=shared>Shared <small>(for example, server with FTP access only and no access to php.ini)</small></label><br>
        <input type=radio id=dedi name=stype value=d onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=dedi>Dedicated or VPS <small>(server with full root ssh access)</small></label><br>
        <div id="hostinginfo" style="display: none">If you are on a shared or dedicated server, please give your hosting provider and their URL:
            <table>
                <tr><td><label for=hostprovider>Name of your hosting provider</label></td><td><input type=text id="hostprovider" name=hostprovider value="$hostprovider"></td></tr>
                <tr><td><label for=hosturl>URL of your hosting provider</label></td><td><input type=text id="hosturl" name=hosturl value="$hosturl"></td></tr>
            </table>
        </div>
        <input type=radio id=local name=stype value=l onclick="document.getElementById('hostinginfo').style.display = 'none';"><label for=local>Local install</label>
        <p><input type=submit value=Next onclick="return (input_ok(this) && showOverlay());"></p>
    </form>
EOT;
    return $form;
}

function phpinfo_page()
{
    info_disabled_check();
    if (function_is_disabled('phpinfo')) {
        echo "phpinfo is disabled on this server";
    } else {
        @phpinfo();
    }
}

function loader_check_page($ext_name = LOADER_EXTENSION_NAME)
{
    heading();

    $rtl_path = try_runtime_loading_if_applicable();
	
    if (extension_loaded($ext_name)) {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        $php_str = ' for PHP ' . $phpv;
        echo '<div class="success">';
        echo '<h4>Loader Installed Successfully</h4>';
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' <strong>is installed</strong> and encoded files should run successfully.';
        if ($newer_version) {
            echo ' Please note though that you have an old version of the ionCube Loader.</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            loader_upgrade_instructions($lv,$newer_version);
        } else {
            echo '</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            if ($is_legacy_loader) {
                loader_upgrade_instructions($lv,true);
            }
        }
        successful_install_end_instructions($rtl_path);
    } else {
        echo '<div class="failure">';
        echo '<h4>Loader Not Installed</h4>';
        echo '<p>The ionCube Loader is <b>not</b> currently installed successfully.</p>';
	
        if (!is_null($rtl_path)) {
            echo '<p>Runtime loading was attempted but has failed.</p>';
            echo '</div>';
            $rt_errors = runtime_loading_errors();
            if (!empty($rt_errors)) {
                list_loader_errors($rt_errors);
            } 
            link_to_php_ini_instructions();
        } else {
            echo '</div>';
            list_loader_errors();
        }
    }
	
    send_stats('check');
    footer(true);
}

function ini_loader_errors()
{
    $errors = array();
    if (SERVER_SHARED == find_server_type() && !own_php_ini_possible(true)) {
        $errors[ERROR_INI_USER_CANNOT_CREATE] = "It appears that you are not be able to create your own ini files on your shared server. <br><strong>You will need to ask your server administrator to install the ionCube Loader for you.</strong>";
    }
    $loader_loc = find_loader(false);
    if (is_string($loader_loc)) {
        if (!shared_and_runtime_loading()) {
            $sys = get_sysinfo();
            if (empty($sys['PHP_INI'])) {
                $errors[ERROR_INI_NO_PATH] = 'No file path found for the PHP configuration file (php.ini).';
            } elseif (!@file_exists($sys['PHP_INI'])) {
                $errors[ERROR_INI_NOT_FOUND] = 'The PHP configuration file (' . $sys['PHP_INI'] .') cannot be found.';
            }
        }
        $errors = $errors + loader_compatibility_test($loader_loc);
    } else {
        $errors = $errors + $loader_loc;
        $fs_location = find_loader_filesystem();
        if (!empty($fs_location)) {
            $fs_loader_errors = loader_compatibility_test($fs_location);
            if (!empty($fs_loader_errors)) {
                $errors[ERROR_LOADER_WRONG_GENERAL] = "The loader file found at $fs_location is not the correct one for your system.";
            }
            $errors = $errors + $fs_loader_errors;
        }
    } 
    return $errors;
}

function unix_path_dir($dir = '')
{
    if (empty($dir)) {
        $dir = dirname(__FILE__);
    }
    if (is_ms_windows()) {
        $dir = str_replace('\\','/',substr($dir,2));
    }
    return $dir;
}

function unrecognised_inis_webspace($startdir)
{
    $ini_list = array();

    $ini_name = ini_file_name();
    $sys = get_sysinfo();
    $depth = substr_count($startdir,'/');

    $rel_path = '';
    $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
    for ($seps = 0; $seps < $depth; $seps++) {
        $full_ini_loc = @realpath($startdir . '/' . $rel_path) . DIRECTORY_SEPARATOR . $ini_name;
        if (@file_exists($full_ini_loc) && $sys['PHP_INI'] != $full_ini_loc) {
            $ini_list[] = @realpath($full_ini_loc);
        }

        if (dirname($full_ini_loc) == $rootpath) {
            break;
        }
        $rel_path .= '../';
    }
    return $ini_list;
}

function correct_loader_wrong_location()
{
    $loader_location_pair = array();
    $loader_location = find_loader_filesystem();
    if (is_string($loader_location) && !empty($loader_location)) {
        $loader_errors = loader_compatibility_test($loader_location);
        if (empty($loader_errors)) {
            $ini_loader = scan_inis_for_loader();
            if (!empty($ini_loader['location'])) {
                $ini_loader_errors = loader_compatibility_test($ini_loader['location']);
                if (!empty($ini_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = dirname($ini_loader['location']);
                }
            } else {
                $std_dir = loader_install_dir(find_server_type());
                $std_ld_path = $std_dir . DIRECTORY_SEPARATOR . get_loader_name();
                if (@file_exists($std_ld_path)) {
                    $stdloc_loader_errors = loader_compatibility_test($std_ld_path);
                } else {
                    $stdloc_loader_errors = array("Loader file does not exist.");
                }
                if (!empty($stdloc_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = $std_dir;
                }
            }
        }
    }
    return $loader_location_pair;
}

function ini_loader_warnings()
{
    $warnings = array();
    if (find_server_type() == SERVER_SHARED)
    {
        if (own_php_ini_possible()) {
            $sys = get_sysinfo();
            $ini_name = ini_file_name();
            $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
            $root_ini_file = $rootpath . DIRECTORY_SEPARATOR . $ini_name;
            $cgibinpath = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
            $cgibin_ini_file = (empty($cgibinpath))?'':$cgibinpath . DIRECTORY_SEPARATOR . $ini_name;
            $here = unix_path_dir();
            $ini_files = unrecognised_inis_webspace($here);
            $shared_ini_loc = shared_ini_location();
            $shared_ini_file = $shared_ini_loc . DIRECTORY_SEPARATOR . $ini_name;
            $ini_dir = dirname($sys['PHP_INI']);
            $all_ini_locations_used = !empty($ini_files);
            foreach ($ini_files as $full_ini_loc) {
                $advice = "The file $full_ini_loc is not being recognised by PHP.";
                $advice .= " Please check that the name and location of the file are correct.";
                if (!ini_same_dir_as_wizard()) {
                    $ini_loc_dir = dirname($full_ini_loc);
                    if (!@file_exists($shared_ini_file) && !empty($shared_ini_loc) && $ini_loc_dir != $shared_ini_loc && $ini_dir != $shared_ini_loc) {
                        $all_ini_locations_used = false;
                        $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $shared_ini_loc . "</code>.";
                    } else {
                        if (!@file_exists($root_ini_file) && $rootpath != $shared_ini_loc && $full_ini_loc != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $rootpath . "</code>.";
                        } 
                        if (!empty($cgibin_ini_file) && !@file_exists($cgibin_ini_file) && $cgibinpath != $shared_ini_loc && $full_ini_loc != $cgibinpath && $cgibinpath != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= "  Please try copying the <code>$full_ini_loc</code> file to <code>" . $cgibinpath . "</code>.";
                        }
                        $herepath = realpath($here);
                        $here_ini_file = $herepath . DIRECTORY_SEPARATOR . $ini_name;
                        if (!@file_exists($here_ini_file) && $herepath != $rootpath && $herepath != $cgibinpath) {
                            $all_ini_locations_used = false;
                            $advice .= " It may be necessary to copy the <code>$full_ini_loc</code> file to <code>$herepath</code> and to all " . (is_ms_windows()?'folders':'directories') . ' in which you have encoded files';
                        }
                    }
                } else {
                    $all_ini_locations_used = false;
                }
                $warnings[] = $advice;
            }
            if ($all_ini_locations_used) {
                $warnings[] = "<strong>It looks as if ini files are not being recognised in any of the standard locations in your webspace. Please contact your hosting provider to check whether you can create your own PHP ini file and where it should go.</strong>";
            }
        } else {
            if (own_php_ini_possible(true)) {
                $warnings[] = "You may not be able to create your own ini files on your shared server. <br><strong>You might need to ask your server administrator to install the ionCube Loader for you.</strong>";
            }
        }
    } else {
        $loader_dir_pair = correct_loader_wrong_location();
        if (!empty($loader_dir_pair)) {
            $advice = "The correct loader for your system has been found at <code>${loader_dir_pair['loader']}</code>."; 
            if ($loader_dir_pair['loader'] != $loader_dir_pair['newloc']) {
                $advice .= " Please copy the loader from <code>${loader_dir_pair['loader']}</code> to <code>${loader_dir_pair['newloc']}</code>.";
            }
            $warnings[] = $advice;
        }
    }
    return $warnings;
}

function list_loader_errors($errors = array(),$warnings = array(),$suggest_restart = true)
{
    $default = get_default_address();
    $retry_message = '';

    
    if (empty($errors)) {
        $errors = ini_loader_errors();
        if (empty($warnings)) {
            $warnings = ini_loader_warnings();
        }
    }
	
    if (!empty($errors)) {
        $try_again = '<a href="#" onClick="window.location.href=window.location.href">try again</a>';
	
        echo '<div class="alert">';
        if (count($errors) > 1) {
            echo 'The following problems have been found with the ionCube Loader installation:';
            $retry_message = "Please correct those errors and $try_again.";
        } else {
            echo 'The following problem has been found with the ionCube Loader installation:';
            $retry_message = "Please correct that error and $try_again.";
        }
        if (array_key_exists(ERROR_INI_USER_CANNOT_CREATE,$errors)) {
            $retry_message = '';
        }
        echo make_list($errors,"ul");
        echo '</div>';
        if (!empty($warnings)) {
            echo '<div class="warning">';
            echo 'Please also note the following:';
            echo make_list($warnings,"ul");
            echo '</div>';
        }
    } elseif (!empty($warnings)) {
        echo '<div class="warning">';
        echo 'There are the following potential problems:';
        echo make_list($warnings,"ul");
        echo '</div>';
    } elseif ($suggest_restart) {
        if (SERVER_SHARED == find_server_type()) {
            echo "<p>Please contact your server administrator about installing the ionCube Loader.</p>";
        } else {
            if (selinux_is_enabled()) {
                echo "<p>It appears that SELinux is enabled on your server. This might be solved by running the command <code>restorecon [full path to loader file]</code> as root.</p>";
            } elseif (grsecurity_is_enabled()) {
                echo "<p>It appears that grsecurity is enabled on your server. Please run the command, <code>execstack -c [full path to loader file]</code> and then restart your web server.</p>";
            } else {
                $sysinfo = get_sysinfo();
                $ss = $sysinfo['SS'];
				if ($ss == 'PHP-FPM') {
					echo "<p>Please check that PHP-FPM has been restarted.</p>";
                } elseif (!$sysinfo['CGI_CLI'] || is_ms_windows()) {
                    echo "<p>Please check that the $ss web server software has been restarted.</p>";
                } 
            }
        }
    }
    echo '<div>';
    echo $retry_message;
    echo " You may wish to view the following for further help:";
    echo make_list(help_resources($errors),"ul");
    echo '<a href="' . $default . '">Click here to go back to the start of the Loader Wizard</a>.</div>';
}

function phpconfig_page()
{
    info_disabled_check();
    $sys = get_sysinfo();
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        } else {
			if (!preg_match('`^.*\.ini$`',$ini_file_name) || preg_match('`/`',$ini_file_name) || preg_match('`\\\`',$ini_file_name)) {
				die("Illegal file name $ini_file_name");
			}
		}
        header('Content-Type: text/plain');
        header('Content-Disposition: attachment; filename=' . $ini_file_name);
    } else {
        header('Content-Type: text/plain');
    }
    $exclude_original = get_request_parameter('newlinesonly');
    $prepend = get_request_parameter('prepend');
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    if (!empty($exclude_original) || !empty($prepend)) {
        $loader_dir = loader_install_dir($server_type);
        $zend_lines = zend_extension_lines($loader_dir);
        echo join(PHP_EOL,$zend_lines);
        echo PHP_EOL;
    }
    if (empty($ini_file_name) || empty($sys['PHP_INI_DIR']) || ($sys['PHP_INI_BASENAME'] == $ini_file_name)) {
        $original_ini_file = isset($sys['PHP_INI'])?$sys['PHP_INI']:'';
    } else {
        $original_ini_file = $sys['PHP_INI_DIR'] . DIRECTORY_SEPARATOR . $ini_file_name;
    }
    if (empty($exclude_original) && !empty($original_ini_file) && @file_exists($original_ini_file)) {
        if (!empty($download)) {
            @readfile($original_ini_file);
        } else {
            echo all_ini_contents();
        } 
    }
}

function extra_page($check_access_to_info = true)
{
    if ($check_access_to_info) {
		info_disabled_check();
	}
    heading();
    $sys = get_sysinfo();
    $ini_loader = scan_inis_for_loader();
    $ini_loader_path = $ini_loader['location'];
    $loader_path = find_loader(true);
    $ldinf = get_loaderinfo();
    $self = get_self();
    echo "<h4>Additional Information</h4>";
    echo "<table>";
    $lines = array();
    if (is_string($loader_path)) {
        $lines['Loader is at'] = $loader_path;
        $loader_system = loader_system($loader_path);
        if (!empty($loader_system)) {
            $lines['Loader OS code'] = $loader_system['oscode'];
            $lines['Loader architecture'] = $loader_system['arch'];
            $lines['Loader word size'] = $loader_system['wordsize'];
            $lines['Loader PHP version'] = $loader_system['php_version'];
            $lines['Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Loader compiler'] = $loader_system['compiler'];
            $lines['Loader version'] = $loader_system['loader_version'];
            $lines['File size is'] = filesize($loader_path) . " bytes.";
            $lines['MD5 sum is'] = md5_file($loader_path);
        }
        $lines['Loader file'] = "<a href=\"$self?page=loaderbin\">Download loader file</a>";
    } else {
        $lines['Loader file'] = "Loader cannot be found.";
    }
    $lines['Loader found in ini file'] = empty($ini_loader_path)?"No":"Yes";
    if (!empty($ini_loader_path) && (!is_string($loader_path) || $ini_loader_path != $loader_path)) {
        $lines['Loader location found in ini file'] =  $ini_loader_path;
        $loader_system = loader_system($ini_loader_path);
        if (!empty($loader_system)) {
            $lines['Ini Loader OS code'] = $loader_system['oscode'];
            $lines['Ini Loader architecture'] = $loader_system['arch'];
            $lines['Ini Loader word size'] = $loader_system['wordsize'];
            $lines['Ini Loader PHP version'] = $loader_system['php_version'];
            $lines['Ini Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Ini Loader compiler'] = $loader_system['compiler'];
            $lines['Ini Loader version'] = $loader_system['loader_version'];
        }
    }
    $lines["OS extra security"] = (selinux_is_enabled() || possibly_selinux())?"SELinux":(grsecurity_is_enabled()?"Grsecurity":"None");
    $lines['PHPRC is'] = $sys['PHPRC'];
    $lines['INI DIR is'] = $sys['PHP_INI_DIR'];
    $lines['Additional INI files'] = $sys['PHP_INI_ADDITIONAL'];
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    $lines['Server type is'] = server_type_string();
    $lines["PHP uname"] = $ldinf['uname'];
    $lines['Server word size is'] = $ldinf['wordsize'];
    $lines['Disabled functions'] = ini_get('disable_functions');
    $writeable_dirs = writeable_directories();
    $lines['Writeable loader locations'] = (empty($writeable_dirs))?"<em>None</em>":join(", ",$writeable_dirs);
    if (!empty($_SESSION['hostprovider'])) {
        $lines['Hosting provider'] = $_SESSION['hostprovider'];
        $lines['Provider URL'] = $_SESSION['hosturl'];
    }
    foreach ($lines as $h => $i) {
        $v = (empty($i))?'<em>EMPTY</em>':$i;
        echo '<tr><th>'. $h . ':</th>' . '<td>' . $v . '</td></tr>';
    }
    echo "</table>";
    footer(true);
}

function loaderbin_page()
{
    info_disabled_check();
    $loader_path = find_loader(true);
    if (is_string($loader_path)) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. basename($loader_path));
        @readfile($loader_path);
    }
}



function GoDaddy_root($html_root = '')
{
    if (empty($_SESSION['not_go_daddy']) && empty($_SESSION['godaddy_root'])) {
        $godaddy_pattern = "[\\/]home[\\/]content[\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z]+[\\/]html";

        if (empty($html_root)) {
            $html_root =  $_SERVER['DOCUMENT_ROOT'];
        }
        if (preg_match("@$godaddy_pattern@i",$html_root,$matches)) {
            $_SESSION['godaddy_root'] = $matches[0];
        } else {
            $_SESSION['not_go_daddy'] = 1;
            $_SESSION['godaddy_root'] = '';
        } 
    } elseif (!empty($_SESSION['not_go_daddy'])) {
        $_SESSION['godaddy_root'] = '';
    }
    if (!empty($_SESSION['godaddy_root'])) {
        $_SESSION['hostprovider'] = 'GoDaddy';
        $_SESSION['hosturl'] = 'www.godaddy.com';
    }
    return $_SESSION['godaddy_root'];
}

function GoDaddy_windows_instructions()
{
    $instr = "It appears that you are hosted on a Windows server at GoDaddy.<br/>";
    $instr .= "Please change to a Linux hosting plan at GoDaddy.<br />";
    $instr .=  "If you <a href=\"https://help.godaddy.com/\">contact their support team</a> they should be able to switch you to a Linux server.";

    echo $instr;
}

function GoDaddy_linux_instructions($html_dir)
{
    $base = get_base_address();
    $loader_name = get_loader_name();
    $zend_extension_line="<code>zend_extension = $html_dir/ioncube/$loader_name</code>";
    $php_ini_name = is_php_version_or_greater(5,0)?'php5.ini':'php.ini';
    $ini_path = $html_dir . '/' . $php_ini_name;

    $instr = array();
    $instr[] = 'In your html directory, ' . $html_dir . ', create a sub-directory called <b>ioncube</b>.';
    if (@file_exists($ini_path)) {
       $instr[] = "Edit the $php_ini_name in your  $html_dir and add the following line to the <b>top</b> of the file:<br>" . $zend_extension_line ;
    } else {
        $instr[] = "<a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=s&amp;download=1&amp;prepend=1\">Save this $php_ini_name file</a> and upload it to your html directory, $html_dir";
    }
    $instr[] = 'Download the <a target="_blank" href="' . IONCUBE_DOWNLOADS_SERVER . '"/ioncube_loaders_lin_x86.zip">Linux ionCube Loaders</a>.';
    $instr[] = 'Unzip the loaders and upload them into the ioncube directory you created previously.';
    $instr[] = 'The encoded files should now be working.';

    echo '<div class=panel>';
    echo (make_list($instr));
    echo '</div>';
}

function GoDaddy_page()
{
    $base = get_base_address();

    heading();

        $inst_str = '<h4>GoDaddy Installation Instructions</h4>';
        $inst_str .= '<p>It appears that you are hosted with GoDaddy (<a target="_blank" href="https://www.godaddy.com/">www.godaddy.com</a>). ';
        $inst_str .= "If that is <b>not</b> the case then please <a href=\"$base&amp;page=default&amp;host=ngd\">click here to go to the main page of this installation wizard</a>.</p>";
        $inst_str .= "<p>If you have already installed the loader then please <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the loader</a>.</p>";

        echo $inst_str;

        if (is_ms_windows()) {
            GoDaddy_windows_instructions();
        } else {
            GoDaddy_linux_instructions($_SESSION['godaddy_root']);
        }

    send_stats('gd_default');

    footer(true);
}



function get_request_parameter($param_name)
{
    static $request_array;

    if (!isset($request_array)) {
        if (isset($_GET)) {
            $request_array = $_GET;
        } elseif (isset($HTTP_GET_VARS)) {
            $request_array = $HTTP_GET_VARS;
        }
    }

    if (isset($request_array[$param_name])) {
        $return_value = strip_tags($request_array[$param_name]);
    } else {
        $return_value = null;
    }
    return $return_value;
}

function make_list($list_items,$list_type='ol')
{
    $html = '';
    if (!empty($list_items)) {
        $html .= "<$list_type>";
        $html .= '<li>';
        $html .= join('</li><li>',$list_items);
        $html .= '</li>';
        $html .= "</$list_type>";
    }
    return $html;
} 

function make_archive_list($basename,$archives_list = array(),$download_server = IONCUBE_DOWNLOADS_SERVER)
{
    if (empty($archives_list)) {
        $archives_list = array('tar.gz','zip');
    }

    foreach ($archives_list as $a) {
        $link_text = $a;
        $ext_sep = '.';
        $archive_list[] = "<a href=\"$download_server/$basename$ext_sep$a\">$link_text</a>";
    }

    return make_list($archive_list,"ul");
}

function error($m)
{
    die("<b>ERROR:</b> <span class=\"error\">$m</span><p>Please help us improve this script by <a href=\"". SUPPORT_SITE . "\">reporting this error</a> and including the URL to the script so that we can test it.");
}


function filter_server_input($server_var)
{
	$res = htmlspecialchars($_SERVER[$server_var], ENT_QUOTES, "UTF-8");
	return $res;
}

function failsafe_get_self()
{
    $result = '';
    $sfn = filter_server_input('SCRIPT_FILENAME');
    $dr = $_SERVER['DOCUMENT_ROOT'];
    if (!empty($sfn) && !empty($dr)) {
        if ($dr == '/' || $dr == '\\') {
            $result = $sfn;
        } else {
            $drpos = strpos($sfn,$dr);
            if ($drpos === 0) {
                $drlen = strlen($dr);
                $result = substr($sfn,$drlen);
            }
        }
        $result = str_replace('\\','/',$result);
    }
    if (empty($result)) {
        $result = DEFAULT_SELF;
    }
    return $result;
}

function get_self()
{ 
	$page = '';
    if (empty($_SERVER['PHP_SELF'])) {
        if (empty($_SERVER['SCRIPT_NAME'])) {
            if (empty($_SERVER['REQUEST_URI'])) {
                $page = failsafe_get_self();
            } else {
                $page = filter_server_input('REQUEST_URI');
            }
        } else {
            $page = filter_server_input('SCRIPT_NAME');
        }
    } else {
        $page = filter_server_input('PHP_SELF');
    }
	return $page;
}

function get_default_page()
{
    $godaddy_root = GoDaddy_root();
    if (empty($godaddy_root)) {
         $page = 'default';
    } else {
         $page = 'GoDaddy';
    }
    return $page;
}

function get_base_address()
{
    $self = get_self();
    $remote_timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?'timeout=1':'timeout=0';
    $using_ini = (isset($_SESSION['use_ini_method']) && $_SESSION['use_ini_method'])?'ini=1':'ini=0';
    return $self . '?' . $remote_timeout . '&' . $using_ini;
}

function get_default_address($include_timeout = true)
{
    if ($include_timeout) {
        $base =  get_base_address();
        $base .= "&amp;";
    } else {
        $base = get_self();
        $base .= "?";
    }
    $page = get_default_page();

    return $base . 'page=' . $page;
}

function heading()
{
    $self = get_self();

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <meta name="robots" content="noindex, nofollow">
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <script type="text/javascript">
            function showOverlay()
            {
                document.getElementById('overlay').style.display = 'block';
                return true;
            }

            function hideOverlay()
            {
                document.getElementById('overlay').style.display = 'none';
                return true;
            }
        </script>
    </head>
    <body onload="hideOverlay()">
    <div id="overlay">
        <div id="inner_overlay">Checking server configuration<br>Please wait</div>
    </div>
    <div id="header">
        <img src="?page=logo" alt="ionCube logo">
    </div>
	<div id="important">
	<h3 class="important">IMPORTANT: Ensure that This Script Is Removed When No Longer Required</h3>
	</div>
    <div id="main">
    <h2>ionCube Loader Wizard</h2>
EOT;
}

function footer($update_info = null)
{
    $self = get_self();
    $base = get_base_address();
    $default = get_default_address(false);
    $year = gmdate("Y");

    echo "</div>";
    echo "<div id=\"footer\">" .
    "Copyright ionCube Ltd. 2002-$year | " .
    "Loader Wizard version " . script_version() . " ";

    if ($update_info === true) {
        $update_info = check_for_wizard_update(false);  
    }
    $loader_wizard_loc = LOADER_WIZARD_URL;
    $wizard_version_string =<<<EOT
    <script type="text/javascript">
    var xmlhttp;
    function version_check()
    { 
        var body = document.getElementsByTagName('body')[0];
        var ldel = document.getElementById('loading');
        if (!ldel) {
            body.innerHTML += '<div id="loading"></div>';
            ldel = document.getElementById('loading');
        }
        ldel.innerHTML = '<p>Retrieving Wizard version information<br>Please wait</p>';
        ldel.style.display = 'block';
        ldel.style.height = '300px';
        ldel.style.left = '200px';
        ldel.style.border = '4px #660000 solid';
        if (window.XMLHttpRequest) {
            xmlhttp=new XMLHttpRequest();
        } else {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            var loadedOkay = 0;
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                var wizardversion = xmlhttp.responseText;
                var msg;
                clearTimeout(xmlHttpTimeout);
                buttons = '';
                if (wizardversion == '1') {
                    msg = 'You have the current version of the<br>ionCube Loader Wizard'; 
                } else if (wizardversion != '0') {
                    msg = 'A new version, ' + wizardversion + ', of the loader wizard is available';
                    buttons = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; window.open(\'$loader_wizard_loc\'); return false">Get new version</button> &nbsp;'; 
                } else {
                    msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
                }
                buttons += '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>'; 
                ldel.innerHTML = '<p>' + msg +  '<br>' + buttons + '</p>';
            }
        }
        xmlhttp.open("GET",'$self?page=wizardversion&wizard_only=1&clear_info=1',true);
        xmlhttp.send();
        var xmlHttpTimeout=setTimeout(ajaxTimeout,7000);
    }
    function ajaxTimeout(){
       xmlhttp.abort();
       msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
       button = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>';
       var ldel = document.getElementById('loading');
       ldel.innerHTML = '<p>' + msg +  '<br>' + button + '</p>';
    }
    </script>
EOT;

    $wizard_version_string .= '('; 
    if ($update_info === null) {
        $wizard_version_string .= '<a target="_blank" href="' . $loader_wizard_loc . '" onclick="version_check();return false;">check for new version</a>';
    } else if ($update_info !== false) {
        $wizard_version_string .= '<a href="' . LOADERS_PAGE .'" target="_blank">download version ' . $update_info . '</a>';
    } else {
        $wizard_version_string .=  "current";
    }
    $wizard_version_string .= ')'; 
    echo $wizard_version_string;

    $server_type_code = server_type_code();
	
	if (!info_should_be_disabled(true)) {
		echo " | <a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo</a>";
		echo " | <a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a>";
		echo " | <a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional</a>";
	}

    echo " | <a href=\"$default\" onclick=\"showOverlay();\">wizard start</a>";
    echo " | <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">loader test</a>";
    echo ' | <a href="' . LOADERS_PAGE . '" target="loaders">loaders</a>';

    echo "</div>\n";
    echo "\n</body></html>\n";
}

function css_page()
{
    header('Content-Type: text/css');
    echo <<<EOT
    body {
        font-family: verdana, helvetica, arial, sans-serif;
        font-size: 10pt;
        line-height: 150%;
        margin: 0px;
        min-height: 400px;
        position: relative;
    }

    code {
        color: #c00080;
    }

    li {
        margin-top: 10px;
    }
    #overlay {
        display: block;
        z-index: 100;
        position: absolute;
        top: 0;
        left: 0;
        padding: 0;
        margin: 0;
        width: 100%;
        height: 100%;
        background-color: white;
    }
    #inner_overlay {
        display: block;
        z-index: 100;
        position: absolute;
        font-size: 200%;
        color: #660000;
        top: 50%;
        left: 25%;
        width: 460px;
        height: 460px;
        line-height: 200%;
        text-align: center;
        vertical-align: middle;
    }

    #loading {
        display: block;
        position: absolute;
        top: 33%;
        left: 25%;
        margin: auto;
        height: 320px;
        width: 460px;
        padding: 4px;
        color: #660000;
        background-color: white;
        z-index: 100;
    }

    #loading p {
        position: absolute;
        margin-top: 10px;
        text-align: center;
        vertical-align: middle;
        padding-left: 40px;
        padding-right: 30px;
        font-size: 200%;
        line-height: 200%;
    }

    #loading p span#status{
        font-size: 60%;
        line-height: 120%;
    }
    #loading p#noscript {
        font-size: 120%;
        line-height: 120%;
        position: absolute;
        text-align: left;
        padding-top: 10px;
        bottom: 0;
    }
    #loading p#noscript a {
        text-align: center;
    }

    #loading button {
        margin-top: 20px;
        line-height: 100%;
        padding-top: 4px;
        padding-bottom: 4px;
    }


    h4 {
        margin-bottom: 0;
        padding-bottom: 4px;
    }

    p,#main div {
        max-width: 1000px;
        width: 75%;
    }

    #hostinginfo {
        margin-top: 10px;
        margin-left: 20px;
    }
    #hostinginfo table {
        font-size: 1.00em;
    }
    #hostinginfo table td {
        padding-right: 4px;
    }
    #hostinginfo input {
        margin-top: 6px;
    }

    #hostinginfo label {
        margin-left: 6px;
    }

    th {
        text-align: left;
    }
	
	#important {
		margin-top: 12px;
	} 
	h3.important {
		margin: 0;
		border: 0;
        border-top: 1px solid #660000;
		border-bottom: 1px solid #660000;
        padding: 1ex 0 1ex 0;
        background-color: #CB2430;
		text-align: center;
        color: #ffffff; 
        width: 100%;
	}

    .alert {
        margin: 2ex 0;
        border: 1px solid #660000;
        padding: 1ex 1em;
        background-color: #ffeeee;
        color: #660000; 
        width: 75%;
    }

    .warning {
        margin: 2ex 0;
        border: 1px solid #FFBF00;
        padding: 1ex 1em;
        background-color: #FDF5E6;
        color: #000000; 
        width: 75%;
    }

    .success {
        margin: 2ex 0;
        border: 1px solid #006600;
        padding: 1ex 1em;
        background-color: #EEFFEE;
        color: #000000; 
        width: 75%;
    }

    .error {
        color: #FF0000;
    }

    .panel {
        border: 1px solid #c0c0c0;
        background-color: #f0f0f0;
        width: 75%;
        padding: 1ex 1em;
    }
	
	.terminal {
		border: none;
		background-color: #000000;
		color: #ffffff;
		width: 50%;
		padding: 1ex 1em;
	}

    #header {
        background: #fff;
    }

    #footer {
        border-top: 1px solid #404040;
        margin-top: 20px;
        padding-top: 10px;
        padding-left: 20px;
        font-size: 75%;
        text-align: left;
    }

    #main {
        margin: 20px;
    }
	
	
	#main .ic24 {
		position: relative;
		width: 75%;
		height: auto;
		border-width: 1px 1px 1px 1px;
		border-style: solid;
		border-color: #4B8DF8;   
		background-color: #EFEFFF;
		padding: 12px;
		padding-top: 16px;
		padding-bottom: 8px;
		margin-top: 20px;
		overflow: hidden;
	}
	
	#main .ic24 p {
		width: 100%;
	}
	
	
	#main .ic24graphic {
		position: relative;
		width: auto;
		height: auto;
		border: none;
		padding: 0px;
		padding-right: 16px;
		margin: 0px;
		float: left;
		
	}
	
	#main #ic24info {
		position: relative;
		width: auto;
		height: auto;
		float: left;
	}
	
	#main #ic24info a {
		color: #0B4DB8;
		text-decoration: none;
	}
	
	#main #ic24logo {
		max-width: 132px;
		max-height: 132px;
	}
	
EOT;
}

function logo_page()
{
$img_encoded = 'iVBORw0KGgoAAAANSUhEUgAAAakAAACABAMAAABD1osiAAAAKlBMVEUAAAAAAADnHCwAAAAAAAAAAAAAAAAAAABMCQ4AAADnHCznHCznHCwAAAAjcBE1AAAADHRSTlMAeDRHwSqg4BJl/PLTJLuIAAAF1UlEQVR42u2by4vTQBzHp3TTzR6EBtfXYS/+BZW6Pg6FFavgoRDBBx4KFd+HQgWFvQQqiuJhoeL7sP+LR0EPlj6yPfz+F5NMZ77TmmJjM3ZT5nNpOzvNzGcev5lMusxgMBgMBoPBYDAYDAaDwWDQwel5YRnC/jkvbZYdjFV2MFbZwVhlB2OVIVZyb2HIED/n5AfLEj/nhWUJY5UdjFV2MFbZwVgdMqzNZydXz2qrf59Kq2a1NmTsRnfVrLZOfj3VrrkrZuVb/dpBvZEJqzOOc5TNQ75rjXKDtV+ZsNoi6rJ52OhZwxONwiGwsi46zqnt1Kx8r7N8q/wmRfhP3BSsrK7VW/u13krDysGwT8o5kvilxa2YZ/U2eulEC0KhCTlLCo0UrPYff7Tfe+2lWt0glTT6qjB02e0eW6ZVjiZYaF4hq+eXlmll1yik75TL5eMeDVOxsj89hNQyrN5QyDFRm9GCVmCZVrYXBr4OE9w8ZFbBCNr+x646ycAhs/o3moFUj62Y1UY4/txVs9oLrAZs1azCAVhaNSsLgXNpVt/+dlNXZAplx4mLiXecU5hHhcBqN6lV/p3znk1xEYUltfr+t0J/4dN1jwKGWIg+VKuBdL5JAQ9EYj34ILOAjWq12lG+eE2xsk9EF/7CFN7WKOCpq9kK2/CTyp93mFUbpyKRZmwNi2oX4Y0dfgULd8QL4vRdvVavJ+6XYLVPIQjmHq9xAqvbJBTa8paTBCOtVpZHY1DrSmCF7flABotBIiuLJM+RQdJJO1qoVnUKqfLh1pBWrX10YVu0ciuRVXjlfpUiXGSmp85xdFaaT7thZUV95I5DRldaDYJPT8oXmyQqnYP0nFZetL23tgjtsT/e8uc9mKa3XsFqL3Rpy3YsCSufhwmrJgbeGmo/jxUCjd2UzWWFg1EuEzv6rJoY4ftyQapghBRElda5cxKrEfaPvGPWw+Esyx1ps8pHhaP0LqxK8p7KZwFHklt1kEqNcbsNcFfT12a1zgtEv7WFVZehB93xUGVJrPg7MXgPxotDUWlCV5dVhYtgjhV5KuLd+jixktjqYHoHmVcLw9fSt2ry8lDBlrAqKomN5FZI5aX0+Rztqmk7uqywtGKhRQ+KmbeT3AoDDN89gsJQBQ1WWFrFpmgkIruq2kpuhWCASFNBYXxN1GGFKk1XqqLWiXjeOvpv3n2gpBDm4dtL1aqnyaqAcA2bGCu0d3Ir5GkSPasKsFlO3WpNGf68P3wdVhs84tRIRZ/VEUwWfIyxwo4puRUiDh0+q2jntnJWOf6aplVv+VZ5VGMBq3tlhQuarNYnw3V9Zgzkr8PFYiByAi0xcM7ILva+7kJWNeyktVoV5l2FeSI1kluh8UKrlnar6dv2qNhejBVG6yDeaifOajg5X9tR4sH/sLIIBeFTjJV4JMImmd5KNmGFvHxfyV9Guq2mDvnQc9NWyIuOBWrD2BSzZ4fsHi6rzUq26cRdY2e2VSU+ChJ6IDdh1Zi+wylAVa9VfWqu+2y2VYFiO6uGzHsTVj01WOxgsOq3KqB0nMbMsLK96fNxKVASgrDCSogcHjpbq5WNg1WcVsRY4Zi3i1Xblqm7OLFXrHbRWn2GxUG/FduX0yIHwRlWFomD3ojrT+Vxje+KE3tYiQ6ym3JJKKidnW9rscJkuSwOiUdsphXO5P2724y9PPOI+njMMSyxOzWiTViF7/0v4kS6gzEcZA0545X0WbFmVClnk1B4vJXsDYArcPzXitUxCnhW5f070SyXHGfTw1jUYVUgMGKzrTBKQQk/LonYzSlWxToyFuOapaXRim2hqd2/WbFbJEBlLTx8k1a1QNmaai0eUMBAp5XVFFIdNtMqVqs/nhmvpGQuSJRWUmHoMsl5klzRacWsE4Sn3TOswMtH9Mfvbj+L36JNWrFzUgqcE6ofdf8X9PXN6qWjbF5eOverV51ye/ICd+NCWv549er0ha3o69vMYDAYDAaDwWAwGAwGg8FgSJffF2mwYDNbStYAAAAASUVORK5CYII=';

    header('Content-Type: image/png');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}

function ic24logo_page()
{
	$img_encoded = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6b3NiPSJodHRwOi8vd3d3Lm9wZW5zd2F0Y2hib29rLm9yZy91cmkvMjAwOS9vc2IiCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB2ZXJzaW9uPSIxLjAiCiAgIHdpZHRoPSI2OTAiCiAgIGhlaWdodD0iNjkxLjI1IgogICB2aWV3Qm94PSIwIDAgNTUyIDU1MyIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgaWQ9InN2ZzMwMzUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImlvbkN1YmUyNF9jdWJlLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwODMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzQ5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTM1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzMzkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzMxIgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTMzMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzMjUiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzI3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NSIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4ODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NzMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODc1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDEiCiAgICAgICB4MT0iNDQzNS40NDI0IgogICAgICAgeTE9IjI5NDkuMDQyIgogICAgICAgeDI9IjQ4MzQuMzkyMSIKICAgICAgIHkyPSIyOTQ5LjA0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTgiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjAiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxOCIKICAgICBpZD0ibmFtZWR2aWV3MzA4MSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC45NjUzODc0IgogICAgIGlua3NjYXBlOmN4PSI3MjQuNTI3MjIiCiAgICAgaW5rc2NhcGU6Y3k9IjMzMy4xMTQ1MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMzAzNSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMCIKICAgICBmaXQtbWFyZ2luLWxlZnQ9IjAiCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIKICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDM3Ij4KQ3JlYXRlZCBieSBwb3RyYWNlIDEuMTEsIHdyaXR0ZW4gYnkgUGV0ZXIgU2VsaW5nZXIgMjAwMS0yMDEzCjxyZGY6UkRGPgogIDxjYzpXb3JrCiAgICAgcmRmOmFib3V0PSIiPgogICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICA8ZGM6dHlwZQogICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICA8L2NjOldvcms+CjwvcmRmOlJERj4KPC9tZXRhZGF0YT4KICA8ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMSwwLDAsLTAuMSwtNCw1NTcpIgogICAgIGlkPSJnMzAzOSIKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO3N0cm9rZTpub25lIj4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIC0yLDg2OCAtMyw4NjcgLTg2NywzIC04NjgsMiAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA0MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDMiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDM4MjcsNTU2MyBjIC00LC0zIC03LC0zOTUgLTcsLTg3MCBsIDAsLTg2MyA4NzAsMCA4NzAsMCAwLDg3MCAwLDg3MCAtODYzLDAgYyAtNDc1LDAgLTg2NywtMyAtODcwLC03IHoiCiAgICAgICBpZD0icGF0aDMwNDUiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDI4MDAgMCwtODcwIDg2OCwyIDg2NywzIDMsODY4IDIsODY3IC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDciCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDE5MzAsMjgwMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiBtIDEwMzUsNjMwIGMgODAsLTMxIDE1NCwtMTAyIDE5MSwtMTgzIDI1LC01NCAyOCwtNzQgMjksLTE1NyAwLC0xOTAgLTc0LC0zMTggLTM0NCwtNTkyIGwgLTE3NCwtMTc4IDI3NiwwIDI3NywwIDAsLTgwIDAsLTgwIC00MDcsMiAtNDA4LDMgLTMsNTYgLTMsNTUgMTgxLDE3NCBjIDM1NSwzMzkgNDUyLDQ5MyA0MjMsNjY3IC0xOSwxMDYgLTcxLDE2MiAtMTcyLDE4NCAtOTIsMjAgLTIwMiwtNiAtMjkzLC02OSBsIC00NiwtMzEgLTI2LDU4IGMgLTE0LDMyIC0yNiw2MiAtMjYsNjYgMCwyMiAxNDcsOTkgMjI4LDEyMCA4MiwyMSAyMjEsMTQgMjk3LC0xNSB6IgogICAgICAgaWQ9InBhdGgzMDQ5IgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAzODIyLDI4MDMgMywtODY4IDg2OCwtMyA4NjcsLTIgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAyLC04NjcgeiBtIDExNzgsMjQyIDAsLTM5NSA5MCwwIDkwLDAgMCwtNzAgMCwtNzAgLTkwLDAgLTkwLDAgMCwtMTcwIDAsLTE3MCAtODUsMCAtODUsMCAwLDE3MCAwLDE3MCAtMjkwLDAgLTI5MCwwIDAsNjMgMCw2NCAyODEsNDAxIDI4MSw0MDIgOTQsMCA5NCwwIDAsLTM5NSB6IgogICAgICAgaWQ9InBhdGgzMDUxIgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA0NzkwLDMxNzMgYyAtMjQsLTQzIC0xMTEsLTE3MiAtMTk1LC0yODggLTgzLC0xMTUgLTE1NSwtMjE2IC0xNTksLTIyMiAtNiwtMTAgMzUsLTEzIDE5MywtMTMgbCAxOTksMCA0LDI5OCBjIDIsMTYzIDMsMjk4IDIsMzAwIC0xLDIgLTIxLC0zMiAtNDQsLTc1IHoiCiAgICAgICBpZD0icGF0aDMwNTMiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NTM0MSk7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTg1MTYsMTc0MyBjIC0zLC04MzUgLTksLTE1NTMgLTEyLC0xNTk1IGwgLTYsLTc4IDE3MCwwIDE3MCwwIDcsODggYyAzLDQ4IDksMTI3IDEzLDE3NiBsIDcsODkgNDAsLTU5IGMgNTMsLTc3IDE2MCwtMTgxIDIyOSwtMjIzIDEyOCwtNzcgMjQ4LC0xMTEgNDIxLC0xMTggMjEwLC05IDM4NywzOCA1NTIsMTQ3IDI3NiwxODEgNDM4LDQ4MiA0NzQsODc5IDM5LDQzMyAtMTA1LDgzOSAtMzc1LDEwNTYgLTE1NSwxMjUgLTMzMCwxODUgLTU0MSwxODUgLTE5OSwwIC0zNTcsLTQwIC00OTMsLTEyNiAtNzEsLTQ1IC0xODMsLTE1MyAtMjI1LC0yMTkgbCAtMzIsLTUwIC0zLDY4MyAtMiw2ODIgLTE5NCwwIC0xOTQsMCAtNiwtMTUxNyB6IG0gMTE1NSwyMjMgYyAxNDksLTMyIDMwNSwtMTQ4IDM4OCwtMjg5IDc5LC0xMzUgMTIxLC0zMTMgMTIxLC01MTIgMCwtMTk2IC0zNSwtMzU2IC0xMDgsLTUwMCAtNDMsLTg0IC0xNzEsLTIxNyAtMjQ5LC0yNTggLTc3LC00MSAtMTkyLC02NyAtMjk0LC02NyAtMTE2LDAgLTE3NywxMyAtMjc4LDYyIC0xNDYsNjkgLTI1OCwyMDMgLTMxNywzNzggLTE3LDQ5IC0xOSw4OCAtMTksMzYwIDAsMzA1IDAsMzA1IDI3LDM4NSAzNywxMDkgOTEsMTk2IDE2OSwyNzUgNzQsNzQgMTkwLDE0MSAyODYsMTY0IDc2LDE5IDE5MSwxOSAyNzQsMiB6IgogICAgICAgaWQ9InBhdGgzMDU1IgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE3NCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTQ2MTAsMzEzOSBjIC01MTgsLTY1IC05NDQsLTM1NyAtMTE2NCwtNzk3IC0xNDEsLTI4MCAtMjAxLC02MzYgLTE2NiwtOTgzIDcyLC03MTEgNDgwLC0xMTc3IDExNDcsLTEzMTAgMjExLC00MiA1NTcsLTM2IDgxMywxMiAxMTksMjMgMzIwLDg2IDMyNiwxMDMgNiwxNyAtNzIsMzExIC04MiwzMDkgLTUsLTEgLTQ5LC0xNiAtOTcsLTMzIC0xNDcsLTUyIC0yNjIsLTcxIC00NzAsLTc3IC0yMTAsLTYgLTMyMCw0IC00NTcsNDQgLTQzNywxMjYgLTcwNSw0NzIgLTc2MSw5NzkgLTE1LDE0MCAtNSwzODggMjAsNTE0IDYwLDI5OSAxOTgsNTM2IDQwMyw2OTAgMjIzLDE2OSA0NzIsMjM4IDgwOCwyMjcgMTg0LC02IDMwNywtMjggNDQyLC03OCA0NiwtMTYgODksLTMxIDk2LC0zMiA5LC0xIDMwLDQ5IDYyLDE1MyAyNyw4NSA0OCwxNTUgNDcsMTU2IC01Miw0MCAtMjc2LDEwMSAtNDU3LDEyMyAtOTcsMTMgLTQxNCwxMiAtNTEwLDAgeiIKICAgICAgIGlkPSJwYXRoMzA1NyIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNzApIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczNzAsMjg1NSAwLC0xOTUgMjEwLDAgMjEwLDAgMCwxOTUgMCwxOTUgLTIxMCwwIC0yMTAsMCAwLC0xOTUgeiIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNjYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIzODg2LDMwMjQgYyAtOTksLTE4IC0yNjQsLTczIC0zNDgsLTExNSAtNzEsLTM1IC0yMTgsLTEzMCAtMjM3LC0xNTMgLTEwLC0xMiAwLC00MCA1MCwtMTUwIDM0LC03NSA2MywtMTM2IDY1LC0xMzYgMSwwIDM2LDI0IDc3LDUzIDE2NiwxMTkgMzI0LDE3NiA1MTMsMTg0IDMwOCwxNCA1MDMsLTEwOCA1ODAsLTM2MiAxNCwtNDYgMTksLTkzIDE5LC0yMDAgLTEsLTE3MSAtMTksLTI0NyAtMTAwLC00MTAgLTEzMCwtMjYxIC0zODAsLTU0MyAtMTA0NCwtMTE4MCBsIC0yNTAsLTI0MCAtMSwtMTIyIDAsLTEyMyA5MzUsMCA5MzUsMCAwLDE2NSAwLDE2NSAtNjU3LDAgLTY1NywwIDEwOSwxMDEgYyA2MSw1NiAyMTgsMjEwIDM1MCwzNDMgMzQyLDM0NSA1MTgsNTYzIDYzNCw3ODYgMTc5LDM0NSAxOTgsNjc4IDU3LDk2NSAtODEsMTYzIC0xODgsMjcwIC0zNTEsMzUxIC0xNDEsNzAgLTIxOSw4NiAtNDI1LDkwIC0xMjUsMiAtMTk4LC0xIC0yNTQsLTEyIHoiCiAgICAgICBpZD0icGF0aDMwNjEiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE2MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMjY2ODEsMjk3NyBjIC02LC04IC0yOTksLTQyNSAtNjUxLC05MjggbCAtNjQwLC05MTQgMCwtMTMyIDAsLTEzMyA2ODAsMCA2ODAsMCAwLC00MDAgMCwtNDAwIDE4NSwwIDE4NSwwIDAsNDAwIDAsNDAwIDIwNSwwIDIwNSwwIDAsMTU1IDAsMTU1IC0yMDUsMCAtMjA1LDAgMCw5MDUgMCw5MDUgLTIxNCwwIGMgLTE2NiwwIC0yMTYsLTMgLTIyNSwtMTMgeiBtIDcxLC0xMDg0IC0zLC03MTMgLTQ4MCwwIGMgLTM4MiwwIC00NzksMyAtNDczLDEzIDUsNiAxNjYsMjMwIDM1OCw0OTcgMzQ3LDQ4MSAzOTksNTYwIDUzMCw3OTggMzgsNjggNjksMTIyIDcwLDEyMCAwLC0yIDAsLTMyNCAtMiwtNzE1IHoiCiAgICAgICBpZD0icGF0aDMwNjMiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE1OCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTE5MjcsMjI4OCBjIC0xMDgsLTEwIC0yNDgsLTU1IC0zNDEsLTExMCAtODIsLTQ4IC0yMDMsLTE2MCAtMjQ3LC0yMjkgLTE3LC0yNyAtMzQsLTQ3IC0zOCwtNDQgLTMsNCAtMTAsODIgLTE2LDE3MyBsIC0xMCwxNjcgLTE3OSwzIC0xNzgsMiA2LC00NyBjIDQsLTI3IDksLTUxNyAxMiwtMTA5MCBsIDYsLTEwNDMgMTk5LDAgMTk4LDAgMyw3MjcgMyw3MjggMzEsNzIgYyAxMTMsMjYwIDM0MSwzOTggNTk4LDM2MiAxNjQsLTIyIDI3NiwtMTAzIDM0NiwtMjUxIDczLC0xNTQgNzIsLTE0OCA3NywtOTM1IGwgNSwtNzAzIDE5NCwwIDE5NCwwIDAsNzIzIGMgMCw3OTYgLTIsODI0IC02Miw5OTcgLTEyMSwzNDcgLTQyMCw1MzMgLTgwMSw0OTggeiIKICAgICAgIGlkPSJwYXRoMzA2NSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNTQpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczOTAsMTE4MCAwLC0xMTEwIDE5MCwwIDE5MCwwIDAsMTExMCAwLDExMTAgLTE5MCwwIC0xOTAsMCAwLC0xMTEwIHoiCiAgICAgICBpZD0icGF0aDMwNjciCiAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMTUwKSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA5MTk5LDIyODAgYyAtMjIwLC0zNyAtNDE4LC0xMzggLTU3MCwtMjg5IC0xNTAsLTE1MSAtMjQyLC0zMjkgLTI5NSwtNTcxIC0yNiwtMTE5IC0yNywtNDI5IC0xLC01NDcgNTIsLTI0NCAxNDksLTQyNiAzMDUsLTU3NSAxODcsLTE3OCAzOTYsLTI2NCA2NjgsLTI3NSA1MDAsLTIxIDkxMiwyNTEgMTA2NSw3MDQgNTQsMTYxIDY0LDIzMCA2Myw0NDggMCwxNjcgLTMsMjE1IC0yMSwyOTEgLTEwMyw0NDEgLTM5MCw3MzAgLTgwMyw4MDggLTg3LDE3IC0zMjYsMjAgLTQxMSw2IHogbSAzMzQsLTMwNSBjIDI1NSwtNjYgNDM4LC0zMDggNDg3LC02NDQgMTcsLTExNiA4LC0zNDMgLTE4LC00NDIgLTY0LC0yNDMgLTE5NywtNDIzIC0zNzQsLTUwOCAtMTA1LC01MCAtMTg0LC02NiAtMjk2LC01OCAtMjIxLDE1IC0zOTMsMTM2IC01MDgsMzU5IC02NiwxMjkgLTk1LDI1MCAtMTAxLDQyNSAtMTEsMzA4IDY3LDU0NSAyMzYsNzE0IDgxLDgxIDE1OCwxMjYgMjYxLDE1MyA3MywxOSAyNDEsMjAgMzEzLDEgeiIKICAgICAgIGlkPSJwYXRoMzA2OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNDYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIxNzUwLDIyNzUgYyAtMzUyLC03MCAtNjExLC0zMDUgLTczOSwtNjY4IC01OCwtMTY1IC03NSwtMjcxIC03NSwtNDc3IC0xLC0yMDQgMTAsLTI3OSA2NiwtNDQ3IDExOSwtMzYwIDQyMCwtNTk4IDgyNiwtNjUzIDEyNywtMTggMzkyLC04IDU0MiwyMCAxMjIsMjIgMzYwLDk2IDM2MCwxMTEgMCwxOCAtNjMsMjY0IC02OSwyNzEgLTMsNCAtNTEsLTggLTEwNiwtMjcgLTE1NCwtNTEgLTI3MiwtNjggLTQ3NSwtNjggLTIwMywwIC0yNzgsMTUgLTQwOSw4MyAtMjE0LDExMSAtMzI4LDMwMiAtMzU2LDU5OCBsIC03LDcyIDc2NSwwIGMgNjg4LDAgNzY1LDIgNzcxLDE2IDEyLDMyIDYsMzAzIC05LDM5MCAtNDMsMjQ0IC0xMzQsNDMzIC0yNzcsNTcwIC0xMTUsMTEyIC0yMzUsMTc0IC00MDAsMjA4IC05NCwxOSAtMzE0LDIwIC00MDgsMSB6IG0gMzUzLC0yOTUgYyAyMDcsLTY0IDMzOCwtMjU3IDM2MywtNTM1IGwgNywtNzUgLTU3NywwIC01NzYsMCAwLDIzIGMgMCw1MiA0MiwxODcgODYsMjc1IDgyLDE2OCAyMjcsMjkyIDM3NCwzMjEgMzAsNiA2NCwxMyA3NSwxNSA0MSwxMCAxODUsLTUgMjQ4LC0yNCB6IgogICAgICAgaWQ9InBhdGgzMDcxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE0MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gNDAsOTEwIDAsLTg3MCA4NjgsMiA4NjcsMyAzLDg2OCAyLDg2NyAtODcwLDAgLTg3MCwwIDAsLTg3MCB6IgogICAgICAgaWQ9InBhdGgzMDc1IgogICAgICAgc3R5bGU9ImZpbGw6I2MwMWQyZTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDkxMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA3NyIKICAgICAgIHN0eWxlPSJmaWxsOiNjMDFkMmU7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMzgyMCw5MTAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNzkiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICA8L2c+Cjwvc3ZnPgo=';
	header('Content-Type: image/svg+xml');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}
alt-php52-ioncube-loader/README.txt000064400000007751150431076120012655 0ustar00                            The ionCube Loader 
                            ------------------

This package contains:

* ionCube Loaders

* a Loader Wizard script to assist with Loader installation (loader-wizard.php)

* the License document for use of the Loader and encoded files (LICENSE.txt)

* User Guide describing options that can be configured through a php.ini file.  
  There are options that may improve performance, particularly with files on
  a network drive. Options for the ionCube24 intrusion protection and PHP error
  reporting service (ioncube24.com) are also described.


INSTALLATION
============

Quick Guide for experienced system admins
-----------------------------------------

The Loader is a PHP engine extension, so should be referenced with 
a zend_extension line in a php.ini file. It must be the first engine
extension to be installed. 

The Loader must be for the correct operating system, match the 
PHP version, and for whether PHP is built as thread-safe (TS) or not. 
All information required for installing is available on a phpinfo page. 

For example, if your web server is 64 bit Linux, thread safety is disabled,
PHP is version 8.1.8, the main php.ini file is /etc/php.ini and you
have unpacked Loaders to /usr/local/ioncube, you would:

1) edit /etc/php.ini
2) at the top of the php.ini file add

zend_extension = /usr/local/ioncube/ioncube_loader_lin_8.1.so

3) restart the PHP environment (i.e. Apache, php-fpm, etc.)

4) Check a phpinfo page and the Loader should show up in the Zend Engine box.


Assisted Installation with the Loader Wizard
--------------------------------------------

1. Upload the contents of this package to a directory/folder called ioncube
   within the top level of your web scripts area. This is sometimes called the
   "web root" or "document root". Common names for this location are "www",
   "public_html", and "htdocs", but it may be different on your server.

2. Launch the Loader Wizard script in your browser. For example:
     https://yourdomain/ioncube/loader-wizard.php

   If the wizard is not found, check carefully the location on your server
   where you uploaded the Loaders and the wizard script. 

3. Follow the steps given by the Loader Wizard. If you have full access to the 
   server then installation should be easy. If your hosting plan is more limited, 
   you may need to ask your hosting provider for assistance. 

4. The Loader Wizard can automatically create a ticket in our support system
   if installation is unsuccessful, and we are happy to assist in that case.

   YouTube with a search for "ioncube loader wizard" also gives some helpful 
   examples of installation.


WHERE TO INSTALL THE LOADERS
============================

The Loader Wizard should be used to guide the installation process but the
following are the standard locations for the Loader files. Loader file
packages can be obtained from https://www.ioncube.com/loaders.php

Please check that you have the correct package of Loaders for your system.

Installing to a remote SHARED server
------------------------------------

* Upload the Loader files to a directory/folder called ioncube within your
  main web scripts area.  (This will probably be where you placed the
  loader-wizard.php script.)


Installing to a remote UNIX/LINUX DEDICATED or VPS server
---------------------------------------------------------

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, /usr/local/ioncube


** Installing to a remote WINDOWS DEDICATED or VPS server

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, C:\windows\system32


64-BIT LOADERS FOR WINDOWS
--------------------------

64-bit Loaders for Windows are available for PHP 5.5 upwards.
The Loader Wizard will not give directions for installing 64-bit Loaders for
any earlier version of PHP 5.

Copyright (c) 2002-2025 ionCube Ltd.           Last revised January 2025
pear/Structures_Graph/docs/generate.sh000064400000000555150431076200014060 0ustar00#!/bin/sh
(cd ..; tar czf docs/arch.tgz "{arch}")
rm -Rf "../{arch}"
rm -Rf ./html
mkdir -p ./html
phpdoc --directory ../Structures,./tutorials --target ./html --title "Structures_Graph Documentation" --output "HTML:frames" --defaultpackagename structures_graph --defaultcategoryname structures --pear 
(cd ..; tar --absolute-names -xzf docs/arch.tgz)
#rm arch.tgz
pear/Structures_Graph/docs/html/classtrees_Structures_Graph.html000064400000002530150431076200021313 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title></title>
			<link rel="stylesheet" href="media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
						
<!-- Start of Class Data -->
<H2>
	
</H2>
<h2>Root class Structures_Graph</h2>
<ul>
<li><a href="Structures_Graph/Structures_Graph.html">Structures_Graph</a></li></ul>

<h2>Root class Structures_Graph_Manipulator_AcyclicTest</h2>
<ul>
<li><a href="Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html">Structures_Graph_Manipulator_AcyclicTest</a></li></ul>

<h2>Root class Structures_Graph_Manipulator_TopologicalSorter</h2>
<ul>
<li><a href="Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html">Structures_Graph_Manipulator_TopologicalSorter</a></li></ul>

<h2>Root class Structures_Graph_Node</h2>
<ul>
<li><a href="Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a></li></ul>

	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</body>
</html>pear/Structures_Graph/docs/html/packages.html000064400000001641150431076210015340 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title></title>
			<link rel="stylesheet" href="media/stylesheet.css" />
			<link rel="stylesheet" href="media/banner.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="banner">
				<div class="banner-title">Structures_Graph</div>
				<div class="banner-menu">
	        <table cellpadding="0" cellspacing="0" style="width: 100%">
	          <tr>
              <td>
								              </td>
              <td style="width: 2em">&nbsp;</td>
              <td style="text-align: right">
								              </td>
						</tr>
          </table>
				</div>
			</div>
		</body>
	</html>pear/Structures_Graph/docs/html/index.html000064400000001761150431076220014675 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//FR"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<!-- Generated by phpDocumentor on Fri, 30 Jan 2004 16:37:28 +0000  -->
  <title>Structures_Graph Documentation</title>
  <meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
</head>

<FRAMESET rows='100,*'>
	<FRAME src='packages.html' name='left_top' frameborder="1" bordercolor="#999999">
	<FRAMESET cols='25%,*'>
		<FRAME src='li_Structures_Graph.html' name='left_bottom' frameborder="1" bordercolor="#999999">
		<FRAME src='Structures_Graph/tutorial_Structures_Graph.pkg.html' name='right' frameborder="1" bordercolor="#999999">
	</FRAMESET>
	<NOFRAMES>
		<H2>Frame Alert</H2>
		<P>This document is designed to be viewed using the frames feature.
		If you see this message, you are using a non-frame-capable web client.</P>
	</NOFRAMES>
</FRAMESET>
</HTML>pear/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html000064400000010141150431076230030475 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Docs For Class Structures_Graph_Manipulator_TopologicalSorter</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			
<h2 class="class-name">Class Structures_Graph_Manipulator_TopologicalSorter</h2>

<a name="sec-description"></a>
<div class="info-box">
	<div class="info-box-title">Description</div>
	<div class="nav-bar">
					<span class="disabled">Description</span> |
															<a href="#sec-method-summary">Methods</a> (<a href="#sec-methods">details</a>)
						
			</div>
	<div class="info-box-body">
		<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">The Structures_Graph_Manipulator_TopologicalSorter is a manipulator  which is able to return the set of nodes in a graph, sorted by topological  order.</p>
<p class="description"><p>A graph may only be sorted topologically iff it's a DAG. You can test it  with the Structures_Graph_Manipulator_AcyclicTest.</p></p>
	<ul class="tags">
				<li><span class="field">see:</span> <a href="../Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html">Structures_Graph_Manipulator_AcyclicTest</a></li>
				<li><span class="field">copyright:</span> (c) 2004 by S�rgio Carvalho</li>
				<li><span class="field">author:</span> S�rgio Carvalho &lt;<a href="mailto:sergio.carvalho@portugalmail.com">mailto:sergio.carvalho@portugalmail.com</a>&gt;</li>
			</ul>
		<p class="notes">
			Located in <a class="field" href="_Structures_Graph_Manipulator_TopologicalSorter_php.html">/Structures/Graph/Manipulator/TopologicalSorter.php</a> (line <span class="field">58</span>)
		</p>
		
				
		<pre></pre>
	
			</div>
</div>



	<a name="sec-method-summary"></a>
	<div class="info-box">
		<div class="info-box-title">Method Summary</span></div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
									<span class="disabled">Methods</span> (<a href="#sec-methods">details</a>)
		</div>
		<div class="info-box-body">			
			<div class="method-summary">
								
				<div class="method-definition">
											<span class="method-result">array</span>
										<a href="#sort" title="details" class="method-name">sort</a>
											(<span class="var-type">mixed</span>&nbsp;<span class="var-name">&$graph</span>)
									</div>
							</div>
		</div>
	</div>		

	
	<a name="sec-methods"></a>
	<div class="info-box">
		<div class="info-box-title">Methods</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
													<a href="#sec-method-summary">Methods</a> (<span class="disabled">details</span>)
						
		</div>
		<div class="info-box-body">
			<A NAME='method_detail'></A>
<a name="methodsort" id="sort"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">sort</span> (line <span class="line-number">133</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">sort returns the graph's nodes, sorted by topological order.</p>
<p class="description"><p>The result is an array with  as many entries as topological levels. Each entry in this array is an array of nodes within  the given topological level.</p></p>
	<ul class="tags">
				<li><span class="field">return:</span> The graph's nodes, sorted by topological order.</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">array</span>
		<span class="method-name">
			sort
		</span>
					(<span class="var-type">mixed</span>&nbsp;<span class="var-name">&$graph</span>)
			</div>
	
		
		
	</div>
						
		</div>
	</div>
	
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>pear/Structures_Graph/docs/html/Structures_Graph/Structures_Graph.html000064400000021273150431076240022400 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Docs For Class Structures_Graph</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			
<h2 class="class-name">Class Structures_Graph</h2>

<a name="sec-description"></a>
<div class="info-box">
	<div class="info-box-title">Description</div>
	<div class="nav-bar">
					<span class="disabled">Description</span> |
															<a href="#sec-method-summary">Methods</a> (<a href="#sec-methods">details</a>)
						
			</div>
	<div class="info-box-body">
		<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">The Structures_Graph class represents a graph data structure.</p>
<p class="description"><p>A Graph is a data structure composed by a set of nodes, connected by arcs.  Graphs may either be directed or undirected. In a directed graph, arcs are  directional, and can be traveled only one way. In an undirected graph, arcs  are bidirectional, and can be traveled both ways.</p></p>
	<ul class="tags">
				<li><span class="field">copyright:</span> (c) 2004 by S�rgio Carvalho</li>
				<li><span class="field">author:</span> S�rgio Carvalho &lt;<a href="mailto:sergio.carvalho@portugalmail.com">mailto:sergio.carvalho@portugalmail.com</a>&gt;</li>
			</ul>
		<p class="notes">
			Located in <a class="field" href="_Structures_Graph_php.html">/Structures/Graph.php</a> (line <span class="field">56</span>)
		</p>
		
				
		<pre></pre>
	
			</div>
</div>



	<a name="sec-method-summary"></a>
	<div class="info-box">
		<div class="info-box-title">Method Summary</span></div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
									<span class="disabled">Methods</span> (<a href="#sec-methods">details</a>)
		</div>
		<div class="info-box-body">			
			<div class="method-summary">
								
				<div class="method-definition">
											<span class="method-result">Structures_Graph</span>
										<a href="#Structures_Graph" title="details" class="method-name">Structures_Graph</a>
											([<span class="var-type">boolean</span>&nbsp;<span class="var-name">$directed</span> = <span class="var-default">true</span>])
									</div>
								
				<div class="method-definition">
											<span class="method-result">void</span>
										<a href="#addNode" title="details" class="method-name">addNode</a>
											(<span class="var-type"><a href="../Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a></span>&nbsp;<span class="var-name">&$newNode</span>)
									</div>
								
				<div class="method-definition">
											<span class="method-result">array</span>
										<a href="#getNodes" title="details" class="method-name">&amp;getNodes</a>
										()
									</div>
								
				<div class="method-definition">
											<span class="method-result">boolean</span>
										<a href="#isDirected" title="details" class="method-name">isDirected</a>
										()
									</div>
								
				<div class="method-definition">
											<span class="method-result">void</span>
										<a href="#removeNode" title="details" class="method-name">removeNode</a>
											(<span class="var-type"><a href="../Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a></span>&nbsp;<span class="var-name">&$node</span>)
									</div>
							</div>
		</div>
	</div>		

	
	<a name="sec-methods"></a>
	<div class="info-box">
		<div class="info-box-title">Methods</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
													<a href="#sec-method-summary">Methods</a> (<span class="disabled">details</span>)
						
		</div>
		<div class="info-box-body">
			<A NAME='method_detail'></A>
<a name="methodStructures_Graph" id="Structures_Graph"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">Constructor Structures_Graph</span> (line <span class="line-number">76</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Constructor</p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">Structures_Graph</span>
		<span class="method-name">
			Structures_Graph
		</span>
					([<span class="var-type">boolean</span>&nbsp;<span class="var-name">$directed</span> = <span class="var-default">true</span>])
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type">boolean</span>
				<span class="var-name">$directed</span><span class="var-description">: Set to true if the graph is directed. Set to false if it is not directed. (Optional, defaults to true)</span>			</li>
				</ul>
		
		
	</div>
<a name="methodaddNode" id="addNode"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">addNode</span> (line <span class="line-number">102</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Add a Node to the Graph</p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">void</span>
		<span class="method-name">
			addNode
		</span>
					(<span class="var-type"><a href="../Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a></span>&nbsp;<span class="var-name">&$newNode</span>)
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type"><a href="../Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a></span>
				<span class="var-name">&$newNode</span><span class="var-description">: The node to be added.</span>			</li>
				</ul>
		
		
	</div>
<a name="methodgetNodes" id="getNodes"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">getNodes</span> (line <span class="line-number">151</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.</p>
	<ul class="tags">
				<li><span class="field">return:</span> The set of nodes in this graph</li>
				<li><span class="field">see:</span> <a href="../Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html">Structures_Graph_Manipulator_TopologicalSorter</a></li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">array</span>
		<span class="method-name">
			&amp;getNodes
		</span>
				()
			</div>
	
		
		
	</div>
<a name="methodisDirected" id="isDirected"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">isDirected</span> (line <span class="line-number">89</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Return true if a graph is directed</p>
	<ul class="tags">
				<li><span class="field">return:</span> true if the graph is directed</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">boolean</span>
		<span class="method-name">
			isDirected
		</span>
				()
			</div>
	
		
		
	</div>
<a name="methodremoveNode" id="removeNode"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">removeNode</span> (line <span class="line-number">138</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Remove a Node from the Graph</p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
				<li><span class="field">todo:</span> This is unimplemented</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">void</span>
		<span class="method-name">
			removeNode
		</span>
					(<span class="var-type"><a href="../Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a></span>&nbsp;<span class="var-name">&$node</span>)
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type"><a href="../Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a></span>
				<span class="var-name">&$node</span><span class="var-description">: The node to be removed from the graph</span>			</li>
				</ul>
		
		
	</div>
						
		</div>
	</div>
	
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>pear/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html000064400000007462150431076240030254 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Docs for page AcyclicTest.php</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			
<h2 class="file-name">/Structures/Graph/Manipulator/AcyclicTest.php</h2>

<a name="sec-description"></a>
<div class="info-box">
	<div class="info-box-title">Description</div>
	<div class="nav-bar">
					<span class="disabled">Description</span> |
							<a href="#sec-classes">Classes</a>
			|							<a href="#sec-includes">Includes</a>
												</div>
	<div class="info-box-body">	
		<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">This file contains the definition of the Structures_Graph_Manipulator_AcyclicTest graph manipulator.</p>
	<ul class="tags">
				<li><span class="field">see:</span> <a href="../Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html">Structures_Graph_Manipulator_AcyclicTest</a></li>
			</ul>
		
			</div>
</div>
		
	<a name="sec-classes"></a>	
	<div class="info-box">
		<div class="info-box-title">Classes</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
			<span class="disabled">Classes</span>
			|							<a href="#sec-includes">Includes</a>
																		</div>
		<div class="info-box-body">	
			<table cellpadding="2" cellspacing="0" class="class-table">
				<tr>
					<th class="class-table-header">Class</th>
					<th class="class-table-header">Description</th>
				</tr>
								<tr>
					<td style="padding-right: 2em; vertical-align: top">
						<a href="../Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html">Structures_Graph_Manipulator_AcyclicTest</a>
					</td>
					<td>
											The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator  which tests whether a graph contains a cycle.
										</td>
				</tr>
							</table>
		</div>
	</div>

	<a name="sec-includes"></a>	
	<div class="info-box">
		<div class="info-box-title">Includes</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
							<a href="#sec-classes">Classes</a>
				|						<span class="disabled">Includes</span>
														</div>
		<div class="info-box-body">	
			<a name="_PEAR_php"><!-- --></a>
<div class="oddrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name">'PEAR.php'</span>)
			(line <span class="line-number">35</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
<a name="_Structures/Graph_php"><!-- --></a>
<div class="evenrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name"><a href="../Structures_Graph/_Structures_Graph_php.html">'Structures/Graph.php'</a></span>)
			(line <span class="line-number">37</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
<a name="_Structures/Graph/Node_php"><!-- --></a>
<div class="oddrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name"><a href="../Structures_Graph/_Structures_Graph_Node_php.html">'Structures/Graph/Node.php'</a></span>)
			(line <span class="line-number">39</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
		</div>
	</div>
	
	
	
	
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>pear/Structures_Graph/docs/html/Structures_Graph/tutorial_Structures_Graph.pkg.html000064400000011106150431076250025076 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Structures_Graph Tutorial</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			

<div><a name="package.database.structures_graph.tutorial"></a><div class="ref-title-box"><h1 class="ref-title">Structures_Graph Tutorial</h1>
  <h2 class="ref-purpose">A first tour of graph datastructure manipulation</h2></div>
 <span><a name="package.database.structures_graph.tutorial.intro"></a><h2 class="title">Introduction</h2><p>Structures_Graph is a package for creating and manipulating graph datastructures. A graph is a set of objects, called nodes, connected by arcs. When used as a datastructure, usually nodes contain data, and arcs represent relationships between nodes. When arcs have a direction, and can be travelled only one way, graphs are said to be directed. When arcs have no direction, and can always be travelled both ways, graphs are said to be non directed.</p>
  <p>Structures_Graph provides an object oriented API to create and directly query a graph, as well as a set of Manipulator classes to extract information from the graph.</p></span>
 <span><a name="package.database.structures_graph.tutorial.creation"></a><h2 class="title">Creating a Graph</h2><p>Creating a graph is done using the simple constructor:
   <pre class="listing"><pre>
require_once 'Structures/Graph.php';

$directedGraph =&amp; new Structures_Graph(true);
$nonDirectedGraph =&amp; new Structures_Graph(false);
    </pre></pre>
   and passing the constructor a flag telling it whether the graph should be directed. A directed graph will always be directed during its lifetime. It's a permanent characteristic.</p>
  <p>To fill out the graph, we'll need to create some nodes, and then call Graph::addNode.
   <pre class="listing"><pre>
require_once 'Structures/Graph/Node.php';

$nodeOne =&amp; new Structures_Graph_Node();
$nodeTwo =&amp; new Structures_Graph_Node();
$nodeThree =&amp; new Structures_Graph_Node();

$directedGraph-&gt;addNode(&amp;$nodeOne);
$directedGraph-&gt;addNode(&amp;$nodeTwo);
$directedGraph-&gt;addNode(&amp;$nodeThree);
    </pre></pre>
   and then setup the arcs:
   <pre class="listing"><pre>
$nodeOne-&gt;connectTo($nodeTwo);
$nodeOne-&gt;connectTo($nodeThree);
    </pre></pre>
   Note that arcs can only be created after the nodes have been inserted into the graph.</p></span>
 <span><a name="package.database.structures_graph.tutorial.nodesanddata"></a><h2 class="title">Associating Data</h2><p>Graphs are only useful as datastructures if they can hold data. Structure_Graph stores data in nodes. Each node contains a setter and a getter for its data.
   <pre class="listing"><pre>
$nodeOne-&gt;setData(&quot;Node One's Data is a String&quot;);
$nodeTwo-&gt;setData(1976);
$nodeThree-&gt;setData('Some other string');

print(&quot;NodeTwo's Data is an integer: &quot; . $nodeTwo-&gt;getData());
    </pre></pre></p>
  <p>Structure_Graph nodes can also store metadata, alongside with the main data. Metadata differs from regular data just because it is stored under a key, making it possible to store more than one data reference per node. The metadata getter and setter need the key to perform the operation:
   <pre class="listing"><pre>
$nodeOne-&gt;setMetadata('example key', &quot;Node One's Sample Metadata&quot;);
print(&quot;Metadata stored under key 'example key' in node one: &quot; . $nodeOne-&gt;getMetadata('example key'));
$nodeOne-&gt;unsetMetadata('example key');
    </pre></pre></p></span>
 <span><a name="package.database.structures_graph.tutorial.querying"></a><h2 class="title">Querying a Graph</h2><p>Structures_Graph provides for basic querying of the graph:
   <pre class="listing"><pre>
// Nodes are able to calculate their indegree and outdegree
print(&quot;NodeOne's inDegree: &quot; . $nodeOne-&gt;inDegree());
print(&quot;NodeOne's outDegree: &quot; . $nodeOne-&gt;outDegree());

// and naturally, nodes can report on their arcs
$arcs = $nodeOne-&gt;getNeighbours();
for ($i=0;$i&lt;sizeof($arcs);$i++) {
    print(&quot;NodeOne has an arc to &quot; . $arcs[$i]-&gt;getData());
}
    </pre></pre></p></span></div>


	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html000064400000010525150431076260031435 0ustar00pear<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Docs for page TopologicalSorter.php</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			
<h2 class="file-name">/Structures/Graph/Manipulator/TopologicalSorter.php</h2>

<a name="sec-description"></a>
<div class="info-box">
	<div class="info-box-title">Description</div>
	<div class="nav-bar">
					<span class="disabled">Description</span> |
							<a href="#sec-classes">Classes</a>
			|							<a href="#sec-includes">Includes</a>
												</div>
	<div class="info-box-body">	
		<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">This file contains the definition of the Structures_Graph_Manipulator_TopologicalSorter class.</p>
	<ul class="tags">
				<li><span class="field">see:</span> <a href="../Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html">Structures_Graph_Manipulator_TopologicalSorter</a></li>
			</ul>
		
			</div>
</div>
		
	<a name="sec-classes"></a>	
	<div class="info-box">
		<div class="info-box-title">Classes</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
			<span class="disabled">Classes</span>
			|							<a href="#sec-includes">Includes</a>
																		</div>
		<div class="info-box-body">	
			<table cellpadding="2" cellspacing="0" class="class-table">
				<tr>
					<th class="class-table-header">Class</th>
					<th class="class-table-header">Description</th>
				</tr>
								<tr>
					<td style="padding-right: 2em; vertical-align: top">
						<a href="../Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html">Structures_Graph_Manipulator_TopologicalSorter</a>
					</td>
					<td>
											The Structures_Graph_Manipulator_TopologicalSorter is a manipulator  which is able to return the set of nodes in a graph, sorted by topological  order.
										</td>
				</tr>
							</table>
		</div>
	</div>

	<a name="sec-includes"></a>	
	<div class="info-box">
		<div class="info-box-title">Includes</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
							<a href="#sec-classes">Classes</a>
				|						<span class="disabled">Includes</span>
														</div>
		<div class="info-box-body">	
			<a name="_PEAR_php"><!-- --></a>
<div class="oddrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name">'PEAR.php'</span>)
			(line <span class="line-number">35</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
<a name="_Structures/Graph_php"><!-- --></a>
<div class="evenrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name"><a href="../Structures_Graph/_Structures_Graph_php.html">'Structures/Graph.php'</a></span>)
			(line <span class="line-number">37</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
<a name="_Structures/Graph/Node_php"><!-- --></a>
<div class="oddrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name"><a href="../Structures_Graph/_Structures_Graph_Node_php.html">'Structures/Graph/Node.php'</a></span>)
			(line <span class="line-number">39</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
<a name="_Structures/Graph/Manipulator/AcyclicTest_php"><!-- --></a>
<div class="evenrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name"><a href="../Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html">'Structures/Graph/Manipulator/AcyclicTest.php'</a></span>)
			(line <span class="line-number">41</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
		</div>
	</div>
	
	
	
	
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>pear/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html000064400000007410150431076270027242 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Docs For Class Structures_Graph_Manipulator_AcyclicTest</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			
<h2 class="class-name">Class Structures_Graph_Manipulator_AcyclicTest</h2>

<a name="sec-description"></a>
<div class="info-box">
	<div class="info-box-title">Description</div>
	<div class="nav-bar">
					<span class="disabled">Description</span> |
															<a href="#sec-method-summary">Methods</a> (<a href="#sec-methods">details</a>)
						
			</div>
	<div class="info-box-body">
		<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator  which tests whether a graph contains a cycle.</p>
<p class="description"><p>The definition of an acyclic graph used in this manipulator is that of a  DAG. The graph must be directed, or else it is considered cyclic, even when  there are no arcs.</p></p>
	<ul class="tags">
				<li><span class="field">copyright:</span> (c) 2004 by S�rgio Carvalho</li>
				<li><span class="field">author:</span> S�rgio Carvalho &lt;<a href="mailto:sergio.carvalho@portugalmail.com">mailto:sergio.carvalho@portugalmail.com</a>&gt;</li>
			</ul>
		<p class="notes">
			Located in <a class="field" href="_Structures_Graph_Manipulator_AcyclicTest_php.html">/Structures/Graph/Manipulator/AcyclicTest.php</a> (line <span class="field">55</span>)
		</p>
		
				
		<pre></pre>
	
			</div>
</div>



	<a name="sec-method-summary"></a>
	<div class="info-box">
		<div class="info-box-title">Method Summary</span></div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
									<span class="disabled">Methods</span> (<a href="#sec-methods">details</a>)
		</div>
		<div class="info-box-body">			
			<div class="method-summary">
								
				<div class="method-definition">
											<span class="method-result">boolean</span>
										<a href="#isAcyclic" title="details" class="method-name">isAcyclic</a>
											(<span class="var-type">mixed</span>&nbsp;<span class="var-name">&$graph</span>)
									</div>
							</div>
		</div>
	</div>		

	
	<a name="sec-methods"></a>
	<div class="info-box">
		<div class="info-box-title">Methods</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
													<a href="#sec-method-summary">Methods</a> (<span class="disabled">details</span>)
						
		</div>
		<div class="info-box-body">
			<A NAME='method_detail'></A>
<a name="methodisAcyclic" id="isAcyclic"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">isAcyclic</span> (line <span class="line-number">126</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">isAcyclic returns true if a graph contains no cycles, false otherwise.</p>
	<ul class="tags">
				<li><span class="field">return:</span> true iff graph is acyclic</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">boolean</span>
		<span class="method-name">
			isAcyclic
		</span>
					(<span class="var-type">mixed</span>&nbsp;<span class="var-name">&$graph</span>)
			</div>
	
		
		
	</div>
						
		</div>
	</div>
	
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>pear/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_Node_php.html000064400000006356150431076300024355 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Docs for page Node.php</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			
<h2 class="file-name">/Structures/Graph/Node.php</h2>

<a name="sec-description"></a>
<div class="info-box">
	<div class="info-box-title">Description</div>
	<div class="nav-bar">
					<span class="disabled">Description</span> |
							<a href="#sec-classes">Classes</a>
			|							<a href="#sec-includes">Includes</a>
												</div>
	<div class="info-box-body">	
		<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">This file contains the definition of the Structures_Graph_Node class</p>
	<ul class="tags">
				<li><span class="field">see:</span> <a href="../Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a></li>
			</ul>
		
			</div>
</div>
		
	<a name="sec-classes"></a>	
	<div class="info-box">
		<div class="info-box-title">Classes</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
			<span class="disabled">Classes</span>
			|							<a href="#sec-includes">Includes</a>
																		</div>
		<div class="info-box-body">	
			<table cellpadding="2" cellspacing="0" class="class-table">
				<tr>
					<th class="class-table-header">Class</th>
					<th class="class-table-header">Description</th>
				</tr>
								<tr>
					<td style="padding-right: 2em; vertical-align: top">
						<a href="../Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a>
					</td>
					<td>
											The Structures_Graph_Node class represents a Node that can be member of a  graph node set.
										</td>
				</tr>
							</table>
		</div>
	</div>

	<a name="sec-includes"></a>	
	<div class="info-box">
		<div class="info-box-title">Includes</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
							<a href="#sec-classes">Classes</a>
				|						<span class="disabled">Includes</span>
														</div>
		<div class="info-box-body">	
			<a name="_PEAR_php"><!-- --></a>
<div class="evenrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name">'PEAR.php'</span>)
			(line <span class="line-number">35</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
<a name="_Structures/Graph_php"><!-- --></a>
<div class="oddrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name"><a href="../Structures_Graph/_Structures_Graph_php.html">'Structures/Graph.php'</a></span>)
			(line <span class="line-number">37</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
	
</div>
		</div>
	</div>
	
	
	
	
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>pear/Structures_Graph/docs/html/Structures_Graph/_Structures_Graph_php.html000064400000010207150431076310023377 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Docs for page Graph.php</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			
<h2 class="file-name">/Structures/Graph.php</h2>

<a name="sec-description"></a>
<div class="info-box">
	<div class="info-box-title">Description</div>
	<div class="nav-bar">
					<span class="disabled">Description</span> |
							<a href="#sec-classes">Classes</a>
			|							<a href="#sec-includes">Includes</a>
			|							<a href="#sec-constants">Constants</a>
										</div>
	<div class="info-box-body">	
		<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">The Graph.php file contains the definition of the Structures_Graph class</p>
	<ul class="tags">
				<li><span class="field">see:</span> <a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></li>
			</ul>
		
			</div>
</div>
		
	<a name="sec-classes"></a>	
	<div class="info-box">
		<div class="info-box-title">Classes</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
			<span class="disabled">Classes</span>
			|							<a href="#sec-includes">Includes</a>
				|										<a href="#sec-constants">Constants</a>
															</div>
		<div class="info-box-body">	
			<table cellpadding="2" cellspacing="0" class="class-table">
				<tr>
					<th class="class-table-header">Class</th>
					<th class="class-table-header">Description</th>
				</tr>
								<tr>
					<td style="padding-right: 2em; vertical-align: top">
						<a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a>
					</td>
					<td>
											The Structures_Graph class represents a graph data structure.
										</td>
				</tr>
							</table>
		</div>
	</div>

	<a name="sec-includes"></a>	
	<div class="info-box">
		<div class="info-box-title">Includes</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
							<a href="#sec-classes">Classes</a>
				|						<span class="disabled">Includes</span>
			|							<a href="#sec-constants">Constants</a>
															</div>
		<div class="info-box-body">	
			<a name="_Structures/Graph/Node_php"><!-- --></a>
<div class="oddrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name"><a href="../Structures_Graph/_Structures_Graph_Node_php.html">'Structures/Graph/Node.php'</a></span>)
			(line <span class="line-number">37</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Graph Node</p>
	
</div>
<a name="_PEAR_php"><!-- --></a>
<div class="evenrow">
	
	<div>
		<span class="include-title">
			<span class="include-type">require_once</span>
			(<span class="include-name">'PEAR.php'</span>)
			(line <span class="line-number">35</span>)
		</span>
	</div>

	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">PEAR base classes</p>
	
</div>
		</div>
	</div>
	
	<a name="sec-constants"></a>	
	<div class="info-box">
		<div class="info-box-title">Constants</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
							<a href="#sec-classes">Classes</a>
				|										<a href="#sec-includes">Includes</a>
				|						<span class="disabled">Constants</span>
											</div>
		<div class="info-box-body">	
			<a name="defineSTRUCTURES_GRAPH_ERROR_GENERIC"><!-- --></a>
<div class="oddrow">
	
	<div>
		<span class="const-title">
			<span class="const-name">STRUCTURES_GRAPH_ERROR_GENERIC</span> = 100
			(line <span class="line-number">40</span>)
		</span>
	</div>
	
	<!-- ========== Info from phpDoc block ========= -->
	
		
</div>
		</div>
	</div>
	
	
	
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:28 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>pear/Structures_Graph/docs/html/Structures_Graph/Structures_Graph_Node.html000064400000050071150431076320023342 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Docs For Class Structures_Graph_Node</title>
			<link rel="stylesheet" href="../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
			<div class="page-body">			
<h2 class="class-name">Class Structures_Graph_Node</h2>

<a name="sec-description"></a>
<div class="info-box">
	<div class="info-box-title">Description</div>
	<div class="nav-bar">
					<span class="disabled">Description</span> |
															<a href="#sec-method-summary">Methods</a> (<a href="#sec-methods">details</a>)
						
			</div>
	<div class="info-box-body">
		<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">The Structures_Graph_Node class represents a Node that can be member of a  graph node set.</p>
<p class="description"><p>A graph node can contain data. Under this API, the node contains default data,  and key index data. It behaves, thus, both as a regular data node, and as a  dictionary (or associative array) node.</p><p>Regular data is accessed via getData and setData. Key indexed data is accessed  via getMetadata and setMetadata.</p></p>
	<ul class="tags">
				<li><span class="field">copyright:</span> (c) 2004 by S�rgio Carvalho</li>
				<li><span class="field">author:</span> S�rgio Carvalho &lt;<a href="mailto:sergio.carvalho@portugalmail.com">mailto:sergio.carvalho@portugalmail.com</a>&gt;</li>
			</ul>
		<p class="notes">
			Located in <a class="field" href="_Structures_Graph_Node_php.html">/Structures/Graph/Node.php</a> (line <span class="field">57</span>)
		</p>
		
				
		<pre></pre>
	
			</div>
</div>



	<a name="sec-method-summary"></a>
	<div class="info-box">
		<div class="info-box-title">Method Summary</span></div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
									<span class="disabled">Methods</span> (<a href="#sec-methods">details</a>)
		</div>
		<div class="info-box-body">			
			<div class="method-summary">
								
				<div class="method-definition">
											<span class="method-result">Structures_Graph_Node</span>
										<a href="#Structures_Graph_Node" title="details" class="method-name">Structures_Graph_Node</a>
										()
									</div>
								
				<div class="method-definition">
											<span class="method-result">boolean</span>
										<a href="#connectsTo" title="details" class="method-name">connectsTo</a>
											(<span class="var-type">mixed</span>&nbsp;<span class="var-name">&$target</span>)
									</div>
								
				<div class="method-definition">
											<span class="method-result">void</span>
										<a href="#connectTo" title="details" class="method-name">connectTo</a>
											(<span class="var-type"><a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></span>&nbsp;<span class="var-name">&$destinationNode</span>)
									</div>
								
				<div class="method-definition">
											<span class="method-result">mixed</span>
										<a href="#getData" title="details" class="method-name">&amp;getData</a>
										()
									</div>
								
				<div class="method-definition">
											<span class="method-result"><a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></span>
										<a href="#getGraph" title="details" class="method-name">&amp;getGraph</a>
										()
									</div>
								
				<div class="method-definition">
											<span class="method-result">mixed</span>
										<a href="#getMetadata" title="details" class="method-name">&amp;getMetadata</a>
											(<span class="var-type">string</span>&nbsp;<span class="var-name">$key</span>, [<span class="var-type">boolean</span>&nbsp;<span class="var-name">$nullIfNonexistent</span> = <span class="var-default">false</span>])
									</div>
								
				<div class="method-definition">
											<span class="method-result">array</span>
										<a href="#getNeighbours" title="details" class="method-name">getNeighbours</a>
										()
									</div>
								
				<div class="method-definition">
											<span class="method-result">integer</span>
										<a href="#inDegree" title="details" class="method-name">inDegree</a>
										()
									</div>
								
				<div class="method-definition">
											<span class="method-result">boolean</span>
										<a href="#metadataKeyExists" title="details" class="method-name">metadataKeyExists</a>
											(<span class="var-type">string</span>&nbsp;<span class="var-name">$key</span>)
									</div>
								
				<div class="method-definition">
											<span class="method-result">integer</span>
										<a href="#outDegree" title="details" class="method-name">outDegree</a>
										()
									</div>
								
				<div class="method-definition">
											<span class="method-result">mixed</span>
										<a href="#setData" title="details" class="method-name">setData</a>
											(<span class="var-type">mixed</span>&nbsp;<span class="var-name">$data</span>)
									</div>
								
				<div class="method-definition">
											<span class="method-result">void</span>
										<a href="#setGraph" title="details" class="method-name">setGraph</a>
											(<span class="var-type"><a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></span>&nbsp;<span class="var-name">&$graph</span>)
									</div>
								
				<div class="method-definition">
											<span class="method-result">void</span>
										<a href="#setMetadata" title="details" class="method-name">setMetadata</a>
											(<span class="var-type">string</span>&nbsp;<span class="var-name">$key</span>, <span class="var-type">mixed</span>&nbsp;<span class="var-name">$data</span>)
									</div>
								
				<div class="method-definition">
											<span class="method-result">void</span>
										<a href="#unsetMetadata" title="details" class="method-name">unsetMetadata</a>
											(<span class="var-type">string</span>&nbsp;<span class="var-name">$key</span>)
									</div>
							</div>
		</div>
	</div>		

	
	<a name="sec-methods"></a>
	<div class="info-box">
		<div class="info-box-title">Methods</div>
		<div class="nav-bar">
			<a href="#sec-description">Description</a> |
													<a href="#sec-method-summary">Methods</a> (<span class="disabled">details</span>)
						
		</div>
		<div class="info-box-body">
			<A NAME='method_detail'></A>
<a name="methodStructures_Graph_Node" id="Structures_Graph_Node"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">Constructor Structures_Graph_Node</span> (line <span class="line-number">78</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Constructor</p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">Structures_Graph_Node</span>
		<span class="method-name">
			Structures_Graph_Node
		</span>
				()
			</div>
	
		
		
	</div>
<a name="methodconnectsTo" id="connectsTo"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">connectsTo</span> (line <span class="line-number">275</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Test wether this node has an arc to the target node</p>
	<ul class="tags">
				<li><span class="field">return:</span> True if the two nodes are connected</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">boolean</span>
		<span class="method-name">
			connectsTo
		</span>
					(<span class="var-type">mixed</span>&nbsp;<span class="var-name">&$target</span>)
			</div>
	
		
		
	</div>
<a name="methodconnectTo" id="connectTo"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">connectTo</span> (line <span class="line-number">236</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Connect this node to another one.</p>
<p class="description"><p>If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created.</p></p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">void</span>
		<span class="method-name">
			connectTo
		</span>
					(<span class="var-type"><a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></span>&nbsp;<span class="var-name">&$destinationNode</span>)
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type"><a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></span>
				<span class="var-name">&$destinationNode</span><span class="var-description">: Node to connect to</span>			</li>
				</ul>
		
		
	</div>
<a name="methodgetData" id="getData"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">getData</span> (line <span class="line-number">119</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Node data getter.</p>
<p class="description"><p>Each graph node can contain a reference to one variable. This is the getter for that reference.</p></p>
	<ul class="tags">
				<li><span class="field">return:</span> Data stored in node</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">mixed</span>
		<span class="method-name">
			&amp;getData
		</span>
				()
			</div>
	
		
		
	</div>
<a name="methodgetGraph" id="getGraph"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">getGraph</span> (line <span class="line-number">90</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Node graph getter</p>
	<ul class="tags">
				<li><span class="field">return:</span> Graph where node is stored</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result"><a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></span>
		<span class="method-name">
			&amp;getGraph
		</span>
				()
			</div>
	
		
		
	</div>
<a name="methodgetMetadata" id="getMetadata"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">getMetadata</span> (line <span class="line-number">171</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Node metadata getter</p>
<p class="description"><p>Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an  associative array or in a dictionary. This method gets the data under the given key. If the key does  not exist, an error will be thrown, so testing using metadataKeyExists might be needed.</p></p>
	<ul class="tags">
				<li><span class="field">return:</span> Metadata Data stored in node under given key</li>
				<li><span class="field">access:</span> public</li>
				<li><span class="field">see:</span> <a href="../Structures_Graph/Structures_Graph_Node.html#methodmetadataKeyExists">Structures_Graph_Node::metadataKeyExists()</a></li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">mixed</span>
		<span class="method-name">
			&amp;getMetadata
		</span>
					(<span class="var-type">string</span>&nbsp;<span class="var-name">$key</span>, [<span class="var-type">boolean</span>&nbsp;<span class="var-name">$nullIfNonexistent</span> = <span class="var-default">false</span>])
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type">string</span>
				<span class="var-name">$key</span><span class="var-description">: Key</span>			</li>
					<li>
				<span class="var-type">boolean</span>
				<span class="var-name">$nullIfNonexistent</span><span class="var-description">: nullIfNonexistent (defaults to false).</span>			</li>
				</ul>
		
		
	</div>
<a name="methodgetNeighbours" id="getNeighbours"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">getNeighbours</span> (line <span class="line-number">262</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Return nodes connected to this one.</p>
	<ul class="tags">
				<li><span class="field">return:</span> Array of nodes</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">array</span>
		<span class="method-name">
			getNeighbours
		</span>
				()
			</div>
	
		
		
	</div>
<a name="methodinDegree" id="inDegree"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">inDegree</span> (line <span class="line-number">309</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Calculate the in degree of the node.</p>
<p class="description"><p>The indegree for a node is the number of arcs entering the node. For non directed graphs,  the indegree is equal to the outdegree.</p></p>
	<ul class="tags">
				<li><span class="field">return:</span> In degree of the node</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">integer</span>
		<span class="method-name">
			inDegree
		</span>
				()
			</div>
	
		
		
	</div>
<a name="methodmetadataKeyExists" id="metadataKeyExists"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">metadataKeyExists</span> (line <span class="line-number">151</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Test for existence of metadata under a given key.</p>
<p class="description"><p>Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an  associative array or in a dictionary. This method tests whether a given metadata key exists for this node.</p></p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">boolean</span>
		<span class="method-name">
			metadataKeyExists
		</span>
					(<span class="var-type">string</span>&nbsp;<span class="var-name">$key</span>)
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type">string</span>
				<span class="var-name">$key</span><span class="var-description">: Key to test</span>			</li>
				</ul>
		
		
	</div>
<a name="methodoutDegree" id="outDegree"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">outDegree</span> (line <span class="line-number">333</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Calculate the out degree of the node.</p>
<p class="description"><p>The outdegree for a node is the number of arcs exiting the node. For non directed graphs,  the outdegree is always equal to the indegree.</p></p>
	<ul class="tags">
				<li><span class="field">return:</span> Out degree of the node</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">integer</span>
		<span class="method-name">
			outDegree
		</span>
				()
			</div>
	
		
		
	</div>
<a name="methodsetData" id="setData"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">setData</span> (line <span class="line-number">134</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Node data setter</p>
<p class="description"><p>Each graph node can contain a reference to one variable. This is the setter for that reference.</p></p>
	<ul class="tags">
				<li><span class="field">return:</span> Data to store in node</li>
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">mixed</span>
		<span class="method-name">
			setData
		</span>
					(<span class="var-type">mixed</span>&nbsp;<span class="var-name">$data</span>)
			</div>
	
		
		
	</div>
<a name="methodsetGraph" id="setGraph"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">setGraph</span> (line <span class="line-number">104</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Node graph setter. This method should not be called directly. Use Graph::addNode instead.</p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
				<li><span class="field">see:</span> <a href="../Structures_Graph/Structures_Graph.html#methodaddNode">Structures_Graph::addNode()</a></li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">void</span>
		<span class="method-name">
			setGraph
		</span>
					(<span class="var-type"><a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></span>&nbsp;<span class="var-name">&$graph</span>)
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type"><a href="../Structures_Graph/Structures_Graph.html">Structures_Graph</a></span>
				<span class="var-name">&$graph</span><span class="var-description">: Set the graph for this node.</span>			</li>
				</ul>
		
		
	</div>
<a name="methodsetMetadata" id="setMetadata"><!-- --></a>
<div class="evenrow">
	
	<div class="method-header">
		<span class="method-title">setMetadata</span> (line <span class="line-number">214</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Node metadata setter</p>
<p class="description"><p>Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an  associative array or in a dictionary. This method stores data under the given key. If the key already exists,  previously stored data is discarded.</p></p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">void</span>
		<span class="method-name">
			setMetadata
		</span>
					(<span class="var-type">string</span>&nbsp;<span class="var-name">$key</span>, <span class="var-type">mixed</span>&nbsp;<span class="var-name">$data</span>)
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type">string</span>
				<span class="var-name">$key</span><span class="var-description">: Key</span>			</li>
					<li>
				<span class="var-type">mixed</span>
				<span class="var-name">$data</span><span class="var-description">: Data</span>			</li>
				</ul>
		
		
	</div>
<a name="methodunsetMetadata" id="unsetMetadata"><!-- --></a>
<div class="oddrow">
	
	<div class="method-header">
		<span class="method-title">unsetMetadata</span> (line <span class="line-number">196</span>)
	</div> 
	
	<!-- ========== Info from phpDoc block ========= -->
<p class="short-description">Delete metadata by key</p>
<p class="description"><p>Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an  associative array or in a dictionary. This method removes any data that might be stored under the provided key.  If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence.</p></p>
	<ul class="tags">
				<li><span class="field">access:</span> public</li>
			</ul>
	
	<div class="method-signature">
		<span class="method-result">void</span>
		<span class="method-name">
			unsetMetadata
		</span>
					(<span class="var-type">string</span>&nbsp;<span class="var-name">$key</span>)
			</div>
	
			<ul class="parameters">
					<li>
				<span class="var-type">string</span>
				<span class="var-name">$key</span><span class="var-description">: Key</span>			</li>
				</ul>
		
		
	</div>
						
		</div>
	</div>
	
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</div></body>
</html>pear/Structures_Graph/docs/html/media/banner.css000064400000000611150431076330015731 0ustar00body 
{ 
	background-color: #CCCCFF; 
	margin: 0px; 
	padding: 0px;
}

/* Banner (top bar) classes */

.banner {  }

.banner-menu 
{ 
	clear: both;
	padding: .5em;
	border-top: 2px solid #6666AA;	
}

.banner-title 
{ 
	text-align: right; 
	font-size: 20pt; 
	font-weight: bold; 
	margin: .2em;
}

.package-selector 
{ 
	background-color: #AAAADD; 
	border: 1px solid black; 
	color: yellow;
}
pear/Structures_Graph/docs/html/media/stylesheet.css000064400000011604150431076330016661 0ustar00a { color: #336699; text-decoration: none; }
a:hover { color: #6699CC; text-decoration: underline; }
a:active { color: #6699CC; text-decoration: underline; }

body { background : #FFFFFF; }
body, table { font-family: Georgia, Times New Roman, Times, serif; font-size: 10pt }
p, li { line-height: 140% }
a img { border: 0px; }
dd { margin-left: 0px; padding-left: 1em; }

/* Page layout/boxes */

.info-box {}
.info-box-title { margin: 1em 0em 0em 0em; padding: .25em; font-weight: normal; font-size: 14pt; border: 2px solid #999999; background-color: #CCCCFF }
.info-box-body { border: 1px solid #999999; padding: .5em; }
.nav-bar { font-size: 8pt; white-space: nowrap; text-align: right; padding: .2em; margin: 0em 0em 1em 0em; }

.oddrow { background-color: #F8F8F8; border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em}
.evenrow { border: 1px solid #AAAAAA; padding: .5em; margin-bottom: 1em}

.page-body { max-width: 800px; margin: auto; }
.tree dl { margin: 0px }

/* Index formatting classes */

.index-item-body { margin-top: .5em; margin-bottom: .5em}
.index-item-description { margin-top: .25em }
.index-item-details { font-weight: normal; font-style: italic; font-size: 8pt }
.index-letter-section { background-color: #EEEEEE; border: 1px dotted #999999; padding: .5em; margin-bottom: 1em}
.index-letter-title { font-size: 12pt; font-weight: bold }
.index-letter-menu { text-align: center; margin: 1em }
.index-letter { font-size: 12pt }

/* Docbook classes */

.description {}
.short-description { font-weight: bold; color: #666666; }
.tags {	padding-left: 0em; margin-left: 3em; color: #666666; list-style-type: square; }
.parameters {	padding-left: 0em; margin-left: 3em; font-style: italic; list-style-type: square; }
.redefinitions { font-size: 8pt; padding-left: 0em; margin-left: 2em; }
.package {  }
.package-title { font-weight: bold; font-size: 14pt; border-bottom: 1px solid black }
.package-details { font-size: 85%; }
.sub-package { font-weight: bold; font-size: 120% }
.tutorial { border-width: thin; border-color: #0066ff }
.tutorial-nav-box { width: 100%; border: 1px solid #999999; background-color: #F8F8F8; }
.nav-button-disabled { color: #999999; }
.nav-button:active, 
.nav-button:focus, 
.nav-button:hover { background-color: #DDDDDD; outline: 1px solid #999999; text-decoration: none }
.folder-title { font-style: italic }

/* Generic formatting */

.field { font-weight: bold; }
.detail { font-size: 8pt; }
.notes { font-style: italic; font-size: 8pt; }
.separator { background-color: #999999; height: 2px; }
.warning {  color: #FF6600; }
.disabled { font-style: italic; color: #999999; }

/* Code elements */

.line-number {  }

.class-table { width: 100%; }
.class-table-header { border-bottom: 1px dotted #666666; text-align: left}
.class-name { color: #000000; font-weight: bold; }

.method-summary { padding-left: 1em; font-size: 8pt }
.method-header { }
.method-definition { margin-bottom: .3em }
.method-title { font-weight: bold; }
.method-name { font-weight: bold; }
.method-signature { font-size: 85%; color: #666666; margin: .5em 0em }
.method-result { font-style: italic; }

.var-summary { padding-left: 1em; font-size: 8pt; }
.var-header { }
.var-title { margin-bottom: .3em }
.var-type { font-style: italic; }
.var-name { font-weight: bold; }
.var-default {}
.var-description { font-weight: normal; color: #000000; }

.include-title {  }
.include-type { font-style: italic; }
.include-name { font-weight: bold; }

.const-title {  }
.const-name { font-weight: bold; }

/* Syntax highlighting */

.src-code {  border: 1px solid #336699; padding: 1em; background-color: #EEEEEE; }

.src-comm { color: green; }
.src-id {  }
.src-inc { color: #0000FF; }
.src-key { color: #0000FF; }
.src-num { color: #CC0000; }
.src-str { color: #66cccc; }
.src-sym { font-weight: bold; }
.src-var { }

.src-php { font-weight: bold; }

.src-doc { color: #009999 }
.src-doc-close-template { color: #0000FF }
.src-doc-coretag { color: #0099FF; font-weight: bold }
.src-doc-inlinetag { color: #0099FF }
.src-doc-internal { color: #6699cc }
.src-doc-tag { color: #0080CC }
.src-doc-template { color: #0000FF }
.src-doc-type { font-style: italic }
.src-doc-var { font-style: italic }

/* tutorial */

.authors {  }
.author { font-style: italic; font-weight: bold }
.author-blurb { margin: .5em 0em .5em 2em; font-size: 85%; font-weight: normal; font-style: normal }
.example { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em }
.listing { border: 1px dashed #999999; background-color: #EEEEEE; padding: .5em; white-space: nowrap }
.release-info { font-size: 85%; font-style: italic; margin: 1em 0em }
.ref-title-box {  }
.ref-title {  }
.ref-purpose { font-style: italic; color: #666666 }
.ref-synopsis {  }
.title { font-weight: bold; margin: 1em 0em 0em 0em; padding: .25em; border: 2px solid #999999; background-color: #CCCCFF  }
.cmd-synopsis { margin: 1em 0em }
.cmd-title { font-weight: bold }
.toc { margin-left: 2em; padding-left: 0em }

pear/Structures_Graph/docs/html/todolist.html000064400000001554150431076340015432 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>Todo List</title>
			<link rel="stylesheet" href="media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
						<div align="center"><h1>Todo List</h1></div>
<h2>Structures_Graph</h2>
<h3><a href="Structures_Graph/Structures_Graph.html#methodremoveNode">Structures_Graph::removeNode()</a></h3>
<ul>
    <li>This is unimplemented</li>
</ul>
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</body>
</html>pear/Structures_Graph/docs/html/errors.html000064400000001325150431076350015102 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title>phpDocumentor Parser Errors and Warnings</title>
			<link rel="stylesheet" href="media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
						<a href="#Post-parsing">Post-parsing</a><br>
	<p class="notes" id="credit">
		Documentation generated on Fri, 30 Jan 2004 16:37:29 +0000 by <a href="http://www.phpdoc.org" target="_blank">phpDocumentor 1.2.3</a>
	</p>
	</body>
</html>pear/Structures_Graph/docs/html/elementindex.html000064400000036407150431076360016261 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title></title>
			<link rel="stylesheet" href="media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
						<a name="top"></a>
<h2>Full index</h2>
<h3>Package indexes</h3>
<ul>
	<li><a href="elementindex_Structures_Graph.html">Structures_Graph</a></li>
</ul>
<br />
<div class="index-letter-menu">
	<a class="index-letter" href="elementindex.html#a">a</a>
	<a class="index-letter" href="elementindex.html#c">c</a>
	<a class="index-letter" href="elementindex.html#g">g</a>
	<a class="index-letter" href="elementindex.html#i">i</a>
	<a class="index-letter" href="elementindex.html#m">m</a>
	<a class="index-letter" href="elementindex.html#n">n</a>
	<a class="index-letter" href="elementindex.html#o">o</a>
	<a class="index-letter" href="elementindex.html#r">r</a>
	<a class="index-letter" href="elementindex.html#s">s</a>
	<a class="index-letter" href="elementindex.html#t">t</a>
	<a class="index-letter" href="elementindex.html#u">u</a>
</div>

	<a name="a"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">a</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">addNode</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodaddNode">Structures_Graph::addNode()</a> in Graph.php</div>
							<div class="index-item-description">Add a Node to the Graph</div>
					</dd>
			<dt class="field">
						<span class="include-title">AcyclicTest.php</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html">AcyclicTest.php</a> in AcyclicTest.php</div>
					</dd>
		</dl>
	<a name="c"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">c</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">connectsTo</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodconnectsTo">Structures_Graph_Node::connectsTo()</a> in Node.php</div>
							<div class="index-item-description">Test wether this node has an arc to the target node</div>
					</dd>
			<dt class="field">
						<span class="method-title">connectTo</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodconnectTo">Structures_Graph_Node::connectTo()</a> in Node.php</div>
							<div class="index-item-description">Connect this node to another one.</div>
					</dd>
		</dl>
	<a name="g"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">g</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">getData</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodgetData">Structures_Graph_Node::getData()</a> in Node.php</div>
							<div class="index-item-description">Node data getter.</div>
					</dd>
			<dt class="field">
						<span class="method-title">getGraph</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodgetGraph">Structures_Graph_Node::getGraph()</a> in Node.php</div>
							<div class="index-item-description">Node graph getter</div>
					</dd>
			<dt class="field">
						<span class="method-title">getMetadata</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodgetMetadata">Structures_Graph_Node::getMetadata()</a> in Node.php</div>
							<div class="index-item-description">Node metadata getter</div>
					</dd>
			<dt class="field">
						<span class="method-title">getNeighbours</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodgetNeighbours">Structures_Graph_Node::getNeighbours()</a> in Node.php</div>
							<div class="index-item-description">Return nodes connected to this one.</div>
					</dd>
			<dt class="field">
						<span class="method-title">getNodes</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodgetNodes">Structures_Graph::getNodes()</a> in Graph.php</div>
							<div class="index-item-description">Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.</div>
					</dd>
			<dt class="field">
						<span class="include-title">Graph.php</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_php.html">Graph.php</a> in Graph.php</div>
					</dd>
		</dl>
	<a name="i"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">i</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">inDegree</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodinDegree">Structures_Graph_Node::inDegree()</a> in Node.php</div>
							<div class="index-item-description">Calculate the in degree of the node.</div>
					</dd>
			<dt class="field">
						<span class="method-title">isAcyclic</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html#methodisAcyclic">Structures_Graph_Manipulator_AcyclicTest::isAcyclic()</a> in AcyclicTest.php</div>
							<div class="index-item-description">isAcyclic returns true if a graph contains no cycles, false otherwise.</div>
					</dd>
			<dt class="field">
						<span class="method-title">isDirected</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodisDirected">Structures_Graph::isDirected()</a> in Graph.php</div>
							<div class="index-item-description">Return true if a graph is directed</div>
					</dd>
		</dl>
	<a name="m"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">m</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">metadataKeyExists</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodmetadataKeyExists">Structures_Graph_Node::metadataKeyExists()</a> in Node.php</div>
							<div class="index-item-description">Test for existence of metadata under a given key.</div>
					</dd>
		</dl>
	<a name="n"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">n</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="include-title">Node.php</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_Node_php.html">Node.php</a> in Node.php</div>
					</dd>
		</dl>
	<a name="o"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">o</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">outDegree</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodoutDegree">Structures_Graph_Node::outDegree()</a> in Node.php</div>
							<div class="index-item-description">Calculate the out degree of the node.</div>
					</dd>
		</dl>
	<a name="r"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">r</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">removeNode</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodremoveNode">Structures_Graph::removeNode()</a> in Graph.php</div>
							<div class="index-item-description">Remove a Node from the Graph</div>
					</dd>
		</dl>
	<a name="s"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">s</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">setData</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodsetData">Structures_Graph_Node::setData()</a> in Node.php</div>
							<div class="index-item-description">Node data setter</div>
					</dd>
			<dt class="field">
						<span class="method-title">setGraph</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodsetGraph">Structures_Graph_Node::setGraph()</a> in Node.php</div>
							<div class="index-item-description">Node graph setter. This method should not be called directly. Use Graph::addNode instead.</div>
					</dd>
			<dt class="field">
						<span class="method-title">setMetadata</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodsetMetadata">Structures_Graph_Node::setMetadata()</a> in Node.php</div>
							<div class="index-item-description">Node metadata setter</div>
					</dd>
			<dt class="field">
						<span class="method-title">sort</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html#methodsort">Structures_Graph_Manipulator_TopologicalSorter::sort()</a> in TopologicalSorter.php</div>
							<div class="index-item-description">sort returns the graph's nodes, sorted by topological order.</div>
					</dd>
			<dt class="field">
						Structures_Graph
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html">Structures_Graph</a> in Graph.php</div>
							<div class="index-item-description">The Structures_Graph class represents a graph data structure.</div>
					</dd>
			<dt class="field">
						<span class="method-title">Structures_Graph</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodStructures_Graph">Structures_Graph::Structures_Graph()</a> in Graph.php</div>
							<div class="index-item-description">Constructor</div>
					</dd>
			<dt class="field">
						<span class="const-title">STRUCTURES_GRAPH_ERROR_GENERIC</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_php.html#defineSTRUCTURES_GRAPH_ERROR_GENERIC">STRUCTURES_GRAPH_ERROR_GENERIC</a> in Graph.php</div>
					</dd>
			<dt class="field">
						Structures_Graph_Manipulator_AcyclicTest
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html">Structures_Graph_Manipulator_AcyclicTest</a> in AcyclicTest.php</div>
							<div class="index-item-description">The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator  which tests whether a graph contains a cycle.</div>
					</dd>
			<dt class="field">
						Structures_Graph_Manipulator_TopologicalSorter
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html">Structures_Graph_Manipulator_TopologicalSorter</a> in TopologicalSorter.php</div>
							<div class="index-item-description">The Structures_Graph_Manipulator_TopologicalSorter is a manipulator  which is able to return the set of nodes in a graph, sorted by topological  order.</div>
					</dd>
			<dt class="field">
						<span class="method-title">Structures_Graph_Node</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodStructures_Graph_Node">Structures_Graph_Node::Structures_Graph_Node()</a> in Node.php</div>
							<div class="index-item-description">Constructor</div>
					</dd>
			<dt class="field">
						Structures_Graph_Node
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a> in Node.php</div>
							<div class="index-item-description">The Structures_Graph_Node class represents a Node that can be member of a  graph node set.</div>
					</dd>
		</dl>
	<a name="t"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">t</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="include-title">TopologicalSorter.php</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html">TopologicalSorter.php</a> in TopologicalSorter.php</div>
					</dd>
		</dl>
	<a name="u"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">u</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">unsetMetadata</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodunsetMetadata">Structures_Graph_Node::unsetMetadata()</a> in Node.php</div>
							<div class="index-item-description">Delete metadata by key</div>
					</dd>
		</dl>

<div class="index-letter-menu">
	<a class="index-letter" href="elementindex.html#a">a</a>
	<a class="index-letter" href="elementindex.html#c">c</a>
	<a class="index-letter" href="elementindex.html#g">g</a>
	<a class="index-letter" href="elementindex.html#i">i</a>
	<a class="index-letter" href="elementindex.html#m">m</a>
	<a class="index-letter" href="elementindex.html#n">n</a>
	<a class="index-letter" href="elementindex.html#o">o</a>
	<a class="index-letter" href="elementindex.html#r">r</a>
	<a class="index-letter" href="elementindex.html#s">s</a>
	<a class="index-letter" href="elementindex.html#t">t</a>
	<a class="index-letter" href="elementindex.html#u">u</a>
</div>	</body>
</html>pear/Structures_Graph/docs/html/li_Structures_Graph.html000064400000004760150431076370017566 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title></title>
			<link rel="stylesheet" href="media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
						<div class="package-title">Structures_Graph</div>
<div class="package-details">

	<dl class="tree">
		
		<dt class="folder-title">Description</dt>
		<dd>
			<a href='classtrees_Structures_Graph.html' target='right'>Class trees</a><br />
			<a href='elementindex_Structures_Graph.html' target='right'>Index of elements</a><br />
							<a href="todolist.html" target="right">Todo List</a><br />
					</dd>
	
							
							
									<dt class="folder-title">Tutorials/Manuals</dt>
					<dd>
											<dl class="tree">
						<dt class="folder-title">Package-level</dt>
						<dd>
													<div><a href="Structures_Graph/tutorial_Structures_Graph.pkg.html" target="right">Structures_Graph Tutorial</a></div>

												</dd>
						</dl>
										
										
										</dd>
													<dt class="folder-title">Classes</dt>
											<dd><a href='Structures_Graph/Structures_Graph.html' target='right'>Structures_Graph</a></dd>
											<dd><a href='Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html' target='right'>Structures_Graph_Manipulator_AcyclicTest</a></dd>
											<dd><a href='Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html' target='right'>Structures_Graph_Manipulator_TopologicalSorter</a></dd>
											<dd><a href='Structures_Graph/Structures_Graph_Node.html' target='right'>Structures_Graph_Node</a></dd>
																						<dt class="folder-title">Files</dt>
											<dd><a href='Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html' target='right'>AcyclicTest.php</a></dd>
											<dd><a href='Structures_Graph/_Structures_Graph_php.html' target='right'>Graph.php</a></dd>
											<dd><a href='Structures_Graph/_Structures_Graph_Node_php.html' target='right'>Node.php</a></dd>
											<dd><a href='Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html' target='right'>TopologicalSorter.php</a></dd>
																	
						
			</dl>
</div>
<p class="notes"><a href="http://www.phpdoc.org" target="_blank">phpDocumentor v <span class="field">1.2.3</span></a></p>
</BODY>
</HTML>pear/Structures_Graph/docs/html/elementindex_Structures_Graph.html000064400000037120150431076400021631 0ustar00<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<!-- template designed by Marco Von Ballmoos -->
			<title></title>
			<link rel="stylesheet" href="media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>
		</head>
		<body>
						<a name="top"></a>
<h2>[Structures_Graph] element index</h2>
<a href="elementindex.html">All elements</a>
<br />
<div class="index-letter-menu">
	<a class="index-letter" href="elementindex_Structures_Graph.html#a">a</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#c">c</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#g">g</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#i">i</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#m">m</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#n">n</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#o">o</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#r">r</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#s">s</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#t">t</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#u">u</a>
</div>

	<a name="a"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">a</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">addNode</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodaddNode">Structures_Graph::addNode()</a> in Graph.php</div>
							<div class="index-item-description">Add a Node to the Graph</div>
					</dd>
			<dt class="field">
						<span class="include-title">AcyclicTest.php</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_Manipulator_AcyclicTest_php.html">AcyclicTest.php</a> in AcyclicTest.php</div>
					</dd>
		</dl>
	<a name="c"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">c</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">connectsTo</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodconnectsTo">Structures_Graph_Node::connectsTo()</a> in Node.php</div>
							<div class="index-item-description">Test wether this node has an arc to the target node</div>
					</dd>
			<dt class="field">
						<span class="method-title">connectTo</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodconnectTo">Structures_Graph_Node::connectTo()</a> in Node.php</div>
							<div class="index-item-description">Connect this node to another one.</div>
					</dd>
		</dl>
	<a name="g"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">g</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">getData</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodgetData">Structures_Graph_Node::getData()</a> in Node.php</div>
							<div class="index-item-description">Node data getter.</div>
					</dd>
			<dt class="field">
						<span class="method-title">getGraph</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodgetGraph">Structures_Graph_Node::getGraph()</a> in Node.php</div>
							<div class="index-item-description">Node graph getter</div>
					</dd>
			<dt class="field">
						<span class="method-title">getMetadata</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodgetMetadata">Structures_Graph_Node::getMetadata()</a> in Node.php</div>
							<div class="index-item-description">Node metadata getter</div>
					</dd>
			<dt class="field">
						<span class="method-title">getNeighbours</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodgetNeighbours">Structures_Graph_Node::getNeighbours()</a> in Node.php</div>
							<div class="index-item-description">Return nodes connected to this one.</div>
					</dd>
			<dt class="field">
						<span class="method-title">getNodes</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodgetNodes">Structures_Graph::getNodes()</a> in Graph.php</div>
							<div class="index-item-description">Return the node set, in no particular order. For ordered node sets, use a Graph Manipulator insted.</div>
					</dd>
			<dt class="field">
						<span class="include-title">Graph.php</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_php.html">Graph.php</a> in Graph.php</div>
					</dd>
		</dl>
	<a name="i"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">i</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">inDegree</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodinDegree">Structures_Graph_Node::inDegree()</a> in Node.php</div>
							<div class="index-item-description">Calculate the in degree of the node.</div>
					</dd>
			<dt class="field">
						<span class="method-title">isAcyclic</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html#methodisAcyclic">Structures_Graph_Manipulator_AcyclicTest::isAcyclic()</a> in AcyclicTest.php</div>
							<div class="index-item-description">isAcyclic returns true if a graph contains no cycles, false otherwise.</div>
					</dd>
			<dt class="field">
						<span class="method-title">isDirected</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodisDirected">Structures_Graph::isDirected()</a> in Graph.php</div>
							<div class="index-item-description">Return true if a graph is directed</div>
					</dd>
		</dl>
	<a name="m"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">m</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">metadataKeyExists</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodmetadataKeyExists">Structures_Graph_Node::metadataKeyExists()</a> in Node.php</div>
							<div class="index-item-description">Test for existence of metadata under a given key.</div>
					</dd>
		</dl>
	<a name="n"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">n</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="include-title">Node.php</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_Node_php.html">Node.php</a> in Node.php</div>
					</dd>
		</dl>
	<a name="o"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">o</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">outDegree</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodoutDegree">Structures_Graph_Node::outDegree()</a> in Node.php</div>
							<div class="index-item-description">Calculate the out degree of the node.</div>
					</dd>
		</dl>
	<a name="r"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">r</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">removeNode</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodremoveNode">Structures_Graph::removeNode()</a> in Graph.php</div>
							<div class="index-item-description">Remove a Node from the Graph</div>
					</dd>
		</dl>
	<a name="s"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">s</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">setData</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodsetData">Structures_Graph_Node::setData()</a> in Node.php</div>
							<div class="index-item-description">Node data setter</div>
					</dd>
			<dt class="field">
						<span class="method-title">setGraph</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodsetGraph">Structures_Graph_Node::setGraph()</a> in Node.php</div>
							<div class="index-item-description">Node graph setter. This method should not be called directly. Use Graph::addNode instead.</div>
					</dd>
			<dt class="field">
						<span class="method-title">setMetadata</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodsetMetadata">Structures_Graph_Node::setMetadata()</a> in Node.php</div>
							<div class="index-item-description">Node metadata setter</div>
					</dd>
			<dt class="field">
						<span class="method-title">sort</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html#methodsort">Structures_Graph_Manipulator_TopologicalSorter::sort()</a> in TopologicalSorter.php</div>
							<div class="index-item-description">sort returns the graph's nodes, sorted by topological order.</div>
					</dd>
			<dt class="field">
						Structures_Graph
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html">Structures_Graph</a> in Graph.php</div>
							<div class="index-item-description">The Structures_Graph class represents a graph data structure.</div>
					</dd>
			<dt class="field">
						<span class="method-title">Structures_Graph</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph.html#methodStructures_Graph">Structures_Graph::Structures_Graph()</a> in Graph.php</div>
							<div class="index-item-description">Constructor</div>
					</dd>
			<dt class="field">
						<span class="const-title">STRUCTURES_GRAPH_ERROR_GENERIC</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_php.html#defineSTRUCTURES_GRAPH_ERROR_GENERIC">STRUCTURES_GRAPH_ERROR_GENERIC</a> in Graph.php</div>
					</dd>
			<dt class="field">
						Structures_Graph_Manipulator_AcyclicTest
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Manipulator_AcyclicTest.html">Structures_Graph_Manipulator_AcyclicTest</a> in AcyclicTest.php</div>
							<div class="index-item-description">The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator  which tests whether a graph contains a cycle.</div>
					</dd>
			<dt class="field">
						Structures_Graph_Manipulator_TopologicalSorter
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Manipulator_TopologicalSorter.html">Structures_Graph_Manipulator_TopologicalSorter</a> in TopologicalSorter.php</div>
							<div class="index-item-description">The Structures_Graph_Manipulator_TopologicalSorter is a manipulator  which is able to return the set of nodes in a graph, sorted by topological  order.</div>
					</dd>
			<dt class="field">
						<span class="method-title">Structures_Graph_Node</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodStructures_Graph_Node">Structures_Graph_Node::Structures_Graph_Node()</a> in Node.php</div>
							<div class="index-item-description">Constructor</div>
					</dd>
			<dt class="field">
						Structures_Graph_Node
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html">Structures_Graph_Node</a> in Node.php</div>
							<div class="index-item-description">The Structures_Graph_Node class represents a Node that can be member of a  graph node set.</div>
					</dd>
		</dl>
	<a name="t"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">t</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="include-title">TopologicalSorter.php</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/_Structures_Graph_Manipulator_TopologicalSorter_php.html">TopologicalSorter.php</a> in TopologicalSorter.php</div>
					</dd>
		</dl>
	<a name="u"></a>
	<div class="index-letter-section">
		<div style="float: left" class="index-letter-title">u</div>
		<div style="float: right"><a href="#top">top</a></div>
		<div style="clear: both"></div>
	</div>
	<dl>
			<dt class="field">
						<span class="method-title">unsetMetadata</span>
					</dt>
		<dd class="index-item-body">
			<div class="index-item-details"><a href="Structures_Graph/Structures_Graph_Node.html#methodunsetMetadata">Structures_Graph_Node::unsetMetadata()</a> in Node.php</div>
							<div class="index-item-description">Delete metadata by key</div>
					</dd>
		</dl>

<div class="index-letter-menu">
	<a class="index-letter" href="elementindex_Structures_Graph.html#a">a</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#c">c</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#g">g</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#i">i</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#m">m</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#n">n</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#o">o</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#r">r</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#s">s</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#t">t</a>
	<a class="index-letter" href="elementindex_Structures_Graph.html#u">u</a>
</div>	</body>
</html>pear/PEAR/README000064400000002172150431076430007107 0ustar00PEAR - The PEAR Installer
=========================

What is the PEAR Installer?  What is PEAR?

PEAR is the PHP Extension and Application Repository, found at
http://pear.php.net.  The PEAR Installer is this software, which
contains executable files and PHP code that is used to download
and install PEAR code from pear.php.net.

PEAR contains useful software libraries and applications such as
MDB2 (database abstraction), HTML_QuickForm (HTML forms management),
PhpDocumentor (auto-documentation generator), DB_DataObject
(Data Access Abstraction), and many hundreds more.  Browse all
available packages at http://pear.php.net, the list is constantly
growing and updating to reflect improvements in the PHP language.

DOCUMENTATION
=============

Documentation for PEAR can be found at http://pear.php.net/manual/.
Installation documentation can be found in the INSTALL file included
in this tarball.

WARNING: DO NOT RUN PEAR WITHOUT INSTALLING IT - if you downloaded this
tarball manually, you MUST install it.  Read the instructions in INSTALL
prior to use.


Happy PHPing, we hope PEAR will be a great tool for your development work!

$Id$pear/Net_IDNA2/docs/examples/example_web.php000064400000007325150431076450014661 0ustar00<?php

header( 'Content-Type: text/html; charset=UTF-8' );

require 'Net/IDNA.php';


$idn = Net_IDNA::getInstance();

if (isset($_REQUEST['encode'])) {
    $decoded = isset($_REQUEST['decoded'])? $_REQUEST['decoded'] : '';
    
    try {
        $encoded = $idn->encode($decoded);
    }
    catch (Exception $e) {
        /* just swallow */
    }
}

if (isset($_REQUEST['decode'])) {
    $encoded = isset($_REQUEST['encoded'])? $_REQUEST['encoded'] : '';
    
    try {
        $decoded = $idn->decode($encoded);
    }
    catch (Exception $e) {
        /* just swallow */
    }
}

if (!isset($encoded)) {
    $encoded = '';
}

if (!isset($decoded)) {
    $decoded = '';
}

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>
<head>

<title>Punycode Converter</title>

<meta http-equiv="content-type" content="text/html; charset=UTF-8">

<style type="text/css">

body
{
    font-family:        Helvetica, Arial, sans-serif;
    font-size:          10pt;
    background:         rgb( 255, 255, 255 );
}

#centered
{
    text-align:         center;
    vertical-align:     middle;
}

#round
{
    background-color:   rgb( 240, 240, 240 );
    border:             1px solid black;
    text-align:         center;
    vertical-align:     middle;
    padding:            4px;
}

#subhead
{
    font-size:          8pt;
}

</style>

</head>

<body>

<table width="780" border="0" cellpadding="0" cellspacing="0">
<tr>
    <td id="centered">
    <div id="round">
    <strong>IDNA Converter</strong><br />

    <span id="subhead">
    See <a href="http://faqs.org/rfcs/rfc3490.html" title="IDNA" target="_blank">RFC3490</a>,
    <a href="http://faqs.org/rfcs/rfc3491.html" title="Nameprep, a Stringprep profile" target="_blank">RFC3491</a>,
    <a href="http://faqs.org/rfcs/rfc3492.html" title="Punycode" target="_blank">RFC3492</a> and
    <a href="http://faqs.org/rfcs/rfc3454.html" title="Stringprep" target="_blank">RFC3454</a><br />
    </span>
   
    <br />

    This converter allows you to transfer domain names between the encoded (Punycode) notation and the
    decoded (UTF-8) notation.<br />
   
    Just enter the domain name in the respective field and click on the button right beside it to have
    it converted. Please be aware, that you might even enter complete domain names (like j&#xFC;rgen-m&#xFC;ller.de),
    but without the protocol (<strong>DO NOT</strong> enter http://m&#xFC;ller.de) or an email address.<br />
   
    Since the underlying library is still buggy, we cannot guarantee its usefulness and correctness. You should
    always doublecheck the results given here by converting them back to the original form.<br />
   
    Any productive use is discouraged and prone to fail.<br />
   
    <br />
   
    Make sure, that your browser is capable of the <strong>UTF-8</strong> character encoding.<br />
    
    <br />
    
    <table border="0" cellpadding="2" cellspacing="2" align="center">
    <tr>
        <td class="thead" align="left">Original</td>
        <td class="thead" align="right">Punycode</td>
    </tr>
    
    <tr>
        <td>
        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="GET">
        <input type="text" name="decoded" value="<?php echo $decoded; ?>" size="24" maxlength="255" />
        <input type="submit" name="encode" value="Encode &gt;&gt;" />
        </form>
        </td>
        
        <td>
        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="GET">
        <input type="submit" name="decode" value="&lt;&lt; Decode" />
        <input type="text" name="encoded" value="<?php echo $encoded; ?>" size="24" maxlength="255" />
        </form>
        </td>
    </tr>
    </table>
    </div>
    </td>
</tr>
</table>

</body>
</html>
pear/Net_SMTP/docs/guide.txt000064400000020446150431076500011661 0ustar00======================
 The Net_SMTP Package
======================

--------------------
 User Documentation
--------------------

:Author:    Jon Parise
:Contact:   jon@php.net

.. contents:: Table of Contents
.. section-numbering::

Dependencies
============

The ``PEAR_Error`` Class
------------------------

The Net_SMTP package uses the `PEAR_Error`_ class for all of its `error
handling`_.

The ``Net_Socket`` Package
--------------------------

The Net_Socket_ package is used as the basis for all network communications.
Connection options can be specified via the `$socket_options` construction
parameter::

    $socket_options = array('ssl' => array('verify_peer_name' => false));
    $smtp = new Net_SMTP($host, null, null, false, 0, $socket_options);

**Note:** PHP 5.6 introduced `OpenSSL changes`_. Peer certificate verification
is now enabled by default. Although not recommended, `$socket_options` can be
used to disable peer verification (as shown above).

.. _OpenSSL changes: http://php.net/manual/en/migration56.openssl.php

The ``Auth_SASL`` Package
-------------------------

The `Auth_SASL`_ package is an optional dependency.  If it is available, the
Net_SMTP package will be able to support the DIGEST-MD5_ and CRAM-MD5_ SMTP
authentication methods.  Otherwise, only the LOGIN_ and PLAIN_ methods will
be available.

Error Handling
==============

All of the Net_SMTP class's public methods return a PEAR_Error_ object if an
error occurs.  The standard way to check for a PEAR_Error object is by using
`PEAR::isError()`_::

    if (PEAR::isError($error = $smtp->connect())) {
        die($error->getMessage());
    }

.. _PEAR::isError(): http://pear.php.net/manual/en/core.pear.pear.iserror.php

SMTP Authentication
===================

The Net_SMTP package supports the SMTP authentication standard (as defined
by RFC-2554_).  The Net_SMTP package supports the following authentication
methods, in order of preference:

.. _RFC-2554: http://www.ietf.org/rfc/rfc2554.txt

DIGEST-MD5
----------

The DIGEST-MD5 authentication method uses `RSA Data Security Inc.`_'s MD5
Message Digest algorithm.  It is considered the most secure method of SMTP
authentication.

**Note:** The DIGEST-MD5 authentication method is only supported if the
AUTH_SASL_ package is available.

.. _RSA Data Security Inc.: http://www.rsasecurity.com/

CRAM-MD5
--------

The CRAM-MD5 authentication method has been superseded by the DIGEST-MD5_
method in terms of security.  It is provided here for compatibility with
older SMTP servers that may not support the newer DIGEST-MD5 algorithm.

**Note:** The CRAM-MD5 authentication method is only supported if the
AUTH_SASL_ package is available.

LOGIN
-----

The LOGIN authentication method encrypts the user's password using the
Base64_ encoding scheme.  Because decrypting a Base64-encoded string is
trivial, LOGIN is not considered a secure authentication method and should
be avoided.

.. _Base64: http://www.php.net/manual/en/function.base64-encode.php

PLAIN
-----

The PLAIN authentication method sends the user's password in plain text.
This method of authentication is not secure and should be avoided.

Secure Connections
==================

If `secure socket transports`_ have been enabled in PHP, it is possible to
establish a secure connection to the remote SMTP server::

    $smtp = new Net_SMTP('ssl://mail.example.com', 465);

This example connects to ``mail.example.com`` on port 465 (a common SMTPS
port) using the ``ssl://`` transport.

.. _secure socket transports: http://www.php.net/transports

Sending Data
============

Message data is sent using the ``data()`` method.  The data can be supplied
as a single string or as an open file resource.

If a string is provided, it is passed through the `data quoting`_ system and
sent to the socket connection as a single block.  These operations are all
memory-based, so sending large messages may result in high memory usage.

If an open file resource is provided, the ``data()`` method will read the
message data from the file line-by-line.  Each chunk will be quoted and sent
to the socket connection individually, reducing the overall memory overhead of
this data sending operation.

Header data can be specified separately from message body data by passing it
as the optional second parameter to ``data()``.  This is especially useful
when an open file resource is being used to supply message data because it
allows header fields (like *Subject:*) to be built dynamically at runtime.

::

    $smtp->data($fp, "Subject: My Subject");

Data Quoting
============

By default, all outbound string data is quoted in accordance with SMTP
standards.  This means that all native Unix (``\n``) and Mac (``\r``) line
endings are converted to Internet-standard CRLF (``\r\n``) line endings.
Also, because the SMTP protocol uses a single leading period (``.``) to signal
an end to the message data, single leading periods in the original data
string are "doubled" (e.g. "``..``").

These string transformation can be expensive when large blocks of data are
involved.  For example, the Net_SMTP package is not aware of MIME parts (it
just sees the MIME message as one big string of characters), so it is not
able to skip non-text attachments when searching for characters that may
need to be quoted.

Because of this, it is possible to extend the Net_SMTP class in order to
implement your own custom quoting routine.  Just create a new class based on
the Net_SMTP class and reimplement the ``quotedata()`` method::

    require 'Net_SMTP.php';

    class Net_SMTP_custom extends Net_SMTP
    {
        function quotedata($data)
        {
            /* Perform custom data quoting */
        }
    }

Note that the ``$data`` parameter will be passed to the ``quotedata()``
function `by reference`_.  This means that you can operate directly on
``$data``.  It also the overhead of copying a large ``$data`` string to and
from the ``quotedata()`` method.

.. _by reference: http://www.php.net/manual/en/language.references.pass.php

Server Responses
================

The Net_SMTP package retains the server's last response for further
inspection.  The ``getResponse()`` method returns a 2-tuple (two element
array) containing the server's response code as an integer and the response's
arguments as a string.

Upon a successful connection, the server's greeting string is available via
the ``getGreeting()`` method.

Debugging
=========

The Net_SMTP package contains built-in debugging output routines (disabled by
default).  Debugging output must be explicitly enabled via the ``setDebug()``
method::

    $smtp->setDebug(true);

The debugging messages will be sent to the standard output stream by default.
If you need more control over the output, you can optionally install your own
debug handler.

::

    function debugHandler($smtp, $message)
    {
        echo "[$smtp->host] $message\n";
    }

    $smtp->setDebug(true, "debugHandler");


Examples
========

Basic Use
---------

The following script demonstrates how a simple email message can be sent
using the Net_SMTP package::

    require 'Net/SMTP.php';

    $host = 'mail.example.com';
    $from = 'user@example.com';
    $rcpt = array('recipient1@example.com', 'recipient2@example.com');
    $subj = "Subject: Test Message\n";
    $body = "Body Line 1\nBody Line 2";

    /* Create a new Net_SMTP object. */
    if (! ($smtp = new Net_SMTP($host))) {
        die("Unable to instantiate Net_SMTP object\n");
    }

    /* Connect to the SMTP server. */
    if (PEAR::isError($e = $smtp->connect())) {
        die($e->getMessage() . "\n");
    }

    /* Send the 'MAIL FROM:' SMTP command. */
    if (PEAR::isError($smtp->mailFrom($from))) {
        die("Unable to set sender to <$from>\n");
    }

    /* Address the message to each of the recipients. */
    foreach ($rcpt as $to) {
        if (PEAR::isError($res = $smtp->rcptTo($to))) {
            die("Unable to add recipient <$to>: " . $res->getMessage() . "\n");
        }
    }

    /* Set the body of the message. */
    if (PEAR::isError($smtp->data($subj . "\r\n" . $body))) {
        die("Unable to send data\n");
    }

    /* Disconnect from the SMTP server. */
    $smtp->disconnect();

.. _PEAR_Error: http://pear.php.net/manual/en/core.pear.pear-error.php
.. _Net_Socket: http://pear.php.net/package/Net_Socket
.. _Auth_SASL: http://pear.php.net/package/Auth_SASL

.. vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=78 ft=rst:
alt-php55-ioncube-loader/USER-GUIDE.txt000064400000026060150431103020013314 0ustar00ionCube Loader 14.4 User Guide
=====================================

This document describes the available php.ini configuration options of the
ionCube Loader that relate to processing of PHP encoded files, and also the
ionCube24 service. It also describes which encoded files can be run by each
ionCube Loader.

PERFORMANCE OF ENCODED FILES
----------------------------

We recommend that the encoded paths feature (see below) is used 
with encoded files in order to maximise performance.

ENCODED FILES  
-------------

INI entry: ioncube.loader.encoded_paths

Purpose:   Specify the locations of encoded files

  The ionCube Loader will normally examine a PHP file before processing
  to test whether it is encoded, and will run the file itself if necessary.
  Although this checking is very efficient, restricting which files the
  Loader tests for being encoded may give extra performance. If set to 
  a series of paths or files, only files in those locations are tested.

  Entries should be separated by a : on Unix and ; on Windows. 
  A path may be prefixed with + or - to add or remove that path from
  the possible locations. + is assumed if no character is given.


Examples: (... means ioncube.loader.encoded_paths)

  * Site with a single encoded module in /var/www/html/modules/RSS

... = "/var/www/html/modules/RSS"


  * As above, with a site configuration file encoded too.

... = "/var/www/html/modules/RSS:/var/www/html/config/config.php"


  * Encoded files may be anywhere except for /var/www/html/framework

... = "/:-/var/www/html/framework"


  * Site with most modules encoded except for one

... = "/var/www/html/modules:-/var/www/html/modules/plain"


  * As above, with an encoded config file in the plain directory

... = "/site/modules:-/site/modules/plain:/site/modules/plain/config.php"


Locations:

  The ioncube.loader.encoded_paths property can be set in a php.ini
  file, in a .htaccess file (when using Apache), in a .user.ini file
  (when using CGI PHP 5.3+) or using ini_set within a PHP script. In ini
  files only the last value will be used for the encoded_paths property. If
  you wish to build up the value in several lines then, for PHP 5.1+, you
  can use the following syntax:

ioncube.loader.encoded_paths = "/path1"  
ioncube.loader.encoded_paths = ${ioncube.loader.encoded_paths}":/path2"  
; etc...

LIMITATIONS OF LOADERS AND ENCODED FILES
----------------------------------------

Encoded files can, in general, run on versions of PHP equal to
or greater than the source language of the Encoder used to
produce them. So a file produced by the Encoder for PHP 7.2
can be run by the Loaders for PHP 7.2, 7.3 and 7.4, but 7.1. This 
means that the Loaders offer good backwards compatibility, 
however there are the following limitations:

  * The Loader for PHP 8.3 can run files produced by the PHP 8.2 and
    8.3 Encoders.

  * The Loader for PHP 8.2 can only run files produced for
    PHP 8.2. Updates for files produced for PHP 8.1 should
    be obtained to use them with PHP 8.2.

  * The Loader for PHP 8.1 can only run files produced for
    PHP 8.1.

  * The Loaders for PHP 7.1 through 7.4 can only run files 
    produced by the Encoders for PHP 7. 

  * The Loader for PHP 7.0 can only run files produced by the
    Encoder for PHP 5.6.

  * The Loaders for PHP 5.5 and PHP 5.6 cannot run files 
    produced by the PHP 4 Encoder.


IONCUBE24 : real-time intrusion protection and PHP error reporting
---------
### (Available for Linux 32 and 64 bit x86 servers using PHP 7)

ionCube24 (https://ioncube24.com) is an ionCube service that uses the
ionCube Loader to provide both real-time protection against the exploit of
website vulnerabilities and alerting of website errors.

Vulnerabilities in PHP applications are common, particularly in sites using 
Wordpress and other plugin based systems. Exploits result in website
defacement or customer data being compromised, and ionCube24 provides a 
uniquely powerful defense. 

PHP errors can cause intermittent or even persistent blank pages or errors for
visitors until discovered, and without active monitoring this could go
undetected indefinitely. ionCube24 active monitoring ensures you are always
aware of problems in your website code.

ionCube24 is free to try, with the server side support built into the Linux
Loaders as standard. With the Loader installed, ionCube24 can be activated
at any time to give active intrusion protection and error reporting.

## php.ini settings

ionCube24 has a powerful real-time web interface to configure, monitor and
manage things, and there are also settings that can be used in a php.ini
file as summarised below.

The setup process at https://ioncube24.com automatically gives the settings
that you need to get started, but you may wish to make changes yourself
once setup. The default values are given with each example.

### Global settings

INI entry: ic24.enable ; default 0

Purpose: Enable or disable all ionCube24 features. 

This defaults to 0 (off), and in this case no ionCube24 behaviour is
activated.

Example:

  ic24.enable = 1

----------

INI entry: ic24.api_access_key ; provided during setup

Purpose: An authentication key for adminstration requests. 

  This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.api_check_ip ; default 1

Purpose: Specify whether the IP for admin requests should be validated

  If set, ionCube24 refuses access to API functions unless the calling IP
  is a known ionCube IP address. This option should be left with the
  default setting unless web requests pass through a proxy and your site
  appears to be accessed from the IP of the proxy instead of ionCube. Note
  that access to API functions will still be authenticated by access key.

----------

INI entry: ic24.api_max_timeout ; default 7

Purpose: Maximum timeout period when sending notifications to ionCube24.

  The actual period is adaptive so that a brief increase in typical latency
  will favour a timeout followed by a retry rather than a longer than usual
  timeout.

----------

INI entry: ic24.home_dir ; no default

Purpose: The home directory for ionCube24 related system files. 

  A location outside of the web root is recommended.  It should be writable
  by the web server during startup.

Example:

ic24.home_dir = /var/www/ic24_home

----------

INI entry: ic24.update_domains_retry_interval ; default 30

Purpose: The number of seconds to wait before retrying a fetch of the set
of domains being managed.


### Security related settings

INI entry: ic24.sec.enable ; default "auto"

Purpose: Enable the intrusion protection feature of ionCube24.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

INI entry: ic24.sec.initial_state ; default 1

Purpose: The default for whether security should be enabled or
disabled. The default is to enable protection. Any files on a protected
domain will become blocked if they are changed, so setting this to 0 will
avoid accidental blocking when using ionCube24 for the first time.
Protection may be enabled and disabled using the ionCube24 control panel and
also via the User API.

Accepted values:

   * 1 : protection will be active when ionCube24 initialises.
   * 0 : protection will be disabled.

----------

INI entry: ic24.sec.initial_action ; default "block"

Purpose: The initial setting for how new and modified files should be
treated when about to execute. The default is to block. The action is taken
only if protection is enabled, and the setting may be changed via the
ionCube24 control panel.

Accepted values:

   * "block" : prevent execution of new or modified files
   * "allow" : allow execution of new or modified files

Note that depending on the notification settings, a notification may still
be generated when a new or modified file is about to execute even if it is
not blocked.

----------

INI entry: ic24.sec.initial_notify ; default "always"

Purpose: The initial setting for whether a notification is generated the 
first time an unacknowledged new or modified file is attempted to be
executed. This setting can be changed via the ionCube24 control panel.

Accepted values:

   * "always" : always notify of a new modification 
   * "once"   : only the first detected modification is reported
   * "never"  : never notify of new and modified files

----------

INI entry: ic24.sec.exclusion_key ; provided during setup

Purpose: A key that if present at the start of a file, will identify the
file as trusted. This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.sec.trusted_include_paths ; no default

Purpose: List paths from where files can be included and automatically
trusted.

Example:

ic24.sec.trusted_include_paths = "/var/cache:/var/cache2"

Directories can be excluded from the list by prefixing with a minus
character -. e.g.

"/var/cache:-/var/cache/subdir"

This is useful if your site creates and/or modifies files by itself from
time to time, e.g. in a cache directory. Requests that *directly* access
files on a trusted include path will be blocked but the file itself will
not be blocked, so requests that use the file as intended will still work.
See ioncube24.com for more details once signed up.  As an alternative, if
possible we recommend producing files that include the exclusion key.

----------

INI entry: ic24.sec.block_uploaded_files ; default 1

Purpose: If set, block any uploaded files in ionCube24 that are processed
using the standard PHP mechanism for uploaded files. This applies even if
the file is subsequently included and where included files being
automatically approved with the previous setting.

----------

INI entry: ic24.sec.block_stdin ; default 1

Purpose: Refuse code that PHP sees via stdin.  If disabled, code via
stdin will run without security checking as there is no filepath. This
setting should be left on as PHP would normally never receive a script via
stdin.

### PHP Error reporting settings

INI entry: ic24.phperr.enable ; default "auto"

Purpose: Enable reporting of PHP errors to ionCube24.  When enabled, any
non-ignored errors are reported to ionCube24 in realtime, triggering
alerting so errors can be investigated as necessary.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

### Deprecated settings

Deprecated settings are subject to removal in a future
release.

INI entry: ic24.phperr.ignore ; default 0

Purpose: Specify default error levels to always ignore for all domains.

Note that default and per-domain errors to ignore can also be set via the
web interface, and are combined with this setting. Leaving this unset and
using the web interface is recommended for maximum flexibility.

Example: 

ic24.phperr.ignore = E_NOTICE | E_DEPRECATED

(c) ionCube Ltd. 2025
alt-php55-ioncube-loader/USER-GUIDE.pdf000064400000115466150431103020013257 0ustar00%PDF-1.4
1 0 obj
<<
/Title (��Markdown To PDF)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20250130155421Z)
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 33  
813.500000  0]
endobj
9 0 obj
[0 /XYZ 33  
749.750000  0]
endobj
10 0 obj
[0 /XYZ 33  
700.250000  0]
endobj
11 0 obj
[0 /XYZ 33  
131.750000  0]
endobj
12 0 obj
[0 /XYZ 33  
296  0]
endobj
13 0 obj
[0 /XYZ 33  
97.2500000  0]
endobj
14 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [71.2500000  66.5000000  144.750000  75.5000000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 15 0 R
/Resources 17 0 R
/Annots 18 0 R
/MediaBox [0 0 595 842]
>>
endobj
17 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
18 0 obj
[ 14 0 R ]
endobj
15 0 obj
<<
/Length 16 0 R
/Filter /FlateDecode
>>
stream
x��][��8v~�_��FI���@w� �0l A�l���8;��Ϗ.TU�򱪾�(���H�\lR���_�ۗo��#y����|�r�RSd�I���ej�'�P�{��Ï�����s�����~�n�|���{ޡ������/�ɿ��{�_�]��.���#L�,/������Sd�Nu%���=������O�o�>���2)�T������魞�eZ	�s�e�]y��J7ߕ�5X��}�I.����/�ߟ���ㄪ�>Oʰ�WVEXx
=��12����E��?�fy���C���}�5eH��5�^���k���N��%y����׿tjJ!����َ�"�t��ӈ�Gre�s�n�L��)�s��ӈ�GL��=�FL7���,�#��u5yNկ�������|�[�k��ҎTi�=�]<>g<�
G>�#&UE���w ���D�o*D����
aϧ�����Ont)�}���o��ɻ�����/_���ɇ��Ǘ���xy��y�������sf}��6��&-��.#�wV�-�Ϡ��7��t�w�i5����Av
u٣�N5����}�i9>wQ�9�z�v-�-�Ң{��y�TM�K�պ9j
�M�0D0�p?O�|Lg��Y�����a`�9�
�����SL�I7�H˞]��
B�a�X���x�ρ��s,�WSJ�*xs�`����q���-��}���;�ۈqS7���i/ƪ@���~��S1���[^o&�'�^�/8ާ�s�B�+y�����q��6s�1��1w&8�co�����&��:���b�"��eBѷ��R�)g#�fW���x�c׌��H��s0�������ɮ�EVv�:�a�Y
�|��>2��ءӜ�ַ֊��El��|�_w�{�N��A<����v�V)a��-�ë��lr
�E
��Z��-e�`�->S��Y��xݵT�^k�;�
�1M�{�v��w��:I#�(@�(Yw\-t�9]�����4b�Tr:��9cG�<:�&� ^�CQ�j�t�U��	S|�3A�8g��M�^���c�@8Vðf���c��5;�s��@�9�>!�ٽ�5{�����%)�&ěpW7aMW�g7c�R��<����&M��o�ףO��{�Y��Ms���|�tFs�Z-��`�b|����~��z�?��^���{��G~�����o���bN�ҝ[�V���5t��8�q�f5*؈p�:H��a��K�u���–n_��99��F���] p�9��\rSݟ�LfG��Օ�6��` 1|���=ę0 <dz���#��ص�.�#��1J���*K�|�ɔU��T}���=��(��DT��?6��3��)Z���1��xG69Qp$�#�p���T�<��gbo/Į�j��2��|�#��?����������8*I�d�.6��u4r��Y&iRqC�
c���
��PF\Ƥń�<N"H�����,�U�щ�d�>L��N���L����4�шy��w�!�5a<t��k���2���g?�W�g��e�-镫��� @'-��~�7�?�$�h0W�.��-��m@$
�XL�^�3�
��ǁ��L�T(A����e�n����v�W��7����U��\KL�q,����j�^Y!��D���a�M����`p	n��$N&$0�J5��?",�~}�����3��d츮�M���rb�#�($fR��>m��~��E�ofw(n�K�ox,��ŰƄ�H�Z�)&�X�c�n�
3L]0�|�5���x� �b�X�Zڈ��׏��r�_��TK�WL$�W��p���,�9�&F�Q6ܾ����*u��կ9���?���{Z�ߙ���5� �u�_�9��L�O�!h��IH�˴{UN=K�$���ue��B&Bm?ץ��9���b$k�<Я��l���t�!:98"�D�Ah��� ���i㣗4J�r
�v�<b�x�U���9ۊ����E*��__�_ߚ�Y�a�T��[�b{h�l	������"���/MV
��L�/Y����1��1�s~�1�
��Ռ"�׿�Pu�ٰQΫ�p5ח/0oe2J�.�)�^��i�9�TM�&��cE�JkY�?��~��2/Êaeq��r4n).c<C��fD�P�L���ע��φʋc<8�½0�p��Y�k���7�х�k �Ţ7s֍�ni��;�%�҉���vF�c���ե����t��Y��oZ�Se�f��L'r18�X�.��s��K�)Y
8�\�`��v+�i+�$�RɯݗZ���BW��[^��(i���RiY�ʺ��T�V�W�a�2��Z����gԿ��$c���OA����cp�TG�_ ����7N�k����I�a��ğ�-�v)� P�H��\�0;�d��"h�2�W�� �x1��Ȓl�fpıF�âO�s�
(T;�⁀��#�L�I^�l��֯�hT�߮K��J(;�@A9ҒHKV�%Gߪ�T��<���y*��)��<��j0I�ku:OY��<eծUu��w3�d�ZK�<U�k�<��|�5�ɡ{�˯�JiCX�b��dži����~�,�җ��6<rf� �"Kr�7R#��,�(�F�7����aq4�R�.�7p��*�j��vPL��jx�ձ�M�:y9�:��Q��������T�V�:y1�:m|d�1P���`��k-�:���L���
2�g�C�w��߮T�6��5��cr3����-gtR4�7�r�J�4�9ጲZ8Y�!��(,�3Z�m���&E�KV&�n�������)�;����L�2o�2�iP�Vm~��
Jg��z������T�V�A�L�hP�M�o?T��L2v��5�ZH��i��¶8�8
��n�q)p����e!R�<i�B��*�iE�����Y���U��
;�p���� ��U~�m#���ԺS4�(b��]
&�v�Ni)�"�_۵�Q�`��L2v���#O#�MT�ՇQ6���r��֧r@��0p`/~Sj���B(��pձ��0�}�����9b��`�8/�M(��j�S�?Մ��xpx�6���|�v�E3R���.��,�Bԇ4y_�ƶ�03��؝yqY��f�Njj��豤��XǒZ^RK6U�Ϯ�ߖ�a�m�Y	�ӓ`f�ud��s�k߳�hޚ*�
�k�qo�����z�5$�����W��3�k���L*m��|�75/:QT��QS�i����T��bANx��(,~��VLW	'�;�l%�Z8��fn1WGe*^�v�3�s��ֶ�l�Uc�1�cKR��vC�u9��ܤ�;��~��M
[&��g��%_Y8P������IM5V�;��Sk�pT�3]��ϱxw6�j�SL��F��
|� S=`�=��k��T*GsT��b��i�V2T7��j&��G�	#�ln2�R�s�@�i<z����ʉ~����d�0�bB�O��m��"pC0�bN���K=���$���"m���F�{�|��C�P�	�8*��W6
����u��C�����W�2��gn����׳B�
��2_��a�*B\칺 k�@Fv�2FpL���g̼��L�C�1ta��3�Y�H���-�Ӊ��"!�*O>�9�.�[�J��c�p@���K��:u�%�ʑ]�E.j�4�WaY�W�R(�j����׃O�q)��1WF:����i*��=�ƛ��X�-��g1f޽����ύ��J
'V�%����ȓ��UO)���"�0R�s$<�O!ެx���fI3����A0	�?��^뵽�f��i��'�}���a�&lM�42,��
]ji��2�>t���ˠ��`�j�S�c)����;���&U�ݑ�2U���c�慜T���B����֡��ӉM��Y��ϱ���Y�XA�st�bނ6����s ��s?b]Gc�^?����)zLF���S��v<�|�����ݦ0��2�qc�w��왎(û/��-y�>y��~�����#y�!��!y��r0in-���D
)H� ��?�\_�سtY�b����1@ԭ_��)����($����Y3�`���D29K^˕1p�5�b����Mo����7��I~����`�ôue
�1��op��0�`�!�n3QA�V
���P!%��fxp(:�6-Æ��+E{��~���{~�W�v4 d�'pSI�o3ɳ��"�)�1I0�"pN�ΰ*�WRw!�}4�
!����9wV�4�a+d�6�u���S�x�w�1�1;���(��F�}3�s��Q&#�)�@�)LUbc���e�oQ��D���y����lQ�7"�
fQw0<�B3�yaX3�>C6�Ҭ��[fF%`�lw0D�z�fb܁��o]�G
�c� 
�a�"_��gS���`��d^����7#m^z��f��X|1}�sa�HP���,㛹W�욹W��i�^�YӀ��4soW�I�]�m�^=�̽��]��4so7�IƮ�p3��T�`��l;��~s��������n:�0��6m����f�.�,��h�>��J1�vw�x$���G�7+���G���j�ρ�ԍ��<խ��H�7���p��멡�ԍ��<ӯ���T?�/�((�'���ի}GQ�D�H��q^fv�f��
c>9����� ҃M�G0�-��gxැ�ߐ9�>�9�e�o��c�YX���*|��T��;�7�
��M�F?c*Py��ן#SA3��T��5�l�T�2�^66t>��y�_oqS��+'FSA�� �
�j�h��.��E�l�Ekѱ�sĢ�5����,�.��.�w�0c݌��<ӯ�8��}٭Ȣ7n��pBżm�!��84F����z\UjD�F��g��݅`D��Mp-u/��fNp-�N�,˱�ڌ��<խg�2�\Kk�*��ڌ��<ӯ���Z)
��z9�,��D1��Ĭ��-Eq(�8�@T�h��^.�y��$�������$D�
6��PPjG�`�������A��Ϯ'F�R;b�L��҂�&
Joc�欞�i�a"J��#8{��)�pb��:=��Q<ݴx�6:�/ة�|���jѲ��~[�&26N���ĝ>�#CnԒ�#�<;�F��&�rA1���d}5����w0���~$���
�t5�ڟ�$����r�PI��(�2U5�f��9�V7
{̰�c���q�1�v ����r�M�j��p��	�~�t�X:)�v��f1�:��=�#�3ŧp�!R�`�h��x|K�ix��"9����o�R���_ds��E6�\ds��m��{N��0
�Fy,�!{J�O��������I���ޜr�gK�Z�p���jڎ��~s�;g�;UZ���0XLM-Y�g�s�i5D��s�9ֽQ���s��Kp&����gT��nE�k�f���=���33#�7�g�����z�x�w���J�����	JR����zB�v�)�ka���
Ʒⵃ0�����X��Y����Ǟ�NL�G���9ܩ�O��e!�E�Fd�aD��X��\0�$�����S�kk�qo�"��Ҋ��q��|�5�������Yϭ��T59(j�p仼��W���=��A;�Nw<.=�A5�]�<���kF<�j��+��y�*�GT�'e���w�����7bo[&�L�.*���SN[����k#/���53c����.l9H:T96�a�=����#Bm�"T&L�`ج��T��M�p�f����)�
�L�VA���h��@����[Y�9֬SLu
�VC4ᢚVy��{��$�5.U��!�������Sl�)����ɫ��t��k��$��RzQ����x��{ʤ���3΂��������'��H�@����EaJ�%0F6c�JnJ�H�]~=���z$�K��o�=	�R�4�yp`<�k��i�R�@�u�[�ނ�@���< ��p�g��XL���Nل��ݴ>���׮�pc���_j�1�g|`LQ�L�)�Ѷ�>rS0��e�E)��*F�,�^���Y�ê����2X��j��wai�EU]�!�1~T�4^�E"�n���4��ӳ���W�1��r"�Fg&��2��oh�>#.<kU˗��ŀwP�ptk��]�s0l�Zk�����	�F��+����S�>��K~8�|z;�*�~N>�I�˙
endstream
endobj
16 0 obj
6379
endobj
20 0 obj
[1 /XYZ 33  
760.250000  0]
endobj
21 0 obj
[1 /XYZ 33  
672.500000  0]
endobj
22 0 obj
[1 /XYZ 33  
158.750000  0]
endobj
23 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [102  696.500000  175.500000  705.500000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
19 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 24 0 R
/Resources 26 0 R
/Annots 27 0 R
/MediaBox [0 0 595 842]
>>
endobj
26 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
27 0 obj
[ 23 0 R ]
endobj
24 0 obj
<<
/Length 25 0 R
/Filter /FlateDecode
>>
stream
x��][k�H~�_��Ȫ*�.`�maaL���C�dv���d��+�JmK꯺��QIrk㶫���:��\��o>F��#����-zr?o>l�8�I�_T�{������P�}���l�G�7����7���x���h��4�p���"�����_��~�����e��<�_�l��痿�$��TeQ�=�Z���?��V�H�"I�6ڨf,��߽x��=��K�gi�آ��mZ&����&o~���JuE5�迟6�V�?w]�X]���\�؎��:)�Ĕ��]�&�vm�w]X=Q�:Iҩ�V:��k3ݬm�w�~� ���c[׏���,R:z�5j���X��2���KtYq�۫��M�L[�C]�ݶ�b�iV�5:�LRl[t\6��hɷ-YlR�k�ٶ�q���Ӣ�ۊ�ߦ�{F5C;f�ʺgt�t����Ūf�[�kɒ�tG-ۏE�xf�w�j[��768S��c�<CЁʶ-*iሱ�Pccf�W��^�d��;�z�L=���h�N��z�n�gf��ZU“Ep�RU�7�����#P7��6�{C��Y˟k�6�	c���Sg��ʡVKM���ⳍ�vݞ���·u
�֔�􆟁3U�n��h(�.�����u+�d����pl�,`���L��Cڡ�CU�Wam���@��Ң��ū����[��k�G��YQ<6QY�5֞�:�������aLT��W�je�~Ō��%xl��q�4sd���{��p>�}��ӆ��q^�9 >-�B«������lY%�IBʾ��S/��2r�s�	�Jiӌ�Ϝ9��߆׍�q?�؄W�uX�1���0(>?��Q{��P�@s<���
�,���9Ƣ �A�=���fzռ��!Y����2��68��#��`��,����5�ش,�ʌs�72#���-<Z�!��y�(���&��H��1)�3�5�H�㑍p�L��i�׎
�(���(�Ö#�_�������LM߶�I�&��X��Ԝ�Y棢t��=,�O]�`��Lg�c��~��||�Dc<c��]����+F�y����L���M���*y,+S��<�V'T���і��1��P���o������"�yZK𹓃r���;u�Z+ĩS�wwF����윪�o��g܊�=�C�������i^w�3-������-o���
��ma�s�=-�|��[k7��V]|���kty]�����Ϗ���]^EWW��Me��Ԭ[:�-�����@z�x
Yj��$�S����x%�Q��Pnj,T��	.U��9%A�itzSQ6�`֩���qf9J�ך�����!v�Ѐ���=Ϻ1#M=�*�h�ŒӠ�]K��J�^��b''�U���@/Lo�N��:�dD00�h`��]�i�c��P�t!*��IE��|1�I���a*Ɣ���Hr	v�^�ƊNmՎ�9i��lL(�:D�d0�a�ztZ�дCr��H��uW}N�_]��.f�"�=���i�zi]iӥv,�-�#'���̽��AP%n�Ex=�;=���dG���lt��ӬC���Ɣ�8�'Iq
O%,&�
%#�F(�u���u�Y���%Ťp�"_�!r�* �	k	�L��̙�i�H*�S�h�u��u�OMYf�2�5��L��Z0e����u
_�ܨ�I �F�Dcӈ��Ri���U����х���"!���S�J�T#F�I��c��>ƶ��ƒ�k���-�u��Ze7}խ���q�Ͳ
eh��E�'��QO?E{
�	����`7�8z����6`�;���f\?.�w����:�昬7��M m�z���k�۽�た��'Z��^:~z�5����6*���06{�-0��S6/+ΚD�[�vL�'SJZM��RԢ3ؒ÷�?c`�{�Ƕ+Yp�v���
?��CN�=��X���~q��cv��Q�������>;�={C{����-����kf�:�EA�2\�c�(�py� �\}E^G���̉�t\&f'��e| ��Ӣ�ZZhDiaܢ�( %Q�2XQ�h�Y_��2��s�*︨_&N���.����?ӗ
UR+�n���Ƕ͜��"�! �TD*+�H%��0&UcLy�bLnj��1ݞ���0�|��б�ɔtn�H�zI�a@?��>�w��ZO?p���P��p���h��u�?�
����׀���3�����mx>pv�){J�vDxfzD�;��8"J7Ӂ�\8��Ԧ�eo{f��ɫ�2!�TBR�[̙��P�P5��LgL;�[ô���
=�`� �G��n�w�L<
�N�g�O�^��ee�,f��w�2�eW��:���F>���QO�u<gY.N+��
N��Q��xu���g�����5�s�5�iM�2E�y�!���!ѬvFV�t��)X���9'���5�i����j%VPa����%�.����z•���4��D&
��у��PQ��WӔ�K�	D��S�%�S��7f�Dtc(z���c(8���R��#�C�YSl"��S���)�CY��n"���N�}��1o����A�pd���%IJp���T���N�(:ĈR�2��Rr���o���[Ӭ_q��8N�_!��zb��I��b.\�\W5gj��AK�� 2��P9���R�����:5]~��2֣	�)U{}r4P��9㫢!�]�	N���Q:a��H2��ZF�Jx`8c��R�B�<�������L֑��ߕ3k���
ߜߐ��D�R"��rԱ��|��	��Ռ�]�����хSC$�褲�I�59f��]�*�jq�1/�|�cN��#�xl8����*4D�,\�œ�B����6�R���I�3��'զiQI||�OQD��a8���"56,v���f`{�1f�"��)Мq��
 ������E��dZ&\;��:)�:��.�-����I�zc�#X(7��&�J�Ya�sm������5)���r���6�U
�	˘v0T��|�:Õ�3�p4AUA�QSz��l����}���PWN0�o�f&
=P��$p-ҁ$�N-꘠�F��YWa�zeyqJ(�䭭5S@`r�D$�w�eʛ ��ں��k�K��]�ʚH��s-?��eO�C|����`�ū�]��NZ|�^�%�|�f�e{���oCA�L�;%���b\p�q�@�D��Y__q>.+Y�6��dwA��REsj�p�-�Fvi�+���75���g2���t"C��@������iA/L]&&�;ZTa4/J'c¢�u(Cp��"�ra�!,Z��|*Hyx���g�|�!�K��Ҥ���Ɋe^��9��[8P0*e0�D� :ZF�O�+Yu{�4�	�Ǻ7��8,��k�

��֙���%!�F�u�"�{8�؈;N4����\���p��sL�'%�]�G��f��n`竩�ʗ$
��W3���CwӟƼ1�NDY�
<j�?ؕKd=c!�Y��8C�s% vM3��%#v�L�j�|4n��
�3̮���!Z&����C���'�u�>��a`��_E�d��dM�*Ü���C��'�)ܽHת��J�b�	#8��%g��3�e���C�ݭ��$���t��s�;���?����i��fH�MUv�4�2N�~�Y�bE[dg���y�[��u�dE
�pL\���x��5p��_����G�gZ��%-��'�~�q?��i:p>�G{�;<86Ϩ�Z�)E{�Z����Ňo�F�����~������Utu]�����I�Ļ���{��MO(l���>H"=�������.��gڿ�tJ�/~�ǯ�߆Qc�~b&�^`�`�36<S쩹{f1#��<k�;�1��(���*�mN�]*�?�5���P	@�_\!�dR�2LX��%g�$H�&�@#|��
L�B�DR�T-���e��1��r�<Ӄ�#mu}q��O*��d͇2��ZD��S�|ژʒ.mj�c:ϙ�}���Oi��T�ޗ����T����}�m����-q�vY�b0�e�e3!��*u�2bh,�m}ߎ��s�ަ,�)���Z ���w���]�g�z�
S��p"e�0.L��>w$!�S�
�T�����Ϟ�ߊ��s�y����'�Mټ����uK�y.o�7��Ow	0��7�v0����bJcȂ��0��<��Q�;���Ս�Ӎ�@7�N7����tc�W7�N7���:��vtcD7�vd�u�<�=+r��E߽;2��d�=l��S
endstream
endobj
25 0 obj
4362
endobj
29 0 obj
[2 /XYZ 33  
122.750000  0]
endobj
28 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 30 0 R
/Resources 32 0 R
/Annots 33 0 R
/MediaBox [0 0 595 842]
>>
endobj
32 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
33 0 obj
[ ]
endobj
30 0 obj
<<
/Length 31 0 R
/Filter /FlateDecode
>>
stream
x��]߯۶~�_��QDR% ����A�a�C��+��h�
۟?ɢl�G��=�$�-��k]Q$ux~~����}��?��O�>��O7E�l��u��:�B׹�������/����͇͇�߯�a��?>��y�?k�����f:�s��/����������S.�V�����_UQVyը�n�/����߾�~k�Q�uQhm�Q�\F���EcrS��u�'}�޼����)U����\U��sS4ua�F�8�:Ӯ6Y]����������L�6j�U�v��z�-˹]٣G��4�i
�w�6���L���OY?�W��Oݤ_�J�٧�7�����/�k�cd�ʷ�+-+��ck�+��^�y��rp�m�T�)���T����NSTz|��J�'s�G�y���Q��NF�g���}{�iZb)lKC�g�m���>��c��P�mYE�������.�~��J��P����Ŗ芮�G���g�G�s��	���<�|�4��wľ���{�[PO�
�Q|O��RK�����liBQ`�0��R\n{�xf�',3b5����h�>;��\#>.��3��S�˕=�G�p�X�a�7P���]1�z�w�dn{�Tǣ����;�
�
�SL!�9��8^)�~�J��M���k5�S]���&NcO	��J1+
�5���g��A9�U̩'T�نs���;�g;0L���̿o�����$��E!�-�`�_��{��4|����w��s�Ѱ·�~�	֍?����ϡ�)>��,œj��h�,���Jg|^i�]T1l�5o�9�mc
���ŋ�|���kF�3r�
����R/~�hS{?��x^������#�1��+�s���O�!��7�K5Bã�xLU�v��5���`���ю
�C�d���L��L;w�s�<�Hfn�aC�Q
"�,��)d���u�=��D�ak��Q���X�c�/���r����X�a_�����a�8�!4�
a<�8��d�\���!�nʒH�����̬3ұJ��1��v���q4·&�!�:����坨�)�	{K�g�mh|�HD,����vCx�(l�|a�/~��i�*/Ϟ�h�S	O��P��/�DL�c��o���:M&1.Ӯ��T�(m����ДݷMfl���Ƙ�nli
��1��L?^�w�'�q6���l�w�'�W��>7�����7�v�%�R
�b��� v)��:î�����e�?�	̸(0�"f��eR�9�Ue����b�sZs���DZ=�AkΉA[�b��y$�+ft����b��Ġ-�xű쮸�}nor1��ދ4"��`�F�7o^˫��&%��f=G�i��.'~u��{J��$��D�hxw�Y��-����=
����'�m?����+)=Vڙ�R��q��@=Djh����F�ר�D
��$��0f��
f,8
*�<��v�̕#��=&U�EgM�W��:�D���R�wJ���hIK��H�C�T�X�w�J�dV�@� ]SPeF�L!�i�zj_JU���g�0)��l�X�{�q�2%c�)܏�M؟�%���?NȾ1=$��Uy�X���X��-���9F�m���}��G�5�<�k���G(��7��
�M�k��-9��5�I��6L���a��t%�2�0%u���l@1Ʀ	��X5!��	�V�l�F��HuW��>ӏ煐n�	!�gu?��Pwō�s�x��vJ=�:I�'|Xc	��W�J(I��'P�a�[N[���d.��=1Hٸ06>q&��u���O�sc�W���C��J1�2����Ʀ%ƣ�H(��*S�����4Ʉ`��.�:x � 6+�l��`� R"r��k�uJdu�%ci��Ho�Ա�t�3$қ���\۵%�PJ�? �u%��Y��jb�8%]�Y�D���Dz�B�x8Z��͛bo�ԁ��JJ��;��)���Q;����N�Kn�i��o�$x�#��G�:�DG�K��D��z�R�R�BZ���C(=�x�B�����l`bс�K����K��f'�����ޛ]��\OJqN)�aJL)α��M3�CJq��g��o��~:���v����9�.믘�}�o�]�~:���֏w����F��a����ڧUvd��F+�S�İ伳X{�d'6U�F6�l���%;Vdx1�����4�k�mz�|���bF��~<���5����cF�7�;��
�M��w��,��C	��"ӞR���͠d��u��o[p���Od\�L�FYe<I�E����7�(p�xJ|�t�;3�\?��[oF�쯘�}��K�s��o�x'f��f��Q1�	e�0�����dV�;�&J�ξ��Ғ~?�c�#�����0:���=r��VE��\]��~�6�p4�4d�0�"�R|�h�3fp������q�9!��;
��"��Ce��<�յ����N�s�s��J�d��ld����P���'[l��+D�8Z-aѽ��=ӆ�rO-8�("�q��XE�0�%��i��$Yr�E{����ej����A0ώ׊��'۴���2��ފ���_��������HA�̖�hG�
5�&7t1��wZ�zO@��.1��c\�9�33P��)*%�V�ܶx=Li"\	;Zq�!Y�:Q$kՅ��z��x��n�Kkԕ*�p�
"�qkPvk0�d�2���N���iķ���)����1���$�� *���s�E��f�p��:�W�4�Z�p�^��>q��f�w�/!x�a�jD����ڬ�V�\W�Q�Np�&zΚ)6��	�������%�X���v'�a��.��4G�]^۫�Ԉ�d�����i���D���ɋ�i���d!���(`E
�S05��d���0�	�<Z�;���l>�%�Clk�T63�j��U�˥�C�-M��z�D8�8Z�=�B1uK/e�i�*�A�_�C��d��=/i�B{��B؏�W�=<�9�<"Sۮ��
���a�����|�sD�����@t����x���M�E���h��D��<�=8��R�i���X
Y�e=3�G������b5�����Z��8�mw�u�xkd=I҄��0>t&Qg��%hG[��{�|�J��?M�-�N���rs�Ө�M��ȾZ2�_D�Mh�VM1�'&1X����{�e뙊�~Y4���p�q1���l���7�
Y�-07l�0�3eO��=?z`�����pNe+�&~jsK��e�zu��H���$|?�Q7�\S�e�R6��e�D�[`w?X@b0~��9.W7�`٬M٦DK)>s�M4�� ���yͮ���,���5b�p¨�!:FP�.ք������I�{Sp��)pS{��u��|kY�1�@ٜs�$u�U��������&�Z@c�h�jA�{�h��0o�;)�e���'�-b�2�#��E#���/���~I*:gAP�T�]��t�mA�==P9��K��Pxw�zp)�K]z�f��uD{2��T�}�+�	C��~.�P�M������R�C�q�{b�K�L�����`���h�
�>A��ݡ�'�*2�*���K6�R��H&�(T9VP�1�e_� !LX_�l.C�'��OW?�2hiLЖI|`����Zp�<�!��U�uHgL!�DJ��FHe�Dʞ{��%�����e�#tsʏ 
Hf\�E�W�[p˄%�y����C6%���~��@���jx�=p�O`�5�ҿ��0>O�r����lS�/
ܣj��d�s�=�Ze�rmp�=%�G���K��LJ"��Aհ����y��~�`рl����d�쌚|�nRluE�23N�Y����sƸ�rB��+3ZٜY��jFs���Q5�9�'K6�K������qn�\��ŝr�RUc.��JL�A&�ɸ�M�q�1u2���x=Tg5�
��y�@L���ك�Tp��)��0�?��*�P+
50�UYY�)Q�n(��2��F
��s��3����>T�X��H�e�
�@D%*�π�ek��j�8��L�,�Ra,�{�Ehk���u+�Eh[����"t�G+;c�iBUu�]�qY�y��������*+(�w��dmelj�륱RyY�x�?I�Y�fl��r��'�ɟ��<�]d�?�W����y��@��m7���@���u��'�M�gpZy�	�
�?�P�8�X��>&������͛�����������y��}����S#��t�Q����/OGKX-yu'qzO��9q�uQfz]j�W�'��q��PR��8.��g�Qp�
�5~���q�#�F0��v���BLj���ui���#��u� �<Ǫ<L�Lj�x���B��$eG�}S~R��1~s�Q`����]��g�F��A\����2�|&�Ō�JL`��tL�
�c�f��I���!�Ʌ���*��h�B6�?�5�r������9S�N1�_89�-�G;2Z���ឪ���LQ��\�S{b�Q�]�u���T�T�I5,�T�J����N�z(��_�����2�'Y-�WF����6�kO��C����T�}�T���V���M�}�3c���7��ucKS�o��g��k?u���订��k�w������~޼�f�l���U�m-w�c�UG+0�,?�
�i*v�2{@(��y���.���DTIej��Տ�"����s�T��T1,���i{̘ژv���D:����y��נ�;���C�a��l��
endstream
endobj
31 0 obj
4897
endobj
35 0 obj
[3 /XYZ 33  
765.500000  0]
endobj
36 0 obj
<<
/__WKANCHOR_2 8 0 R
/__WKANCHOR_4 9 0 R
/__WKANCHOR_6 10 0 R
/__WKANCHOR_a 11 0 R
/__WKANCHOR_8 12 0 R
/__WKANCHOR_c 13 0 R
/__WKANCHOR_e 20 0 R
/__WKANCHOR_g 21 0 R
/__WKANCHOR_i 22 0 R
/__WKANCHOR_k 29 0 R
/__WKANCHOR_m 35 0 R
>>
endobj
39 0 obj
<</Title (��PERFORMANCE OF ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_4
  /Count 0
  /Next 40 0 R
>>
endobj
40 0 obj
<</Title (��ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_6
  /Count 0
  /Next 41 0 R
  /Prev 39 0 R
>>
endobj
41 0 obj
<</Title (��LIMITATIONS OF LOADERS AND ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_8
  /Count 0
  /Next 42 0 R
  /Prev 40 0 R
>>
endobj
44 0 obj
<</Title (��\(Available for Linux 32 and 64 bit x86 servers using PHP 7\))
  /Parent 42 0 R
  /Dest /__WKANCHOR_c
  /Count 0
>>
endobj
42 0 obj
<</Title (��IONCUBE24 : real-time intrusion protection and PHP error reporting)
  /Parent 38 0 R
  /Dest /__WKANCHOR_a
  /Count 0
  /Next 43 0 R
  /Prev 41 0 R
  /First 44 0 R
  /Last 44 0 R
>>
endobj
45 0 obj
<</Title (��Global settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_g
  /Count 0
  /Next 46 0 R
>>
endobj
46 0 obj
<</Title (��Security related settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_i
  /Count 0
  /Next 47 0 R
  /Prev 45 0 R
>>
endobj
47 0 obj
<</Title (��PHP Error reporting settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_k
  /Count 0
  /Next 48 0 R
  /Prev 46 0 R
>>
endobj
48 0 obj
<</Title (��Deprecated settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_m
  /Count 0
  /Prev 47 0 R
>>
endobj
43 0 obj
<</Title (��php.ini settings)
  /Parent 38 0 R
  /Dest /__WKANCHOR_e
  /Count 0
  /Prev 42 0 R
  /First 45 0 R
  /Last 48 0 R
>>
endobj
38 0 obj
<</Title (��ionCube Loader 14.4 User Guide)
  /Parent 37 0 R
  /Dest /__WKANCHOR_2
  /Count 0
  /First 39 0 R
  /Last 43 0 R
>>
endobj
37 0 obj
<</Type /Outlines /First 38 0 R
/Last 38 0 R>>
endobj
49 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/Outlines 37 0 R
/PageMode /UseOutlines
/Dests 36 0 R
>>
endobj
34 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 50 0 R
/Resources 52 0 R
/Annots 53 0 R
/MediaBox [0 0 595 842]
>>
endobj
52 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
53 0 obj
[ ]
endobj
50 0 obj
<<
/Length 51 0 R
/Filter /FlateDecode
>>
stream
x��[mk�8��_��u�jIP
M��AI�>��d�X�e�����?9gc'��L��^wj'�F�g4�������MLf�/bI�ټ��w��'�g�_�Pҽ�нX��ⱸ-n��Ǣm���|(&M_E��|�{��Gh�k��I��W��%�����+_�M+�>~�����*�����~�c����e�Rk��jl�|>3��Rz]=���-C���hU}�.�W֧�(c�&j�ixO�0��F|}W��=v�a��a�:7:�Lsg��xW	S57��ߦ?��.��H��I���3M{�s��l]-I���NOI�;z�m�c1}�c���:]��J(-�E�γ沸/lHތ����<���B,>U�5u��O5����2Va;k�Q�DV�#�:�qʭ��QkZ�$��}ܚ6+�++�Bg<J�N�0�=�s6$�$��=�A�d�Z���>�X0m[���ܬ$׋Y�	��*6�
h�k/Tj��虦=
�v��uԞ�J-�=߶w�Pq����H��'���i±TU���N�X<�����i�j86���e����
+��=J۟guI�m�h����Zs$1Dt��Op�.����}�~h�w-�
�M]�E��w
�-c�"–�t��6C�@V�'~2�r� ����r���ϋw�~���BL�f�o���	�����f�s�i�9�E�/��3�h�69l�B�-%9~Hk�$��A�Ϸ�%���I�x<ж��8�C�Hە�9�'|Ɯ�<��H1尚���o����:��	ýÊ���4u,P��:r��������kF�Lɣ�2o�9�5JX8��o<ی�o��0w�5;j��V��-7q}�a�q�����U�'7�+�wr��^�t}ﵳ1A��o�qi{����"�� �LSZ�����T� ق��dž[-��
J<l-@�5�(�����l5��V(���H�Q���&��Xpu.��AI����X.�D+[K�h{A�y�4��T���8�7=����T���l�p5R�XX�Dl5&[��a	
��g�8&[X��=�$�A�2�A9[Ƒ�>/�U�F�=�l}8��l�q���kΜ���x��yo��Z�)�`Te���/m�(�%N���b(c�S|=Y
[�WN!��a�a�i�:��x‘|�����̄���.Y��3?��>r��b$�f�8�9ebNfb�-�Xqkx�F-��r=^�Y3�U74�}��GʚG{����ɚo��9��L��É�qW
�	���Ki�������i�G?X��8��3��N������돶*��)#�<��������aX�*N�{<��-2��sh�Q�aU?�T/�T2���F��a���F����g�.����13�ގS������ [�'�Y�����B֬�^:�� ��F�_�U�o��u��|˾V���-W��h�#�D���D��~3���
[�Gj�8�18��<���Lk�o�6��L?��K��]bT[^����'_0��ls��K��[��Y{XE�얞�]�^u�����H��Ȍ��d��}����jz�
endstream
endobj
51 0 obj
1581
endobj
54 0 obj
<< /Type /FontDescriptor
/FontName /QCCAAA+Roboto-Regular
/Flags 4 
/FontBBox [-736.816406 -270.996093 1148.43750 1056.15234 ]
/ItalicAngle 0 
/Ascent 927.734375 
/Descent -244.140625 
/CapHeight 927.734375 
/StemV 48.8281250 
/FontFile2 55 0 R
>>
endobj
55 0 obj
<<
/Length1 6976 
/Length 58 0 R
/Filter /FlateDecode
>>
stream
x�}X	\G����{�F�1+Ȍ�`�P`&�7�)ry" �9ܠ� ry+(*�&��&Fr�I0�$���[s=�xd�M6	0��g0׾���ꪯ���5B�
�L8B����j�=���bI��_�y=�����Н����q!l!���';Ư������삲*���`�B`l�1-���#d~&��UE$�,�v#�U����7�	Bh;��`:Rp����$��V,�-BGb�j���!K�������eD$$S�A�e�x?�4�C��Hm�9"'���B�j��S{5�A�M3ϥ����a����F9QG�5��S��rs���R�*Z9�%M1�_��$���Wq
{��Q�87���K��0Q.�LպA��t�'�蝝���>��y?p��rqQ�r����j���G�J�����J��˴HF���t4x�o��v�\�j��b��͍s�Kv�����}{\,�'�4��Sm��MAA;��Vo���m�����3�((D���'�.�J��^�Q�Y�˱
���˰�3Q�޸* ���5k�z�f����6�~�R��]�}��ȲF�uS��F7�� U
R�)u��Ͽ�c�}��q�C�O}��2��_b��LY9ik�=��W���h:�ցCq�[�x::��ip���V=��m���@��Z��)&���p�
�>�r���ө�͐��O��A����.I�C��dg����i�D���Q�Т�5(	�c^UR�w�h�m*�����x~I™��aT�s��=52b~������Y�%���,\'	���y2�� C.���
(����*����z�����<����zy�Yï\ޒ�]�$~X��Sl�&ž]�O=�ych0���b���4�>m���Ҹ=�GG2u�_8������
��g��_<r�9%���7ȝ+�Dv��4ȡ���	�P���*�����R�t�)lk�9��
[6}s�Ͽ(- z��7-��7/GpZ��->	����W��HNJH�O]pLTĬ�����8~�r�������Ӌq�9��~�-���e�B��ՙ�%�J�ʊ/Mݶ�K/TT� *��'6�(�ˁ�Z�=Hʚu�,7eew�wsr�^@�q��!�-@�,����<��t�[�w�3�Of�05�a���Y�L�{A画�-t�3���kȽ��"C�#e��	����B�5�shk�y�;�����[�}7�K�1�v���*�-�ta@#Q�$u�����;�	�i����s����E�1g�
@5E��c7��
N���7��7�aD�w�M[n�ݱ^Z��c�@85<��k���͟s���:���e�:���d���(%���z�r栱
�o�me�Ĝɀ�Q0��l���N�b�se%��f���[�fN(-?_��a�5�!A%ً�KČi.SfL���ٺz���}zf��5ST3f��Oܓ�`��ؔ$�Gf�`��C	���e�����S��7����h�Qy��j�Fx}CϳM�Qh&����fU�A���P\t!�R��C�.����:���g�C�����R��=0i�/�f�7��96Ԓ��|�8���g
�:Gc0���:���l�ε�!��j�C����_�!Ӻ���@lx�e�@L秅���榦ܬ�C�,���*���М��Q�us�L�O��{�ȎTo��q2_�}��3��-�Ȫpu��Ip)�y�f4��xk-i�O�x�8�e	��&7��Ouv@И��g0�T���� 6�gҁR�y��^��@��7�lc;r�&
��Y7s��R p���Wh�:l�<y��ox`����Bqp�9u��zl�Ĉ�fzt'HrS��{�,6\�75X���/���Ū��C�,k2�&� Β�Y^�I9DL���-9Ē�-�	�Aa�O��⋗�L]�E���	ډ�ا�c�-Y����!�`�^q�?����C�򲑃��܀́�Z���8�\��ҁ��O&%u/\0��{%��m�ɝƧ��ص�z����N@����{�y
�i��J����t��K�4L�Yf�)�e/_2�vU�\+/*�K�8�a�PV�|DĶ����Eb�5��h��um�z��\n܋Ѹ9i�:��s�w�^*e�>�M��8Z���U�8`XG
9}�M���-v���q��q;����|I8�ֿ���28����6:���;��>$i�y��:��yj_��"=nNN�w��,~��#b���bRӱ�r���<�ďCk[��;�b㫑[F'�#��caP�5��%�����f�6GF��n���}q=�h+���X�r��:7��{�{�
������*��l��H��F8-ԞY(3R{{��I�o!m�����.q��o�~��r3p����¹vH�R�V�W��`@;�?|I�ʸ�	�Z��i���an搋�=7��ws�,�g[�C�E����
w��Do�q{��e:�x�S��zE�Ͽ�3��Xc��Ajd�a��^�/�g?6ԇE�B�s!hw$�Ò�v�Ce~V8UT�NSz���m,�&<�f[h��4W��/q�H�`��i��\ø�ܔ��lQo�0I��ѰȲ����AK����	�	����[{N�7�F��5ԟ�i�z���?���A^��73��]�u���ĸ��Wr�?�,!>���w(������w삦ъ�d��9���
{�'��pn��_�&�S��{T��j��j��C��Q��Ć(8K�e�?������2w6]��NP�~s|�3T��x����]��[fa ��_h.^��\��u��,�o��!����Z��r"�s
ӡ��.8�Ҟ�K�钘��_�>p�fK�©���C�'�w���x&�47�$����1)� �.A�X�eV5<@�Q$!��H��$ǣ�?��o�,_��b|����1q�Lv��gs��ں���kSo�]I��s�<U\�矑��.*�-0��7_��7?6��tn�?����>2j���ܹR̟����2�����Ar@�\��;M�_�i.�]����P*��{�c}�F�I��a�S�r_��F��GLs@��t�,�L��Y	��e��Ξr-�
��VUmqۓ�l������%�^}��+d}�#~� ֈ_v���@<��
HqҨm�1����-M������_��N{09���Y�1����y~4��W�:V\��Oࡺz���K�û�z�
R���nc�C��

���?�;������@�|��@��k�M�/�Q
U2m@�Z����������{<�?����v�ֱ��1F���L]���2�)
�~*��w?�׉�22�\	��\s3�ف���ѠF�1�p���a4�bW�IH~%�~c~vVn�k���6|��
v=va!�[�Ö�ԯ��w�K@��O>�Ry�/�,X�b���+���4\��k~A�b��G�$���߁|T>SG���z��@CKmd�Ⱥ�Pl��[����V-^�i�[W6m鍈ظ����{[8/(�EO��^LY�r����1k�g�� $�nS`���d�͟��z+jU�h'����b.��r�zDox�XD�Gr8�'8�;0���koG��y5A��G`�_-�A�5�^�K�������~I��\���a`���Po�,���}F�nS�����1Q
O,[q�aIuٿoK�����mz1�v@n�,
-�킁D\����x���˽/��&`�6���G]��W
��5 �Y�ꖳ�{�5�ؑ�A�kX���.޴��k7â�%k
�Be��}�����O'�au��a ~S�8�ޅ�s���+^,*����k��$&���k����H���P\�
*-


(*	F���yi�C�<�,'&Noga[±Z]��1����3��19��;.������-{�t�)�'Xt�p��qw�s�����]�0/�\��uN���c�s��J���l����G���d���ؗ\~	q4��~�*`��w-eI��Ҙ��a�.�>"l��U[�]�t۶�G����u����/!��ի�ڒV�&�FF�F)�;�S�NB��Q_d���;W���4�.�q�����*��o�����K"A�L샩5Q�!;�/����ˌ��1u՚M��b�]� $h=Ƞc����G}��R:��eŌ��'�Wԥ�}�0R��Y���4��F�_�f��ZO1��]3�m���z0Ƃ�	T��x	9q{���0��0�=�*��7��� F�
��qęat;�T��b�?�����s�ϛ���<Y?��s2�7&^���4�8�yp����P��m��'?<�G�����1CvO�<S�����E����8�PvO���+�k%�����"��\�*�I%��r�!��<�C(�h�ů$|I��a�FҍEO'�]��U$Y(%�Kē�ƶY-�H=Bl�[D��3z�52�)�X�%�!]��8#�$�N��82�{�8��=r���1�I�lߏ'6^X��.��#d}�l������$
�x��Fҁe
�D��Ä��d:�Kƾ(,EXJ���C���+I&J�Dw�F�z��Ë$���,��x�O�D:�.��t#�;�rq\%w�����Z^�g�����`/L��B���p_��"d�&�Q��Z./���$����M�M��36l�ٺ��l�m���4f՘�1c��<6�IKd�#i�/;r�A��b�3�wZ���s�:��oX�<�oY�����u����d�
g�^@�HX?��)�z�Z�Ek��5k] n䶵.#N���Ǔx��IYGJH�"٤��P��o	��F��'�
#�$����"���w�Y�R+�H���8��֕�de���<<=U!FcV~�*�0m�jQ~�*�}*U�f�f�Td��X\o-�2,$ָ�X��H.��㒩H��fd�秖����Cg��V)�k�M�-��
��?�0���c��k�����x6�����x�p��EJ�-b����8�K~��'f��|d'
{
%��bO$�8�!‰ç�Ħ-++�3���rvjQjZv�lcI֜�����Ҍ�9�aA�qA�^�q��G+�
endstream
endobj
58 0 obj
5244
endobj
56 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Roboto-Regular
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 54 0 R
/CIDToGIDMap /Identity
/W [0 [440 241 566 547 646 547 557 526 246 534 540 559 336 557 557 261 643 512 676 592 546 519 869 324 481 241 557 344 557 626 707 195 557 270 745 469 564 611 548 682 866 647 707 651 589 880 339 345 492 240 503 557 557 562 448 210 564 557 557 557 557 618 274 409 631 317 237 ]
]
>>
endobj
57 0 obj
<< /Length 826 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0042> [<0069> <006F> <006E> <0043> <0075> <0062> <0065> <0020> <004C> <0061> <0064> <0072> <0031> <0034> <002E> <0055> <0073> <0047> <0054> <0068> <0063> <006D> <0074> <0076> <006C> <0070> <0066> <0067> <0050> <0048> <002C> <0032> <0049> <0077> <0079> <0045> <0052> <0046> <004F> <004D> <0041> <004E> <0044> <0053> <0057> <0028> <0029> <0078> <003A> <006B> <0035> <0033> <002B> <005F> <003B> <0071> <0037> <0038> <0030> <0036> <0042> <002D> <002F> <0056> <0022> <006A> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
6 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Roboto-Regular
/Encoding /Identity-H
/DescendantFonts [56 0 R]
/ToUnicode 57 0 R>>
endobj
59 0 obj
<< /Type /FontDescriptor
/FontName /QHCAAA+Consolas
/Flags 4 
/FontBBox [-432.128906 -302.246093 677.246093 1011.23046 ]
/ItalicAngle 0 
/Ascent 742.675781 
/Descent -257.324218 
/CapHeight 742.675781 
/StemV 70.3125000 
/FontFile2 60 0 R
>>
endobj
60 0 obj
<<
/Length1 11900 
/Length 63 0 R
/Filter /FlateDecode
>>
stream
x��yytǙgW7�� �H$��M���/�%ID @�hZ�%��x��-;vd[����$���x2Il����;M6;���y��y����Yٱw=~�l�W�
�e�X�+tuu�W���jR����8�P�������`����%Vf�Ux�o������c�hde��e��X�<�L�=<�����}���u<�<�6�����ߚ(ʌ�/.��[�ڨ'(ʢ�g6^��ێ��\MQ�a�͢�(1E��(
�;�kj��

i����E-�J�7��՛@��c�R]TwS���'hZ:E�)�o���bލ2S"j��D��̀�
8EJ�7;��J��:\��`��_G0P���K���f�$��Pe�_���!frMD��*U��@p@���h����.�;�c{��~Ra�K
d�R���D)SH*�*d����5��n��g���x�mv����5FCqQ�`�r����`tnZZ�T�*�R��^�����A6{��*'CN�r��`�>��{�#�3j7��2�L&/S�f���T��j��L=���S�ĔL�R���Xƿ,3�-f�N���(�c��"�Q6����*�uא����w���4j~<��+���wN�[L�M���X���}�d:1>��b���TZgecS��PsyE�R�r9C�};�B�e��[
��8]�a��
<��90��r"�����L
���Zde���[�o��k���}��:u4�&��Rt��k�e�R��ܳR����rW�<32|y�'X+˖;]����
�r��P���ڽ���!T(��ܭk�x��n~¼���sb�
`}h�?�(��üпep���@�}�����������7���V�3�N������4*�щ��	��W:�Ln�hW��~�ď�M!�,e1���NY(��pI6,R��I�y󌤦ʍ�yvx�|��Zv����ݡ�J�ԾW���x��Z���~|�������LTӆo`i]���.~!U�9s�,�o�޽���s�`���XOW�W�}�c���^�pT�ܾ@������Se������� n�x�;�j�[�*�]�������g6�r�F���3hd
�V�x�
b�΂f>O��:���
~B���yv�I�(�IN�cD����oyk�g\Nvpr���[������D|d�)d1��⨫�i�Ֆ;�Z��5ώ�AbF")�>��:��g��Ӄ[����clr����]��ju.w�	�3����_�V��h*l5�kg�:MqQQ�Fge��U�+*F��H��ZQkQ�����q��Vi���7�xt��壍�G�P�:���1?'�F�<�`����(�
�+ǝ��q����o�t+����;���yi|dϤB����~���@����;=�Z�����P���j�vn�xh���.g0������PR�˟S(d�B�!�����1��])*�����`Vi
T�؅�I���9�n�(U>恟���p�Q=�*�#�b�Q��9�/�ռxF24:>3������!�3�u�r��;w���b��^g9�H���G~z�>PQ�ӵ��/�xr_k��*�0[�
d?)hؐ�2�+RG�-(v�y�����3#���*�pEy������\�Ku~������(6Z<�mkG�.�͊f��p
��,���x�}k�7�܀=�T0/�hw(y@�k���PwV�������.?+���X��5L|5���Ţ"nJ����y����~:���k�6X��6�W)��\i���z}�~�}d��~���֦{����%�4>�Z�8R�p?{��$�L��bdU6���|fh�7/{�G�=�.W��eI���$�'��OdZ��3��$7w��Cj)������5�Ȇ��6���F���]��Lks�ɿ����ll��W[W��=911��BPf xO_s�ۣ׫U���ᕖ��;�5�xkL�B.���{&;�+���˂��\�+)�R"��Qc�F�F��hL*��Q�u{�몽����Y��P&/Ui�&�V�Ҫ4P�X�+�5���������OT<�"�V�Y�.V(����ʚ,j�m�B���ػ�c���Xs��-���%��������Kp��r��q��Ľ��V:tZTTR�**)���A��6�����֎�S˨�.r����t���
:�����j�]Q��ZSӾg�Ζ�r�x�"j�j��hJ���W@i�q�/p��k/����p���i�$wg��w�4�ɡ3�v�Gw�T榛�~��ysm�E����]���ij@5S�O�����ןC���;�7�����o���\'�큹e�8�~�5�G��[�,��u��h����Ք�d���х�7��O�(�=��"���)��]�ʆM�_���Fy�-�^j*�L�K
eE��R�J�5؞��EQiY��t�����Qo4����G�Ӛ
v��u��>���N	
����Z;B���aW�H�4��lY;�\�Y��e�C�@
�T��e1�Kp�9�/�&8/9�z�ZL0�r�|N��rhR�ĥ���/tZ��dc]�/��{����2UyECco��t�D]����Xg��Y�Q��~֊�Ck��McuMg���`��g���}�aZ2l�v�Y͞*����5��1xȫV�E�N�$T�	�6�h�p�
�!����`&X�=�����:�\NU)Bf���������3[����2}�	(��.��|��OZ�u���v��jF3�1C��"\��^��(�x2\���jƶd�������:�ƈDi���hktVZ�0�hc��M�`����\e	�\��ru�3���'8���4�%#��
�k�`�g�҉��v��)J3A7:
΂$d���^'2}-r��p�?�^G�}k��wf��K��B�S�cHI���M��Խ�zh3P�]�U'�t�[Q���v��5(WF��)�Ѩ$<�ug�}LƤ,1[�C㝡&���@Ն
��;jk�d��uLM�l<Ԥ7�45`T��
��u���D�I,�`���
G�%֘��'w��)�����q7���H$���bv���X+U�-.wm��6Y�J�i���qgW��Vo,.R��Zi0"SZf����}�m5�F�Z��c�`S(�(S�4z��+�^�5�f����Z0n�W��6{I�Q����Huj�F��i���
6-V��R�����b���#��k	�x�G?"u

 ��\�e�|��ܴq�=���3�\�LJ����v�{���xg�������B�A�W/}㟿8�}#uS�\�M5C����`d6e9��ʅ�NU�q6 ��ñ�R5�8�SƆ`CMS������'�`��r������G�5vn�:����YWoc���ͪ�6�"��@@�PG{Q���t5���DZ({�H.s�F+[�in�ꮩ1�D}$Q�J.�JD�
���q55�h�h���6�S
_��-�'Z^5���&*,f�s�4v��1'�ߥ� =�^G��;��z@�@TK�ԣ�Co�?���5Y�k���Alt�
���P��߼��͢�����:��l�{X!7�+��G�z�>���W?�W�f����6�5��9R�rt�X�w獡S�sTB��ǵ��:0
�������
F�NKꚚ�C�Cm�͵6�w�M���zg��\T��B�7:+��>X�hߧV�ڵk��'�M>���BB^懰+�4��x�v���o�ݻ�
�\VTl4y�[G{��n�9x|bp~�U���!}�ڵ��
�
�j8��U�ʖ��ZBc]����m]�ݽ}#��J��Q�QF�.ɈAP����}y�a��ƻ\�kFo";�.�?̈́W��_Y�~?q�CQ1He�s�P�wɝ�9!A�u�pb�G��M�b��깕/��ї�#���:���XG��B��v�N[n�V5�6�\.�f�d�]����U�@_�	�ҏ<u���^=B��=#Ǐ]~��N�]�=ǎ���ag�X�[
ٹ�n��9p\�ZY3z:�q�Ve)��w���vl��Zf�%U�D
!�ڲp�Cͽ}û"F�ƀ1�頻he��_s���
��_�D:�-Vi�1�Ev[}� .�Μ��{n�aO9�/��0����>�>��Nr��&�6�:Ɲ@��O�Пq�v	���W�ז8�~���7��&+Z��!��y,�8�
�ܕW��o+�{�vÁ��3��T��x�j�@��ׇ�;۷�����P(��궎�'��R��%]W���-��.g��嬘�5l0��[#�z��ҨG��o�j�����\")+-��ڂ�*����Q�,���=�q���\^P {<mm��ݶ��@�wV���K��S�E�o�Kk���_Ҷ��tPlz�;���I��p��
%�"H�T���=��x
z�"S�$kܴش����K��k��%1�y{uwˑ��t�[�ET��<[������juW
���=�������J�\����Ѷ�J�J���\Ύ��=m�J��~��N��r�ښ�G��|���nO��vt�ȑ�dNo��U��S旦ý[�pb��O�!����ƩGT��!w�yU��GE�����k��&������b�-T��P���SO��N�S7���N�\�{�C�Tn>Ư+c�����~���'�tW�؞H|���;��ػ붆�ɂ��ߌ��>X׍��m�w���~���|����g��
w�W�Y��d������������������� �z ~�q��"**������‘/s�G#���S�!���qxW���u�́���Cm�j�^lz�,������
hU���}���~��2��"mX?�0�[��]�p�e��;���ze��o���sc�ûv�j�t�8�ؤ�������]{�����F4E�H*"\<`1�h�{���+��O��yY�߁#�'���~��)ķط�ׅ%m����v��ȳ�K��F��5���D�Ǐ�YB)�/c��^��s��
wܖD�����]�F	�;���`�3p�m�p�@�愶�%h)a-�B�П��S	��C��	h^��Vh[x~��К��o�
<bd�����D����>A���oL#s��>�D�!J�>��.�'��şK�%A�i���NH�)}��t�
�>Q�O�JY�짲��Z�G~^���mE�bX1���⇊�ElQ+�n�z��۟%��멜=�B���B���ӧB_D ��S
�.�%0>%�TzW�PzP�R��q�/��'�&��W���WPy��/Bۋ� �ƒK�	�F	W���R�i�Oì
}������Q��@�)=r}	�	})u�	��C��~!���B_&�M��rj\���WP�J�ѧ�cB��J��Q߃J�j�:*�T��Pi*Ee��RY�^|��a$�$ԉ,�M%�b��06G�ûy��=��oW��c�uvG<�NeR�Y�7�^L���x*�c�	vw|n>�aw�2���X��m0	�6�d&�C�0�~�����R"�۹o����:-�ͻl7N����PJ�@YxKg@6��Ja�+h��0�,Qk�X ��1�<~3�w6�y^��fG��a�)NL��`��g�0�M����p���e��<�̥SK�x8�ZX'㱌�N��c�@�Ѵ�X�PUDh7�������/E��7���T*{7]�A>�P,���g�x���,�s��������~�҄�y�
4��^J�u��ό���%s"D�,Y���`�B��=��]�(�������2�[�'4Ä���=�%c��>9/��b��8���𔀧Cdk,JV����V|�f5�7ssz��ě�9�7)b�X��X�0�:��bLk(#�a��(C�����=*�'ފmrX�����eBiC�Q��E�+dw�;<�_\+C�()�k(����ܕ�3A,�[=}��2M�� c1�>���#���uZ�ܻ{B�;���M_H��$��9�2y�_ ��z��
҄A�	���狷-�	<�1�՘�9�x,ː��9��ab�$p��!F}I�)mX{KB8���;-ț\K�x��%�J+ٛ��y�[5�!���Uy��*�*)�Fn~�{zR���B�`��s��s4#؟�WΧp��lI�ov=��=8A�&�s���2#D���躟�OY�_�̟!=LPae]�9��3dn>�-�q{�/Ģ�l*�.ebl<�.�Ss���B<9�ƒ���Tr!��\NF�d�4��#K�l8�e�e�A6YH%S��p��Kf1��b,��C�&I=2N�#YȒ�|�p���Lx!�.ǣ�j6?cS�(�]Y�-��xf5�>�y�ga��T*
dR�H��3R�p�07���'c��t:�YL%��C;
��@0�$؉x2�Z��<F��Dx�
'�ex�ē��%���<V�.���f"��M��Tzv���˂�$I�q<F7)!��ԛZJ�ci�	V9�,C�_H�� �B?�I����i!��X2
��NPVd"�X���Xr4�����%��I,A�n���4�Ľ��B,NdZ�|>�f��l�
D�?�������$dk0Of>��cB3 ?�5����[�,6��D*�����e����6�
g�1vf�=N�`�lО	�yG[��%�<��E(�j�Z&����[����B���E���8�n�/5��.���.//�r���P���q~�6�%��C��,A�4A���9�x�lx&?��R�^��|�]ɫS��8����G��Wr���@.�1(���P,���pQRje׫�e�W��;���o ���ǕE����r<-���ȸYn���OU��M2�]�?�U�6�~mP�Ȅ|���#�T��r�f��3
���%K�˕˜>/+_�$I~�QIy=�o�i�ߍ�k{�P
�H=|*Erp�[�����_W�g16T���'8��c�l{7���]�dq�X��G�����ш�:�BL/��0!� ����ީ$�^U���������w�L'`	�M�#<P����i��V�]��|I�aWH�D*��)��9ň�2^j)���"vg�3K,n�XmU-1.��%R���/BY��0`���lx)���3���;�	
endstream
endobj
63 0 obj
7274
endobj
61 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Consolas
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 59 0 R
/CIDToGIDMap /Identity
/DW 545 >>
endobj
62 0 obj
<< /Length 742 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0036> [<0069> <006F> <006E> <0063> <0075> <0062> <0065> <002E> <006C> <0061> <0064> <0072> <005F> <0070> <0074> <0068> <0073> <003A> <003B> <002B> <002D> <002F> <0076> <0077> <006D> <0052> <0053> <0020> <003D> <0022> <0066> <0067> <006B> <0031> <0024> <007B> <007D> <0032> <0034> <0030> <0079> <0078> <0037> <0033> <0045> <004E> <004F> <0054> <0049> <0043> <007C> <0044> <0050> <0041> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Consolas
/Encoding /Identity-H
/DescendantFonts [61 0 R]
/ToUnicode 62 0 R>>
endobj
2 0 obj
<<
/Type /Pages
/Kids 
[
5 0 R
19 0 R
28 0 R
34 0 R
]
/Count 4
/ProcSet [/PDF /Text /ImageB /ImageC]
>>
endobj
xref
0 64
0000000000 65535 f 
0000000009 00000 n 
0000038255 00000 n 
0000000187 00000 n 
0000000282 00000 n 
0000000756 00000 n 
0000029337 00000 n 
0000038121 00000 n 
0000000319 00000 n 
0000000362 00000 n 
0000000405 00000 n 
0000000449 00000 n 
0000000493 00000 n 
0000000530 00000 n 
0000000574 00000 n 
0000001080 00000 n 
0000007535 00000 n 
0000000877 00000 n 
0000001053 00000 n 
0000007863 00000 n 
0000007556 00000 n 
0000007600 00000 n 
0000007644 00000 n 
0000007688 00000 n 
0000008188 00000 n 
0000012626 00000 n 
0000007985 00000 n 
0000008161 00000 n 
0000012691 00000 n 
0000012647 00000 n 
0000013009 00000 n 
0000017982 00000 n 
0000012813 00000 n 
0000012989 00000 n 
0000020361 00000 n 
0000018003 00000 n 
0000018047 00000 n 
0000020194 00000 n 
0000020020 00000 n 
0000018298 00000 n 
0000018452 00000 n 
0000018591 00000 n 
0000018987 00000 n 
0000019859 00000 n 
0000018784 00000 n 
0000019263 00000 n 
0000019391 00000 n 
0000019554 00000 n 
0000019723 00000 n 
0000020257 00000 n 
0000020679 00000 n 
0000022336 00000 n 
0000020483 00000 n 
0000020659 00000 n 
0000022357 00000 n 
0000022621 00000 n 
0000027977 00000 n 
0000028459 00000 n 
0000027956 00000 n 
0000029477 00000 n 
0000029735 00000 n 
0000037122 00000 n 
0000037327 00000 n 
0000037101 00000 n 
trailer
<<
/Size 64
/Info 1 0 R
/Root 49 0 R
>>
startxref
38374
%%EOF
alt-php55-ioncube-loader/LICENSE.txt000064400000025020150431103020012760 0ustar00LICENCE AGREEMENT FOR THE IONCUBE PHP LOADER, PROVIDED TO ENABLE THE USE
OF IONCUBE ENCODED FILES AND AS PART OF THE IONCUBE24 SERVICE (ioncube24.com)

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING THE
LOADER SOFTWARE. THE INSTALLATION AND/OR USE OR COPYING OF THE IONCUBE PHP
LOADER SOFTWARE INDICATES YOUR ACCEPTANCE OF THIS LICENCE AGREEMENT.  IF YOU
DO NOT ACCEPT THE TERMS OF THIS LICENCE AGREEMENT, DO NOT INSTALL, COPY
AND/OR USE THE LOADER SOFTWARE.

DEFINITIONS

The following definitions shall apply in this document:

LOADER shall mean the ionCube PHP Loader software package or collection 
of Loaders, including any modifications or upgrades to the software, used for
executing PHP scripts previously encoded with the ionCube PHP Encoder
software to render them non-humanly readable, and any associated
documentation or electronic or online materials relating to the software.

ENCODER shall mean any ionCube PHP Encoder software or service used for the
purpose of producing non-humanly readable encoded files from PHP scripts.

ENCODED FILE shall mean a non-humanly readable file produced by the 
Encoder and being derived from humanly readable PHP script source.

PROVIDER shall mean ionCube Ltd.

USER/YOU shall mean any entity who has downloaded or obtained through any
other means a version of the Loader software.


1 LICENSE ENTITLEMENT 

1.1 The Loader is provided without charge.  Title to the Loader does not pass
to the user in any circumstances.  The Loader is supplied as object code.

1.2 The provider grants a personal, non-transferable, non-exclusive licence to
use the Loader in accordance with the terms and conditions of this Licence
Agreement.

1.3 The installation or downloading and use of the Loader entitles the user
to install and use the Loader for its own internal lawful purposes.


2 DISTRIBUTION 

2.1 The Loader may be freely distributed to third parties alone or as 
part of a distribution containing other items provided that this license
is also included. 

2.2 The Loader may under no circumstances be branded as another product, 
whether distributed or not. 

2.3 Distribution as part of a commercial product is permitted provided such
distribution is in accordance with clauses 2.1 and 2.2 with respect to the 
Loader.


3 ANALYSIS / REVERSE ENGINEERING / MODIFICATION 

Except insofar as the user is permitted to do so in accordance with applicable
law:

3.1 Any analysis of the Loader and embedded data by any means and by
any entity whether human or otherwise and including but without limitation to
discover details of internal operation, to reverse engineer, to de-compile
object code, or to modify for the purposes of modifying behaviour is
forbidden.

3.2 Any analysis of encoded files by any means and by any entity whether human
or otherwise and including but without limitation to discover details of file
format or for the purposes of modifying behaviour or scope of their usage is
forbidden.


4 WARRANTY

THE LOADER SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
WARRANTIES INCLUDING BUT WITHOUT LIMITATION THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE ARE
DISCLAIMED. THE PROVIDER DOES NOT WARRANT THAT THE LOADER IS UNINTERRUPTED
OR ERROR FREE, NOR THAT THE OPERATION OF THE LOADER WILL FUNCTION IN
CONJUNCTION WITH ANY OTHER PRODUCT.  


5 LIMITATION OF LIABILITY 

5.1 IN NO EVENT WILL THE PROVIDER OF THE LOADER BE LIABLE TO THE USER OR ANY
PARTY FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR OTHER
CONSEQUENTIAL DAMAGES ARISING DIRECTLY OR INDIRECTLY FROM THIS LICENCE
AGREEMENT OR ANY USE OF THE LOADER OR ENCODED FILES, EVEN IF THE PROVIDER IS
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

5.2 THE LOADER IS PROVIDED ON AN "AS IS" BASIS.  THE PROVIDER EXCLUDES ALL
WARRANTIES, CONDITIONS, TERMS, UNDERTAKINGS AND REPRESENTATIONS (EXCLUDING
FRAUDULENT MISREPRESENTATION) OF ANY KIND, EXPRESS OR IMPLIED, STATUTORY OR
OTHERWISE IN CONNECTION WITH THE LOADER TO THE FULLEST EXTENT PERMITTED BY
LAW.

5.3 DOWNLOADING THE LOADER IS AT YOUR OWN RISK AND THE PROVIDER DOES NOT
ACCEPT LIABILITY FOR ANY DIRECT OR INDIRECT LOSS OR DAMAGE HOWSOEVER CAUSED AS
A RESULT OF ANY COMPUTER VIRUSES, BUGS, TROJAN HORSES, WORMS, SOFTWARE BOMBS
OR OTHER SIMILAR PROGRAMS ARISING FROM YOUR USE OF THE LOADER.  WHILST THE
PROVIDER WILL DO ITS BEST TO ENSURE THAT THE LOADER IS FREE FROM SUCH
DESTRUCTIVE PROGRAMS, IT IS YOUR RESPONSIBILITY TO TAKE REASONABLE PRECAUTIONS
TO SCAN FOR SUCH DESTRUCTIVE PROGRAMS DOWNLOADED FROM THE INTERNET.

5.4 THE PROVIDER'S MAXIMUM LIABILITY FOR ANY LOSS OR DAMAGE ARISING FROM THIS
LICENCE AGREEMENT SHALL IN ANY EVENT BE LIMITED IN THE SOLE DISCRETION OF THE
PROVIDER TO THE REPLACEMENT OF THE LOADER PRODUCT.

5.5 DUE TO THE NATURE OF THE INTERNET, THE PROVIDER CANNOT GUARANTEE THAT ANY
E-MAILS OR OTHER ELECTRONIC TRANSMISSIONS WILL BE SENT TO YOU OR RECEIVED BY
THE PROVIDER OR THAT THE CONTENT OF SUCH TRANSMISSIONS WILL BE SECURE DURING
TRANSMISSION.


6 BUG FIXING AND PRODUCT SUPPORT 

6.1 The provider will use reasonable endeavours to provide support to users.
The provider will at their discretion only provide support for the latest
release.

6.2 Support comprises of fault reporting via tickets and fault diagnosis,
recommendations on workarounds, and where reasonably possible a timely
resolution.

6.3 The user accepts that on occasion the ability of the provider to meet
anticipated or published support schedules may be impaired due to, but without
limitation, Internet service provider failures or software failures that
affect the ability to communicate for an indeterminate period.

6.4 The provider reserves the right to refuse to provide support at any time.

6.5 The provider wishes to maintain and offer a product of the highest
possible quality, and accordingly may from time to time and at its discretion
make product changes for the purpose of correcting behaviour in variance to
the published specification or the user's reasonable expectations. 

6.6 The provider reserves the right to charge for support where the user does
not have a valid support plan in place, or where the support offered exceeds
the scope of the active support plan.


7 PRODUCT UPGRADES

7.1 The provider may from time to time release product upgrades. These will
be provided free of charge and attempts made to provide a timely notification
to customers of the existence of any new release.


8 ERRORS AND OMISSIONS

Whilst reasonable endeavours are made to ensure the accuracy of documentation
concerning the details of the Loader, the user accepts the possibility of
inaccuracies in information presented in any format, including email
communications and online services. The provider shall under no circumstances
be liable for any events that arise as a result of unintentional inaccuracies
or omissions.


9 USER INDEMNITY

You agree to fully indemnify, defend and hold the provider harmless
immediately upon demand from and against all actions, liability, claims,
losses, damages, costs and expenses (including legal/attorney fees) incurred
by the provider arising directly or indirectly as a result of your breach of
this Licence Agreement.


10 INTELLECTUAL PROPERTY RIGHTS

10.1 The user acknowledges that the Loader and associated documentation and
materials contain proprietary information of the provider and are and shall
remain the exclusive property of the provider and/or its licensors and all
title, copyright, trade marks, trade names, patents and other intellectual
property rights therein of whatever nature shall remain the sole property of
the provider and/or its licensors.

10.2 No title to or rights of ownership, copyright or other intellectual
property in the Loader is transferred to the user (other than the licence
rights expressly granted in this Licence Agreement).


11 TERMINATION

11.1 The provider reserves the right to terminate this Licence Agreement
immediately by notice in writing against the user if the user is in breach of
any terms and conditions of this Licence Agreement.

11.2 Termination of this Licence Agreement for any reason shall be without
prejudice to any other rights or remedies of the provider which may have
arisen on or before the date of termination under this Licence Agreement or in
law.

11.3 The provisions of the following clauses shall survive any termination of
this agreement; clause 3, 5, 10 and 13.


12 GENERAL

12.1 The provider reserves the right to transfer or assign all or any of its
rights and duties and responsibilities set out in this Licence Agreement to
another party.

12.2 Headings have been included for convenience only and will not be used in
construing any provision of this Licence Agreement.

12.3 No delay or failure by the provider to exercise any powers, rights or
remedies under this Licence Agreement will operate as a waiver of them nor
will any single or partial exercise of any such powers, rights or remedies
include any other or further exercise of them.

12.4 If any part of this Licence Agreement is found by a court of competent
jurisdiction or other competent authority to be invalid, unlawful or
unenforceable then such part shall be severed from the remainder of this
Licence Agreement which will continue to be valid and enforceable to the
fullest extent permitted by applicable law.

12.5 This Licence Agreement including the documents or other sources referred
to herein supersede all prior representations, understandings and agreements
between the user and the provider relating to the Loader and sets forth the
entire agreement and understanding between the user and the provider relating
to the Loader.

12.6 Nothing in this Licence Agreement shall be deemed to constitute a
partnership between you and the provider nor constitute either party being an
agent of the other party.

12.7 This Agreement does not create any rights or benefits enforceable by any
person not a party to it (within the meaning of the U.K.Contracts (Rights of
Third Parties) Act 1999) except that a person who under clause 12.1 is a
permitted successor or assignee of the rights or benefits of the provider may
enforce such rights or benefits.


13 GOVERNING LAW AND JURISDICTION

This License Agreement and any issues relating thereto shall be construed and
interpreted in accordance with the laws of England and subject to the
exclusive jurisdiction of the English courts.

Copyright (c) 2002-2024 ionCube Ltd.          Last revised 23-April-2015
alt-php55-ioncube-loader/loader-wizard.php000064400000541746150431103030014435 0ustar00<?php // -*- c++ -*-

/** 
 * ionCube Loader install Wizard
 *
 * ionCube is a registered trademark of ionCube Ltd. 
 *
 * Copyright (c) ionCube Ltd. 2002-2022
 */


 

define ('ERROR_UNKNOWN_OS',1);
define ('ERROR_UNSUPPORTED_OS',2);
define ('ERROR_UNKNOWN_ARCH',3);
define ('ERROR_UNSUPPORTED_ARCH',4);
define ('ERROR_UNSUPPORTED_ARCH_OS',5);
define ('ERROR_WINDOWS_64_BIT',6);
define ('ERROR_PHP_UNSUPPORTED',7);
define ('ERROR_PHP_DEBUG_BUILD',8);
define ('ERROR_RUNTIME_EXT_DIR_NOT_FOUND',101);
define ('ERROR_RUNTIME_LOADER_FILE_NOT_FOUND',102);
define ('ERROR_INI_NOT_FIRST_ZE',201);
define ('ERROR_INI_WRONG_ZE_START',202);
define ('ERROR_INI_ZE_LINE_NOT_FOUND',203);
define ('ERROR_INI_LOADER_FILE_NOT_FOUND',204);
define ('ERROR_INI_NOT_FULL_PATH',205);
define ('ERROR_INI_NO_PATH',206);
define ('ERROR_INI_NOT_FOUND',207);
define ('ERROR_INI_NOT_READABLE',208);
define ('ERROR_INI_MULTIPLE_IC_LOADER_LINES',209);
define ('ERROR_INI_USER_INI_NOT_FOUND',210);
define ('ERROR_INI_USER_CANNOT_CREATE',211);
define ('ERROR_LOADER_UNEXPECTED_NAME',301);
define ('ERROR_LOADER_NOT_READABLE',302);
define ('ERROR_LOADER_PHP_MISMATCH',303);
define ('ERROR_LOADER_NONTS_PHP_TS',304);
define ('ERROR_LOADER_TS_PHP_NONTS',305);
define ('ERROR_LOADER_WRONG_OS',306);
define ('ERROR_LOADER_WRONG_ARCH',307);
define ('ERROR_LOADER_WRONG_GENERAL',308);
define ('ERROR_LOADER_WIN_SERVER_NONWIN',321);
define ('ERROR_LOADER_WIN_NONTS_PHP_TS',322);
define ('ERROR_LOADER_WIN_TS_PHP_NONTS',323);
define ('ERROR_LOADER_WIN_PHP_MISMATCH',324);
define ('ERROR_LOADER_WIN_COMPILER_MISMATCH',325);
define ('ERROR_LOADER_NOT_FOUND',380);
define ('ERROR_LOADER_PHP_VERSION_UNKNOWN',390);


define ('SERVER_UNKNOWN',0);
define ('HAS_PHP_INI',1);
define ('SERVER_SHARED',2); 
define ('SERVER_VPS',5); 
define ('SERVER_DEDICATED',7); 
define ('SERVER_LOCAL',9);

define ('IONCUBE_IP_ADDRESS',
			'94.101.154.134');
define  ('IONCUBE_ACCESS_ADDRESS',
			'lwaccess.ioncube.com');
define ('LOADERS_PAGE',
            'https://loaders.ioncube.com/'); 
define ('SUPPORT_SITE',
            'https://support.ioncube.com/');                                 
define ('WIZARD_SUPPORT_TICKET_DEPARTMENT',
			'3');
define ('LOADER_FORUM_URL',
            'https://forum.ioncube.com/viewforum.php?f=4');                  
define ('LOADERS_FAQ_URL',
            'https://www.ioncube.com/faqs/loaders.php');                     
define ('UNIX_ERRORS_URL',
            'https://www.ioncube.com/loaders/unix_startup_errors.php');      
define ('LOADER_WIZARD_URL',
            LOADERS_PAGE);                                                  
define ('ENCODER_URL',
            'https://www.ioncube.com/sa_encoder.php');                       
define ('LOADER_VERSION_URL',
            'https://www.ioncube.com/feeds/product_info/versions.php');    
define ('WIZARD_LATEST_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-wizard'); 
define ('PHP_COMPILERS_URL',
            LOADER_VERSION_URL . '?item=php-compilers');
define ('LOADER_PLATFORM_URL',
            LOADER_VERSION_URL . '?item=loader-platforms-all');   
define ('LOADER_LATEST_VERSIONS_URL',
            LOADER_VERSION_URL . '?item=loader-versions'); 
define ('LOADER_PHP_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-php-support'); 
define ('WIZARD_STATS_URL',
            'https://www.ioncube.com/feeds/stats/wizard.php');    
define ('IONCUBE_DOWNLOADS_SERVER',
            'https://downloads.ioncube.com/loader_downloads');          
define ('IONCUBE24_URL',
			'https://ioncube24.com');
define ('IONCUBE_CONNECT_TIMEOUT',4);

define ('DEFAULT_SELF','/ioncube/loader-wizard.php');
define ('LOADER_NAME_CHECK',true);
define ('LOADER_EXTENSION_NAME','ionCube Loader');
define ('LOADER_SUBDIR','ioncube');
define ('WINDOWS_IIS_LOADER_DIR', 'system32');
define ('ADDITIONAL_INI_FILE_NAME','00-ioncube.ini');
define ('UNIX_SYSTEM_LOADER_DIR','/usr/local/ioncube');
define ('RECENT_LOADER_VERSION','4.0.7');
define ('LATEST_LOADER_MAJOR_VERSION',12);
define ('LOADERS_PACKAGE_PREFIX','ioncube_loaders_');
define ('SESSION_LIFETIME_MINUTES',360);
define ('WIZARD_EXPIRY_MINUTES',2880);
define ('IONCUBE_WIZARD_EXPIRY_MINUTES',10080);
define ('MIN_INITIALISE_TIME',4);
define ('IC24_ENABLED_INI_PROPERTY',"ic24.enable");

    run();


function php4_http_build_query($formdata, $numeric_prefix = null, $key = null ) {
    $res = array();
    foreach ((array)$formdata as $k=>$v) {
        $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
        if ($key) $tmp_key = $key.'['.$tmp_key.']';
        if ( is_array($v) || is_object($v) ) {
            $res[] = php4_http_build_query($v, null , $tmp_key);
        } else {
            $res[] = $tmp_key."=".urlencode($v);
        }
   }
   $separator = ini_get('arg_separator.output');
   return implode($separator, $res);
}


function script_version()
{
    return "2.73";
}

function retrieve_latest_wizard_version()
{
    $v = false;

    $s = trim(remote_file_contents(WIZARD_LATEST_VERSION_URL));
    if (preg_match('/^\d+([.]\d+)*$/', $s)) {
        $v = $s;
    }

    return $v;
}

function latest_wizard_version()
{
    if (!isset($_SESSION['latest_wizard_version'])) {
        $_SESSION['latest_wizard_version'] = retrieve_latest_wizard_version();
    } 
    return $_SESSION['latest_wizard_version'];
}

function update_is_available($lv)
{
    if (is_numeric($lv)) {
        $lv_parts = explode('.',$lv);
        $script_parts = explode('.',script_version());
        return ($lv_parts[0] > $script_parts[0] || ($lv_parts[0] == $script_parts[0] && $lv_parts[1] > $script_parts[1]));
    } else {
        return null;
    }
}

function check_for_wizard_update($echo_message = false)
{
    $latest_version = latest_wizard_version();
    $update_available = update_is_available($latest_version);

    if ($update_available) {
        if ($echo_message) {
            echo '<p class="alert">An updated version of this Wizard script is available <a href="' . LOADER_WIZARD_URL . '">here</a>.</p>';
        }
        return $latest_version;
    } else {
        return $update_available;
    }
}


function remote_file_contents($url)
{
    $remote_file_opening = ini_get('allow_url_fopen');
    $contents = false;
    if (isset($_SESSION['timing_out']) && $_SESSION['timing_out']) {
        return false;
    }
    @session_write_close();
    $timing_out = 0;
    if ($remote_file_opening) {
        $fh = @fopen($url,'rb');
        if ($fh) {
            stream_set_blocking($fh,0);
            stream_set_timeout($fh,IONCUBE_CONNECT_TIMEOUT);
            while (!feof($fh)) {
                $result = fread($fh, 8192);
                $info = stream_get_meta_data($fh);
                $timing_out = $info['timed_out']?1:0;
                if ($timing_out) {
                    break;
                }
                if ($result !== false) {
                    $contents .= $result;
                } else {
                    break;
                }
            }
            fclose($fh);
        } else {
            $timing_out = 1;
        }
    } elseif (extension_loaded('curl')) {
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,IONCUBE_CONNECT_TIMEOUT);
            $output = curl_exec($ch);
            $info = curl_getinfo($ch);
            $timing_out = ($info['http_code'] >= 400)?1:0;
            curl_close($ch);

            if (is_string($output)) {
                $contents = $output;
            }
    } else {
        $timing_out = 1;
    }
    @session_start();
    $_SESSION['timing_out'] = $timing_out;
    return $contents;
}

function php_version()
{
    $v = explode('.',PHP_VERSION);

    return array(
           'major'      =>  $v[0],
           'minor'      =>  $v[1],
           'release'    =>  $v[2]);
}

function php_version_maj_min()
{
    $vprts = php_version();
    return ($vprts['major'] . '.' . $vprts['minor']);
}

function is_supported_php_version()
{
    $v = php_version(); 

    return ((($v['major'] == 4) && ($v['minor'] >= 1)) ||
      (($v['major'] == 5) && (($v['minor'] >= 1) || ($v['release'] >= 3))) ||
	  $v['major'] == 7 || ($v['major'] == 8 && $v['minor'] >= 1));
}

function is_php_version_or_greater($major,$minor,$release = 0)
{
    $version = php_version();
    return ($version['major'] > $major || 
            ($version['major'] == $major && $version['minor'] > $minor) ||
            ($version['major'] == $major && $version['minor'] == $minor && $version['release'] >= $release));
}

function ini_file_name()
{
    $sysinfo = get_sysinfo();
    return (!empty($sysinfo['PHP_INI'])?$sysinfo['PHP_INI_BASENAME']:'php.ini');
}

function get_remote_session_value($session_var,$remote_url,$default_function)
{
    if (!isset($_SESSION[$session_var])) {
        $serialised_res = remote_file_contents($remote_url);
        $unserialised_res = @unserialize($serialised_res);
        if (empty($unserialised_res)) {
            $unserialised_res = call_user_func($default_function);
        } else {
			$_SESSION['remote_access_successful'] = 1;
		}
        if (false === $unserialised_res) {
            $unserialised_res = '';
        }
        $_SESSION[$session_var] = $unserialised_res;
    }
    return $_SESSION[$session_var];
}

function get_file_contents($file)
{
    if (function_exists('file_get_contents')) {
        $strs = @file_get_contents($file);
    } else {
        $lines = @file($file);
        $strs = join(' ',$lines);
    }
    return $strs;
}

function default_platform_list()
{
    $platforms = array();


    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6', 'is_legacy' => 1,       'os_mod' => '_vc6',     'arch'=>'x86',  'dirname'=>'win32', 'us1-dir'=>'windows_vc6/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6 (Non-TS)',   'is_legacy' => 1,  'os_mod' => '_nonts_vc6',   'arch'=>'x86',  'dirname'=>'win32-nonts', 'us1-dir'=>'windows_vc6/x86-nonts' );

    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9',        'os_mod' => '_vc9',     'arch'=>'x86',  'dirname'=>'win32_vc9', 'us1-dir'=>'windows_vc9/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9 (Non-TS)',   'os_mod' => '_nonts_vc9',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc9', 'us1-dir'=>'windows_vc9/x86-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86',  'dirname'=>'win32_vc11', 'us1-dir'=>'windows_vc11/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc11', 'us1-dir'=>'windows_vc11/x86-nonts' );
	
	$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86-64',  'dirname'=>'win64_vc11', 'us1-dir'=>'windows_vc11/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc11', 'us1-dir'=>'windows_vc11/amd64-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86',  'dirname'=>'win32_vc14', 'us1-dir'=>'windows_vc14/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc14', 'us1-dir'=>'windows_vc14/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86-64',  'dirname'=>'win64_vc14', 'us1-dir'=>'windows_vc14/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc14', 'us1-dir'=>'windows_vc14/amd64-nonts' );
	
		 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86',  'dirname'=>'win32_vc15', 'us1-dir'=>'windows_vc15/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc15', 'us1-dir'=>'windows_vc15/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86-64',  'dirname'=>'win64_vc15', 'us1-dir'=>'windows_vc15/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc15', 'us1-dir'=>'windows_vc15/amd64-nonts' );

    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86',      'dirname'=>'linux_i686-glibc2.3.4', 'us1-dir'=>'linux/x86');
    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86-64',   'dirname'=>'linux_x86_64-glibc2.3.4', 'us1-dir'=>'linux/x86_64');
$platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc',      'dirname'=>'linux_ppc-glibc2.3.4','us1-dir'=>'linux/ppc');
            $platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc64',    'dirname'=>'linux_ppc64-glibc2.5','us1-dir'=>'linux/ppc64');
    

$platforms[] = array('os'=>'dra', 'os_human'=>'DragonFly', 'arch'=>'x86',      'dirname'=>'dragonfly_i386-1.7', 'us1-dir'=>'Dragonfly/x86');

$platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 4', 'os_mod'=>'_4',  'arch'=>'x86',      'dirname'=>'freebsd_i386-4.8', 'us1-dir'=>'FreeBSD/v4');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86',      'dirname'=>'freebsd_i386-6.2', 'us1-dir'=>'FreeBSD/v6/x86');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-6.2', 'us1-dir'=>'FreeBSD/v6/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86',      'dirname'=>'freebsd_i386-7.3', 'us1-dir'=>'FreeBSD/v7/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-7.3', 'us1-dir'=>'FreeBSD/v7/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86',      'dirname'=>'freebsd_i386-8.0', 'us1-dir'=>'FreeBSD/v8/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-8.0', 'us1-dir'=>'FreeBSD/v8/AMD64');
    
    $platforms[] = array('os'=>'bsd', 'os_human'=>'BSDi',     'is_legacy' => 1,           'arch'=>'x86',      'dirname'=>'bsdi_i386-4.3.1');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86',      'dirname'=>'netbsd_i386-2.1','us1-dir'=>'NetBSD/x86');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86-64',   'dirname'=>'netbsd_amd64-2.0','us1-dir'=>'NetBSD/x86_64');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.2', 'os_mod'=>'_4.2',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.2', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.5', 'os_mod'=>'_4.5',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.5', 'us1-dir'=>'OpenBSD/x86');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.6', 'os_mod'=>'_4.6',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.6', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.7', 'os_mod'=>'_4.7',  'arch'=>'x86-64', 'dirname'=>'openbsd_amd64-4.7', 'us1-dir' => 'OpenBSD/x86_64');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',    'is_legacy' => 1, 'arch'=>'ppc',      'dirname'=>'osx_powerpc-8.5','us1-dir'=>'OSX/ppc');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86',      'dirname'=>'osx_i386-8.11','us1-dir'=>'OSX/x86');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86-64',       'dirname'=>'osx_x86-64-10.2','us1-dir'=>'OSX/x86_64');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',  'is_legacy' => 1,          'arch'=>'sparc',    'dirname'=>'solaris_sparc-5.9', 'us1-dir'=>'Solaris/sparc');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',            'arch'=>'x86',      'dirname'=>'solaris_i386-5.10','us1-dir'=>'Solaris/x86');

    return $platforms;
}

function get_loader_platforms()
{
    return get_remote_session_value('loader_platform_info',LOADER_PLATFORM_URL,'default_platform_list');
}

function get_platforminfo()
{
    static $platforminfo;

    if (empty($platforminfo)) {
        $platforminfo = get_loader_platforms();
    }
    return $platforminfo;
}

function default_php_versions()
{
	return array();
}

function get_php_versions()
{
	return get_remote_session_value('php_version_info',LOADER_PHP_VERSION_URL,'default_php_versions');
}


function get_max_php_version_supported()
{
	static $max_php_version;
	
	if (empty($max_php_version)) {
		$php_versions = get_php_versions();
		
		$dirname = calc_dirname();
		
		if (array_key_exists($dirname,$php_versions)) {
			$max_php_version = $php_versions[$dirname];
		} else {
			$max_php_version = NULL;
		}
	}
	
	return $max_php_version;
}

function is_after_max_php_version_supported()
{
	$is_too_recent_php = false;
	
	$supported_php_version = get_max_php_version_supported();
	
	if (!is_null($supported_php_version)) {
		$pversion = php_version();
		
		$supported_parts = explode('.',$supported_php_version);
		$is_too_recent_php = ($supported_parts[0] < $pversion['major'] || ($supported_parts[0] == $pversion['major'] && $supported_parts[1] < $pversion['minor']));
	}
	
	if ($is_too_recent_php) {
		return $supported_php_version;
	} else {
		return false;
	}
}

function supported_os_variants($os_code,$arch_code)
{
    if (empty($os_code)) {
        return ERROR_UNKNOWN_OS;
    }
    if (empty($arch_code)) {
        return ERROR_UNKNOWN_ARCH;
    }

    $os_found = false;
    $arch_found = false;
    $os_arch_matches = array();
    $pinfo = get_platforminfo();

    foreach ($pinfo as $p) {
        if ($p['os'] == $os_code && $p['arch'] == $arch_code) {
            $os_arch_matches[$p['os_human']] = (isset($p['os_mod']))?(0 + (int) str_replace('_','',$p['os_mod'])):'';
        } 
        if ($p['os'] == $os_code) {
            $os_found = true;
        } elseif ($p['arch'] == $arch_code) {
            $arch_found = true;
        }
    }
    if (!empty($os_arch_matches)) {
        asort($os_arch_matches);
        return $os_arch_matches;
    } elseif (!$os_found) {
        return ERROR_UNSUPPORTED_OS;
    } elseif (!$arch_found) {
        return ERROR_UNSUPPORTED_ARCH;
    } else {
        return ERROR_UNSUPPORTED_ARCH_OS;
    }
}

function default_win_compilers()
{
    return array('VC6','VC9','VC11','VC14','VC15', 'VC16');
}

function supported_win_compilers()
{
    static $win_compilers;

    if (empty($win_compilers)) {
        $win_compilers = find_win_compilers();
    }
    return $win_compilers;
}

function find_win_compilers()
{
    return get_remote_session_value('php_compilers_info',PHP_COMPILERS_URL,'default_win_compilers');
}

function server_software_info()
{
    $ss = array('full' => '','short' => '');
    $ss['full'] = $_SERVER['SERVER_SOFTWARE'];

    if (preg_match('/apache/i', $ss['full'])) {
        $ss['short'] = 'Apache';
    } else if (preg_match('/IIS/',$ss['full'])) {
        $ss['short'] = 'IIS';
    } else {
        $ss['short'] = '';
    }
    return $ss;
}

function match_arch_pattern($str)
{
    $arch = null;
    $arch_patterns = array(
             'i.?86'        => 'x86',
             'x86[-_]64'    => 'x86',
             'x86'          => 'x86',
             'amd64'        => 'x86',
             'SMP Tue Jan 01 00:00:00 CEST 2000 all GNU\/Linux' => 'x86',
             'ppc64'        => 'ppc',
             'ppc'          => 'ppc',
             'powerpc'      => 'ppc',
             'sparc'        => 'sparc',
             'sun'          => 'sparc',
			 'armv7l'       => 'armv7l',
             'aarch64'      => 'aarch64'
         );

    foreach ($arch_patterns as $token => $a) {
        if (preg_match("/$token/i", $str)) {
          $arch = $a;
          break;
        }
    }
    return $arch;
}

function required_loader_arch($mach_info,$os_code,$wordsize)
{
    if ($os_code == 'win') {
        $arch = ($wordsize == 32)?'x86':'x86-64';
    } elseif (!empty($os_code)) {
        $arch = match_arch_pattern($mach_info);
        if ($wordsize == 64) {
            if ($arch == 'x86') {
                $arch = 'x86-64';
            } elseif ($arch == 'ppc') {
                $arch = 'ppc64';
            }
        }
    } else {
        $arch = ERROR_UNKNOWN_ARCH;
    }
    return $arch;
}

function uname($part = 'a')
{
    $result = '';
    if (!function_is_disabled('php_uname')) {
        $result = @php_uname($part);
    } elseif (function_exists('posix_uname') && !function_is_disabled('posix_uname')) {
        $posix_equivs = array(
                     'm' => 'machine',
                     'n' => 'nodename',
                     'r' => 'release',
                     's' => 'sysname'
                 );
        $puname = @posix_uname();
        if ($part == 'a' || !array_key_exists($part,$posix_equivs)) {
           $result = join(' ',$puname);
        } else {
           $result = $puname[$posix_equivs[$part]];
        }
    } else {
        if (!function_is_disabled('phpinfo')) {
            ob_start();
            phpinfo(INFO_GENERAL);
            $pinfo = ob_get_contents();
            ob_end_clean();
            if (preg_match('~System.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$match)) {
                $uname = $match[2];
                if ($part == 'r') {
                    if (!empty($uname) && preg_match('/\S+\s+\S+\s+([0-9.]+)/',$uname,$matchver)) {
                        $result = $matchver[1];
                    } else {
                        $result = '';
                    }
                } else {
                    $result = $uname;
                }
            }
        } else {
            $result = '';
        }
    }
    return $result;
}

function calc_word_size($os_code)
{
    $wordsize = null;
    if ('win' === $os_code) {
        ob_start();
        phpinfo(INFO_GENERAL);
        $pinfo = ob_get_contents();
        ob_end_clean();
        if (preg_match('~Compiler.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$compmatch)) {
            if (preg_match("/(VC[0-9]+)/i",$compmatch[2],$vcmatch)) {
                $compiler = strtoupper($vcmatch[1]);
            } elseif (stripos(trim($compmatch[2]),"Visual C++ 2019") === 0) {
                $compiler = 'VC16';
            } else {
                $compiler = 'VC6';
            }
        } else {
            $compiler = 'VC6';
        }
        if ($compiler === 'VC9' || $compiler === 'VC11' || $compiler === 'VC14' 
                || $compiler === 'VC15' || $compiler === 'VC16') {
			if (preg_match('~Architecture.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$archmatch)) {
				if (preg_match("/x64/i",$archmatch[2])) {
					$wordsize = 64;
				} else {
					$wordsize = 32;
				}
            } elseif (isset($_ENV['PROCESSOR_ARCHITECTURE']) && preg_match('~(amd64|x86-64|x86_64)~i',$_ENV['PROCESSOR_ARCHITECTURE'])) {
                if (preg_match('~Configure Command.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$confmatch)) {
                    if (preg_match('~(x64|lib64|system64)~i',$confmatch[2])) {
                        $wordsize = 64;
                    }
                }
            } else {
				$wordsize = 32;
			}
        }
    }
    if (empty($wordsize)) {
        $wordsize = ((-1^0xffffffff)?64:32);
    }
    return $wordsize;
}

function required_loader($unamestr = '')
{
    $un = empty($unamestr)?uname():$unamestr;

    $php_major_version = substr(PHP_VERSION,0,3);

    $os_name = substr($un,0,strpos($un,' '));
    $os_code = empty($os_name)?'':strtolower(substr($os_name,0,3));

    $wordsize = calc_word_size($os_code);

	if ($os_code == 'win' && $wordsize == 64 && $php_major_version < '5.5') {
        $arch = ERROR_WINDOWS_64_BIT;
	} else {
		$arch = required_loader_arch($un,$os_code,$wordsize);
	}
    if (!is_string($arch)) {
        return $arch;
    }
    $os_variants = supported_os_variants($os_code,$arch);
    if (!is_array($os_variants)) {
        return $os_variants;
    }

    $os_ver = '';
    if (preg_match('/([0-9.]+)/',uname('r'),$match)) {
        $os_ver = $match[1];
    }
    $os_ver_parts = preg_split('@\.@',$os_ver);

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $loader_sfix = (($os_code == 'win') ? 'dll' : 'so');
    $file = "ioncube_loader_{$os_code_h}_{$php_major_version}.{$loader_sfix}";

    if ($os_code == 'win') {
        $os_name = 'Windows';
        $file_ts = $file;
        $os_name_qual = 'Windows';
    } else {
        $os_names = array_keys($os_variants);
        if (count($os_variants) > 1) {
            $parts = explode(" ",$os_names[0]); 
            $os_name = $parts[0];
            $os_name_qual = $os_name . ' ' . $os_ver_parts[0] . '.' . $os_ver_parts[1];
        } else {
            $os_name = $os_names[0];
            $os_name_qual = $os_name;
        }
        $file_ts = "ioncube_loader_{$os_code_h}_{$php_major_version}_ts.{$loader_sfix}";
    }

    return array(
           'uname'      =>  $un,
           'arch'       =>  $arch,
           'oscode'     =>  $os_code,
           'oscode_h'   =>  $os_code_h,
           'osname'     =>  $os_name,
           'osnamequal' =>  $os_name_qual,
           'osvariants' =>  $os_variants,
           'osver'      =>  $os_ver,
           'osver2'     =>  $os_ver_parts,
           'file'       =>  $file,
           'file_ts'    =>  $file_ts,
           'wordsize'   =>  $wordsize
       );
}

function ic_system_info()
{
    $thread_safe = null;
    $debug_build = null;
    $cgi_cli = false;
	$is_fpm = false;
    $is_cgi = false;
    $is_cli = false;
    $php_ini_path = '';
    $php_ini_dir = '';
    $php_ini_add = '';
    $is_supported_compiler = true;
    $php_compiler = is_ms_windows()?'VC6':'';

    ob_start();
    phpinfo(INFO_GENERAL);
    $php_info = ob_get_contents();
    ob_end_clean();

    $breaker = (php_sapi_name() == 'cli')?"\n":'</tr>';
    $lines = explode($breaker,$php_info);
    foreach ($lines as $line) {
        if (preg_match('/command/i',$line)) {
          continue;
        }

        if (preg_match('/thread safety/i', $line)) {
          $thread_safe = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('/debug build/i', $line)) {
          $debug_build = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('~configuration file.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
          $php_ini_path = $match[2];

          if (!@file_exists($php_ini_path)) {
                $php_ini_path = '';
          }
        }
        if (preg_match('~dir for additional \.ini files.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_dir = $match[2];
            if (!@file_exists($php_ini_dir)) {
                $php_ini_dir = '';
            }
        }
        if (preg_match('~additional \.ini files parsed.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_add = $match[2];
        }
        if (preg_match('/compiler/i',$line)) {
            $supported_match = join('|',supported_win_compilers());
            $is_supported_compiler = preg_match("/($supported_match)/i",$line);
            if (preg_match("/(VC[0-9]+)/i",$line,$match)) {
                $php_compiler = strtoupper($match[1]);
            } elseif (preg_match("/Visual C\+\+ 2017/i",$line)) {
				$php_compiler = "VC15";
				$is_supported_compiler = true;
            } elseif (preg_match("/Visual C\+\+ 2019/i",$line)) {
				$php_compiler = "VC16";
				$is_supported_compiler = true;
			} else {
                $php_compiler = '';
            }
        }
    }
    $is_cgi = strpos(php_sapi_name(),'cgi') !== false;
    $is_cli = strpos(php_sapi_name(),'cli') !== false;
	$is_fpm = strpos(php_sapi_name(),'fpm-fcgi') !== false;
    $cgi_cli = $is_cgi || $is_cli;

    $ss = server_software_info();
	
	if ($is_fpm) {
		$ss['short'] = 'PHP-FPM';
		$ss['full'] = 'PHP-FPM ' . $ss['full'];
	}

    if (!$php_ini_path && function_exists('php_ini_loaded_file')) {
        $php_ini_path = php_ini_loaded_file();
        if ($php_ini_path === false) {
            $php_ini_path = '';
        }
    }
    if (!empty($php_ini_path)) {
        $real_path = @realpath($php_ini_path);
        if (false !== $real_path) {
            $php_ini_path = $real_path;
        }
    }

    $php_ini_basename = basename($php_ini_path);

    return array(
           'THREAD_SAFE'        => $thread_safe,
           'DEBUG_BUILD'        => $debug_build,
           'PHP_INI'            => $php_ini_path,
           'PHP_INI_BASENAME'   => $php_ini_basename,
           'PHP_INI_DIR'        => $php_ini_dir,
           'PHP_INI_ADDITIONAL' => $php_ini_add,
           'PHPRC'              => getenv('PHPRC'),
           'CGI_CLI'            => $cgi_cli,
           'IS_CGI'             => $is_cgi,
           'IS_CLI'             => $is_cli,
		   'IS_FPM'				=> $is_fpm,
           'PHP_COMPILER'       => $php_compiler,
           'SUPPORTED_COMPILER' => $is_supported_compiler,
           'FULL_SS'            => $ss['full'],
           'SS'                 => $ss['short']);
}

function is_possibly_dedicated_or_local()
{
    $sys = get_sysinfo();

    return (empty($sys['PHP_INI']) || !@file_exists($sys['PHP_INI']) || (is_readable($sys['PHP_INI']) && (0 !== strpos($sys['PHP_INI'],$_SERVER['DOCUMENT_ROOT']))));
}

function is_local()
{
    $ret = false;
    if ($_SERVER["SERVER_NAME"] == 'localhost') {
        $ret = true;
    } else {
        $ip_address = strtolower($_SERVER["REMOTE_ADDR"]);
        if (strpos(':',$ip_address) === false) {
            $ip_parts = explode('.',$ip_address);
            $ret = (($ip_parts[0] == 10) || 
                    ($ip_parts[0] == 172 && $ip_parts[1] >= 16 &&  $ip_parts[1] <= 31) ||
                    ($ip_parts[0] == 192 && $ip_parts[1] == 168));
        } else {
            $ret = ($ip_address == '::1') || (($ip_address[0] == 'f') && ($ip_address[1] >= 'c' && $ip_address[1] <= 'f'));
        }
    }
    return $ret;
}

function is_shared()
{
    return !is_local() && !is_possibly_dedicated_or_local();
}

function find_server_type($chosen_type = '',$type_must_be_chosen = false,$set_session = false)
{
    $server_type = SERVER_UNKNOWN;
    if (empty($chosen_type)) {
        if ($type_must_be_chosen) {
            $server_type = SERVER_UNKNOWN;
        } else {
            if (isset($_SESSION['server_type']) && $_SESSION['server_type'] != SERVER_UNKNOWN) {
                $server_type = $_SESSION['server_type'];
            } elseif (is_local()) {
                $server_type = SERVER_LOCAL;
            } elseif (!is_possibly_dedicated_or_local()) {
                $server_type = SERVER_SHARED;
            } else {
                $server_type = SERVER_UNKNOWN;
            } 
        }
    } else {
        switch ($chosen_type)  {
            case 's':
                $server_type = SERVER_SHARED;
                break;
            case 'd':
                $server_type = SERVER_DEDICATED;
                break;
            case 'l':
                $server_type = SERVER_LOCAL;
                break;
            default:
                $server_type = SERVER_UNKNOWN;
                break;
        }
    }
    if ($set_session) {
        $_SESSION['server_type'] = $server_type;
    }
    return $server_type;
}

function server_type_string()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_string = 'SHARED';
            break;
        case SERVER_LOCAL:
            $server_string = 'LOCAL';
            break;
        case SERVER_DEDICATED:
            $server_string = 'DEDICATED';
            break;
        default:
            $server_string = 'UNKNOWN';
            break;
    }
    return $server_string;
}

function server_type_code()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_char = 's';
            break;
        case SERVER_LOCAL:
            $server_char = 'l';
            break;
        case SERVER_DEDICATED:
            $server_char = 'd';
            break;
        default:
            $server_char = '';
            break;
    }
    return $server_char;
}

function get_sysinfo()
{
    static $sysinfo;

    if (empty($sysinfo)) {
        $sysinfo = ic_system_info();
    }
    return $sysinfo;
}

function get_loaderinfo()
{
    static $loader;

    if (empty($loader)) {
        $loader = required_loader();
    }
    return $loader;
}

function is_ms_windows()
{
    $loader_info = get_loaderinfo();
    return ($loader_info['oscode'] == 'win');
}

function function_is_disabled($fn_name)
{
    $disabled_functions=explode(',',ini_get('disable_functions'));
    return in_array($fn_name, $disabled_functions);
}

function selinux_is_enabled()
{
    $se_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('sestatus');
        $se_enabled = preg_match('/enabled/i',$cmd);
    }

    return $se_enabled;
}

function grsecurity_is_enabled()
{
    $gr_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('gradm -S');
        $gr_enabled = preg_match('/enabled/i',$cmd);
    }

    return $gr_enabled;
}

function threaded_and_not_cgi()
{
    $sys = get_sysinfo();
    return($sys['THREAD_SAFE'] && !$sys['IS_CGI']);
}

function is_restricted_server($only_safe_mode = false)
{
    $disable_functions = ini_get('disable_functions');
    $open_basedir = ini_get('open_basedir');
    $php_restrictions = !empty($disable_functions) || !empty($open_basedir);
    $system_restrictions = selinux_is_enabled() || grsecurity_is_enabled();
    $non_safe_mode_restrictions = $php_restrictions || $system_restrictions;
    return (ini_get('safe_mode') || (!$only_safe_mode && $non_safe_mode_restrictions));
}

function server_restriction_warnings()
{
    $warnings = array();

    if (find_server_type() == SERVER_SHARED) {
        if (is_restricted_server()) {
            $warnings[] = "Server restrictions are in place which might affect the operation of this Loader Wizard or prevent the installation of the Loader.";
        }
    } else {
        $warning_suffix = "This may affect the operation of this Loader Wizard.";
        if (ini_get('safe_mode')) {
            $warnings[] = "Safe mode is in effect on the server. " . $warning_suffix;
        } 
        $disabled_functions = ini_get('disable_functions');
        if (!empty($disabled_functions)) {
            $warnings[] = "Some functions are disabled through disable_functions. " . $warning_suffix;
        }
        $open_basedir = ini_get('open_basedir');
        if (!empty($open_basedir)) {
            $warnings[] = "Open basedir restrictions are in effect. " . $warning_suffix;
        }
    }
    return $warnings;
}

function own_php_ini_possible($only_safe_mode = false)
{
    $sysinfo = get_sysinfo();
    return ($sysinfo['CGI_CLI'] && !is_ms_windows() && !is_restricted_server($only_safe_mode));
}

function extension_dir()
{
    $extdir = ini_get('extension_dir');
    if ($extdir == './' || ($extdir == '.\\' && is_ms_windows())) {
        $extdir = '.';
    }
    return $extdir;
}

function possibly_selinux()
{
    $loaderinfo = get_loaderinfo();
    $se_env = (getenv("SELINUX_INIT"));
    return (strtolower($loaderinfo['osname']) == 'linux' && $se_env && ($se_env == 'Yes' || $se_env == '1'));
}

function ini_same_dir_as_wizard()
{
    $sys = get_sysinfo();
    return dirname($sys['PHP_INI']) == dirname(__FILE__); 
}

function extension_dir_path()
{
    $ext_dir = extension_dir();
    if ($ext_dir == '.' || (dirname($ext_dir) == '.')) {
        $ext_dir_path = @realpath($ext_dir);
    } else {
        $ext_dir_path = $ext_dir;
    }
    return $ext_dir_path;
}

function get_loader_name()
{
    $u = uname();
    $sys = get_sysinfo();
    $os = substr($u,0,strpos($u,' '));
    $os_code = strtolower(substr($u,0,3));

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $php_version = phpversion();
    $php_family = substr($php_version,0,3);

    $loader_sfix = (($os_code == 'win') ? '.dll' : (($sys['THREAD_SAFE'])?'_ts.so':'.so'));
    $loader_name="ioncube_loader_{$os_code_h}_{$php_family}{$loader_sfix}";

    return $loader_name;
}

function get_reqd_version($variants)
{
    $exact_match = false;
    $nearest_version = 0;
    $loader_info = get_loaderinfo();
    $os_version = $loader_info['osver2'][0] . '.' . $loader_info['osver2'][1];
    $os_version_major = $loader_info['osver2'][0];
    foreach ($variants as $v) {
        if ($v == $os_version || (is_int($v) && $v == $os_version_major)) {
            $exact_match = true;
            $nearest_version = $v;
            break;
        } elseif ($v > $os_version) {
            break;
        } else {
            $nearest_version = $v;
        }
    }
    return (array($nearest_version,$exact_match));
}

function get_default_loader_dir_webspace()
{
    return ($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . LOADER_SUBDIR);
}

function get_loader_location($loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = get_default_loader_dir_webspace();
    }
    $loader_name = get_loader_name(); 
    return ($loader_dir . DIRECTORY_SEPARATOR . $loader_name);
}

function get_loader_location_from_ini($php_ini = '')
{
    $errors = array();
    if (empty($php_ini)) {
        $sysinfo = get_sysinfo();
        $php_ini = $sysinfo['PHP_INI'];
    }
    if (!@file_exists($php_ini)) {
        if (empty($php_ini)) {
            $errors[ERROR_INI_NOT_FOUND] = "The configuration file could not be found.";
        } else {
            $errors[ERROR_INI_NOT_FOUND] = "The $php_ini file could not be found.";
        }
    } elseif (!is_readable($php_ini)) {
        $errors[ERROR_INI_NOT_READABLE] = "The $php_ini file could not be read.";
    }
    if (!empty($errors)) {
        return array('location' => '', 'errors' => $errors);
    } 
    $lines = file($php_ini);
    $ext_start = zend_extension_line_start();
    $wrong_ext_start = ($ext_start == 'zend_extension')?'zend_extension_ts':'zend_extension';
    $loader_path = '';
    $loader_name_match = "ioncube_loader";
    foreach ($lines as $l) {
        if (preg_match("/^\s*$ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$corr_matches)) {
            if (preg_match("/$loader_name_match/i",$corr_matches[1])) {
                if (!empty($loader_path)) {
                    $errors[ERROR_INI_MULTIPLE_IC_LOADER_LINES] = "It appears that multiple $ext_start lines for the ionCube Loader have been included in the configuration file, $php_ini.";
                }
                $loader_path = $corr_matches[1];
            } else {
                if (empty($loader_path)) {
                    $errors[ERROR_INI_NOT_FIRST_ZE] = "The ionCube Loader must be the first Zend extension listed in the configuration file, $php_ini.";
                }
            }
        }
        if (empty($loader_path)) {
            if (preg_match("/^\s*$wrong_ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$bad_start_matches)) {
                if (preg_match("/$loader_name_match/i",$bad_start_matches[1])) {
                    $bad_zend_ext_msg = "The line for the ionCube Loader in the configuration file, $php_ini, should start with $ext_start and <b>not</b> $wrong_ext_start.";
                    $errors[ERROR_INI_WRONG_ZE_START] = $bad_zend_ext_msg;
                    $loader_path = $bad_start_matches[1];
                }
            }
        }
    }
    $loader_path = trim($loader_path);
    if ($loader_path === '') {
        $errors[ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration file, $php_ini.";
    } elseif (!@file_exists($loader_path)) {
        $errors[ERROR_INI_LOADER_FILE_NOT_FOUND] = "The loader file  $loader_path, listed in the configuration file, $php_ini, does not exist or is not accessible.";
    } elseif (basename($loader_path) == $loader_path) {
        $errors[ERROR_INI_NOT_FULL_PATH] = "A full path must be specified for the loader file in the configuration file, $php_ini.";
    }
    return array('location' => $loader_path, 'errors' => $errors);
}

function zend_extension_line_missing($ini_path)
{
    $loader_loc = get_loader_location_from_ini($ini_path);
    return (!empty($loader_loc['errors']) && array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$loader_loc['errors']));
}

function find_additional_ioncube_ini()
{
    $sys = get_sysinfo();
    $ioncube_ini = '';

    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
        foreach ($ini_files as $f) {
            $fn = trim($f);
            $bfn = basename($fn);
            if (preg_match('/ioncube/i',$bfn)) {
                $ioncube_ini = $fn;
                break;
            }
        }
    }
    return $ioncube_ini;
}

function get_additional_ini_files()
{
    $sys = get_sysinfo();
    $ini_files = array();
    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
    }
    return (array_map('trim',$ini_files));
}

function all_ini_contents()
{
    $sys = get_sysinfo();
    $output = '';

    $output .= ";;; *MAIN INI FILE AT ${sys['PHP_INI']}* ;;;" . PHP_EOL;
    $output .= get_file_contents($sys['PHP_INI']);
    $other_inis = get_additional_ini_files();
    foreach ($other_inis as $inif) {
        $output .= ";;; *Additional ini file at $inif* ;;;" . PHP_EOL;
        $output .= get_file_contents($inif);
    }
    $here = unix_path_dir();
    $unrec_ini_files = unrecognised_inis_webspace($here);
    foreach ($unrec_ini_files as $urinif) {
        $output .= ";;; *UNRECOGNISED INI FILE at $urinif* ;;;" . PHP_EOL;
        $output .= get_file_contents($urinif);
    }
    return $output;
}

function scan_inis_for_loader()
{
    $ldloc = array('location' => '', 'errors' => array());
    $sysinfo = get_sysinfo();
    if (empty($sysinfo['PHP_INI'])) {
        $ini_files_not_found = array("Main ini file");
        $ini_file_list = get_additional_ini_files();
    } else {
        $ini_files_not_found = array();
        $ini_file_list = array_merge(array($sysinfo['PHP_INI']),get_additional_ini_files());
    }
    $server_type = find_server_type();
    $shared_server = SERVER_SHARED == $server_type;
    foreach ($ini_file_list as $f) {
        $ldloc = get_loader_location_from_ini($f);
        if (array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$ldloc['errors'])) {
            unset($ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND]);
        } 
        if ($shared_server && array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            if (false == user_ini_space_path($f)) {
                $ldloc['errors'][ERROR_INI_NOT_FOUND] = "A system ini file cannot be found or read by the Wizard - you cannot do anything about this on your shared server.";
            } else {
                $ldloc['errors'][ERROR_INI_USER_INI_NOT_FOUND] = $ldloc['errors'][ERROR_INI_NOT_FOUND];
            }
        } elseif (array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            $ini_files_not_found[] = $f;
        }
        if (!empty($ldloc['location'])) {
            break;
        }
    }
    if (!empty($ini_files_not_found)) {
        $plural = (count($ini_files_not_found) > 1)?"s":"";
        $ldloc['errors'][ERROR_INI_NOT_FOUND] = "The following ini file$plural could not be found by the Wizard: " . join(',',$ini_files_not_found);
        if (is_restricted_server()) {
            $ldloc['errors'][ERROR_INI_NOT_FOUND] .= "<br> This may be due to server restrictions in place.";
        }
    }
    if (empty($ldloc['location'])) {
        $ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration.";
    }
    return $ldloc;
}

function find_loader_filesystem()
{
    $ld_inst_dir = loader_install_dir(find_server_type());
    $loader_name = get_loader_name();
    $suggested_loader_path = $ld_inst_dir . DIRECTORY_SEPARATOR . $loader_name;
    if (@file_exists($suggested_loader_path)) {
        $location = $suggested_loader_path;
    } elseif (@file_exists($loader_name)) {
        $location = @realpath($loader_name);
    } else {
        $ld_loc = get_loader_location();
        if (@file_exists($ld_loc)) {
            $location = $ld_loc;
        } else {
            $location = '';
        }
    }
    return $location;
}

function find_loader($search_directories_if_not_ini = false)
{
    $sysinfo = get_sysinfo();
    $php_ini = $sysinfo['PHP_INI'];
    $rtl_path = get_runtime_loading_path_if_applicable();
    $location = '';
    $errors = array();

    if (!empty($rtl_path)) {
        $location = $rtl_path;
    } else {
        $loader_ini = scan_inis_for_loader();
        $location = $loader_ini['location'];
        $errors = $loader_ini['errors'];
    }
    if (empty($location) && (empty($errors) || $search_directories_if_not_ini)) {
        $errors = array(); 
        $location = find_loader_filesystem();
        if (empty($location)) {
            $errors[ERROR_LOADER_NOT_FOUND] = 'The loader file could not be found in standard locations.';
        }
    }
    if (!empty($errors)) {
        return $errors;
    } else {
        return $location;
    }
}

function zend_extension_line_start()
{
    $sysinfo = get_sysinfo();
    $is_53_or_later = is_php_version_or_greater(5,3);
    return (is_bool($sysinfo['THREAD_SAFE']) && $sysinfo['THREAD_SAFE'] && !$is_53_or_later ? 'zend_extension_ts' : 'zend_extension');
}

function ioncube_loader_version_information()
{
    $old_version = true;
    $liv = "";
    $lv = "";
    $mv = 0;
    if (function_exists('ioncube_loader_iversion')) {
        $liv = ioncube_loader_iversion();
        $lv = sprintf("%d.%d.%d", $liv / 10000, ($liv / 100) % 100, $liv % 100);

        $latest_version =  get_latestversion();

        $lat_parts = explode('.',$latest_version);
        $cur_parts = explode('.',$lv);

        if (($cur_parts[0] > $lat_parts[0]) || 
            ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] > $lat_parts[1]) ||
             ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] == $lat_parts[1] && $cur_parts[2] >= $lat_parts[2])) {
            $old_version = false;
        } else {
            $old_version = $latest_version;
        }
        $mv = $cur_parts[0];
    }
    return array($lv,$mv,$old_version);
}

function default_loader_version_info()
{
    return array();
}

function get_loader_version_info()
{
    return get_remote_session_value('loader_version_info',LOADER_LATEST_VERSIONS_URL,'default_loader_version_info');
}

function calc_platform()
{
    $platform = array();
    $platform_info = get_platforminfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($osvar,$exact_match) = get_reqd_version($loader['osvariants']);
    } else {
        $osvar = null;
        if (is_ms_windows()) {
            $sys = get_sysinfo();
            $phpc = (empty($sys['PHP_COMPILER']))?'vc6':strtolower($sys['PHP_COMPILER']); 
            $osvar = ($sys['THREAD_SAFE']?'':'nonts_') . $phpc;
        }
    }
    foreach ($platform_info as $p) {
        if ($p['os'] == $loader['oscode'] && $p['arch'] == $loader['arch'] && (empty($osvar) || $p['os_mod'] == "_" . $osvar)) {
            $platform = $p;
            break;
        }
    }
    return $platform;
}

function get_platform()
{
    static $this_platform;

    if (!isset($this_platform)) {
        $this_platform = calc_platform();
    }

    return $this_platform;
}

function is_legacy_platform()
{
    $platform = get_platform();
    return array_key_exists('is_legacy',$platform);
}

function calc_dirname()
{
    $dirname = '';
    $platform = get_platform();
    if (!empty($platform)) {
        $dirname = $platform['dirname'];
    }
    return $dirname;
}

function calc_loader_latest_version()
{
    $lv_info = get_loader_version_info();
    $latest_version = RECENT_LOADER_VERSION;
    if (!empty($lv_info)) {
        $dirname = calc_dirname();
      
        if (!empty($dirname)) {
            $compiler_specific_version = false;
            if (is_ms_windows()) {
                $sys = get_sysinfo();
                $phpc = strtolower($sys['PHP_COMPILER']);
                if (!empty($phpc)) {
                    $dirname_comp = $dirname . "_" . $phpc;
                    if (array_key_exists($dirname_comp,$lv_info)) {
                        $latest_version = $lv_info[$dirname_comp];
                        $compiler_specific_version = true;
                    }
                }
            }
            if (!$compiler_specific_version && array_key_exists($dirname,$lv_info)) {
                $latest_version = $lv_info[$dirname];
            }
        } 
    }
    return $latest_version;
}

function get_latestversion()
{
    static $latest_version;

    if (empty($latest_version)) {
        $latest_version = calc_loader_latest_version();
    }
    return $latest_version;
}


function runtime_loader_location()
{
    $loader_path = false;
    $ext_path = extension_dir_path();
    if ($ext_path !== false) {
        $id = $ext_path;
        $here = dirname(__FILE__);
        if (isset($id[1]) && $id[1] == ':') {
            $id = str_replace('\\','/',substr($id,2));
            $here = str_replace('\\','/',substr($here,2));
        }
        $rd=str_repeat('/..',substr_count($id,'/')).$here.'/';
        $i=strlen($rd);

        $loader_loc = DIRECTORY_SEPARATOR . basename($here) . DIRECTORY_SEPARATOR . get_loader_name();
        while($i--) {
            if($rd[$i]=='/') {
                $loader_path = runtime_location_exists($ext_path,$rd,$i,$loader_loc);
                if ($loader_path !== false) {
                    break;
                }
            }
        }

        if (!$loader_path && !empty($loader_loc) && @file_exists($loader_loc)) {
            $loader_path = basename($loader_loc);
        }
    }
    return $loader_path;
}

function runtime_location_exists($ext_dir,$path_str,$sep_pos,$loc_name)
{
    $sub_path = substr($path_str,0,$sep_pos);
    $lp = $sub_path . $loc_name;
    $fqlp = $ext_dir.$lp;

    if(@file_exists($fqlp)) {
        return $lp;
    } else {
        return false;
    }
}

function runtime_loading_is_possible() {
    return !((is_php_version_or_greater(5,2,5)) || is_restricted_server() || !ini_get('enable_dl') || !function_exists('dl') || function_is_disabled('dl') || threaded_and_not_cgi());
}

function shared_and_runtime_loading()
{
    return (find_server_type() == SERVER_SHARED && empty($_SESSION['use_ini_method']) && runtime_loading_is_possible());
}

function get_valid_runtime_loading_path($ignore_loading_check = false)
{
    if ($ignore_loading_check || runtime_loading_is_possible()) {
        return runtime_loader_location();
    } else {
        return false;
    }
}

function runtime_loading($rtl_path = null)
{
    if (empty($rtl_path)) {
        $rtl_path = get_valid_runtime_loading_path();
    }
    if (!empty($rtl_path) && @dl($rtl_path)) {
        return $rtl_path;
    } else {
        return false;
    }
}

function get_runtime_loading_path_if_applicable()
{
    $rtl = null;
    if (shared_and_runtime_loading()) {
        $rtl = get_valid_runtime_loading_path();
    }
    return $rtl;
}

function try_runtime_loading_if_applicable()
{
    $rtl_path = get_runtime_loading_path_if_applicable();
    if (!empty($rtl_path)) {
        return runtime_loading($rtl_path);
    } else {
        return $rtl_path;
    }
}

function runtime_loading_instructions()
{
    $default = get_default_address();
    echo '<h4>Runtime Loading Instructions</h4>';
    echo '<div class=panel>';
    echo '<p>On your shared server the Loader can be installed using the runtime loading method.';
    echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";

    if ('.' == extension_dir()) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        echo "Please note that on your system the Loader <em>must</em> be present in the same " . $dirphrase . " as the first encoded file accessed.";
    }
    echo '<ol>';
    loader_download_instructions(); 
    $loader_dir = loader_install_instructions(SERVER_SHARED,dirname(__FILE__));
    shared_test_instructions();
    echo '</ol>';
    echo '</div>';
}

function runtime_loading_errors()
{
    $errors = array();
    $ext_path = extension_dir_path();
    if (false === $ext_path) {
        $errors[ERROR_RUNTIME_EXT_DIR_NOT_FOUND] = "Extensions directory cannot be found.";
    } else {
        $expected_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . get_loader_name();
        if (!@file_exists($expected_file)) {
            $errors[ERROR_RUNTIME_LOADER_FILE_NOT_FOUND] = "The Loader file was expected to be at $expected_file but could not be found.";
        } else {
            $errors = loader_compatibility_test($expected_file);
        }
    }
    return $errors;
}


function windows_package_name()
{
    $sys = get_sysinfo();
	$loader = get_loaderinfo();
    return (LOADERS_PACKAGE_PREFIX . 'win' . '_' . ($sys['THREAD_SAFE']?'':'nonts_') . strtolower($sys['PHP_COMPILER']) .  '_' . $loader['arch']);
}

function unix_package_name()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($reqd_version,$exact_match) = get_reqd_version($loader['osvariants']);
        if ($reqd_version) {
            $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $reqd_version . '_' . $loader['arch'];
        } else {
            $basename = "";
        }
    } else {
        $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $loader['arch'];
    }
    return array($basename,$multiple_os_versions);
}

function loader_download_instructions()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;

    if (is_ms_windows()) {
        if (is_bool($sysinfo['THREAD_SAFE'])) {
            $download_str = '<li>Download the following archive of Windows ' . $sysinfo['PHP_COMPILER'];
            if (!$sysinfo['THREAD_SAFE']) {
                $download_str .= ' non-TS';
            }
            $download_str .= ' ' . $loader['arch'] . ' Loaders:';
            echo $download_str;
            $basename = windows_package_name();
            echo make_archive_list($basename,array('zip'));
            echo 'A Loaders archive can also be downloaded from <a href="' . LOADERS_PAGE . '" target="loaders">' . LOADERS_PAGE . '</a>.';
        } else {
            echo '<li>Download a Windows Loaders archive from <a href="' . LOADERS_PAGE  . '" target=loaders>here</a>. If PHP is built with thread safety disabled, use the Windows non-TS Loaders.';
        }
    } else {
        list($basename,$multiple_os_versions) = unix_package_name(); 
        if ($basename == "") {
            echo '<li>Download a ' . $loader['osname'] . ' ' . $loader['arch'] . ' Loaders archive from <a href="' . LOADERS_PAGE . '" target="loaders">here</a>.';
            echo "<br>Your system appears to be ${loader['osnamequal']} for ${loader['wordsize']} bit. If Loaders are not available for that exact release of ${loader['osname']}, Loaders built for an earlier release should work. Note that you may need to install back compatibility libraries for the operating system.";
            echo '<br>If you cannot find a suitable loader then please raise a ticket at <a href="'. SUPPORT_SITE . '">our support helpdesk</a>.';
        } else {
            echo '<li>Download one of the following archives of Loaders for ' . $loader['osnamequal'] . ' ' . $loader['arch'] . ':'; 
            if (SERVER_SHARED == find_server_type()) {
                $archives = array('zip','tar.gz');
            } else {
                $archives = array('tar.gz','zip');
            }
            echo make_archive_list($basename,$archives);
            echo "</p>";
            if ($multiple_os_versions && !$exact_match) {
                echo "<p>Note that you may need to install back compatibility libraries for  ${loader['osname']}.</p>";
            }
        }
    }

    echo '</li>';
}

function ini_dir()
{
    $sysinfo = get_sysinfo();
    $parent_dir = '';
    if (!empty($sysinfo['PHP_INI'])) {
        $parent_dir = dirname($sysinfo['PHP_INI']);
    } else {
        $parent_dir = $_SERVER["PHPRC"];
        if (@is_file($parent_dir)) {
            $parent_dir = dirname($parent_dir);
        }
    }
    return $parent_dir;
}

function unix_install_dir()
{
    $ext_dir = extension_dir_path();
    $cur_dir = @realpath('.');
    if (empty($ext_dir) || $ext_dir == $cur_dir) {
        $loader_dir = UNIX_SYSTEM_LOADER_DIR;
    } else {
        $loader_dir = $ext_dir;
    }
    return $loader_dir;
}

function windows_install_dir()
{
    $sysinfo = get_sysinfo();
    if ($sysinfo['SS'] == 'IIS') {
        if (false === ($ext_dir = extension_dir_path())) {
            $parent_dir = ini_dir();
            $ext_dir = $parent_dir . '\\ext';
            if (!empty($parent_dir) && @file_exists($ext_dir)) {
                $loader_dir = $ext_dir;
            } else {
                $loader_dir = $_SERVER['windir'] . '\\' . WINDOWS_IIS_LOADER_DIR;
            }
        } else {
            $loader_dir = $ext_dir;
        }
    } else {
        if (false === ($ext_dir = extension_dir_path())) {
			$parent_dir = ini_dir();
			$loader_dir = $parent_dir . '\\' . 'ioncube';
		} else {
			$loader_dir = $ext_dir;
		}
    }
    return $loader_dir;
}

function loader_install_dir($server_type)
{
    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $loader_dir = get_default_loader_dir_webspace();
    } elseif (is_ms_windows()) {
        $loader_dir = windows_install_dir();
    } else {
        $loader_dir = unix_install_dir();
    }
    return $loader_dir;
}

function writeable_directories()
{
    $root_path = @realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    $root_path_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
    $above_root_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/../cgi-bin");

    $paths = array();
    foreach (array($root_path,$above_root_path,$root_path_cgi_bin,$above_root_cgi_bin) as $p) {
        if (@is_writeable($p)) {
            $paths[] = $p;
        }
    }
    return $paths;
}

function loader_install_instructions($server_type,$loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = loader_install_dir($server_type);
    }
    if (SERVER_LOCAL == $server_type) {
        echo "<li>Put the Loader files in <code>$loader_dir</code></li>";
    } else {
        echo "<li>Transfer the Loaders to your web server and install in <code>$loader_dir</code></li>";
    }
    return $loader_dir;
}

function zend_extension_lines($loader_dir)
{
    $zend_extension_lines = array();
    $sysinfo = get_sysinfo();
    $qt = (is_ms_windows()?'"':'');
    $loader = get_loaderinfo();

    if (!is_bool($sysinfo['THREAD_SAFE']) || !$sysinfo['THREAD_SAFE']) {
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file'] . $qt;
        $zend_extension_lines[] = "zend_extension = " . $path;
    }
    if ((!is_bool($sysinfo['THREAD_SAFE']) && !is_php_version_or_greater(5,3)) || $sysinfo['THREAD_SAFE']) {
        $line_start = is_php_version_or_greater(5,3)?'zend_extension':'zend_extension_ts';
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file_ts'] . $qt;
        $zend_extension_lines[] = $line_start . " = " . $path;
    }
    return $zend_extension_lines;
}

function user_ini_base()
{
    $doc_root_path = realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    if (!empty($above_root_path) && @is_writeable($above_root_path)) {
        $start_path = $above_root_path;
    } else {
        $start_path = $doc_root_path;
    }
    return $start_path;
}

function user_ini_space_path($file)
{
    $user_base = user_ini_base();
    $fpath = @realpath($file);
    if (!empty($fpath) && (0 === strpos($fpath,$user_base))) {
        return $fpath;
    } else {
        return false;
    }
}

function default_ini_path()
{
    return (realpath($_SERVER['DOCUMENT_ROOT']));
}

function shared_ini_location()
{
    $phprc = getenv('PHPRC');
    if (!empty($phprc)) {
        $phprc_path = user_ini_space_path($phprc);
        if (false !== $phprc_path) {
            return $phprc_path;
        } else {
            return default_ini_path();
        }
    } else {
        return default_ini_path();
    }
}


function zend_extension_instructions($server_type,$loader_dir)
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();
    $editing_ini = true;

    $php_ini_name = ini_file_name();

    if (isset($sysinfo['PHP_INI']) && @file_exists($sysinfo['PHP_INI'])) {
        $php_ini_path = $sysinfo['PHP_INI'];
    } else {
        $php_ini_path = '';
    }

    if (is_bool($sysinfo['THREAD_SAFE'])) {
        $kwd = zend_extension_line_start();
    } else {
        $kwd = 'zend_extension/zend_extension_ts';
    }

    $server_type_code = server_type_code();

    $zend_extension_lines = zend_extension_lines($loader_dir);

    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $ini_dir = shared_ini_location();
        $php_ini_path = $ini_dir . DIRECTORY_SEPARATOR . $php_ini_name;
        if (@file_exists($php_ini_path)) {
            $edit_line = "<li>Edit the <code>$php_ini_name</code> in the <code>$ini_dir</code> directory";
            if (zend_extension_line_missing($php_ini_path) && @is_writeable($php_ini_path) && @is_writeable($ini_dir)) {
                if (function_exists('file_get_contents')) {
                    $ini_strs = @file_get_contents($php_ini_path);
                } else {
                    $lines = @file($php_ini_path);
                    $ini_strs = join(' ',$lines);
                }
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                        fwrite($fh,$zl . PHP_EOL);
                    }
                    fwrite($fh,$ini_strs);
                    fclose($fh);
                    $editing_ini = false;
                    echo "<li>Your php.ini file at $php_ini_path has been modified to include the necessary line for the ionCube Loader.";
                } else {
                    echo $edit_line;
                }
            } else {
               echo $edit_line;
            }
        } else {
            $download_ini_file = "<li><a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">Save this  <code>$php_ini_name</code> file</a> and upload it to <code>$ini_dir</code> (full path on your server).";
            if (@is_writeable($ini_dir)) {
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                       fwrite($fh,$zl . PHP_EOL);
                    }
                    if (!empty($sysinfo['PHP_INI']) && is_readable($sysinfo['PHP_INI'])) {
                        if (function_exists('file_get_contents')) {
                           $ini_strs = @file_get_contents($sysinfo['PHP_INI']);
                        } else {
                           $lines = @file($sysinfo['PHP_INI']);
                           $ini_strs = join(' ',$lines);
                        }
                        fwrite($fh,$ini_strs);
                    }
                    fclose($fh); 
                    echo "<li>A <code>$php_ini_name</code> file has been created for you in <code>$ini_dir</code>.";
                } else {
                    echo $download_ini_file;
                }
            } else {
                echo $download_ini_file;
            }
            $editing_ini = false;
        }
    } elseif (!empty($sysinfo['PHP_INI'])) {
        if (empty($sysinfo['PHP_INI_DIR'])) {
            echo "<li>Edit the file <code>${sysinfo['PHP_INI']}</code>";
        } else {
            $php_ini_path = find_additional_ioncube_ini();
            if (empty($php_ini_path)) {
                $php_ini_name = ADDITIONAL_INI_FILE_NAME;
                echo "<li><a href=\"$base&amp;page=phpconfig&amp;download=1&amp;newlinesonly=1&amp;ininame=$php_ini_name&amp;stype=$server_type_code\">Save this $php_ini_name file</a> and put it in your ini files directory, <code>${sysinfo['PHP_INI_DIR']}</code>";
                $editing_ini = false;
            } else {
                $php_ini_name = basename($php_ini_path);
                echo "<li>Edit the file <code>$php_ini_path</code>";
            }
        }
    } else {
        echo "<li>Edit the system <code>$php_ini_name</code> file";
    }
    if ($editing_ini) {
        echo " and <b>before</b> any other $kwd lines ensure that the following is included:<br>";
        foreach ($zend_extension_lines as $zl) {
            echo "<code>$zl</code><br>";
        }
        if (!empty($php_ini_path)) {
            if (zend_extension_line_missing($php_ini_path)) {
                echo "<a>Alternatively, replace your current <code>$php_ini_path</code> file with <a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">this new $php_ini_name file</a>."; 
            }
        }
    }
    echo '</li>';
}

function server_restart_instructions()
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();

    if ($sysinfo['SS']) {
		if ($sysinfo['SS'] == 'PHP-FPM') {
			echo "<li>Restart PHP-FPM.</li>";
		} else {
			echo "<li>Restart the ${sysinfo['SS']} server software.</li>";
		}
    } else {
        echo "<li>Restart the server software.</li>";
    }

    echo "<li>When the server software has restarted, <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the Loader</a>.</li>";

	if ($sysinfo['SS'] && $sysinfo['SS'] == 'PHP-FPM') {
		echo '<li>If the Loader installation failed, check the PHP-FPM error log file for errors.</li>';
    } elseif ($sysinfo['SS'] == 'Apache' && !is_ms_windows()) {
        echo '<li>If the Loader installation failed, check the Apache error log file for errors and see our guide to <a target="unix_errors" href="'. UNIX_ERRORS_URL . '">Unix related errors</a>.</li>';
    }
}

function shared_test_instructions()
{
    $base = get_base_address();
    echo "<li><a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">Click here to test the Loader</a>.</li>";
}

function link_to_php_ini_instructions()
{
    $default = get_default_address();
    echo "<p><a href=\"{$default}&amp;stype=s&amp;ini=1\">Please click here for instructions on using the php.ini method instead</a>.</p>";
}

function php_ini_instruction_list($server_type)
{
    echo '<h4>Installation Instructions</h4>';
    echo '<div class=panel>';
    echo '<ol>';

    loader_download_instructions(); 
    $loader_dir = loader_install_instructions($server_type);
    zend_extension_instructions($server_type,$loader_dir);
    if ($server_type != SERVER_SHARED || !own_php_ini_possible()) {
        server_restart_instructions();
    } else {
        shared_test_instructions();
    } 
    echo '</ol>';
    echo '</div>';
}

function php_ini_install_shared($give_preamble = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();
    if ($give_preamble) {
        echo "<p>On your <strong>shared</strong> server, the Loader should be installed using a <code>$php_ini_name</code> configuration file.";
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";
    }

    if (own_php_ini_possible()) {
        echo '<p>With your hosting account, you may be able to use your own PHP configuration file.</p>';
    } else {
        echo "<p>It appears that you cannot install the ionCube Loader using the <code>$php_ini_name</code> file. Your server provider or system administrator should be able to perform the installation for you. Please refer them to the following instructions.</p>";
    }

    php_ini_instruction_list(SERVER_SHARED);
}

function php_ini_install($server_type_desc = null, $server_type = SERVER_DEDICATED, $required = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();

    echo '<p>';
    if ($server_type_desc) {
        echo "For a <strong>$server_type_desc</strong> server ";
    } else {
        echo "For this server ";
    }

    if ($required) {
        echo "you should install the ionCube Loader using the <code>$php_ini_name</code> configuration file.";
    } else {
        echo "installing the ionCube Loader using the <code>$php_ini_name</code> file is recommended.";
    }
    if ($server_type_desc) {
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a $server_type_desc server</a>.)";
    }
    echo '</p>';
      
    php_ini_instruction_list($server_type);
}



function help_resources($error_list = array())
{
	$self = get_self();
    $base = get_base_address();
    $server_type_code = server_type_code();
    $server_type = find_server_type();
    $sysinfo = get_sysinfo();
    $resources = array(
            '<a target="_blank" href="' . LOADERS_FAQ_URL . '">ionCube Loaders FAQ</a>',
            '<a target="_blank" href="' . LOADER_FORUM_URL . '">ionCube Loader Forum</a>'
        );
    if (SERVER_SHARED != $server_type || own_php_ini_possible(true)) {
		$support_info = array ( 
			'department' 		=> WIZARD_SUPPORT_TICKET_DEPARTMENT,
			'subject' 			=> "ionCube Loader installation problem",
			'message' 			=> support_ticket_information()
		   );
		if (SERVER_LOCAL == $server_type && !info_should_be_disabled()) {
			$temp_files = system_info_temporary_files();
		} else {
			$temp_files = NULL;
		}
		if (!empty($temp_files)) {
			$support_info['ini'] = base64_encode(file_get_contents($temp_files['ini']));
			$support_info['phpinfo'] = base64_encode(file_get_contents($temp_files['phpinfo']));
			$support_info['additional'] = base64_encode(file_get_contents($temp_files['additional']));
			
			$loader_path = find_loader(true);
			if (is_string($loader_path)) {		
				$support_info['loader'] = base64_encode(file_get_contents($loader_path));
				$support_info['loader_name'] = basename($loader_path);
			} else {
				$support_info['loader'] = '';
				$support_info['loader_name'] = '';
			}
		} else {
			$support_info['ini'] = '';
			$support_info['phpinfo'] = '';
			$support_info['additional'] = '';
			$support_info['loader'] = '';
			$support_info['loader_name'] = '';
		}
		 
        $resources[2] = '<form action="' . SUPPORT_SITE . 'lw_index.php' .'" method="POST" id="support-ticket"><a href="" onclick="document.getElementById(\'support-ticket\').submit(); return false;">Raise a support ticket through our helpdesk</a>';
		$resources[2] .= '<input type="hidden" name="department" value="' . $support_info['department'] . '"/>';
		$resources[2] .= '<input type="hidden" name="subject" value="' . $support_info['subject'] . '"/>';
		$resources[2] .= '<input type="hidden" name="message" value="' . $support_info['message'] . '"/>';
		if (!empty($temp_files)) {
			$resources[2] .= '<input type="hidden" name="phpinfo" value="' . $support_info['phpinfo'] . '"/>';
			$resources[2] .= '<input type="hidden" name="ini" value="' . $support_info['ini'] . '"/>';
			$resources[2] .= '<input type="hidden" name="additional" value="' . $support_info['additional'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader" value="' . $support_info['loader'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader_name" value="' . $support_info['loader_name'] . '"/>';
		}
		$resources[2] .= '</form>';
    } 
	
    if (SERVER_SHARED == $server_type && own_php_ini_possible(true) && !user_ini_space_path($sysinfo['PHP_INI'])) {
        $resources[3] = '<strong>Please check with your host that you can create php.ini files that will override the system one.</strong>';
    }
    return $resources;
}

function system_info_temporary_files()
{
    $tmpfname_ini = get_tempnam("/tmp", "INI");
    $tmpfname_ini .= ".ini";
    $fh_ini = @fopen($tmpfname_ini,'wb');
    if ($fh_ini) {
        $config = all_ini_contents();
        fwrite($fh_ini,$config);
        fclose($fh_ini);
    } else {
        $tmpfname_ini = '';
    }

    $tmpfname_pinf = get_tempnam("/tmp", "PIN");
    $tmpfname_pinf .= ".html";
    $fh_pinfo = @fopen($tmpfname_pinf,'wb');
    if ($fh_pinfo) {
        ob_start();
        @phpinfo();
        $pinfo = ob_get_contents();
        ob_end_clean();
        fwrite($fh_pinfo,$pinfo);
        fclose($fh_pinfo);
    } else {
        $tmpfname_pinf = '';
    }

    $tmpfname_add = get_tempnam("/tmp", "ADD");
    $tmpfname_add .= ".html";
    $fh_add = @fopen($tmpfname_add,'wb');
    if ($fh_add) {
        ob_start();
        extra_page(false);
        $extra = ob_get_contents();
        ob_end_clean();
        fwrite($fh_add,$extra);
        fclose($fh_add);
    } else {
        $tmpfname_add = '';
    }

    if (empty($tmpfname_ini) || empty($tmpfname_pinf) || empty($tmpfname_add)) {
        return (array());
    } else {
        return (array('ini'           =>   $tmpfname_ini,
                      'phpinfo'       =>   $tmpfname_pinf,
                      'additional'    =>   $tmpfname_add));
    }
}

function get_tempnam($default_tmp_dir = '', $prefix = '')
{
	if (function_exists('sys_get_temp_dir')) {
		return tempnam(sys_get_temp_dir(),$prefix);
	} else {
		return @tempnam($default_tmp_dir, $prefix);
	}
}
function system_info_archive_page()
{
    info_disabled_check();
	$server_type = find_server_type();
	if (SERVER_LOCAL != $server_type) {
		exit;
	}
    $loader = find_loader(true);
    if (is_string($loader)) {
        $loader_file = $loader;
    } else {
        $loader_file = '';
    }
    $all_files = system_info_temporary_files();
    if (!empty($all_files)) {
        if (!empty($loader_file)) {
            $all_files['loader'] = $loader_file;
        }
        $archive_name =  get_tempnam('/tmp',"ARC");
        if (extension_loaded('zip')) {
            $archive_name .= '.zip';
            $zip = @new ZipArchive();
            $mode = @constant("ZIPARCHIVE::OVERWRITE");
            if (!$zip || $zip->open($archive_name, $mode)!==TRUE) {
                $archive_name = '';
            } else {
                foreach($all_files as $f) {
                    $zip->addFile($f,basename($f));
                }
                $zip->close();
            }
        } elseif (extension_loaded('zlib') && !is_ms_windows()) {
            $tar_name = $archive_name . ".tar";
            $all_files_str = join(' ',$all_files);
            $script = "tar -chf $tar_name $all_files_str";
            $result = @system($script,$retval);
            if ($result !== false) {
                $archive_name = $tar_name . '.gz';
                $zp = gzopen($archive_name,"w9");
                $tar_contents = get_file_contents($tar_name);
                gzwrite($zp,$tar_contents);
                gzclose($zp);
            } else {
                $archive_name = '';
            }
        } else {
            $archive_name = '';
        }
    } else {
        $archive_name = '';
    }
    if ($archive_name) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. $archive_name);
        @readfile($archive_name);
    } else {
        $self = get_self();
        $base = get_base_address();
        $server_type_code = server_type_code();
        heading();
        echo "<p>A downloadable archive of system information could not be created.<br> 
            <strong>Please save each of the following and then attach those files to the support ticket:</strong></p>"; 
        echo "<ul>";
        echo "<li><a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo()</a></li>";
        echo "<li><a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a></li>";
        echo "<li><a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional information</a></li>";
        echo "<li><a href=\"$self?page=loaderbin\">loader file</a></li>";
        echo "</ul>";
        footer(true);
    }
}

function support_ticket_information($error_list = array())
{
    $sys = get_sysinfo();
    $ld = get_loaderinfo();

    $ticket_strs = array();
    $ticket_strs[] = "PLEASE DO NOT REMOVE THE FOLLOWING INFORMATION\r\n";
    $ticket_strs[] = "==============\r\n";
    if (!empty($error_list)) {
        $ticket_strs[] = "[hr]";
        $ticket_strs[] = "ERRORS";
        $ticket_strs[] = "[table]";
        $ticket_strs[] = '[tr][td]' . join('[/td][/tr][tr][td]',$error_list) . '[/td][/tr]';
        $ticket_strs[] = "[/table]";
    }
    $ticket_strs[] = "[hr]";
    $ticket_strs[] = "SYSTEM INFORMATION";
    $info_lines = array();
    $info_lines["Wizard version"] = script_version();
    $info_lines["PHP uname"] = $ld['uname'];
    $info_lines["Machine architecture"] = $ld['arch'];
    $info_lines["Word size"] = $ld['wordsize'];
    $info_lines["Operating system"] = $ld['osname'] . ' ' . $ld['osver'];
    if (selinux_is_enabled() || possibly_selinux()) {
        $info_lines["Security enhancements"] = "SELinux";
    } elseif (grsecurity_is_enabled()) {
        $info_lines["Security enhancements"] = "Grsecurity";
    } else {
        $info_lines["Security enhancements"] = "None";
    }
    $info_lines["PHP version"] = PHP_VERSION; 
    if ($sys['DEBUG_BUILD']) {
        $info_lines["DEBUG BUILD"] = "DEBUG BUILD OF PHP";
    }
    if (!$sys['SUPPORTED_COMPILER']) {
        $info_lines["SUPPORTED PHP COMPILER"] = "FALSE";
        $info_lines["PHP COMPILER"] = $sys['PHP_COMPILER'];
    }
    $info_lines["Is CLI?"] = ($sys['IS_CLI']?"Yes":"No");
    $info_lines["Is CGI?"] = ($sys['IS_CGI']?"Yes":"No");
    $info_lines["Is thread-safe?"] = ($sys['THREAD_SAFE']?"Yes":"No");
    $info_lines["Web server"] = $sys['FULL_SS'];
    $info_lines["Server type"] = server_type_string();
    $info_lines["PHP ini file"] = $sys['PHP_INI'];
    if (!@file_exists($sys['PHP_INI'])) {
        $info_lines["Ini file found"] = "INI FILE NOT FOUND";
    } else {
        if (is_readable($sys['PHP_INI'])) {
            $info_lines["Ini file found"] = "INI FILE READABLE";
        } else {
            $fh = @fopen($sys['PHP_INI'],"rb");
            if ($fh === false) {
                $info_lines["Ini file found"] = "INI FILE FOUND BUT POSSIBLY NOT READABLE";
            } else {
                $info_lines["Ini file found"] = "INI FILE READABLE";
            }
        }
    }
    $info_lines["PHPRC"] = $sys['PHPRC'];
    $loader_path = find_loader();
    if (is_string($loader_path)) {
        $info_lines["Loader path"] =  $loader_path;
        $info_lines["Loader file size"] = filesize($loader_path) . " bytes.";
        $info_lines["Loader MD5 sum"] =  md5_file($loader_path);
    } else {
        $info_lines["Loader path"] =  "LOADER PATH NOT FOUND";
    }
    $server_type_code = server_type_code();
    if (!empty($_SESSION['hostprovider'])) {
      $info_lines['Hosting provider'] = $_SESSION['hostprovider'];
      $info_lines['Provider URL'] = $_SESSION['hosturl'];
    }
    $info_lines["Wizard script path"] = '[url]http://' . $_SERVER["HTTP_HOST"] . get_self() . '?stype='. $server_type_code . '[/url]';
    $ticket_strs[] = "[table]";
    foreach ($info_lines as $h => $i) {
        $value = (empty($i))?'EMPTY':$i;
        $ticket_strs[] = '[tr][td]' . $h . '[/td]' . '[td]' . $value . '[/td][/tr]';
    }
    $ticket_strs[] = '[/table]';
    $ticket_strs[] = '[hr]';
    $ticket_strs[] = "\r\n==============\r\n";
    $ticket_strs[] = "PLEASE ENTER ANY ADDITIONAL INFORMATION BELOW\r\n";

    $support_ticket_str = join('',$ticket_strs);
    return urlencode($support_ticket_str);
}

function wizard_stats_data($page_id)
{
    $data = array();

    try_runtime_loading_if_applicable();
    $sysinfo = get_sysinfo();
    $ldinfo = get_loaderinfo();

    $data['sessionid'] = session_id();
    $data['wizard_version'] = script_version();
    $data['server_type'] = server_type_code();
    $data['hostprovider'] = (isset($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $data['hosturl'] = (isset($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $data['page_id'] = $page_id;
    $data['loader_state'] = (extension_loaded(LOADER_EXTENSION_NAME))?'installed':'failure';
    $data['ini_location'] = $sysinfo['PHP_INI'];
    $data['is_cgi'] = ($sysinfo['IS_CGI'])?"yes":"no";
    $data['is_ts'] = ($sysinfo['THREAD_SAFE'])?"yes":"no";
    $data['arch'] = $ldinfo['arch'];
    $data['php_version'] = PHP_VERSION;
    $data['os'] = $ldinfo['osname'];
    $data['word_size'] = $ldinfo['wordsize'];
    $data['referrer'] =  $_SERVER["HTTP_HOST"] . get_self();

    return $data;
}

function send_stats($page_id = 'default')
{
    $server_type = find_server_type();
    $res = false;

    if (SERVER_LOCAL != $server_type) {
        $stats_data = wizard_stats_data($page_id);

        if (!isset($_SESSION['stats_sent'][$page_id][$stats_data['loader_state']])) {
            $url = WIZARD_STATS_URL;

            if (!empty($stats_data)) {
                if(function_exists('http_build_query')) {
                    $qparams = http_build_query($stats_data);
                } else {
                    $qparams = php4_http_build_query($stats_data);
                }
                $url .= '?' . $qparams;
                $res = remote_file_contents($url);
            }
            $_SESSION['stats_sent'][$page_id][$stats_data['loader_state']] = 1;
        } else {
            $res = true;
        }
    } else {
        $res = 'LOCAL';
    }
    return $res;
}

function os_arch_string_check($loader_str)
{
    $errors = array();
    if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_str,$os_matches)) {
        $loader_info = get_loaderinfo();
        $dirname = calc_dirname();
        $packed_osname = preg_replace('/\s/','',strtolower($loader_info['osname']));
        if (strtolower($dirname) != $os_matches[1] && $packed_osname != $os_matches[2]) {
            $errors[ERROR_LOADER_WRONG_OS] = "You have the wrong loader for your operating system, ". $loader_info['osname'] . ".";
        } else {
            $loader_wordsize = (strpos($os_matches[3],'64') === false)?32:64;
            if ($loader_info['arch'] != ($ap = required_loader_arch($os_matches[3],$loader_info['oscode'],$loader_wordsize))) {
                $err_str = "You have the wrong loader for your machine architecture.";
                $err_str .= " Your system is " . $loader_info['arch'];
                $err_str .= " but the loader you are using is for " . $ap . ".";
                $errors[ERROR_LOADER_WRONG_ARCH] = $err_str;
            }
        }
    }
    return $errors;
}

function get_loader_strings($loader_location)
{
    if (function_exists('file_get_contents')) {
        $loader_strs = @file_get_contents($loader_location);
    } else {
        $lines = @file($loader_location);
        $loader_strs = join(' ',$lines);
    }
    return $loader_strs;
}

function loader_system($loader_location)
{
    $loader_system = array();
    $loader_strs = get_loader_strings($loader_location);

    if (!empty($loader_strs)) {

        if (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
            $loader_system['oscode'] = 'win';
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '_nonts')?0:1;
			if (preg_match("/_localtime([0-9][0-9])/i",$loader_strs,$size_matches)) {
				$loader_system['wordsize'] = ($size_matches[1] == '64')?64:32;
			} else {
				$loader_system['wordsize'] = 32;
			}
            $loader_system['arch'] = ($loader_system['wordsize'] == 64)?'x86-64':'x86';
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
			if ($loader_system['php_version_major'] == 8 && $loader_system['php_version_minor'] >= 1) {
				$loader_system['compiler'] = 'VC16';
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] >= 2) {
				$loader_system['compiler'] = 'VC15'; 
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] < 2) {
				$loader_system['compiler'] = 'VC14'; 
			} elseif ($loader_system['php_version_major'] == 5 && $loader_system['php_version_minor'] >= 5) {
				$loader_system['compiler'] = 'VC11'; 
			} elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_system['compiler'] = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_system['compiler'] = 'VC6';
            }
        } elseif (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '-ts')?1:0;
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
            if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_strs,$os_matches)) {
                $loader_system['oscode'] = strtolower(substr($os_matches[2],0,3));
                $loader_system['wordsize'] = (strpos($os_matches[3],'64') === false)?32:64;
                $loader_system['arch'] = required_loader_arch($os_matches[3],$loader_system['oscode'],$loader_system['wordsize']);
                $loader_system['compiler'] = $os_matches[4];
            }
        }
        if (preg_match("/ionCube Loader Version\s+(\S+)/",$loader_strs,$loader_version)) {
            $loader_system['loader_version'] = $loader_version[1];
		} elseif (preg_match("/ioncube_loader_(\d{1,2}\.\d\.\d{1,2})\./",$loader_strs,$loader_version)){
			$loader_system['loader_version'] = $loader_version[1];
        } else {
            $loader_system['loader_version'] = 'UNKNOWN';
        }
        if (isset($loader_system['php_version_major'])) {
            $loader_system['php_version'] = $loader_system['php_version_major'] . '.' . $loader_system['php_version_minor'];
        }
    }
    return $loader_system;
}

function loader_compatibility_test($loader_location)
{
    $errors = array();

    $sysinfo = get_sysinfo();
    if (LOADER_NAME_CHECK) {
        $installed_loader_name = basename($loader_location);
        $expected_loader_name = get_loader_name();
        if ($installed_loader_name != $expected_loader_name) {
            $errors[ERROR_LOADER_UNEXPECTED_NAME] = "The installed loader (<code>$installed_loader_name</code>) does not have the name expected (<code>$expected_loader_name</code>) for your system. Please check that you have the correct loader for your system.";
        }
    }
    if (empty($errors) && !is_readable($loader_location)) {
        $execute_error = "The loader at $loader_location does not appear to be readable.";
        $execute_error .= "<br>Please check that it exists and is readable.";
        $execute_error .= "<br>Please also check the permissions of the containing ";
        $execute_error .= (is_ms_windows()?'folder':'directory') . '.';
		if ($sysinfo['SS'] == 'PHP-FPM') {
			$execute_error .= "<br>Please also check that PHP-FPM has been restarted.";
        } elseif (($sysinfo['SS'] == 'IIS') || !($sysinfo['IS_CGI'] || $sysinfo['IS_CLI'])) {
            $execute_error .= "<br>Please also check that the web server has been restarted.";
        }
        $execute_error .= ".";
        $errors[ERROR_LOADER_NOT_READABLE] = $execute_error;
    }
    $loader_strs = get_loader_strings($loader_location);
    $phpv = php_version(); 
    if (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
        if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
            $loader_php = $version_matches[1] . "." . $version_matches[2];
            $server_php =  $phpv['major'] . "." .  $phpv['minor'];
            $errors[ERROR_LOADER_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
        }
        if (is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'] && !is_ms_windows() && !(isset($version_matches[4]) && $version_matches[4] == '-ts')) {
            $errors[ERROR_LOADER_NONTS_PHP_TS] = "Your server is running a thread-safe version of PHP but the loader is not a thread-safe version.";
        } elseif (isset($version_matches[4]) && $version_matches[4] == '-ts' && !(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'])) {
            $errors[ERROR_LOADER_TS_PHP_NONTS] = "Your server is running a non-thread-safe version of PHP but the loader is a thread-safe version.";
        }
    } elseif (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
        if (!is_ms_windows()) {
            $errors[ERROR_LOADER_WIN_SERVER_NONWIN] = "You have a Windows loader but your server does not appear to be running Windows.";
        } else {
            if (isset($version_matches[4]) && $version_matches[4] == '_nonts' && is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) {
                $errors[ERROR_LOADER_WIN_NONTS_PHP_TS] = "You have the non-thread-safe version of the Windows loader but you need the thread-safe one.";
            } elseif (!(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) && !(isset($version_matches[4]) && $version_matches[4] == '_nonts')) {
                $errors[ERROR_LOADER_WIN_TS_PHP_NONTS] = "You have the thread-safe version of the Windows loader but you need the non-thread-safe one."; 
            }
            if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
                $loader_php = $version_matches[1] . "." . $version_matches[2];
                $server_php =  $phpv['major'] . "." .  $phpv['minor'];
                $errors[ERROR_LOADER_WIN_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
            }
                        
            if ($version_matches[1] == 8 && $version_matches[2] >= 1) {
                $loader_compiler = 'VC16';
            } elseif ($version_matches[1] == 7 && $version_matches[2] >= 2) {
                $loader_compiler = 'VC15'; 
            } elseif ($version_matches[1] == 7) {
                $loader_compiler = 'VC14'; 
            } elseif ($version_matches[1] == 5 && $version_matches[2] >= 5) {
                $loader_compiler = 'VC11'; 
            } elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_compiler = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_compiler = 'VC6';
            }
            if ($loader_compiler != $sysinfo['PHP_COMPILER']) {
                $errors[ERROR_LOADER_WIN_COMPILER_MISMATCH] = "Your loader was built using $loader_compiler but you need the loader built using ${sysinfo['PHP_COMPILER']}.";
            }
        }
    } else {
            $errors[ERROR_LOADER_PHP_VERSION_UNKNOWN] = "The PHP version for the loader cannot be determined - please check that you have a valid ionCube Loader.";
    } 
    $errors += os_arch_string_check($loader_strs);

    return $errors;
}


function shared_server()
{
    if (!$rtl_path = runtime_loading()) {
        if (empty($_SESSION['use_ini_method']) && runtime_loading_is_possible()) {
            runtime_loading_instructions();
        } else {
            php_ini_install_shared();
        }
    } else {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        echo "<p>The ionCube Loader $lv for PHP $phpv has been successfully installed.</p>";
        $is_legacy_loader = loader_major_version_instructions($mv);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,$newer_version);
        }
        successful_install_end_instructions($rtl_path);
    }
}

function dedicated_server()
{
    php_ini_install('dedicated or VPS', SERVER_DEDICATED, true);
}

function local_install()
{
    php_ini_install('local',SERVER_LOCAL, true);
}


function unregister_globals()
{
    if (!ini_get('register_globals')) {
        return;
    }

    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

function clear_session($persist = array())
{
    $persist['not_go_daddy'] = empty($_SESSION['not_go_daddy'])?0:1;
    $persist['use_ini_method'] = empty($_SESSION['use_ini_method'])?0:1;
    $persist['server_type'] = empty($_SESSION['server_type'])?SERVER_UNKNOWN:$_SESSION['server_type'];
    @session_destroy();
    $_SESSION = array();
    $_SESSION['CREATED'] = time();
    $_SESSION = $persist;
}

function can_archive()
{
	return (extension_loaded('zip') || (extension_loaded('zlib') && !is_ms_windows()));
}

function is_ioncube()
{
        return (($_SERVER["REMOTE_ADDR"] == IONCUBE_IP_ADDRESS) || ($_SERVER["REMOTE_ADDR"] == gethostbyname(IONCUBE_ACCESS_ADDRESS)));
}

function can_reach_ioncube()
{
	return (isset($_SESSION['remote_access_successful']));
}

function info_should_be_disabled($only_allow_ioncube = false)
{
    $elapsed = time() - max(filemtime(__FILE__),filectime(__FILE__));
	
	if (is_ioncube()) {
		$cutoff_time = IONCUBE_WIZARD_EXPIRY_MINUTES * 60;
	} else {
		if (!$only_allow_ioncube && !extension_loaded(LOADER_EXTENSION_NAME)) {
			$cutoff_time = WIZARD_EXPIRY_MINUTES * 60;
		} else {
			return true;
		}
	}
	
    return ($elapsed > $cutoff_time);
}

function info_disabled_text()
{
    return "The information you have tried to access has been disabled for security reasons. Please re-install this Loader Wizard script and try again.";
}

function info_disabled_check()
{
    if (info_should_be_disabled()) {
        heading();
        echo info_disabled_text();
        footer(true);
        exit;
    }
}

function run()
{

	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (preg_match('/googlebot/i',$user_agent)) {
		exit;
	}
    unregister_globals();
    if (is_php_version_or_greater(4,3,0)) {
        ini_set('session.use_only_cookies',1);
    }
    $session_ok = @session_start();

    if (!defined('PHP_EOL')) {
        if (is_ms_windows()) {
            define('PHP_EOL',"\r\n");
        } else {
            define('PHP_EOL',"\n");
        }
    }

    if (!isset($_SESSION['CREATED'])) {
        $_SESSION['CREATED'] = time();
    } elseif (time() - $_SESSION['CREATED'] > SESSION_LIFETIME_MINUTES * 60 ) {
        clear_session(); 
    }
    if (!isset($_SERVER)) $_SERVER =& $HTTP_SERVER_VARS;

    (php_sapi_name() == 'cli') && die("This script should only be run by a web server.\n");

    $page = get_request_parameter('page');
    $host = get_request_parameter('host');
    $clear = get_request_parameter('clear');
    $ini = get_request_parameter('ini');
    $timeout = get_request_parameter('timeout');

    if ($timeout) {
        $_SESSION['timing_out'] = 1;
        $_SESSION['initial_run'] = 0;
    }

    if (!empty($host)) {
        if ($host == 'ngd') {
            $_SESSION['not_go_daddy'] = 1;
        }
    }
    if (!empty($ini)) {
        $_SESSION['use_ini_method'] = 1;
    }

    if (!empty($clear)) {
        clear_session();
        unset($_SESSION['not_go_daddy']);
        unset($_SESSION['use_ini_method']);
        unset($_SESSION['server_type']);
    } else {
        $stype = get_request_parameter('stype');
        $hostprovider = get_request_parameter('hostprovider');
        $hosturl = get_request_parameter('hosturl');
        if (!empty($hostprovider)) {
            $_SESSION['hostprovider'] = $hostprovider;
            $_SESSION['hosturl'] = $hosturl;
        }
        $server_type = find_server_type($stype,false,true);
    }
    if ($session_ok && !$timeout && !isset($_SESSION['initial_run']) && empty($page)) {
        $_SESSION['initial_run'] = 1;
        initial_page();
        @session_write_close();
        exit;
    } else {
        $_SESSION['initial_run'] = 0;
    }

    if (empty($_SESSION['server_type'])) {
        $_SESSION['server_type'] = SERVER_UNKNOWN;
    }

    if (empty($page) || !function_exists($page . "_page")) {
        $page = get_default_page();
    } 

    $fn = "{$page}_page";
    $fn();

    @session_write_close();
    exit(0);
}

function wizardversion_page()
{
    $start_time = time();
    $wizard_version_only = get_request_parameter('wizard_only');
    $clear_session_info = get_request_parameter('clear_info');
    if ($clear_session_info) {
        unset($_SESSION['timing_out']);
        unset($_SESSION['latest_wizard_version']);
    }
    $wizard_version = latest_wizard_version();
    $message = '';
    if (false === $wizard_version) {
        $message = "0";
    } elseif (update_is_available($wizard_version)) {
        $message = "$wizard_version";
    } else {
        $message = "1";
    }
    echo $message;
    @session_write_close();
    exit(0);
}

function platforminfo_page()
{
    $message = '';
    $platforms = get_loader_platforms();
    $message = empty($platforms)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function loaderversion_page()
{
    $message = '';
    $loader_versions = get_loader_version_info();
    $message = empty($loader_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function compilerversion_page()
{
    $message = '';
    $compiler_versions = find_win_compilers();
    $message = empty($compiler_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function initial_page()
{
    $self = get_self();
    $start_page = get_default_address(false);
    $stage_timeout = 7000;
    $step_lag = 500;

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <style type="text/css">
        body {
            height: 100%;
            width: 100%;
        }
        </style>
        <script type="text/javascript">
        var timingOut = 0;
        var xmlHttpTimeout;
        var ajax;
        var statusPar;
        var stage_timeout = $stage_timeout;
        var step_lag = $step_lag;

        function checkNextStep(ajax,expected,continuation) {
            if (ajax.readyState==4 && ajax.status==200)
            {
                clearTimeout(xmlHttpTimeout);
                if (ajax.responseText == expected) {
                   setTimeout('',step_lag);
                   continuation();
                } else {
                   statusPar.innerHTML = 'Unable to check for update<br>script continuing';
                   setTimeout("window.location.href = '$start_page&timeout=1'",1000);
                }
            }
        }

        function getXmlHttp() {
            if (window.XMLHttpRequest) {
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xmlhttp;
        }
        var startMainLoaderWizard = function() {
            window.location.href = '$start_page';
        }
        var loaderVersionCheck = function() {
            statusPar.innerHTML = 'Stage 4/4: Getting latest loader versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",startMainLoaderWizard);
            }
            xmlHttp.open("GET","$self?page=loaderversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var platformCheck = function() {
            statusPar.innerHTML = 'Stage 3/4: Getting platform information';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",loaderVersionCheck);
            }
            xmlHttp.open("GET","$self?page=platforminfo",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var compilerVersionCheck = function() {
            statusPar.innerHTML = 'Stage 2/4: Getting compiler versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",platformCheck);
            }
            xmlHttp.open("GET","$self?page=compilerversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var startChecks = function() {
            statusPar = document.getElementById('status');
            statusPar.innerHTML = 'Stage 1/4: Getting Loader Wizard version';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",compilerVersionCheck);
            }
            xmlHttp.open("GET","$self?page=wizardversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        function ajaxTimeout(){
           ajax.abort();
           statusPar.innerHTML = 'Cannot reach server<br>script continuing';
           setTimeout("window.location.href = '$start_page&timeout=1'",1000);
        }
        </script>
    </head>
    <body>

    <div id="loading"><script type="text/javascript">document.write('<p>Initialising<br>ionCube Loader Wizard<br><span id="status"></span></p>');</script><p id="noscript">Your browser does not support JavaScript so the ionCube Loader Wizard initialisation cannot be made now. This script can get the latest loader version information from the ionCube server when you go to the next page.<br>Please choose one of the following. <br>If the script appears to hang please restart the script and choose the "NO" option.<br><br><br><a href="$start_page">YES - my server DOES have internet access</a><br><br><a href="$start_page&timeout=1">NO - my server does NOT have internet access</a></p></div>
    <script type="text/javascript">
        document.getElementById('noscript').style.display = 'none';
        window.onload = startChecks;
    </script>
    </body>
    </html>
EOT;
}

function default_page($loader_extension = LOADER_EXTENSION_NAME)
{
    $self = get_self();
    foreach (array('self') as $vn) {
        if (empty($$vn)) {
			$server_data = print_r($_SERVER,true);
            error("Unable to initialise ($vn)". ' $_SERVER is: ' . $server_data);
        }
    }

    heading();

    $wizard_update = check_for_wizard_update(true);

    $rtl = try_runtime_loading_if_applicable();

    $server_type = find_server_type();

    if (extension_loaded($loader_extension) && $server_type != SERVER_UNKNOWN) {
        loader_already_installed($rtl);
    } else {
        loader_not_installed();
    }
    send_stats('default');

    footer($wizard_update);
}

function uninstall_wizard_instructions()
{
    echo '<p><strong>For security reasons we advise that you remove this Wizard script from your server now that the ionCube Loader is installed.</strong></p>';
}

function contact_script_provider_instructions()
{
    echo '<p>Please contact the script provider if you do experience any problems running encoded files.</p>';
}

function may_need_to_copy_ini()
{
    $sys = get_sysinfo();
    if (ini_same_dir_as_wizard() && $sys['IS_CGI']) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        $ini = ini_file_name();
        echo "<p>Please note that if encoded files in a different $dirphrase from the Wizard fail then you should attempt to copy the $ini file to each $dirphrase in which you have encoded files.</p>";
    }
}

function ioncube_24_is_available()
{
	$loaderinfo = get_loaderinfo();
	$php_ver = php_version();
   
	return ($loaderinfo['oscode'] == 'lin' && (($php_ver['major'] == 5 && $php_ver['minor'] >= 3) || $php_ver['major'] > 5) );
}

function ioncube_24_is_enabled()
{
	$ic24_enabled = ini_get(IC24_ENABLED_INI_PROPERTY);
	return $ic24_enabled;
}

function ioncube_24_information()
{
    if (ioncube_24_is_available() && !ioncube_24_is_enabled()) {
        $self = get_self();
        echo '<div class="ic24">';
        echo '<div class="ic24graphic">';
        echo '<a target="_blank" href="' . IONCUBE24_URL . '"><img id="ic24logo" src="' . $self . '?page=ic24logo" alt="ionCube24 logo"></a>';
        echo '</div>';
        echo '<div id="ic24info">';
        echo '<p><strong>Bonus Features!</strong> The ionCube Loader can also give ';
        echo '<strong>real-time intrusion protection</strong> to protect against malware and <strong>PHP error reporting</strong> ';
        echo 'to alert when things go wrong on your website.</p>';
        echo '<p>These features are disabled by default but easily activated. ';
        echo '<strong><a target="_blank" href="' . IONCUBE24_URL . '">visit ioncube24.com</a></strong> to find out more.</p>';
        echo '</div>';
        echo '</div>';
    }
}

function cli_install_instructions()
{

	if (is_php_version_or_greater(5,3)) {
		$cli_loader_installed = shell_exec('php -r "echo extension_loaded(\"' . LOADER_EXTENSION_NAME . '\");"');
		
		if (!$cli_loader_installed) {
			$cli_php_ini_output = shell_exec("php --ini");
			
			$ini_loader_loc = scan_inis_for_loader();
		
			if (!is_null($cli_php_ini_output)) {
				echo '<div class="panel">';
				echo '<h4>Loader Installation for Command-Line (CLI) PHP</h4>';
				echo "<p>At present it does not look like the ionCube Loader is installed for command-line (CLI) PHP.</p>";
				echo "<p>Please note that if you need to run the CLI PHP, such as for <strong>cron jobs</strong>, then please ensure the zend_extension line for the ionCube Loader is included in your CLI PHP configuration.</p>";
				
				if (!empty($ini_loader_loc['location'])) {
					echo "<p>The zend_extension line that needs to be copied is:</p>";
					echo "<p><kbd>zend_extension = " . $ini_loader_loc['location'] . "</kbd></p>";
				}
				
				echo "<p>Your CLI PHP Configuration is:</p>";
				echo '<div class="terminal">';
				echo "<pre>";
				echo $cli_php_ini_output;
				echo "</pre>";
				echo '</div>';
				echo '</div>';
			}
		}
	}
}

function successful_install_end_instructions($rtl_path = null)
{
    if (empty($rtl_path)) {
        may_need_to_copy_ini();
    } elseif (is_string($rtl_path)) {
        echo "<p>The runtime loading method of installation was used with path <code>$rtl_path</code></p>";
    }
    contact_script_provider_instructions();
    if (is_legacy_platform()) {
        legacy_platform_instructions();
    }
	
	if (!is_ms_windows() && is_php_version_or_greater(5,3)) {
		cli_install_instructions();
	}
	
    uninstall_wizard_instructions();
	
	ioncube_24_information();
}

function loader_major_version_instructions($mv)
{
    if ($mv < LATEST_LOADER_MAJOR_VERSION) {
        echo "<p><strong>The installed version of the Loader cannot run files produced by the most recent ionCube Encoder.</strong>";
        echo " You will need a version " . LATEST_LOADER_MAJOR_VERSION . " ionCube Loader to run such files.</p>";
    }
    return ($mv < LATEST_LOADER_MAJOR_VERSION);
}

function loader_already_installed($rtl = null)
{
    list($lv,$mv,$newer_version) = ioncube_loader_version_information();
    $phpv = php_version_maj_min();
    $php_str = ' for PHP ' . $phpv;
    echo '<div class="success">';
    echo '<h4>Loader Installed</h4>';
    if ($newer_version) {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is <strong>already installed</strong> but it is an old version.';
        echo ' It is recommended that the Loader be upgraded to the latest version if possible.</p>';
        $know_latest_version = is_string($newer_version);
        $is_legacy_loader = loader_major_version_instructions($mv);
        echo '</div>';
        loader_upgrade_instructions($lv,$newer_version);
    } else {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is already installed and encoded files should run without problems.</p>'; 
        echo '</div>';
        $is_legacy_loader = loader_major_version_instructions($mv,true);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,true);
        }
    }

    successful_install_end_instructions($rtl);
}

function loader_upgrade_instructions($installed_version,$newer_version)
{
    if ($newer_version) {
        echo '<div class="panel">';
        echo '<h4>Loader Upgrade Instructions</h4>';
        $restart_needed = true;
        $server_type = find_server_type();
        if ($server_type == SERVER_SHARED || $server_type == SERVER_UNKNOWN) {
            $loader_path = find_loader(true);
            if (!is_string($loader_path) || false === user_ini_space_path($loader_path)) {
                $verb_case = ($server_type == SERVER_UNKNOWN)?"may":"will";
                echo "<p>Please note that you $verb_case need your system administrator to do the following to upgrade. The web server will need to be restarted after the loader file is changed.</p>";
            }
            $restart_needed = false;
        }
        if (is_string($newer_version)) {
            $version_str = "version $newer_version";
        } else {
            $version_str = "a newer version";
        }
        $loader_name =  get_loader_name();
        echo "<p>To upgrade from version $installed_version to $version_str of the ionCube Loader, please replace your existing loader file, $loader_name, with
            the file of the same name from one of the following packages:</p>";
        if (is_ms_windows()) {
            $basename = windows_package_name();
        } else {
            list($basename,$multiple_os_versions) = unix_package_name();
        }
        echo make_archive_list($basename,array('zip','tar.gz'));
        if ($restart_needed) {
            echo "<p>Once you have replaced the loader file please restart your web server.</p>";
        }
        echo '</div>';
    }
}

function legacy_platform_warning()
{
    $leg_warn = '<p><strong>You are on a platform on which ionCube Loaders are no longer being developed. ';
    $leg_warn .= 'Loaders on your platform may not be able to run files produced by the latest ionCube Encoder. ';
    $leg_warn .= 'Please switch, if possible, to a platform on which loaders are currently supported. ';
    $leg_warn .= 'A list of currently supported platforms is shown on our <a href="' . LOADERS_PAGE . '" target="loaders">loaders page</a>.</strong></p>';

    return $leg_warn;
}

function legacy_platform_instructions()
{
    echo legacy_platform_warning();
}

function loader_not_installed()
{
    $loader = get_loaderinfo();
    $sysinfo = get_sysinfo();

    $stype = get_request_parameter('stype');
    $manual_select = get_request_parameter('manual');
    $host_type = find_server_type($stype,$manual_select,true);

    if ($host_type != SERVER_UNKNOWN && is_array($loader) && !$sysinfo['DEBUG_BUILD']) {
        $warnings = server_restriction_warnings();
        if (is_legacy_platform()) {
            $warnings[] = legacy_platform_warning();
        }
        if (empty($_SESSION['use_ini_method']) && $host_type == SERVER_SHARED && runtime_loading_is_possible()) {
            $errors = runtime_loading_errors();
        } else {
            $errors = ini_loader_errors();
            $warnings = array_merge($warnings,ini_loader_warnings());
        }
        if (!empty($errors)) {
            if (count($errors) > 1) {
                $problem_str = "Please note that the following problems currently exist";
            } else {
                $problem_str = "Please note that the following problem currently exists";
            }
            echo '<div class="alert">' .$problem_str . ' with the ionCube Loader installation:';
            echo make_list($errors,"ul"); 
            echo '</div>';
        }
        if (!empty($warnings)) {
            $addword = empty($errors)?'':'also';
            $plural = (count($warnings)>1)?'s':'';
            echo '<div class="warning">';
            echo "Please note $addword the following issue$plural:";
            echo make_list($warnings,"ul"); 
            echo '</div>';
        }
    }
    if (!isset($stype)) {
        echo '<p>To use files that have been protected by the <a href="' . ENCODER_URL . '" target=encoder>ionCube PHP Encoder</a>, a component called the ionCube Loader must be installed.</p>';
    }

    if (!is_supported_php_version()) {
        echo '<p>Your server is running PHP version ' . PHP_VERSION . ' and is
                unsupported by ionCube Loaders.  Recommended PHP 4 versions are PHP 4.2 or higher, 
                PHP 5.1 or higher for PHP 5, PHP 7.1 or higher for PHP 7 and PHP 8.1 or higher for PHP 8. Please note that there is not an ionCube Loader for PHP 8.0.</p>';
	} elseif ($latest_supported_php_version = is_after_max_php_version_supported()) {
		echo '<strong>Your server is running PHP version ' . PHP_VERSION . ' and is
                currently unsupported by any ionCube Loaders. <br/>This may change in the future if a Loader is produced for your PHP platform.<br/>In the meantime please downgrade PHP to version ' . $latest_supported_php_version . '.</strong>';
    } elseif ($sysinfo['DEBUG_BUILD']) {
         echo '<p>Your server is currently running a debug build of PHP. The Loader cannot be installed with a debug build of PHP. Please ensure that PHP is reconfigured with debug disabled. Note that debug builds of PHP cannot help in debugging PHP scripts.</p>'; 
    } elseif (!is_array($loader)) {
        if ($loader == ERROR_WINDOWS_64_BIT) {
            echo '<p>Loaders for 64-bit PHP on Windows are not currently available. However, if you <b>install and run 32-bit PHP</b> the corresponding 32-bit loader for Windows should work.</p>';
            if ($sysinfo['THREAD_SAFE']) {
                echo '<li>Download one of the following archives of 32-bit Windows x86 loaders:';
            } else {
                echo '<li>Download one of the following archives of 32-bit Windows non-TS x86 loaders:';
            }
            echo make_archive_list(windows_package_name());
        } else {
            echo '<p>There may not be an ionCube Loader available for your type of system at the moment. However, if you create a <a href="'  . SUPPORT_SITE . '">support ticket</a> more advice and information may be available to assist. Please include the URL for this Wizard in your ticket.</p>';
        }
    } elseif (!$sysinfo['SUPPORTED_COMPILER']) {
        $supported_compilers = supported_win_compilers();
        $supported_compiler_string = join('/',$supported_compilers);
        echo '<p>At the current time the ionCube Loader requires PHP to be built with ' . $supported_compiler_string . '. Your PHP software has been built using ' . $sysinfo['PHP_COMPILER'] . '. Supported builds of PHP are available from <a href="https://windows.php.net/download/">PHP.net</a>.';
    } else {
        switch ($host_type) {
            case SERVER_SHARED:
                shared_server();
                break;
            case SERVER_DEDICATED:
                dedicated_server();
                break;
            case SERVER_LOCAL:
                local_install();
                break;
            default:
                echo server_selection_form();
                break;
        }
    }
}

function server_selection_form()
{
    $self = get_self();
    $timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?1:0;
    $hostprovider = (!empty($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $hostprovider = htmlspecialchars($hostprovider, ENT_QUOTES, 'UTF-8');
    $hosturl = (!empty($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $hosturl =  htmlspecialchars($hosturl, ENT_QUOTES, 'UTF-8');
    $form = <<<EOT
    <p>This Wizard will give you information on how to install the ionCube Loader.</p>
    <p>Please select the type of web server that you have and then click Next.</p>
    <script type=text/javascript>
        function trim(s) {
            return s.replace(/^\s+|\s+$/g,"");
        }
        function input_ok() {
            var l = document.getElementById('local');
            if (l.checked) {
                return true;
            } 

            var s = document.getElementById('shared');
            var d = document.getElementById('dedi');

            if (!s.checked && !d.checked) {
                alert("Please select one of the server types.");
                return false;
            } else {
                var hn = document.getElementById('hostprovider');
                var hu = document.getElementById('hosturl');
                var hostprovider = trim(hn.value);
                var hosturl = trim(hu.value);

                if (!hostprovider || !hosturl) {
                    alert("Please enter both a hosting provider name and their URL.");
                    return false;
                }
                if (hostprovider.length < 1) {
                    alert("The hosting provider name should be at least 1 character in length.");
                    return false;
                }
                if (!hosturl.match(/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+/)) {
                    alert("The hosting provider URL is invalid.");
                    return false;
                }
                if (hosturl.length < 4) {
                    alert("The hosting provider URL should be at least 4 characters in length.");
                    return false;
                }
            }
            return true;
        }
    </script>
    <form method=GET action=$self>
        <input type="hidden" name="page" value="default">
        <input type="hidden" name="timeout" value="$timeout">
        <input type=radio id=shared name=stype value=s onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=shared>Shared <small>(for example, server with FTP access only and no access to php.ini)</small></label><br>
        <input type=radio id=dedi name=stype value=d onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=dedi>Dedicated or VPS <small>(server with full root ssh access)</small></label><br>
        <div id="hostinginfo" style="display: none">If you are on a shared or dedicated server, please give your hosting provider and their URL:
            <table>
                <tr><td><label for=hostprovider>Name of your hosting provider</label></td><td><input type=text id="hostprovider" name=hostprovider value="$hostprovider"></td></tr>
                <tr><td><label for=hosturl>URL of your hosting provider</label></td><td><input type=text id="hosturl" name=hosturl value="$hosturl"></td></tr>
            </table>
        </div>
        <input type=radio id=local name=stype value=l onclick="document.getElementById('hostinginfo').style.display = 'none';"><label for=local>Local install</label>
        <p><input type=submit value=Next onclick="return (input_ok(this) && showOverlay());"></p>
    </form>
EOT;
    return $form;
}

function phpinfo_page()
{
    info_disabled_check();
    if (function_is_disabled('phpinfo')) {
        echo "phpinfo is disabled on this server";
    } else {
        @phpinfo();
    }
}

function loader_check_page($ext_name = LOADER_EXTENSION_NAME)
{
    heading();

    $rtl_path = try_runtime_loading_if_applicable();
	
    if (extension_loaded($ext_name)) {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        $php_str = ' for PHP ' . $phpv;
        echo '<div class="success">';
        echo '<h4>Loader Installed Successfully</h4>';
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' <strong>is installed</strong> and encoded files should run successfully.';
        if ($newer_version) {
            echo ' Please note though that you have an old version of the ionCube Loader.</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            loader_upgrade_instructions($lv,$newer_version);
        } else {
            echo '</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            if ($is_legacy_loader) {
                loader_upgrade_instructions($lv,true);
            }
        }
        successful_install_end_instructions($rtl_path);
    } else {
        echo '<div class="failure">';
        echo '<h4>Loader Not Installed</h4>';
        echo '<p>The ionCube Loader is <b>not</b> currently installed successfully.</p>';
	
        if (!is_null($rtl_path)) {
            echo '<p>Runtime loading was attempted but has failed.</p>';
            echo '</div>';
            $rt_errors = runtime_loading_errors();
            if (!empty($rt_errors)) {
                list_loader_errors($rt_errors);
            } 
            link_to_php_ini_instructions();
        } else {
            echo '</div>';
            list_loader_errors();
        }
    }
	
    send_stats('check');
    footer(true);
}

function ini_loader_errors()
{
    $errors = array();
    if (SERVER_SHARED == find_server_type() && !own_php_ini_possible(true)) {
        $errors[ERROR_INI_USER_CANNOT_CREATE] = "It appears that you are not be able to create your own ini files on your shared server. <br><strong>You will need to ask your server administrator to install the ionCube Loader for you.</strong>";
    }
    $loader_loc = find_loader(false);
    if (is_string($loader_loc)) {
        if (!shared_and_runtime_loading()) {
            $sys = get_sysinfo();
            if (empty($sys['PHP_INI'])) {
                $errors[ERROR_INI_NO_PATH] = 'No file path found for the PHP configuration file (php.ini).';
            } elseif (!@file_exists($sys['PHP_INI'])) {
                $errors[ERROR_INI_NOT_FOUND] = 'The PHP configuration file (' . $sys['PHP_INI'] .') cannot be found.';
            }
        }
        $errors = $errors + loader_compatibility_test($loader_loc);
    } else {
        $errors = $errors + $loader_loc;
        $fs_location = find_loader_filesystem();
        if (!empty($fs_location)) {
            $fs_loader_errors = loader_compatibility_test($fs_location);
            if (!empty($fs_loader_errors)) {
                $errors[ERROR_LOADER_WRONG_GENERAL] = "The loader file found at $fs_location is not the correct one for your system.";
            }
            $errors = $errors + $fs_loader_errors;
        }
    } 
    return $errors;
}

function unix_path_dir($dir = '')
{
    if (empty($dir)) {
        $dir = dirname(__FILE__);
    }
    if (is_ms_windows()) {
        $dir = str_replace('\\','/',substr($dir,2));
    }
    return $dir;
}

function unrecognised_inis_webspace($startdir)
{
    $ini_list = array();

    $ini_name = ini_file_name();
    $sys = get_sysinfo();
    $depth = substr_count($startdir,'/');

    $rel_path = '';
    $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
    for ($seps = 0; $seps < $depth; $seps++) {
        $full_ini_loc = @realpath($startdir . '/' . $rel_path) . DIRECTORY_SEPARATOR . $ini_name;
        if (@file_exists($full_ini_loc) && $sys['PHP_INI'] != $full_ini_loc) {
            $ini_list[] = @realpath($full_ini_loc);
        }

        if (dirname($full_ini_loc) == $rootpath) {
            break;
        }
        $rel_path .= '../';
    }
    return $ini_list;
}

function correct_loader_wrong_location()
{
    $loader_location_pair = array();
    $loader_location = find_loader_filesystem();
    if (is_string($loader_location) && !empty($loader_location)) {
        $loader_errors = loader_compatibility_test($loader_location);
        if (empty($loader_errors)) {
            $ini_loader = scan_inis_for_loader();
            if (!empty($ini_loader['location'])) {
                $ini_loader_errors = loader_compatibility_test($ini_loader['location']);
                if (!empty($ini_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = dirname($ini_loader['location']);
                }
            } else {
                $std_dir = loader_install_dir(find_server_type());
                $std_ld_path = $std_dir . DIRECTORY_SEPARATOR . get_loader_name();
                if (@file_exists($std_ld_path)) {
                    $stdloc_loader_errors = loader_compatibility_test($std_ld_path);
                } else {
                    $stdloc_loader_errors = array("Loader file does not exist.");
                }
                if (!empty($stdloc_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = $std_dir;
                }
            }
        }
    }
    return $loader_location_pair;
}

function ini_loader_warnings()
{
    $warnings = array();
    if (find_server_type() == SERVER_SHARED)
    {
        if (own_php_ini_possible()) {
            $sys = get_sysinfo();
            $ini_name = ini_file_name();
            $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
            $root_ini_file = $rootpath . DIRECTORY_SEPARATOR . $ini_name;
            $cgibinpath = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
            $cgibin_ini_file = (empty($cgibinpath))?'':$cgibinpath . DIRECTORY_SEPARATOR . $ini_name;
            $here = unix_path_dir();
            $ini_files = unrecognised_inis_webspace($here);
            $shared_ini_loc = shared_ini_location();
            $shared_ini_file = $shared_ini_loc . DIRECTORY_SEPARATOR . $ini_name;
            $ini_dir = dirname($sys['PHP_INI']);
            $all_ini_locations_used = !empty($ini_files);
            foreach ($ini_files as $full_ini_loc) {
                $advice = "The file $full_ini_loc is not being recognised by PHP.";
                $advice .= " Please check that the name and location of the file are correct.";
                if (!ini_same_dir_as_wizard()) {
                    $ini_loc_dir = dirname($full_ini_loc);
                    if (!@file_exists($shared_ini_file) && !empty($shared_ini_loc) && $ini_loc_dir != $shared_ini_loc && $ini_dir != $shared_ini_loc) {
                        $all_ini_locations_used = false;
                        $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $shared_ini_loc . "</code>.";
                    } else {
                        if (!@file_exists($root_ini_file) && $rootpath != $shared_ini_loc && $full_ini_loc != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $rootpath . "</code>.";
                        } 
                        if (!empty($cgibin_ini_file) && !@file_exists($cgibin_ini_file) && $cgibinpath != $shared_ini_loc && $full_ini_loc != $cgibinpath && $cgibinpath != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= "  Please try copying the <code>$full_ini_loc</code> file to <code>" . $cgibinpath . "</code>.";
                        }
                        $herepath = realpath($here);
                        $here_ini_file = $herepath . DIRECTORY_SEPARATOR . $ini_name;
                        if (!@file_exists($here_ini_file) && $herepath != $rootpath && $herepath != $cgibinpath) {
                            $all_ini_locations_used = false;
                            $advice .= " It may be necessary to copy the <code>$full_ini_loc</code> file to <code>$herepath</code> and to all " . (is_ms_windows()?'folders':'directories') . ' in which you have encoded files';
                        }
                    }
                } else {
                    $all_ini_locations_used = false;
                }
                $warnings[] = $advice;
            }
            if ($all_ini_locations_used) {
                $warnings[] = "<strong>It looks as if ini files are not being recognised in any of the standard locations in your webspace. Please contact your hosting provider to check whether you can create your own PHP ini file and where it should go.</strong>";
            }
        } else {
            if (own_php_ini_possible(true)) {
                $warnings[] = "You may not be able to create your own ini files on your shared server. <br><strong>You might need to ask your server administrator to install the ionCube Loader for you.</strong>";
            }
        }
    } else {
        $loader_dir_pair = correct_loader_wrong_location();
        if (!empty($loader_dir_pair)) {
            $advice = "The correct loader for your system has been found at <code>${loader_dir_pair['loader']}</code>."; 
            if ($loader_dir_pair['loader'] != $loader_dir_pair['newloc']) {
                $advice .= " Please copy the loader from <code>${loader_dir_pair['loader']}</code> to <code>${loader_dir_pair['newloc']}</code>.";
            }
            $warnings[] = $advice;
        }
    }
    return $warnings;
}

function list_loader_errors($errors = array(),$warnings = array(),$suggest_restart = true)
{
    $default = get_default_address();
    $retry_message = '';

    
    if (empty($errors)) {
        $errors = ini_loader_errors();
        if (empty($warnings)) {
            $warnings = ini_loader_warnings();
        }
    }
	
    if (!empty($errors)) {
        $try_again = '<a href="#" onClick="window.location.href=window.location.href">try again</a>';
	
        echo '<div class="alert">';
        if (count($errors) > 1) {
            echo 'The following problems have been found with the ionCube Loader installation:';
            $retry_message = "Please correct those errors and $try_again.";
        } else {
            echo 'The following problem has been found with the ionCube Loader installation:';
            $retry_message = "Please correct that error and $try_again.";
        }
        if (array_key_exists(ERROR_INI_USER_CANNOT_CREATE,$errors)) {
            $retry_message = '';
        }
        echo make_list($errors,"ul");
        echo '</div>';
        if (!empty($warnings)) {
            echo '<div class="warning">';
            echo 'Please also note the following:';
            echo make_list($warnings,"ul");
            echo '</div>';
        }
    } elseif (!empty($warnings)) {
        echo '<div class="warning">';
        echo 'There are the following potential problems:';
        echo make_list($warnings,"ul");
        echo '</div>';
    } elseif ($suggest_restart) {
        if (SERVER_SHARED == find_server_type()) {
            echo "<p>Please contact your server administrator about installing the ionCube Loader.</p>";
        } else {
            if (selinux_is_enabled()) {
                echo "<p>It appears that SELinux is enabled on your server. This might be solved by running the command <code>restorecon [full path to loader file]</code> as root.</p>";
            } elseif (grsecurity_is_enabled()) {
                echo "<p>It appears that grsecurity is enabled on your server. Please run the command, <code>execstack -c [full path to loader file]</code> and then restart your web server.</p>";
            } else {
                $sysinfo = get_sysinfo();
                $ss = $sysinfo['SS'];
				if ($ss == 'PHP-FPM') {
					echo "<p>Please check that PHP-FPM has been restarted.</p>";
                } elseif (!$sysinfo['CGI_CLI'] || is_ms_windows()) {
                    echo "<p>Please check that the $ss web server software has been restarted.</p>";
                } 
            }
        }
    }
    echo '<div>';
    echo $retry_message;
    echo " You may wish to view the following for further help:";
    echo make_list(help_resources($errors),"ul");
    echo '<a href="' . $default . '">Click here to go back to the start of the Loader Wizard</a>.</div>';
}

function phpconfig_page()
{
    info_disabled_check();
    $sys = get_sysinfo();
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        } else {
			if (!preg_match('`^.*\.ini$`',$ini_file_name) || preg_match('`/`',$ini_file_name) || preg_match('`\\\`',$ini_file_name)) {
				die("Illegal file name $ini_file_name");
			}
		}
        header('Content-Type: text/plain');
        header('Content-Disposition: attachment; filename=' . $ini_file_name);
    } else {
        header('Content-Type: text/plain');
    }
    $exclude_original = get_request_parameter('newlinesonly');
    $prepend = get_request_parameter('prepend');
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    if (!empty($exclude_original) || !empty($prepend)) {
        $loader_dir = loader_install_dir($server_type);
        $zend_lines = zend_extension_lines($loader_dir);
        echo join(PHP_EOL,$zend_lines);
        echo PHP_EOL;
    }
    if (empty($ini_file_name) || empty($sys['PHP_INI_DIR']) || ($sys['PHP_INI_BASENAME'] == $ini_file_name)) {
        $original_ini_file = isset($sys['PHP_INI'])?$sys['PHP_INI']:'';
    } else {
        $original_ini_file = $sys['PHP_INI_DIR'] . DIRECTORY_SEPARATOR . $ini_file_name;
    }
    if (empty($exclude_original) && !empty($original_ini_file) && @file_exists($original_ini_file)) {
        if (!empty($download)) {
            @readfile($original_ini_file);
        } else {
            echo all_ini_contents();
        } 
    }
}

function extra_page($check_access_to_info = true)
{
    if ($check_access_to_info) {
		info_disabled_check();
	}
    heading();
    $sys = get_sysinfo();
    $ini_loader = scan_inis_for_loader();
    $ini_loader_path = $ini_loader['location'];
    $loader_path = find_loader(true);
    $ldinf = get_loaderinfo();
    $self = get_self();
    echo "<h4>Additional Information</h4>";
    echo "<table>";
    $lines = array();
    if (is_string($loader_path)) {
        $lines['Loader is at'] = $loader_path;
        $loader_system = loader_system($loader_path);
        if (!empty($loader_system)) {
            $lines['Loader OS code'] = $loader_system['oscode'];
            $lines['Loader architecture'] = $loader_system['arch'];
            $lines['Loader word size'] = $loader_system['wordsize'];
            $lines['Loader PHP version'] = $loader_system['php_version'];
            $lines['Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Loader compiler'] = $loader_system['compiler'];
            $lines['Loader version'] = $loader_system['loader_version'];
            $lines['File size is'] = filesize($loader_path) . " bytes.";
            $lines['MD5 sum is'] = md5_file($loader_path);
        }
        $lines['Loader file'] = "<a href=\"$self?page=loaderbin\">Download loader file</a>";
    } else {
        $lines['Loader file'] = "Loader cannot be found.";
    }
    $lines['Loader found in ini file'] = empty($ini_loader_path)?"No":"Yes";
    if (!empty($ini_loader_path) && (!is_string($loader_path) || $ini_loader_path != $loader_path)) {
        $lines['Loader location found in ini file'] =  $ini_loader_path;
        $loader_system = loader_system($ini_loader_path);
        if (!empty($loader_system)) {
            $lines['Ini Loader OS code'] = $loader_system['oscode'];
            $lines['Ini Loader architecture'] = $loader_system['arch'];
            $lines['Ini Loader word size'] = $loader_system['wordsize'];
            $lines['Ini Loader PHP version'] = $loader_system['php_version'];
            $lines['Ini Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Ini Loader compiler'] = $loader_system['compiler'];
            $lines['Ini Loader version'] = $loader_system['loader_version'];
        }
    }
    $lines["OS extra security"] = (selinux_is_enabled() || possibly_selinux())?"SELinux":(grsecurity_is_enabled()?"Grsecurity":"None");
    $lines['PHPRC is'] = $sys['PHPRC'];
    $lines['INI DIR is'] = $sys['PHP_INI_DIR'];
    $lines['Additional INI files'] = $sys['PHP_INI_ADDITIONAL'];
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    $lines['Server type is'] = server_type_string();
    $lines["PHP uname"] = $ldinf['uname'];
    $lines['Server word size is'] = $ldinf['wordsize'];
    $lines['Disabled functions'] = ini_get('disable_functions');
    $writeable_dirs = writeable_directories();
    $lines['Writeable loader locations'] = (empty($writeable_dirs))?"<em>None</em>":join(", ",$writeable_dirs);
    if (!empty($_SESSION['hostprovider'])) {
        $lines['Hosting provider'] = $_SESSION['hostprovider'];
        $lines['Provider URL'] = $_SESSION['hosturl'];
    }
    foreach ($lines as $h => $i) {
        $v = (empty($i))?'<em>EMPTY</em>':$i;
        echo '<tr><th>'. $h . ':</th>' . '<td>' . $v . '</td></tr>';
    }
    echo "</table>";
    footer(true);
}

function loaderbin_page()
{
    info_disabled_check();
    $loader_path = find_loader(true);
    if (is_string($loader_path)) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. basename($loader_path));
        @readfile($loader_path);
    }
}



function GoDaddy_root($html_root = '')
{
    if (empty($_SESSION['not_go_daddy']) && empty($_SESSION['godaddy_root'])) {
        $godaddy_pattern = "[\\/]home[\\/]content[\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z]+[\\/]html";

        if (empty($html_root)) {
            $html_root =  $_SERVER['DOCUMENT_ROOT'];
        }
        if (preg_match("@$godaddy_pattern@i",$html_root,$matches)) {
            $_SESSION['godaddy_root'] = $matches[0];
        } else {
            $_SESSION['not_go_daddy'] = 1;
            $_SESSION['godaddy_root'] = '';
        } 
    } elseif (!empty($_SESSION['not_go_daddy'])) {
        $_SESSION['godaddy_root'] = '';
    }
    if (!empty($_SESSION['godaddy_root'])) {
        $_SESSION['hostprovider'] = 'GoDaddy';
        $_SESSION['hosturl'] = 'www.godaddy.com';
    }
    return $_SESSION['godaddy_root'];
}

function GoDaddy_windows_instructions()
{
    $instr = "It appears that you are hosted on a Windows server at GoDaddy.<br/>";
    $instr .= "Please change to a Linux hosting plan at GoDaddy.<br />";
    $instr .=  "If you <a href=\"https://help.godaddy.com/\">contact their support team</a> they should be able to switch you to a Linux server.";

    echo $instr;
}

function GoDaddy_linux_instructions($html_dir)
{
    $base = get_base_address();
    $loader_name = get_loader_name();
    $zend_extension_line="<code>zend_extension = $html_dir/ioncube/$loader_name</code>";
    $php_ini_name = is_php_version_or_greater(5,0)?'php5.ini':'php.ini';
    $ini_path = $html_dir . '/' . $php_ini_name;

    $instr = array();
    $instr[] = 'In your html directory, ' . $html_dir . ', create a sub-directory called <b>ioncube</b>.';
    if (@file_exists($ini_path)) {
       $instr[] = "Edit the $php_ini_name in your  $html_dir and add the following line to the <b>top</b> of the file:<br>" . $zend_extension_line ;
    } else {
        $instr[] = "<a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=s&amp;download=1&amp;prepend=1\">Save this $php_ini_name file</a> and upload it to your html directory, $html_dir";
    }
    $instr[] = 'Download the <a target="_blank" href="' . IONCUBE_DOWNLOADS_SERVER . '"/ioncube_loaders_lin_x86.zip">Linux ionCube Loaders</a>.';
    $instr[] = 'Unzip the loaders and upload them into the ioncube directory you created previously.';
    $instr[] = 'The encoded files should now be working.';

    echo '<div class=panel>';
    echo (make_list($instr));
    echo '</div>';
}

function GoDaddy_page()
{
    $base = get_base_address();

    heading();

        $inst_str = '<h4>GoDaddy Installation Instructions</h4>';
        $inst_str .= '<p>It appears that you are hosted with GoDaddy (<a target="_blank" href="https://www.godaddy.com/">www.godaddy.com</a>). ';
        $inst_str .= "If that is <b>not</b> the case then please <a href=\"$base&amp;page=default&amp;host=ngd\">click here to go to the main page of this installation wizard</a>.</p>";
        $inst_str .= "<p>If you have already installed the loader then please <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the loader</a>.</p>";

        echo $inst_str;

        if (is_ms_windows()) {
            GoDaddy_windows_instructions();
        } else {
            GoDaddy_linux_instructions($_SESSION['godaddy_root']);
        }

    send_stats('gd_default');

    footer(true);
}



function get_request_parameter($param_name)
{
    static $request_array;

    if (!isset($request_array)) {
        if (isset($_GET)) {
            $request_array = $_GET;
        } elseif (isset($HTTP_GET_VARS)) {
            $request_array = $HTTP_GET_VARS;
        }
    }

    if (isset($request_array[$param_name])) {
        $return_value = strip_tags($request_array[$param_name]);
    } else {
        $return_value = null;
    }
    return $return_value;
}

function make_list($list_items,$list_type='ol')
{
    $html = '';
    if (!empty($list_items)) {
        $html .= "<$list_type>";
        $html .= '<li>';
        $html .= join('</li><li>',$list_items);
        $html .= '</li>';
        $html .= "</$list_type>";
    }
    return $html;
} 

function make_archive_list($basename,$archives_list = array(),$download_server = IONCUBE_DOWNLOADS_SERVER)
{
    if (empty($archives_list)) {
        $archives_list = array('tar.gz','zip');
    }

    foreach ($archives_list as $a) {
        $link_text = $a;
        $ext_sep = '.';
        $archive_list[] = "<a href=\"$download_server/$basename$ext_sep$a\">$link_text</a>";
    }

    return make_list($archive_list,"ul");
}

function error($m)
{
    die("<b>ERROR:</b> <span class=\"error\">$m</span><p>Please help us improve this script by <a href=\"". SUPPORT_SITE . "\">reporting this error</a> and including the URL to the script so that we can test it.");
}


function filter_server_input($server_var)
{
	$res = htmlspecialchars($_SERVER[$server_var], ENT_QUOTES, "UTF-8");
	return $res;
}

function failsafe_get_self()
{
    $result = '';
    $sfn = filter_server_input('SCRIPT_FILENAME');
    $dr = $_SERVER['DOCUMENT_ROOT'];
    if (!empty($sfn) && !empty($dr)) {
        if ($dr == '/' || $dr == '\\') {
            $result = $sfn;
        } else {
            $drpos = strpos($sfn,$dr);
            if ($drpos === 0) {
                $drlen = strlen($dr);
                $result = substr($sfn,$drlen);
            }
        }
        $result = str_replace('\\','/',$result);
    }
    if (empty($result)) {
        $result = DEFAULT_SELF;
    }
    return $result;
}

function get_self()
{ 
	$page = '';
    if (empty($_SERVER['PHP_SELF'])) {
        if (empty($_SERVER['SCRIPT_NAME'])) {
            if (empty($_SERVER['REQUEST_URI'])) {
                $page = failsafe_get_self();
            } else {
                $page = filter_server_input('REQUEST_URI');
            }
        } else {
            $page = filter_server_input('SCRIPT_NAME');
        }
    } else {
        $page = filter_server_input('PHP_SELF');
    }
	return $page;
}

function get_default_page()
{
    $godaddy_root = GoDaddy_root();
    if (empty($godaddy_root)) {
         $page = 'default';
    } else {
         $page = 'GoDaddy';
    }
    return $page;
}

function get_base_address()
{
    $self = get_self();
    $remote_timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?'timeout=1':'timeout=0';
    $using_ini = (isset($_SESSION['use_ini_method']) && $_SESSION['use_ini_method'])?'ini=1':'ini=0';
    return $self . '?' . $remote_timeout . '&' . $using_ini;
}

function get_default_address($include_timeout = true)
{
    if ($include_timeout) {
        $base =  get_base_address();
        $base .= "&amp;";
    } else {
        $base = get_self();
        $base .= "?";
    }
    $page = get_default_page();

    return $base . 'page=' . $page;
}

function heading()
{
    $self = get_self();

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <meta name="robots" content="noindex, nofollow">
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <script type="text/javascript">
            function showOverlay()
            {
                document.getElementById('overlay').style.display = 'block';
                return true;
            }

            function hideOverlay()
            {
                document.getElementById('overlay').style.display = 'none';
                return true;
            }
        </script>
    </head>
    <body onload="hideOverlay()">
    <div id="overlay">
        <div id="inner_overlay">Checking server configuration<br>Please wait</div>
    </div>
    <div id="header">
        <img src="?page=logo" alt="ionCube logo">
    </div>
	<div id="important">
	<h3 class="important">IMPORTANT: Ensure that This Script Is Removed When No Longer Required</h3>
	</div>
    <div id="main">
    <h2>ionCube Loader Wizard</h2>
EOT;
}

function footer($update_info = null)
{
    $self = get_self();
    $base = get_base_address();
    $default = get_default_address(false);
    $year = gmdate("Y");

    echo "</div>";
    echo "<div id=\"footer\">" .
    "Copyright ionCube Ltd. 2002-$year | " .
    "Loader Wizard version " . script_version() . " ";

    if ($update_info === true) {
        $update_info = check_for_wizard_update(false);  
    }
    $loader_wizard_loc = LOADER_WIZARD_URL;
    $wizard_version_string =<<<EOT
    <script type="text/javascript">
    var xmlhttp;
    function version_check()
    { 
        var body = document.getElementsByTagName('body')[0];
        var ldel = document.getElementById('loading');
        if (!ldel) {
            body.innerHTML += '<div id="loading"></div>';
            ldel = document.getElementById('loading');
        }
        ldel.innerHTML = '<p>Retrieving Wizard version information<br>Please wait</p>';
        ldel.style.display = 'block';
        ldel.style.height = '300px';
        ldel.style.left = '200px';
        ldel.style.border = '4px #660000 solid';
        if (window.XMLHttpRequest) {
            xmlhttp=new XMLHttpRequest();
        } else {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            var loadedOkay = 0;
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                var wizardversion = xmlhttp.responseText;
                var msg;
                clearTimeout(xmlHttpTimeout);
                buttons = '';
                if (wizardversion == '1') {
                    msg = 'You have the current version of the<br>ionCube Loader Wizard'; 
                } else if (wizardversion != '0') {
                    msg = 'A new version, ' + wizardversion + ', of the loader wizard is available';
                    buttons = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; window.open(\'$loader_wizard_loc\'); return false">Get new version</button> &nbsp;'; 
                } else {
                    msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
                }
                buttons += '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>'; 
                ldel.innerHTML = '<p>' + msg +  '<br>' + buttons + '</p>';
            }
        }
        xmlhttp.open("GET",'$self?page=wizardversion&wizard_only=1&clear_info=1',true);
        xmlhttp.send();
        var xmlHttpTimeout=setTimeout(ajaxTimeout,7000);
    }
    function ajaxTimeout(){
       xmlhttp.abort();
       msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
       button = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>';
       var ldel = document.getElementById('loading');
       ldel.innerHTML = '<p>' + msg +  '<br>' + button + '</p>';
    }
    </script>
EOT;

    $wizard_version_string .= '('; 
    if ($update_info === null) {
        $wizard_version_string .= '<a target="_blank" href="' . $loader_wizard_loc . '" onclick="version_check();return false;">check for new version</a>';
    } else if ($update_info !== false) {
        $wizard_version_string .= '<a href="' . LOADERS_PAGE .'" target="_blank">download version ' . $update_info . '</a>';
    } else {
        $wizard_version_string .=  "current";
    }
    $wizard_version_string .= ')'; 
    echo $wizard_version_string;

    $server_type_code = server_type_code();
	
	if (!info_should_be_disabled(true)) {
		echo " | <a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo</a>";
		echo " | <a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a>";
		echo " | <a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional</a>";
	}

    echo " | <a href=\"$default\" onclick=\"showOverlay();\">wizard start</a>";
    echo " | <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">loader test</a>";
    echo ' | <a href="' . LOADERS_PAGE . '" target="loaders">loaders</a>';

    echo "</div>\n";
    echo "\n</body></html>\n";
}

function css_page()
{
    header('Content-Type: text/css');
    echo <<<EOT
    body {
        font-family: verdana, helvetica, arial, sans-serif;
        font-size: 10pt;
        line-height: 150%;
        margin: 0px;
        min-height: 400px;
        position: relative;
    }

    code {
        color: #c00080;
    }

    li {
        margin-top: 10px;
    }
    #overlay {
        display: block;
        z-index: 100;
        position: absolute;
        top: 0;
        left: 0;
        padding: 0;
        margin: 0;
        width: 100%;
        height: 100%;
        background-color: white;
    }
    #inner_overlay {
        display: block;
        z-index: 100;
        position: absolute;
        font-size: 200%;
        color: #660000;
        top: 50%;
        left: 25%;
        width: 460px;
        height: 460px;
        line-height: 200%;
        text-align: center;
        vertical-align: middle;
    }

    #loading {
        display: block;
        position: absolute;
        top: 33%;
        left: 25%;
        margin: auto;
        height: 320px;
        width: 460px;
        padding: 4px;
        color: #660000;
        background-color: white;
        z-index: 100;
    }

    #loading p {
        position: absolute;
        margin-top: 10px;
        text-align: center;
        vertical-align: middle;
        padding-left: 40px;
        padding-right: 30px;
        font-size: 200%;
        line-height: 200%;
    }

    #loading p span#status{
        font-size: 60%;
        line-height: 120%;
    }
    #loading p#noscript {
        font-size: 120%;
        line-height: 120%;
        position: absolute;
        text-align: left;
        padding-top: 10px;
        bottom: 0;
    }
    #loading p#noscript a {
        text-align: center;
    }

    #loading button {
        margin-top: 20px;
        line-height: 100%;
        padding-top: 4px;
        padding-bottom: 4px;
    }


    h4 {
        margin-bottom: 0;
        padding-bottom: 4px;
    }

    p,#main div {
        max-width: 1000px;
        width: 75%;
    }

    #hostinginfo {
        margin-top: 10px;
        margin-left: 20px;
    }
    #hostinginfo table {
        font-size: 1.00em;
    }
    #hostinginfo table td {
        padding-right: 4px;
    }
    #hostinginfo input {
        margin-top: 6px;
    }

    #hostinginfo label {
        margin-left: 6px;
    }

    th {
        text-align: left;
    }
	
	#important {
		margin-top: 12px;
	} 
	h3.important {
		margin: 0;
		border: 0;
        border-top: 1px solid #660000;
		border-bottom: 1px solid #660000;
        padding: 1ex 0 1ex 0;
        background-color: #CB2430;
		text-align: center;
        color: #ffffff; 
        width: 100%;
	}

    .alert {
        margin: 2ex 0;
        border: 1px solid #660000;
        padding: 1ex 1em;
        background-color: #ffeeee;
        color: #660000; 
        width: 75%;
    }

    .warning {
        margin: 2ex 0;
        border: 1px solid #FFBF00;
        padding: 1ex 1em;
        background-color: #FDF5E6;
        color: #000000; 
        width: 75%;
    }

    .success {
        margin: 2ex 0;
        border: 1px solid #006600;
        padding: 1ex 1em;
        background-color: #EEFFEE;
        color: #000000; 
        width: 75%;
    }

    .error {
        color: #FF0000;
    }

    .panel {
        border: 1px solid #c0c0c0;
        background-color: #f0f0f0;
        width: 75%;
        padding: 1ex 1em;
    }
	
	.terminal {
		border: none;
		background-color: #000000;
		color: #ffffff;
		width: 50%;
		padding: 1ex 1em;
	}

    #header {
        background: #fff;
    }

    #footer {
        border-top: 1px solid #404040;
        margin-top: 20px;
        padding-top: 10px;
        padding-left: 20px;
        font-size: 75%;
        text-align: left;
    }

    #main {
        margin: 20px;
    }
	
	
	#main .ic24 {
		position: relative;
		width: 75%;
		height: auto;
		border-width: 1px 1px 1px 1px;
		border-style: solid;
		border-color: #4B8DF8;   
		background-color: #EFEFFF;
		padding: 12px;
		padding-top: 16px;
		padding-bottom: 8px;
		margin-top: 20px;
		overflow: hidden;
	}
	
	#main .ic24 p {
		width: 100%;
	}
	
	
	#main .ic24graphic {
		position: relative;
		width: auto;
		height: auto;
		border: none;
		padding: 0px;
		padding-right: 16px;
		margin: 0px;
		float: left;
		
	}
	
	#main #ic24info {
		position: relative;
		width: auto;
		height: auto;
		float: left;
	}
	
	#main #ic24info a {
		color: #0B4DB8;
		text-decoration: none;
	}
	
	#main #ic24logo {
		max-width: 132px;
		max-height: 132px;
	}
	
EOT;
}

function logo_page()
{
$img_encoded = 'iVBORw0KGgoAAAANSUhEUgAAAakAAACABAMAAABD1osiAAAAKlBMVEUAAAAAAADnHCwAAAAAAAAAAAAAAAAAAABMCQ4AAADnHCznHCznHCwAAAAjcBE1AAAADHRSTlMAeDRHwSqg4BJl/PLTJLuIAAAF1UlEQVR42u2by4vTQBzHp3TTzR6EBtfXYS/+BZW6Pg6FFavgoRDBBx4KFd+HQgWFvQQqiuJhoeL7sP+LR0EPlj6yPfz+F5NMZ77TmmJjM3ZT5nNpOzvNzGcev5lMusxgMBgMBoPBYDAYDAaDwWDQwel5YRnC/jkvbZYdjFV2MFbZwVhlB2OVIVZyb2HIED/n5AfLEj/nhWUJY5UdjFV2MFbZwVgdMqzNZydXz2qrf59Kq2a1NmTsRnfVrLZOfj3VrrkrZuVb/dpBvZEJqzOOc5TNQ75rjXKDtV+ZsNoi6rJ52OhZwxONwiGwsi46zqnt1Kx8r7N8q/wmRfhP3BSsrK7VW/u13krDysGwT8o5kvilxa2YZ/U2eulEC0KhCTlLCo0UrPYff7Tfe+2lWt0glTT6qjB02e0eW6ZVjiZYaF4hq+eXlmll1yik75TL5eMeDVOxsj89hNQyrN5QyDFRm9GCVmCZVrYXBr4OE9w8ZFbBCNr+x646ycAhs/o3moFUj62Y1UY4/txVs9oLrAZs1azCAVhaNSsLgXNpVt/+dlNXZAplx4mLiXecU5hHhcBqN6lV/p3znk1xEYUltfr+t0J/4dN1jwKGWIg+VKuBdL5JAQ9EYj34ILOAjWq12lG+eE2xsk9EF/7CFN7WKOCpq9kK2/CTyp93mFUbpyKRZmwNi2oX4Y0dfgULd8QL4vRdvVavJ+6XYLVPIQjmHq9xAqvbJBTa8paTBCOtVpZHY1DrSmCF7flABotBIiuLJM+RQdJJO1qoVnUKqfLh1pBWrX10YVu0ciuRVXjlfpUiXGSmp85xdFaaT7thZUV95I5DRldaDYJPT8oXmyQqnYP0nFZetL23tgjtsT/e8uc9mKa3XsFqL3Rpy3YsCSufhwmrJgbeGmo/jxUCjd2UzWWFg1EuEzv6rJoY4ftyQapghBRElda5cxKrEfaPvGPWw+Esyx1ps8pHhaP0LqxK8p7KZwFHklt1kEqNcbsNcFfT12a1zgtEv7WFVZehB93xUGVJrPg7MXgPxotDUWlCV5dVhYtgjhV5KuLd+jixktjqYHoHmVcLw9fSt2ry8lDBlrAqKomN5FZI5aX0+Rztqmk7uqywtGKhRQ+KmbeT3AoDDN89gsJQBQ1WWFrFpmgkIruq2kpuhWCASFNBYXxN1GGFKk1XqqLWiXjeOvpv3n2gpBDm4dtL1aqnyaqAcA2bGCu0d3Ir5GkSPasKsFlO3WpNGf68P3wdVhs84tRIRZ/VEUwWfIyxwo4puRUiDh0+q2jntnJWOf6aplVv+VZ5VGMBq3tlhQuarNYnw3V9Zgzkr8PFYiByAi0xcM7ILva+7kJWNeyktVoV5l2FeSI1kluh8UKrlnar6dv2qNhejBVG6yDeaifOajg5X9tR4sH/sLIIBeFTjJV4JMImmd5KNmGFvHxfyV9Guq2mDvnQc9NWyIuOBWrD2BSzZ4fsHi6rzUq26cRdY2e2VSU+ChJ6IDdh1Zi+wylAVa9VfWqu+2y2VYFiO6uGzHsTVj01WOxgsOq3KqB0nMbMsLK96fNxKVASgrDCSogcHjpbq5WNg1WcVsRY4Zi3i1Xblqm7OLFXrHbRWn2GxUG/FduX0yIHwRlWFomD3ojrT+Vxje+KE3tYiQ6ym3JJKKidnW9rscJkuSwOiUdsphXO5P2724y9PPOI+njMMSyxOzWiTViF7/0v4kS6gzEcZA0545X0WbFmVClnk1B4vJXsDYArcPzXitUxCnhW5f070SyXHGfTw1jUYVUgMGKzrTBKQQk/LonYzSlWxToyFuOapaXRim2hqd2/WbFbJEBlLTx8k1a1QNmaai0eUMBAp5XVFFIdNtMqVqs/nhmvpGQuSJRWUmHoMsl5klzRacWsE4Sn3TOswMtH9Mfvbj+L36JNWrFzUgqcE6ofdf8X9PXN6qWjbF5eOverV51ye/ICd+NCWv549er0ha3o69vMYDAYDAaDwWAwGAwGg8FgSJffF2mwYDNbStYAAAAASUVORK5CYII=';

    header('Content-Type: image/png');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}

function ic24logo_page()
{
	$img_encoded = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6b3NiPSJodHRwOi8vd3d3Lm9wZW5zd2F0Y2hib29rLm9yZy91cmkvMjAwOS9vc2IiCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB2ZXJzaW9uPSIxLjAiCiAgIHdpZHRoPSI2OTAiCiAgIGhlaWdodD0iNjkxLjI1IgogICB2aWV3Qm94PSIwIDAgNTUyIDU1MyIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgaWQ9InN2ZzMwMzUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImlvbkN1YmUyNF9jdWJlLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwODMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzQ5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTM1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzMzkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzMxIgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTMzMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzMjUiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzI3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NSIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4ODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NzMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODc1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDEiCiAgICAgICB4MT0iNDQzNS40NDI0IgogICAgICAgeTE9IjI5NDkuMDQyIgogICAgICAgeDI9IjQ4MzQuMzkyMSIKICAgICAgIHkyPSIyOTQ5LjA0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTgiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjAiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxOCIKICAgICBpZD0ibmFtZWR2aWV3MzA4MSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC45NjUzODc0IgogICAgIGlua3NjYXBlOmN4PSI3MjQuNTI3MjIiCiAgICAgaW5rc2NhcGU6Y3k9IjMzMy4xMTQ1MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMzAzNSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMCIKICAgICBmaXQtbWFyZ2luLWxlZnQ9IjAiCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIKICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDM3Ij4KQ3JlYXRlZCBieSBwb3RyYWNlIDEuMTEsIHdyaXR0ZW4gYnkgUGV0ZXIgU2VsaW5nZXIgMjAwMS0yMDEzCjxyZGY6UkRGPgogIDxjYzpXb3JrCiAgICAgcmRmOmFib3V0PSIiPgogICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICA8ZGM6dHlwZQogICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICA8L2NjOldvcms+CjwvcmRmOlJERj4KPC9tZXRhZGF0YT4KICA8ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMSwwLDAsLTAuMSwtNCw1NTcpIgogICAgIGlkPSJnMzAzOSIKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO3N0cm9rZTpub25lIj4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIC0yLDg2OCAtMyw4NjcgLTg2NywzIC04NjgsMiAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA0MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDMiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDM4MjcsNTU2MyBjIC00LC0zIC03LC0zOTUgLTcsLTg3MCBsIDAsLTg2MyA4NzAsMCA4NzAsMCAwLDg3MCAwLDg3MCAtODYzLDAgYyAtNDc1LDAgLTg2NywtMyAtODcwLC03IHoiCiAgICAgICBpZD0icGF0aDMwNDUiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDI4MDAgMCwtODcwIDg2OCwyIDg2NywzIDMsODY4IDIsODY3IC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDciCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDE5MzAsMjgwMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiBtIDEwMzUsNjMwIGMgODAsLTMxIDE1NCwtMTAyIDE5MSwtMTgzIDI1LC01NCAyOCwtNzQgMjksLTE1NyAwLC0xOTAgLTc0LC0zMTggLTM0NCwtNTkyIGwgLTE3NCwtMTc4IDI3NiwwIDI3NywwIDAsLTgwIDAsLTgwIC00MDcsMiAtNDA4LDMgLTMsNTYgLTMsNTUgMTgxLDE3NCBjIDM1NSwzMzkgNDUyLDQ5MyA0MjMsNjY3IC0xOSwxMDYgLTcxLDE2MiAtMTcyLDE4NCAtOTIsMjAgLTIwMiwtNiAtMjkzLC02OSBsIC00NiwtMzEgLTI2LDU4IGMgLTE0LDMyIC0yNiw2MiAtMjYsNjYgMCwyMiAxNDcsOTkgMjI4LDEyMCA4MiwyMSAyMjEsMTQgMjk3LC0xNSB6IgogICAgICAgaWQ9InBhdGgzMDQ5IgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAzODIyLDI4MDMgMywtODY4IDg2OCwtMyA4NjcsLTIgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAyLC04NjcgeiBtIDExNzgsMjQyIDAsLTM5NSA5MCwwIDkwLDAgMCwtNzAgMCwtNzAgLTkwLDAgLTkwLDAgMCwtMTcwIDAsLTE3MCAtODUsMCAtODUsMCAwLDE3MCAwLDE3MCAtMjkwLDAgLTI5MCwwIDAsNjMgMCw2NCAyODEsNDAxIDI4MSw0MDIgOTQsMCA5NCwwIDAsLTM5NSB6IgogICAgICAgaWQ9InBhdGgzMDUxIgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA0NzkwLDMxNzMgYyAtMjQsLTQzIC0xMTEsLTE3MiAtMTk1LC0yODggLTgzLC0xMTUgLTE1NSwtMjE2IC0xNTksLTIyMiAtNiwtMTAgMzUsLTEzIDE5MywtMTMgbCAxOTksMCA0LDI5OCBjIDIsMTYzIDMsMjk4IDIsMzAwIC0xLDIgLTIxLC0zMiAtNDQsLTc1IHoiCiAgICAgICBpZD0icGF0aDMwNTMiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NTM0MSk7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTg1MTYsMTc0MyBjIC0zLC04MzUgLTksLTE1NTMgLTEyLC0xNTk1IGwgLTYsLTc4IDE3MCwwIDE3MCwwIDcsODggYyAzLDQ4IDksMTI3IDEzLDE3NiBsIDcsODkgNDAsLTU5IGMgNTMsLTc3IDE2MCwtMTgxIDIyOSwtMjIzIDEyOCwtNzcgMjQ4LC0xMTEgNDIxLC0xMTggMjEwLC05IDM4NywzOCA1NTIsMTQ3IDI3NiwxODEgNDM4LDQ4MiA0NzQsODc5IDM5LDQzMyAtMTA1LDgzOSAtMzc1LDEwNTYgLTE1NSwxMjUgLTMzMCwxODUgLTU0MSwxODUgLTE5OSwwIC0zNTcsLTQwIC00OTMsLTEyNiAtNzEsLTQ1IC0xODMsLTE1MyAtMjI1LC0yMTkgbCAtMzIsLTUwIC0zLDY4MyAtMiw2ODIgLTE5NCwwIC0xOTQsMCAtNiwtMTUxNyB6IG0gMTE1NSwyMjMgYyAxNDksLTMyIDMwNSwtMTQ4IDM4OCwtMjg5IDc5LC0xMzUgMTIxLC0zMTMgMTIxLC01MTIgMCwtMTk2IC0zNSwtMzU2IC0xMDgsLTUwMCAtNDMsLTg0IC0xNzEsLTIxNyAtMjQ5LC0yNTggLTc3LC00MSAtMTkyLC02NyAtMjk0LC02NyAtMTE2LDAgLTE3NywxMyAtMjc4LDYyIC0xNDYsNjkgLTI1OCwyMDMgLTMxNywzNzggLTE3LDQ5IC0xOSw4OCAtMTksMzYwIDAsMzA1IDAsMzA1IDI3LDM4NSAzNywxMDkgOTEsMTk2IDE2OSwyNzUgNzQsNzQgMTkwLDE0MSAyODYsMTY0IDc2LDE5IDE5MSwxOSAyNzQsMiB6IgogICAgICAgaWQ9InBhdGgzMDU1IgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE3NCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTQ2MTAsMzEzOSBjIC01MTgsLTY1IC05NDQsLTM1NyAtMTE2NCwtNzk3IC0xNDEsLTI4MCAtMjAxLC02MzYgLTE2NiwtOTgzIDcyLC03MTEgNDgwLC0xMTc3IDExNDcsLTEzMTAgMjExLC00MiA1NTcsLTM2IDgxMywxMiAxMTksMjMgMzIwLDg2IDMyNiwxMDMgNiwxNyAtNzIsMzExIC04MiwzMDkgLTUsLTEgLTQ5LC0xNiAtOTcsLTMzIC0xNDcsLTUyIC0yNjIsLTcxIC00NzAsLTc3IC0yMTAsLTYgLTMyMCw0IC00NTcsNDQgLTQzNywxMjYgLTcwNSw0NzIgLTc2MSw5NzkgLTE1LDE0MCAtNSwzODggMjAsNTE0IDYwLDI5OSAxOTgsNTM2IDQwMyw2OTAgMjIzLDE2OSA0NzIsMjM4IDgwOCwyMjcgMTg0LC02IDMwNywtMjggNDQyLC03OCA0NiwtMTYgODksLTMxIDk2LC0zMiA5LC0xIDMwLDQ5IDYyLDE1MyAyNyw4NSA0OCwxNTUgNDcsMTU2IC01Miw0MCAtMjc2LDEwMSAtNDU3LDEyMyAtOTcsMTMgLTQxNCwxMiAtNTEwLDAgeiIKICAgICAgIGlkPSJwYXRoMzA1NyIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNzApIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczNzAsMjg1NSAwLC0xOTUgMjEwLDAgMjEwLDAgMCwxOTUgMCwxOTUgLTIxMCwwIC0yMTAsMCAwLC0xOTUgeiIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNjYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIzODg2LDMwMjQgYyAtOTksLTE4IC0yNjQsLTczIC0zNDgsLTExNSAtNzEsLTM1IC0yMTgsLTEzMCAtMjM3LC0xNTMgLTEwLC0xMiAwLC00MCA1MCwtMTUwIDM0LC03NSA2MywtMTM2IDY1LC0xMzYgMSwwIDM2LDI0IDc3LDUzIDE2NiwxMTkgMzI0LDE3NiA1MTMsMTg0IDMwOCwxNCA1MDMsLTEwOCA1ODAsLTM2MiAxNCwtNDYgMTksLTkzIDE5LC0yMDAgLTEsLTE3MSAtMTksLTI0NyAtMTAwLC00MTAgLTEzMCwtMjYxIC0zODAsLTU0MyAtMTA0NCwtMTE4MCBsIC0yNTAsLTI0MCAtMSwtMTIyIDAsLTEyMyA5MzUsMCA5MzUsMCAwLDE2NSAwLDE2NSAtNjU3LDAgLTY1NywwIDEwOSwxMDEgYyA2MSw1NiAyMTgsMjEwIDM1MCwzNDMgMzQyLDM0NSA1MTgsNTYzIDYzNCw3ODYgMTc5LDM0NSAxOTgsNjc4IDU3LDk2NSAtODEsMTYzIC0xODgsMjcwIC0zNTEsMzUxIC0xNDEsNzAgLTIxOSw4NiAtNDI1LDkwIC0xMjUsMiAtMTk4LC0xIC0yNTQsLTEyIHoiCiAgICAgICBpZD0icGF0aDMwNjEiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE2MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMjY2ODEsMjk3NyBjIC02LC04IC0yOTksLTQyNSAtNjUxLC05MjggbCAtNjQwLC05MTQgMCwtMTMyIDAsLTEzMyA2ODAsMCA2ODAsMCAwLC00MDAgMCwtNDAwIDE4NSwwIDE4NSwwIDAsNDAwIDAsNDAwIDIwNSwwIDIwNSwwIDAsMTU1IDAsMTU1IC0yMDUsMCAtMjA1LDAgMCw5MDUgMCw5MDUgLTIxNCwwIGMgLTE2NiwwIC0yMTYsLTMgLTIyNSwtMTMgeiBtIDcxLC0xMDg0IC0zLC03MTMgLTQ4MCwwIGMgLTM4MiwwIC00NzksMyAtNDczLDEzIDUsNiAxNjYsMjMwIDM1OCw0OTcgMzQ3LDQ4MSAzOTksNTYwIDUzMCw3OTggMzgsNjggNjksMTIyIDcwLDEyMCAwLC0yIDAsLTMyNCAtMiwtNzE1IHoiCiAgICAgICBpZD0icGF0aDMwNjMiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE1OCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTE5MjcsMjI4OCBjIC0xMDgsLTEwIC0yNDgsLTU1IC0zNDEsLTExMCAtODIsLTQ4IC0yMDMsLTE2MCAtMjQ3LC0yMjkgLTE3LC0yNyAtMzQsLTQ3IC0zOCwtNDQgLTMsNCAtMTAsODIgLTE2LDE3MyBsIC0xMCwxNjcgLTE3OSwzIC0xNzgsMiA2LC00NyBjIDQsLTI3IDksLTUxNyAxMiwtMTA5MCBsIDYsLTEwNDMgMTk5LDAgMTk4LDAgMyw3MjcgMyw3MjggMzEsNzIgYyAxMTMsMjYwIDM0MSwzOTggNTk4LDM2MiAxNjQsLTIyIDI3NiwtMTAzIDM0NiwtMjUxIDczLC0xNTQgNzIsLTE0OCA3NywtOTM1IGwgNSwtNzAzIDE5NCwwIDE5NCwwIDAsNzIzIGMgMCw3OTYgLTIsODI0IC02Miw5OTcgLTEyMSwzNDcgLTQyMCw1MzMgLTgwMSw0OTggeiIKICAgICAgIGlkPSJwYXRoMzA2NSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNTQpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczOTAsMTE4MCAwLC0xMTEwIDE5MCwwIDE5MCwwIDAsMTExMCAwLDExMTAgLTE5MCwwIC0xOTAsMCAwLC0xMTEwIHoiCiAgICAgICBpZD0icGF0aDMwNjciCiAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMTUwKSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA5MTk5LDIyODAgYyAtMjIwLC0zNyAtNDE4LC0xMzggLTU3MCwtMjg5IC0xNTAsLTE1MSAtMjQyLC0zMjkgLTI5NSwtNTcxIC0yNiwtMTE5IC0yNywtNDI5IC0xLC01NDcgNTIsLTI0NCAxNDksLTQyNiAzMDUsLTU3NSAxODcsLTE3OCAzOTYsLTI2NCA2NjgsLTI3NSA1MDAsLTIxIDkxMiwyNTEgMTA2NSw3MDQgNTQsMTYxIDY0LDIzMCA2Myw0NDggMCwxNjcgLTMsMjE1IC0yMSwyOTEgLTEwMyw0NDEgLTM5MCw3MzAgLTgwMyw4MDggLTg3LDE3IC0zMjYsMjAgLTQxMSw2IHogbSAzMzQsLTMwNSBjIDI1NSwtNjYgNDM4LC0zMDggNDg3LC02NDQgMTcsLTExNiA4LC0zNDMgLTE4LC00NDIgLTY0LC0yNDMgLTE5NywtNDIzIC0zNzQsLTUwOCAtMTA1LC01MCAtMTg0LC02NiAtMjk2LC01OCAtMjIxLDE1IC0zOTMsMTM2IC01MDgsMzU5IC02NiwxMjkgLTk1LDI1MCAtMTAxLDQyNSAtMTEsMzA4IDY3LDU0NSAyMzYsNzE0IDgxLDgxIDE1OCwxMjYgMjYxLDE1MyA3MywxOSAyNDEsMjAgMzEzLDEgeiIKICAgICAgIGlkPSJwYXRoMzA2OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNDYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIxNzUwLDIyNzUgYyAtMzUyLC03MCAtNjExLC0zMDUgLTczOSwtNjY4IC01OCwtMTY1IC03NSwtMjcxIC03NSwtNDc3IC0xLC0yMDQgMTAsLTI3OSA2NiwtNDQ3IDExOSwtMzYwIDQyMCwtNTk4IDgyNiwtNjUzIDEyNywtMTggMzkyLC04IDU0MiwyMCAxMjIsMjIgMzYwLDk2IDM2MCwxMTEgMCwxOCAtNjMsMjY0IC02OSwyNzEgLTMsNCAtNTEsLTggLTEwNiwtMjcgLTE1NCwtNTEgLTI3MiwtNjggLTQ3NSwtNjggLTIwMywwIC0yNzgsMTUgLTQwOSw4MyAtMjE0LDExMSAtMzI4LDMwMiAtMzU2LDU5OCBsIC03LDcyIDc2NSwwIGMgNjg4LDAgNzY1LDIgNzcxLDE2IDEyLDMyIDYsMzAzIC05LDM5MCAtNDMsMjQ0IC0xMzQsNDMzIC0yNzcsNTcwIC0xMTUsMTEyIC0yMzUsMTc0IC00MDAsMjA4IC05NCwxOSAtMzE0LDIwIC00MDgsMSB6IG0gMzUzLC0yOTUgYyAyMDcsLTY0IDMzOCwtMjU3IDM2MywtNTM1IGwgNywtNzUgLTU3NywwIC01NzYsMCAwLDIzIGMgMCw1MiA0MiwxODcgODYsMjc1IDgyLDE2OCAyMjcsMjkyIDM3NCwzMjEgMzAsNiA2NCwxMyA3NSwxNSA0MSwxMCAxODUsLTUgMjQ4LC0yNCB6IgogICAgICAgaWQ9InBhdGgzMDcxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE0MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gNDAsOTEwIDAsLTg3MCA4NjgsMiA4NjcsMyAzLDg2OCAyLDg2NyAtODcwLDAgLTg3MCwwIDAsLTg3MCB6IgogICAgICAgaWQ9InBhdGgzMDc1IgogICAgICAgc3R5bGU9ImZpbGw6I2MwMWQyZTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDkxMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA3NyIKICAgICAgIHN0eWxlPSJmaWxsOiNjMDFkMmU7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMzgyMCw5MTAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNzkiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICA8L2c+Cjwvc3ZnPgo=';
	header('Content-Type: image/svg+xml');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}
alt-php55-ioncube-loader/README.txt000064400000007751150431103030012647 0ustar00                            The ionCube Loader 
                            ------------------

This package contains:

* ionCube Loaders

* a Loader Wizard script to assist with Loader installation (loader-wizard.php)

* the License document for use of the Loader and encoded files (LICENSE.txt)

* User Guide describing options that can be configured through a php.ini file.  
  There are options that may improve performance, particularly with files on
  a network drive. Options for the ionCube24 intrusion protection and PHP error
  reporting service (ioncube24.com) are also described.


INSTALLATION
============

Quick Guide for experienced system admins
-----------------------------------------

The Loader is a PHP engine extension, so should be referenced with 
a zend_extension line in a php.ini file. It must be the first engine
extension to be installed. 

The Loader must be for the correct operating system, match the 
PHP version, and for whether PHP is built as thread-safe (TS) or not. 
All information required for installing is available on a phpinfo page. 

For example, if your web server is 64 bit Linux, thread safety is disabled,
PHP is version 8.1.8, the main php.ini file is /etc/php.ini and you
have unpacked Loaders to /usr/local/ioncube, you would:

1) edit /etc/php.ini
2) at the top of the php.ini file add

zend_extension = /usr/local/ioncube/ioncube_loader_lin_8.1.so

3) restart the PHP environment (i.e. Apache, php-fpm, etc.)

4) Check a phpinfo page and the Loader should show up in the Zend Engine box.


Assisted Installation with the Loader Wizard
--------------------------------------------

1. Upload the contents of this package to a directory/folder called ioncube
   within the top level of your web scripts area. This is sometimes called the
   "web root" or "document root". Common names for this location are "www",
   "public_html", and "htdocs", but it may be different on your server.

2. Launch the Loader Wizard script in your browser. For example:
     https://yourdomain/ioncube/loader-wizard.php

   If the wizard is not found, check carefully the location on your server
   where you uploaded the Loaders and the wizard script. 

3. Follow the steps given by the Loader Wizard. If you have full access to the 
   server then installation should be easy. If your hosting plan is more limited, 
   you may need to ask your hosting provider for assistance. 

4. The Loader Wizard can automatically create a ticket in our support system
   if installation is unsuccessful, and we are happy to assist in that case.

   YouTube with a search for "ioncube loader wizard" also gives some helpful 
   examples of installation.


WHERE TO INSTALL THE LOADERS
============================

The Loader Wizard should be used to guide the installation process but the
following are the standard locations for the Loader files. Loader file
packages can be obtained from https://www.ioncube.com/loaders.php

Please check that you have the correct package of Loaders for your system.

Installing to a remote SHARED server
------------------------------------

* Upload the Loader files to a directory/folder called ioncube within your
  main web scripts area.  (This will probably be where you placed the
  loader-wizard.php script.)


Installing to a remote UNIX/LINUX DEDICATED or VPS server
---------------------------------------------------------

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, /usr/local/ioncube


** Installing to a remote WINDOWS DEDICATED or VPS server

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, C:\windows\system32


64-BIT LOADERS FOR WINDOWS
--------------------------

64-bit Loaders for Windows are available for PHP 5.5 upwards.
The Loader Wizard will not give directions for installing 64-bit Loaders for
any earlier version of PHP 5.

Copyright (c) 2002-2025 ionCube Ltd.           Last revised January 2025
pear/Finder/Symfony/Component/Finder/CHANGELOG.md000064400000001766150431103070015334 0ustar00CHANGELOG
=========

2.3.0
-----

 * added a way to ignore unreadable directories (via Finder::ignoreUnreadableDirs())
 * unified the way subfolders that are not executable are handled by always throwing an AccessDeniedException exception

2.2.0
-----

 * added Finder::path() and Finder::notPath() methods
 * added finder adapters to improve performance on specific platforms
 * added support for wildcard characters (glob patterns) in the paths passed
   to Finder::in()

2.1.0
-----

 * added Finder::sortByAccessedTime(), Finder::sortByChangedTime(), and
   Finder::sortByModifiedTime()
 * added Countable to Finder
 * added support for an array of directories as an argument to
   Finder::exclude()
 * added searching based on the file content via Finder::contains() and
   Finder::notContains()
 * added support for the != operator in the Comparator
 * [BC BREAK] filter expressions (used for file name and content) are no more
   considered as regexps but glob patterns when they are enclosed in '*' or '?'
pear/Finder/Symfony/Component/Finder/composer.json000064400000001333150431103100016225 0ustar00{
    "name": "symfony/finder",
    "type": "library",
    "description": "Symfony Finder Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Finder\\": "" }
    },
    "target-dir": "Symfony/Component/Finder",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Finder/Symfony/Component/Finder/README.md000064400000001705150431103100014765 0ustar00Finder Component
================

Finder finds files and directories via an intuitive fluent interface.

    use Symfony\Component\Finder\Finder;

    $finder = new Finder();

    $iterator = $finder
      ->files()
      ->name('*.php')
      ->depth(0)
      ->size('>= 1K')
      ->in(__DIR__);

    foreach ($iterator as $file) {
        print $file->getRealpath()."\n";
    }

But you can also use it to find files stored remotely like in this example where
we are looking for files on Amazon S3:

    $s3 = new \Zend_Service_Amazon_S3($key, $secret);
    $s3->registerStreamWrapper("s3");

    $finder = new Finder();
    $finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
    foreach ($finder->in('s3://bucket-name') as $file) {
        print $file->getFilename()."\n";
    }

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Finder/
    $ composer.phar install
    $ phpunit

pear/Finder/Symfony/Component/Finder/LICENSE000064400000002051150431103110014507 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Base/docs/repos/You/yourclass1.php000064400000000150150431103130014002 0ustar00<?php
class erYourClass1
{
    function toString()
    {
      echo "Class 'erYourClass1'\n";
    }
}
?>pear/Base/docs/repos/You/yourclass2.php000064400000000150150431103130014003 0ustar00<?php
class erYourClass2
{
    function toString()
    {
      echo "Class 'erYourClass2'\n";
    }
}
?>pear/Base/docs/repos/Me/myclass1.php000064400000000144150431103150013223 0ustar00<?php
class erMyClass1
{
    function toString()
    {
      echo "Class 'erMyClass1'\n";
    }
}
?>pear/Base/docs/repos/Me/myclass2.php000064400000000144150431103160013225 0ustar00<?php
class erMyClass2
{
    function toString()
    {
      echo "Class 'erMyClass2'\n";
    }
}
?>pear/Base/docs/repos/autoloads/my_autoload.php000064400000000171150431103200015432 0ustar00<?php
    return array (
        'erMyClass1' => 'Me/myclass1.php',
        'erMyClass2' => 'Me/myclass2.php',
    );
?>
pear/Base/docs/repos/autoloads/your_autoload.php000064400000000216150431103210016004 0ustar00<?php
      return array (
           'erYourClass1' => 'You/yourclass1.php',
           'erYourClass2' => 'You/yourclass2.php',
       );
?>
pear/Base/docs/tutorial_lazy_initialization.php000064400000001622150431103220016007 0ustar00<?php
require_once 'tutorial_autoload.php';

// Create a custom class implementing the singleton pattern
class customSingleton
{
    protected static $instance;

    public static function getInstance()
    {
        if ( self::$instance === null )
        {
            self::$instance = new customSingleton();
            ezcBaseInit::fetchConfig( 'customKey', self::$instance );
        }

        return self::$instance;
    }
}

// Implement your configuration class
class customSingletonConfiguration implements ezcBaseConfigurationInitializer
{
    public static function configureObject( $object )
    {
        echo "Configure customSingleton.\n";
        $object->value = 42;
    }
}

// Register for lazy initilization
ezcBaseInit::setCallback( 'customKey', 'customSingletonConfiguration' );

// Configure on first initilization
$object = customSingleton::getInstance();
var_dump( $object->value );

?>
pear/Base/docs/tutorial_example_04.php000064400000002620150431103230013657 0ustar00<?php
require 'tutorial_autoload.php';

class myProgressFinder
{
    static public function findRecursiveCallback( ezcBaseFileFindContext $context, $sourceDir, $fileName, $fileInfo )
    {
        // ignore if we have a directory, but do print a "." and sleep for
        // extra demo time
        if ( $fileInfo['mode'] & 0x4000 )
        {
            echo ".";
            usleep( 100000 );
            return;
        }

        // update the statistics
        $context->elements[] = $sourceDir . DIRECTORY_SEPARATOR . $fileName;
        $context->count++;
        $context->size += $fileInfo['size'];
    }

    static public function findRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array() )
    {
        // create the context, and then start walking over the array
        $context = new ezcBaseFileFindContext;
        ezcBaseFile::walkRecursive( $sourceDir, $includeFilters, $excludeFilters,
                array( 'myProgressFinder', 'findRecursiveCallback' ), $context );

        // collect the statistics (which we don't do anything with in this example)
        $statistics['size'] = $context->size;
        $statistics['count'] = $context->count;

        // return the found and pattern-matched files
        sort( $context->elements );
        return $context->elements;
    }
}

$files = myProgressFinder::findRecursive( dirname( __FILE__ ) );
var_dump( $files );
?>
pear/Base/docs/tutorial.txt000064400000021137150431103240011676 0ustar00eZ Components - Base
~~~~~~~~~~~~~~~~~~~~

.. contents:: Table of Contents

Introduction
============

The Base component provides the basic functionality, such as autoloading, that
all eZ Components need to function properly. The Base component needs to be
loaded specifically. Base can also autoload external class repositories from
outside the eZ Components.

Aside from the autoload functionality, the Base component also contains a number of
generic Exception classes that all inherit from the ezcBaseException class.


Installation
============

The installation and configuration of the eZ Components environment is
described in a separate article. Please refer to the `Components Introduction`_
for instructions on installation and configuration of the eZ Components library
and the Base component.

.. _Components Introduction: /docs/install


Usage
=====

Debugging
---------

By default the ezcBase component's autoload mechanism will not throw an
exception when an autoload class can not be found. In some cases (during
development) it is useful to have an exception with detailed information
about which autoload files were searched for, and in which directories.
ezcBase supports an option that enables this behavior::

    <?php
    $options = new ezcBaseAutoloadOptions;
    $options->debug = true;
    ezcBase::setOptions( $options );
    ?>

**Warning**: Exceptions are ignored when they are thrown from an autoload()
handler in PHP. In order to see the exception message that is thrown when a
class can not be found, you need to catch the exception *in* the autoload()
handler. Your autoload() function could then look like::

    function __autoload( $className )
    {
        try
        {
            ezcBase::autoload( $className );
        }
        catch ( Exception $e )
        {
            echo $e->getMessage();
        }
    }

Preloading
----------

The default autoload policy of the eZ Components is to load every class
file on demand only. It is also possible to load all classes of one
component at the same time, when one of the component's classes is 
requested for the first time. You can change this behavior with the
"preload" option that is available through the ezcBaseAutoloadOptions option
class. You can turn preloading on with::

    <?php
    $options = new ezcBaseAutoloadOptions;
    $options->preload = true;
    ezcBase::setOptions( $options );
    ?>

Please note that preloading will *not* be done for Exception classes.

Adding class repositories located outside eZ Components to autoload system
--------------------------------------------------------------------------

It can be useful to add repositories of user-defined classes to the eZ
Components autoload system.  The ezcBase::addClassRepository() method can be
used to perform this task.  You need to arrange the desired external classes
in a class repository. That is, make sure that classes and corresponding
\*_autoload.php files are named and placed according to the explanations below.
After they are in the proper structure, you can call addClassRepository() with
the proper parameters before you use the external classes.
External classes will then be loaded by autoload system.

ezcBase::addClassRepository() takes two arguments:

- $basePath is the base path for the whole class repository.
- $autoloadDirPath is the path where autoload files for this repository are found. 

The paths in the autoload files are *not* relative to the package directory
as specified by the $basePath argument. In other words, class definition files will
only be searched for in the location $autoloadDirPath.

Consider the following example:

- There is a class repository stored in the directory "./repos".
- Autoload files for this repository are stored in "./repos/autoloads".
- There are two components in this repository: "Me" and "You".
- The "Me" component has the classes "erMyClass1" and "erMyClass2".
- The "You" component has the classes "erYourClass1" and "erYourClass2".

In this case, you need to create the following files in "./repos/autoloads".
Note that the prefix to _autoload.php ("my" and "your") in the filename is the
first part of the classname (excluding the lowercase classname prefix - "er").

Content of my_autoload.php:

.. include:: repos/autoloads/my_autoload.php
   :literal:

Content of your_autoload.php:

.. include:: repos/autoloads/your_autoload.php
   :literal:
 
The directory structure for the external repository is then: ::

    ./repos/autoloads/my_autoload.php
    ./repos/autoloads/your_autoload.php
    ./repos/Me/myclass1.php
    ./repos/Me/myclass2.php
    ./repos/You/yourclass1.php
    ./repos/You/yourclass2.php

To use this repository with the autoload mechanism, use the
following code:

.. include:: tutorial_example_01.php
    :literal:

The above code will output: ::

    Class 'erMyClass2'
    Class 'erYourClass1'

Lazy initialization
-------------------

Lazy initialization is a mechanism to load and configure a component, only 
when it is really used in your application. This mechanism saves time for 
parsing the classes and configuration, when the component is not used at all
during one request. The implementation in ezcBaseInit may be reused by other
applications and components, like the following example will show.

.. include:: tutorial_lazy_initialization.php
   :literal:

The example shows a random class implementing the singleton pattern, which may
be some database connection handler, or anything similar in your case. The
getInstance() method shows a typical PHP 5 implementation except the
additional line 14, which checks, if a configuration callback was provided 
earlier and configures the newly created instance. If no configuration
callback was provided, nothing will happen. The customKey is used to receive 
the right callback from ezcBaseInit and needs to be known by the user, who
wants to define a configuration callback for your class.

In line 32 the class used to configure your instance on creation is defined. 
The first parameter is the key used earlier in the getInstance method, to 
reference the right class, and the second parameter is the name of your 
configuration class.

The configuration class beginning in line 22 just needs to implement the
ezcBaseConfigurationInitializer interface, which defines one
method: configureObject(). This method will be called with the object to
configure as a single parameter. In the example, a new public property on the
customSingleton instance is created, which will be echo'd later to show the 
success of the configuration.

The configuration itself will not happen before the actual instance is created
in line 35 performing the static call on customSingleton::getInstance(). The
var_dump() in the following line shows, that the property value is set and
contains the earlier set value (int) 42.

File Operations
---------------

Finding files recursively
`````````````````````````

This example shows how to use the ezcBaseFile::findRecursive() method:

.. include:: tutorial_example_02.php
   :literal:

The code in this example searches for files in the ``/dat/dev/ezcomponents``
directory. It will only include files that match *all* patterns in the
$includeFilters array (the second parameter). Files that match *any* of the
patterns in the $excludeFilters array (the third parameter) will not be returned.

In other words, the code above searches for files in the ``dat/dev/ezcomponents``
directory, which are in the ``src/`` directory and end with ``_autoload.php``,
except for files that are in the ``/autoload/`` directory.

Removing directories recursively
````````````````````````````````

This example shows how to use the ezcBaseFile::removeRecursive() method:

.. include:: tutorial_example_03.php
   :literal:

This code simply removes the directory ``/dat/dev/ezcomponents/trash`` and all
of its files and sub-directories.

**Warning: Use this function with care, as it has the potential to erase
everything that the current user has access to.**

Overloading the callback
````````````````````````

The ezcBaseFile::findRecursive() method internally uses the
ezcBaseFile::walkRecursive() method to do the actual recursing. The callback
method ezcBaseFile::findRecursiveCallback() is then responsible for collecting
the data. In case you want to do additional things, such as printing progress,
you can either call walkRecursive() yourself with a callback function of your
choice, or overload the ezcBaseFile class and provide a new
findRecursiveCallback() method. The code below uses
ezcBaseFile::walkRecursive() directly in order to display dots for when ever it
finds a new directory:

.. include:: tutorial_example_04.php
   :literal:



..
   Local Variables:
   mode: rst
   fill-column: 79
   End: 
   vim: et syn=rst tw=79
pear/Base/docs/tutorial_example_02.php000064400000000275150431103250013663 0ustar00<?php
require 'tutorial_autoload.php';

$data = ezcBaseFile::findRecursive(
	"/dat/dev/ezcomponents",
	array( '@src/.*_autoload.php$@' ),
	array( '@/autoload/@' )
);
var_dump( $data );

?>
pear/Base/docs/tutorial_example_03.php000064400000000153150431103260013660 0ustar00<?php
require 'tutorial_autoload.php';

ezcBaseFile::removeRecursive( '/dat/dev/ezcomponents/trash' );

?>
pear/Base/docs/tutorial_autoload.php000064400000000757150431103270013546 0ustar00<?php
$dir = dirname( __FILE__ );
$dirParts = explode( DIRECTORY_SEPARATOR, $dir );
switch ( $dirParts[count( $dirParts ) - 3] )
{
    case 'doc': require_once 'ezc/Base/base.php'; break; // pear
    case 'trunk': require_once "$dir/../../Base/src/base.php"; break; // svn
    default: require_once "$dir/../../Base/src/base.php"; break; // bundle
}

/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}
?>
pear/Base/docs/CREDITS000064400000000345150431103300010305 0ustar00CREDITS
=======

eZ Components team
------------------

- Sergey Alexeev
- Sebastian Bergmann
- Jan Borsodi
- Raymond Bosman
- Frederik Holljen
- Kore Nordmann
- Derick Rethans
- Vadym Savchuk
- Tobias Schlitt
- Alexandru Stanoi
pear/Base/docs/tutorial_example_01.php000064400000000327150431103310013655 0ustar00<?php
require_once 'tutorial_autoload.php';

ezcBase::addClassRepository( './repos', './repos/autoloads' );
$myVar1 = new erMyClass2();
$myVar1->toString();
$yourVar1 = new erYourClass1();
$yourVar1->toString();
?>
pear/Base/docs/LICENSE000064400000003042150431103320010271 0ustar00eZ Components Licence
=====================

New BSD Licence
---------------

Copyright (c) 2005-2008, eZ Systems A.S.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials provided
  with the distribution.
* Neither the name of eZ Systems A.S. nor the names of its
  contributors may be used to endorse or promote products derived
  from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pear/TwigBridge/Symfony/Bridge/Twig/CHANGELOG.md000064400000002035150431103370015102 0ustar00CHANGELOG
=========

2.4.0
-----

 * added stopwatch tag to time templates with the WebProfilerBundle

2.3.0
-----

 * added helpers form(), form_start() and form_end()
 * deprecated form_enctype() in favor of form_start()

2.2.0
-----

 * added a `controller` function to help generating controller references
 * added a `render_esi` and a `render_hinclude` function
 * [BC BREAK] restricted the `render` tag to only accept URIs or ControllerReference instances (the signature changed)
 * added a `render` function to render a request
 * The `app` global variable is now injected even when using the twig service directly.
 * Added an optional parameter to the `path` and `url` function which allows to generate
   relative paths (e.g. "../parent-file") and scheme-relative URLs (e.g. "//example.com/dir/file").

2.1.0
-----

 * added global variables access in a form theme
 * added TwigEngine
 * added TwigExtractor
 * added a csrf_token function
 * added a way to specify a default domain for a Twig template (via the
   'trans_default_domain' tag)
pear/TwigBridge/Symfony/Bridge/Twig/composer.json000064400000003332150431103370016014 0ustar00{
    "name": "symfony/twig-bridge",
    "type": "symfony-bridge",
    "description": "Symfony Twig Bridge",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/security-csrf": "~2.4",
        "twig/twig": "~1.12"
    },
    "require-dev": {
        "symfony/form": "~2.2",
        "symfony/http-kernel": "~2.2",
        "symfony/routing": "~2.2",
        "symfony/templating": "~2.1",
        "symfony/translation": "~2.2",
        "symfony/yaml": "~2.0",
        "symfony/security": "~2.4",
        "symfony/stopwatch": "~2.2",
        "symfony/expression-language": "~2.4"
    },
    "suggest": {
        "symfony/form": "For using the FormExtension",
        "symfony/http-kernel": "For using the HttpKernelExtension",
        "symfony/routing": "For using the RoutingExtension",
        "symfony/templating": "For using the TwigEngine",
        "symfony/translation": "For using the TranslationExtension",
        "symfony/yaml": "For using the YamlExtension",
        "symfony/security": "For using the SecurityExtension",
        "symfony/stopwatch": "For using the StopwatchExtension",
        "symfony/expression-language": "For using the ExpressionExtension"
    },
    "autoload": {
        "psr-0": { "Symfony\\Bridge\\Twig\\": "" }
    },
    "target-dir": "Symfony/Bridge/Twig",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/TwigBridge/Symfony/Bridge/Twig/README.md000064400000000463150431103400014545 0ustar00Twig Bridge
===========

Provides integration for [Twig](http://twig.sensiolabs.org/) with various
Symfony2 components.

Resources
---------

If you want to run the unit tests, install dev dependencies before
running PHPUnit:

    $ cd path/to/Symfony/Bridge/Twig/
    $ composer.phar install
    $ phpunit
pear/TwigBridge/Symfony/Bridge/Twig/LICENSE000064400000002051150431103410014267 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Translation/Symfony/Component/Translation/CHANGELOG.md000064400000002172150431103460017505 0ustar00CHANGELOG
=========

2.3.0
-----

 * added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues)
 * added Translator::getFallbackLocales()
 * deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method

2.2.0
-----

 * QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3.
 * [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now
   throws Symfony\Component\Translation\Exception\NotFoundResourceException when a resource cannot be found
   and Symfony\Component\Translation\Exception\InvalidResourceException when a resource is invalid.
 * changed the exception class thrown by some load() methods from \RuntimeException to \InvalidArgumentException
   (IcuDatFileLoader, IcuResFileLoader and QtFileLoader)

2.1.0
-----

 * added support for more than one fallback locale
 * added support for extracting translation messages from templates (Twig and PHP)
 * added dumpers for translation catalogs
 * added support for QT, gettext, and ResourceBundles
pear/Translation/Symfony/Component/Translation/composer.json000064400000001635150431103470020422 0ustar00{
    "name": "symfony/translation",
    "type": "library",
    "description": "Symfony Translation Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/config": "~2.0",
        "symfony/yaml": "~2.2"
    },
    "suggest": {
        "symfony/config": "",
        "symfony/yaml": ""
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Translation\\": "" }
    },
    "target-dir": "Symfony/Component/Translation",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Translation/Symfony/Component/Translation/README.md000064400000001771150431103500017152 0ustar00Translation Component
=====================

Translation provides tools for loading translation files and generating
translated strings from these including support for pluralization.

    use Symfony\Component\Translation\Translator;
    use Symfony\Component\Translation\MessageSelector;
    use Symfony\Component\Translation\Loader\ArrayLoader;

    $translator = new Translator('fr_FR', new MessageSelector());
    $translator->setFallbackLocales(array('fr'));
    $translator->addLoader('array', new ArrayLoader());
    $translator->addResource('array', array(
        'Hello World!' => 'Bonjour',
    ), 'fr');

    echo $translator->trans('Hello World!')."\n";

Resources
---------

Silex integration:

https://github.com/fabpot/Silex/blob/master/src/Silex/Provider/TranslationServiceProvider.php

Documentation:

http://symfony.com/doc/2.4/book/translation.html

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Translation/
    $ composer.phar install
    $ phpunit
pear/Translation/Symfony/Component/Translation/LICENSE000064400000002051150431103510016671 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Routing/Symfony/Component/Routing/CHANGELOG.md000064400000016327150431103560015777 0ustar00CHANGELOG
=========

2.3.0
-----

 * added RequestContext::getQueryString()

2.2.0
-----

 * [DEPRECATION] Several route settings have been renamed (the old ones will be removed in 3.0):

    * The `pattern` setting for a route has been deprecated in favor of `path`
    * The `_scheme` and `_method` requirements have been moved to the `schemes` and `methods` settings

   Before:

   ```
   article_edit:
       pattern: /article/{id}
       requirements: { '_method': 'POST|PUT', '_scheme': 'https', 'id': '\d+' }

   <route id="article_edit" pattern="/article/{id}">
       <requirement key="_method">POST|PUT</requirement>
       <requirement key="_scheme">https</requirement>
       <requirement key="id">\d+</requirement>
   </route>

   $route = new Route();
   $route->setPattern('/article/{id}');
   $route->setRequirement('_method', 'POST|PUT');
   $route->setRequirement('_scheme', 'https');
   ```

   After:

   ```
   article_edit:
       path: /article/{id}
       methods: [POST, PUT]
       schemes: https
       requirements: { 'id': '\d+' }

   <route id="article_edit" pattern="/article/{id}" methods="POST PUT" schemes="https">
       <requirement key="id">\d+</requirement>
   </route>

   $route = new Route();
   $route->setPath('/article/{id}');
   $route->setMethods(array('POST', 'PUT'));
   $route->setSchemes('https');
   ```

 * [BC BREAK] RouteCollection does not behave like a tree structure anymore but as
   a flat array of Routes. So when using PHP to build the RouteCollection, you must
   make sure to add routes to the sub-collection before adding it to the parent
   collection (this is not relevant when using YAML or XML for Route definitions).

   Before:

   ```
   $rootCollection = new RouteCollection();
   $subCollection = new RouteCollection();
   $rootCollection->addCollection($subCollection);
   $subCollection->add('foo', new Route('/foo'));
   ```

   After:

   ```
   $rootCollection = new RouteCollection();
   $subCollection = new RouteCollection();
   $subCollection->add('foo', new Route('/foo'));
   $rootCollection->addCollection($subCollection);
   ```

   Also one must call `addCollection` from the bottom to the top hierarchy.
   So the correct sequence is the following (and not the reverse):

   ```
   $childCollection->->addCollection($grandchildCollection);
   $rootCollection->addCollection($childCollection);
   ```

 * [DEPRECATION] The methods `RouteCollection::getParent()` and `RouteCollection::getRoot()`
   have been deprecated and will be removed in Symfony 2.3.
 * [BC BREAK] Misusing the `RouteCollection::addPrefix` method to add defaults, requirements
   or options without adding a prefix is not supported anymore. So if you called `addPrefix`
   with an empty prefix or `/` only (both have no relevance), like
   `addPrefix('', $defaultsArray, $requirementsArray, $optionsArray)`
   you need to use the new dedicated methods `addDefaults($defaultsArray)`,
   `addRequirements($requirementsArray)` or `addOptions($optionsArray)` instead.
 * [DEPRECATION] The `$options` parameter to `RouteCollection::addPrefix()` has been deprecated
   because adding options has nothing to do with adding a path prefix. If you want to add options
   to all child routes of a RouteCollection, you can use `addOptions()`.
 * [DEPRECATION] The method `RouteCollection::getPrefix()` has been deprecated
   because it suggested that all routes in the collection would have this prefix, which is
   not necessarily true. On top of that, since there is no tree structure anymore, this method
   is also useless. Don't worry about performance, prefix optimization for matching is still done
   in the dumper, which was also improved in 2.2.0 to find even more grouping possibilities.
 * [DEPRECATION] `RouteCollection::addCollection(RouteCollection $collection)` should now only be
   used with a single parameter. The other params `$prefix`, `$default`, `$requirements` and `$options`
   will still work, but have been deprecated. The `addPrefix` method should be used for this
   use-case instead.
   Before: `$parentCollection->addCollection($collection, '/prefix', array(...), array(...))`
   After:
   ```
   $collection->addPrefix('/prefix', array(...), array(...));
   $parentCollection->addCollection($collection);
   ```
 * added support for the method default argument values when defining a @Route
 * Adjacent placeholders without separator work now, e.g. `/{x}{y}{z}.{_format}`.
 * Characters that function as separator between placeholders are now whitelisted
   to fix routes with normal text around a variable, e.g. `/prefix{var}suffix`.
 * [BC BREAK] The default requirement of a variable has been changed slightly.
   Previously it disallowed the previous and the next char around a variable. Now
   it disallows the slash (`/`) and the next char. Using the previous char added
   no value and was problematic because the route `/index.{_format}` would be
   matched by `/index.ht/ml`.
 * The default requirement now uses possessive quantifiers when possible which
   improves matching performance by up to 20% because it prevents backtracking
   when it's not needed.
 * The ConfigurableRequirementsInterface can now also be used to disable the requirements
   check on URL generation completely by calling `setStrictRequirements(null)`. It
   improves performance in production environment as you should know that params always
   pass the requirements (otherwise it would break your link anyway).
 * There is no restriction on the route name anymore. So non-alphanumeric characters
   are now also allowed.
 * [BC BREAK] `RouteCompilerInterface::compile(Route $route)` was made static
   (only relevant if you implemented your own RouteCompiler).
 * Added possibility to generate relative paths and network paths in the UrlGenerator, e.g.
   "../parent-file" and "//example.com/dir/file". The third parameter in
   `UrlGeneratorInterface::generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)`
   now accepts more values and you should use the constants defined in `UrlGeneratorInterface` for
   claritiy. The old method calls with a Boolean parameter will continue to work because they
   equal the signature using the constants.

2.1.0
-----

 * added RequestMatcherInterface
 * added RequestContext::fromRequest()
 * the UrlMatcher does not throw a \LogicException anymore when the required
   scheme is not the current one
 * added TraceableUrlMatcher
 * added the possibility to define options, default values and requirements
   for placeholders in prefix, including imported routes
 * added RouterInterface::getRouteCollection
 * [BC BREAK] the UrlMatcher urldecodes the route parameters only once, they
   were decoded twice before. Note that the `urldecode()` calls have been
   changed for a single `rawurldecode()` in order to support `+` for input
   paths.
 * added RouteCollection::getRoot method to retrieve the root of a
   RouteCollection tree
 * [BC BREAK] made RouteCollection::setParent private which could not have
   been used anyway without creating inconsistencies
 * [BC BREAK] RouteCollection::remove also removes a route from parent
   collections (not only from its children)
 * added ConfigurableRequirementsInterface that allows to disable exceptions 
   (and generate empty URLs instead) when generating a route with an invalid
   parameter value
pear/Routing/Symfony/Component/Routing/composer.json000064400000002361150431103560016701 0ustar00{
    "name": "symfony/routing",
    "type": "library",
    "description": "Symfony Routing Component",
    "keywords": ["routing", "router", "URL", "URI"],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/config": "~2.2",
        "symfony/yaml": "~2.0",
        "symfony/expression-language": "~2.4",
        "doctrine/annotations": "~1.0",
        "psr/log": "~1.0"
    },
    "suggest": {
        "symfony/config": "For using the all-in-one router or any loader",
        "symfony/yaml": "For using the YAML loader",
        "symfony/expression-language": "For using expression matching",
        "doctrine/annotations": "For using the annotation loader"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Routing\\": "" }
    },
    "target-dir": "Symfony/Component/Routing",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Routing/Symfony/Component/Routing/README.md000064400000001732150431103560015437 0ustar00Routing Component
=================

Routing associates a request with the code that will convert it to a response.

The example below demonstrates how you can set up a fully working routing
system:

    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Routing\Matcher\UrlMatcher;
    use Symfony\Component\Routing\RequestContext;
    use Symfony\Component\Routing\RouteCollection;
    use Symfony\Component\Routing\Route;

    $routes = new RouteCollection();
    $routes->add('hello', new Route('/hello', array('controller' => 'foo')));

    $context = new RequestContext();

    // this is optional and can be done without a Request instance
    $context->fromRequest(Request::createFromGlobals());

    $matcher = new UrlMatcher($routes, $context);

    $parameters = $matcher->match('/hello');

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Routing/
    $ composer.phar install
    $ phpunit
pear/Routing/Symfony/Component/Routing/LICENSE000064400000002051150431103560015160 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Process/Symfony/Component/Process/CHANGELOG.md000064400000001341150431103560015743 0ustar00CHANGELOG
=========

2.4.0
-----

 * added the ability to define an idle timeout

2.3.0
-----

 * added ProcessUtils::escapeArgument() to fix the bug in escapeshellarg() function on Windows
 * added Process::signal()
 * added Process::getPid()
 * added support for a TTY mode

2.2.0
-----

 * added ProcessBuilder::setArguments() to reset the arguments on a builder
 * added a way to retrieve the standard and error output incrementally
 * added Process:restart()

2.1.0
-----

 * added support for non-blocking processes (start(), wait(), isRunning(), stop())
 * enhanced Windows compatibility
 * added Process::getExitCodeText() that returns a string representation for
   the exit code returned by the process
 * added ProcessBuilder
pear/Process/Symfony/Component/Process/composer.json000064400000001337150431103560016661 0ustar00{
    "name": "symfony/process",
    "type": "library",
    "description": "Symfony Process Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Process\\": "" }
    },
    "target-dir": "Symfony/Component/Process",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Process/Symfony/Component/Process/README.md000064400000002512150431103570015413 0ustar00Process Component
=================

Process executes commands in sub-processes.

In this example, we run a simple directory listing and get the result back:

    use Symfony\Component\Process\Process;

    $process = new Process('ls -lsa');
    $process->setTimeout(3600);
    $process->run();
    if (!$process->isSuccessful()) {
        throw new RuntimeException($process->getErrorOutput());
    }

    print $process->getOutput();

You can think that this is easy to achieve with plain PHP but it's not especially
if you want to take care of the subtle differences between the different platforms.

And if you want to be able to get some feedback in real-time, just pass an
anonymous function to the ``run()`` method and you will get the output buffer
as it becomes available:

    use Symfony\Component\Process\Process;

    $process = new Process('ls -lsa');
    $process->run(function ($type, $buffer) {
        if ('err' === $type) {
            echo 'ERR > '.$buffer;
        } else {
            echo 'OUT > '.$buffer;
        }
    });

That's great if you want to execute a long running command (like rsync-ing files to a
remote server) and give feedback to the user in real-time.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/XXX/
    $ composer.phar install
    $ phpunit
pear/Process/Symfony/Component/Process/LICENSE000064400000002051150431103570015137 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Serializer/Symfony/Component/Serializer/CHANGELOG.md000064400000003602150431103620017130 0ustar00CHANGELOG
=========

2.4.0
-----

 * added `$context` support for XMLEncoder.

2.3.0
-----

 * added `GetSetMethodNormalizer::setCamelizedAttributes` to allow calling
   camel cased methods for underscored properties

2.2.0
-----

 * [BC BREAK] All Serializer, Normalizer and Encoder interfaces have been
   modified to include an optional `$context` array parameter.
 * The XML Root name can now be configured with the `xml_root_name`
   parameter in the context option to the `XmlEncoder`.
 * Options to `json_encode` and `json_decode` can be passed through
   the context options of `JsonEncode` and `JsonDecode` encoder/decoders.

2.1.0
-----

 * added DecoderInterface::supportsDecoding(),
   EncoderInterface::supportsEncoding()
 * removed NormalizableInterface::denormalize(),
   NormalizerInterface::denormalize(),
   NormalizerInterface::supportsDenormalization()
 * removed normalize() denormalize() encode() decode() supportsSerialization()
   supportsDeserialization() supportsEncoding() supportsDecoding()
   getEncoder() from SerializerInterface
 * Serializer now implements NormalizerInterface, DenormalizerInterface,
   EncoderInterface, DecoderInterface in addition to SerializerInterface
 * added DenormalizableInterface and DenormalizerInterface
 * [BC BREAK] changed `GetSetMethodNormalizer`'s key names from all lowercased
   to camelCased (e.g. `mypropertyvalue` to `myPropertyValue`)
 * [BC BREAK] convert the `item` XML tag to an array

    ``` xml
    <?xml version="1.0"?>
    <response>
        <item><title><![CDATA[title1]]></title></item><item><title><![CDATA[title2]]></title></item>
    </response>
    ```

    Before:

        Array()

    After:

        Array(
            [item] => Array(
                [0] => Array(
                    [title] => title1
                )
                [1] => Array(
                    [title] => title2
                )
            )
        )
pear/Serializer/Symfony/Component/Serializer/composer.json000064400000001353150431103620020042 0ustar00{
    "name": "symfony/serializer",
    "type": "library",
    "description": "Symfony Serializer Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Serializer\\": "" }
    },
    "target-dir": "Symfony/Component/Serializer",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Serializer/Symfony/Component/Serializer/README.md000064400000000674150431103630016605 0ustar00Serializer Component
====================

With the Serializer component its possible to handle serializing data structures,
including object graphs, into array structures or other formats like XML and JSON.
It can also handle deserializing XML and JSON back to object graphs.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Serializer/
    $ composer.phar install
    $ phpunit
pear/Serializer/Symfony/Component/Serializer/LICENSE000064400000002051150431103630016322 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Locale/Symfony/Component/Locale/CHANGELOG.md000064400000000505150431103650015306 0ustar00CHANGELOG
=========

2.1.0
-----

 * added Locale::getIntlIcuVersion(), Locale::getIntlIcuDataVersion(), Locale::getIcuDataVersion() and Locale::getIcuDataDirectory()
 * renamed update-data.php to build-data.php, the script usage changed, now it is easier to update the ICU data
 * updated the ICU data to the release 49.1.2
pear/Locale/Symfony/Component/Locale/composer.json000064400000001374150431103660016225 0ustar00{
    "name": "symfony/locale",
    "type": "library",
    "description": "Symfony Locale Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/intl": ">=2.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Locale\\": "" }
    },
    "target-dir": "Symfony/Component/Locale",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Locale/Symfony/Component/Locale/README.md000064400000000413150431103660014753 0ustar00Locale Component
================

Locale provides fallback code to handle cases when the ``intl`` extension is
missing.

The Locale component is deprecated since version 2.3 and will be removed in
Symfony 3.0. You should use the more capable Intl component instead.
pear/Locale/Symfony/Component/Locale/LICENSE000064400000002051150431103670014502 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Filesystem/Symfony/Component/Filesystem/CHANGELOG.md000064400000000563150431103710017161 0ustar00CHANGELOG
=========

2.3.12
------

 * deprecated dumpFile() file mode argument.

2.3.0
-----

 * added the dumpFile() method to atomically write files
 
2.2.0
-----

 * added a delete option for the mirror() method

2.1.0
-----

 * 24eb396 : BC Break : mkdir() function now throws exception in case of failure instead of returning Boolean value
 * created the component
pear/Filesystem/Symfony/Component/Filesystem/composer.json000064400000001353150431103720020071 0ustar00{
    "name": "symfony/filesystem",
    "type": "library",
    "description": "Symfony Filesystem Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Filesystem\\": "" }
    },
    "target-dir": "Symfony/Component/Filesystem",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Filesystem/Symfony/Component/Filesystem/README.md000064400000002032150431103720016621 0ustar00Filesystem Component
====================

Filesystem provides basic utility to manipulate the file system:

```php
<?php

use Symfony\Component\Filesystem\Filesystem;

$filesystem = new Filesystem();

$filesystem->copy($originFile, $targetFile, $override = false);

$filesystem->mkdir($dirs, $mode = 0777);

$filesystem->touch($files, $time = null, $atime = null);

$filesystem->remove($files);

$filesystem->chmod($files, $mode, $umask = 0000, $recursive = false);

$filesystem->chown($files, $user, $recursive = false);

$filesystem->chgrp($files, $group, $recursive = false);

$filesystem->rename($origin, $target);

$filesystem->symlink($originDir, $targetDir, $copyOnWindows = false);

$filesystem->makePathRelative($endPath, $startPath);

$filesystem->mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array());

$filesystem->isAbsolutePath($file);
```

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Filesystem/
    $ composer.phar install
    $ phpunit
pear/Filesystem/Symfony/Component/Filesystem/LICENSE000064400000002051150431103730016351 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Form/Symfony/Component/Form/CHANGELOG.md000064400000033457150431103760014534 0ustar00CHANGELOG
=========

2.4.0
-----

 * moved CSRF implementation to the new Security CSRF sub-component
 * deprecated CsrfProviderInterface and its implementations
 * deprecated options "csrf_provider" and "intention" in favor of the new options "csrf_token_generator" and "csrf_token_id"

2.3.0
-----

 * deprecated FormPerformanceTestCase and FormIntegrationTestCase in the Symfony\Component\Form\Tests namespace and moved them to the Symfony\Component\Form\Test namespace
 * deprecated TypeTestCase in the Symfony\Component\Form\Tests\Extension\Core\Type namespace and moved it to the Symfony\Component\Form\Test namespace
 * changed FormRenderer::humanize() to humanize also camel cased field name
 * added RequestHandlerInterface and FormInterface::handleRequest()
 * deprecated passing a Request instance to FormInterface::bind()
 * added options "method" and "action" to FormType
 * deprecated option "virtual" in favor "inherit_data"
 * deprecated VirtualFormAwareIterator in favor of InheritDataAwareIterator
 * [BC BREAK] removed the "array" type hint from DataMapperInterface
 * improved forms inheriting their parent data to actually return that data from getData(), getNormData() and getViewData()
 * added component-level exceptions for various SPL exceptions
   changed all uses of the deprecated Exception class to use more specialized exceptions instead
   removed NotInitializedException, NotValidException, TypeDefinitionException, TypeLoaderException, CreationException
 * added events PRE_SUBMIT, SUBMIT and POST_SUBMIT
 * deprecated events PRE_BIND, BIND and POST_BIND
 * [BC BREAK] renamed bind() and isBound() in FormInterface to submit() and isSubmitted()
 * added methods submit() and isSubmitted() to Form
 * deprecated bind() and isBound() in Form
 * deprecated AlreadyBoundException in favor of AlreadySubmittedException
 * added support for PATCH requests
 * [BC BREAK] added initialize() to FormInterface
 * [BC BREAK] added getAutoInitialize() to FormConfigInterface
 * [BC BREAK] added setAutoInitialize() to FormConfigBuilderInterface
 * [BC BREAK] initialization for Form instances added to a form tree must be manually disabled
 * PRE_SET_DATA is now guaranteed to be called after children were added by the form builder,
   unless FormInterface::setData() is called manually
 * fixed CSRF error message to be translated
 * custom CSRF error messages can now be set through the "csrf_message" option
 * fixed: expanded single-choice fields now show a radio button for the empty value

2.2.0
-----

 * TrimListener now removes unicode whitespaces
 * deprecated getParent(), setParent() and hasParent() in FormBuilderInterface
 * FormInterface::add() now accepts a FormInterface instance OR a field's name, type and options
 * removed special characters between the choice or text fields of DateType unless
   the option "format" is set to a custom value
 * deprecated FormException and introduced ExceptionInterface instead
 * [BC BREAK] FormException is now an interface
 * protected FormBuilder methods from being called when it is turned into a FormConfigInterface with getFormConfig()
 * [BC BREAK] inserted argument `$message` in the constructor of `FormError`
 * the PropertyPath class and related classes were moved to a dedicated
   PropertyAccess component. During the move, InvalidPropertyException was
   renamed to NoSuchPropertyException. FormUtil was split: FormUtil::singularify()
   can now be found in Symfony\Component\PropertyAccess\StringUtil. The methods
   getValue() and setValue() from PropertyPath were extracted into a new class
   PropertyAccessor.
 * added an optional PropertyAccessorInterface parameter to FormType,
   ObjectChoiceList and PropertyPathMapper
 * [BC BREAK] PropertyPathMapper and FormType now have a constructor
 * [BC BREAK] setting the option "validation_groups" to ``false`` now disables validation
   instead of assuming group "Default"

2.1.0
-----

 * [BC BREAK] ``read_only`` field attribute now renders as ``readonly="readonly"``, use ``disabled`` instead
 * [BC BREAK] child forms now aren't validated anymore by default
 * made validation of form children configurable (new option: cascade_validation)
 * added support for validation groups as callbacks
 * made the translation catalogue configurable via the "translation_domain" option
 * added Form::getErrorsAsString() to help debugging forms
 * allowed setting different options for RepeatedType fields (like the label)
 * added support for empty form name at root level, this enables rendering forms
   without form name prefix in field names
 * [BC BREAK] form and field names must start with a letter, digit or underscore
   and only contain letters, digits, underscores, hyphens and colons
 * [BC BREAK] changed default name of the prototype in the "collection" type
   from "$$name$$" to "\__name\__". No dollars are appended/prepended to custom
   names anymore.
 * [BC BREAK] improved ChoiceListInterface
 * [BC BREAK] added SimpleChoiceList and LazyChoiceList as replacement of
   ArrayChoiceList
 * added ChoiceList and ObjectChoiceList to use objects as choices
 * [BC BREAK] removed EntitiesToArrayTransformer and EntityToIdTransformer.
   The former has been replaced by CollectionToArrayTransformer in combination
   with EntityChoiceList, the latter is not required in the core anymore.
 * [BC BREAK] renamed
   * ArrayToBooleanChoicesTransformer to ChoicesToBooleanArrayTransformer
   * ScalarToBooleanChoicesTransformer to ChoiceToBooleanArrayTransformer
   * ArrayToChoicesTransformer to ChoicesToValuesTransformer
   * ScalarToChoiceTransformer to ChoiceToValueTransformer
   to be consistent with the naming in ChoiceListInterface.
   They were merged into ChoiceList and have no public equivalent anymore.
 * choice fields now throw a FormException if neither the "choices" nor the
   "choice_list" option is set
 * the radio type is now a child of the checkbox type
 * the collection, choice (with multiple selection) and entity (with multiple
   selection) types now make use of addXxx() and removeXxx() methods in your
   model if you set "by_reference" to false. For a custom, non-recognized
   singular form, set the "property_path" option like this: "plural|singular"
 * forms now don't create an empty object anymore if they are completely
   empty and not required. The empty value for such forms is null.
 * added constant Guess::VERY_HIGH_CONFIDENCE
 * [BC BREAK] The methods `add`, `remove`, `setParent`, `bind` and `setData`
   in class Form now throw an exception if the form is already bound
 * fields of constrained classes without a NotBlank or NotNull constraint are
   set to not required now, as stated in the docs
 * fixed TimeType and DateTimeType to not display seconds when "widget" is
   "single_text" unless "with_seconds" is set to true
 * checkboxes of in an expanded multiple-choice field don't include the choice
   in their name anymore. Their names terminate with "[]" now.
 * deprecated FormValidatorInterface and substituted its implementations
   by event subscribers
 * simplified CSRF protection and removed the csrf type
 * deprecated FieldType and merged it into FormType
 * added new option "compound" that lets you switch between field and form behavior
 * [BC BREAK] renamed theme blocks
   * "field_*" to "form_*"
   * "field_widget" to "form_widget_simple"
   * "widget_choice_options" to "choice_widget_options"
   * "generic_label" to "form_label"
 * added theme blocks "form_widget_compound", "choice_widget_expanded" and
   "choice_widget_collapsed" to make theming more modular
 * ValidatorTypeGuesser now guesses "collection" for array type constraint
 * added method `guessPattern` to FormTypeGuesserInterface to guess which pattern to use in the HTML5 attribute "pattern"
 * deprecated method `guessMinLength` in favor of `guessPattern`
 * labels don't display field attributes anymore. Label attributes can be
   passed in the "label_attr" option/variable
 * added option "mapped" which should be used instead of setting "property_path" to false
 * [BC BREAK] "data_class" now *must* be set if a form maps to an object and should be left empty otherwise
 * improved error mapping on forms
   * dot (".") rules are now allowed to map errors assigned to a form to
     one of its children
 * errors are not mapped to unsynchronized forms anymore
 * [BC BREAK] changed Form constructor to accept a single `FormConfigInterface` object
 * [BC BREAK] changed argument order in the FormBuilder constructor
 * added Form method `getViewData`
 * deprecated Form methods
   * `getTypes`
   * `getErrorBubbling`
   * `getNormTransformers`
   * `getClientTransformers`
   * `getAttribute`
   * `hasAttribute`
   * `getClientData`
 * added FormBuilder methods
   * `getTypes`
   * `addViewTransformer`
   * `getViewTransformers`
   * `resetViewTransformers`
   * `addModelTransformer`
   * `getModelTransformers`
   * `resetModelTransformers`
 * deprecated FormBuilder methods
   * `prependClientTransformer`
   * `appendClientTransformer`
   * `getClientTransformers`
   * `resetClientTransformers`
   * `prependNormTransformer`
   * `appendNormTransformer`
   * `getNormTransformers`
   * `resetNormTransformers`
 * deprecated the option "validation_constraint" in favor of the new
   option "constraints"
 * removed superfluous methods from DataMapperInterface
   * `mapFormToData`
   * `mapDataToForm`
 * added `setDefaultOptions` to FormTypeInterface and FormTypeExtensionInterface
   which accepts an OptionsResolverInterface instance
 * deprecated the methods `getDefaultOptions` and `getAllowedOptionValues`
   in FormTypeInterface and FormTypeExtensionInterface
 * options passed during construction can now be accessed from FormConfigInterface
 * added FormBuilderInterface and FormConfigEditorInterface
 * [BC BREAK] the method `buildForm` in FormTypeInterface and FormTypeExtensionInterface
   now receives a FormBuilderInterface instead of a FormBuilder instance
 * [BC BREAK] the method `buildViewBottomUp` was renamed to `finishView` in
   FormTypeInterface and FormTypeExtensionInterface
 * [BC BREAK] the options array is now passed as last argument of the
   methods
   * `buildView`
   * `finishView`
   in FormTypeInterface and FormTypeExtensionInterface
 * [BC BREAK] no options are passed to `getParent` of FormTypeInterface anymore
 * deprecated DataEvent and FilterDataEvent in favor of the new FormEvent which is
   now passed to all events thrown by the component
 * FormEvents::BIND now replaces FormEvents::BIND_NORM_DATA
 * FormEvents::PRE_SET_DATA now replaces FormEvents::SET_DATA
 * FormEvents::PRE_BIND now replaces FormEvents::BIND_CLIENT_DATA
 * deprecated FormEvents::SET_DATA, FormEvents::BIND_CLIENT_DATA and
   FormEvents::BIND_NORM_DATA
 * [BC BREAK] reversed the order of the first two arguments to `createNamed`
   and `createNamedBuilder` in `FormFactoryInterface`
 * deprecated `getChildren` in Form and FormBuilder in favor of `all`
 * deprecated `hasChildren` in Form and FormBuilder in favor of `count`
 * FormBuilder now implements \IteratorAggregate
 * [BC BREAK] compound forms now always need a data mapper
 * FormBuilder now maintains the order when explicitly adding form builders as children
 * ChoiceType now doesn't add the empty value anymore if the choices already contain an empty element
 * DateType, TimeType and DateTimeType now show empty values again if not required
 * [BC BREAK] fixed rendering of errors for DateType, BirthdayType and similar ones
 * [BC BREAK] fixed: form constraints are only validated if they belong to the validated group
 * deprecated `bindRequest` in `Form` and replaced it by a listener to FormEvents::PRE_BIND
 * fixed: the "data" option supersedes default values from the model
 * changed DateType to refer to the "format" option for calculating the year and day choices instead
   of padding them automatically
 * [BC BREAK] DateType defaults to the format "yyyy-MM-dd" now if the widget is
   "single_text", in order to support the HTML 5 date field out of the box
 * added the option "format" to DateTimeType
 * [BC BREAK] DateTimeType now outputs RFC 3339 dates by default, as generated and
   consumed by HTML5 browsers, if the widget is "single_text"
 * deprecated the options "data_timezone" and "user_timezone" in DateType, DateTimeType and TimeType
   and renamed them to "model_timezone" and "view_timezone"
 * fixed: TransformationFailedExceptions thrown in the model transformer are now caught by the form
 * added FormRegistryInterface, ResolvedFormTypeInterface and ResolvedFormTypeFactoryInterface
 * deprecated FormFactory methods
   * `addType`
   * `hasType`
   * `getType`
 * [BC BREAK] FormFactory now expects a FormRegistryInterface and a ResolvedFormTypeFactoryInterface as constructor argument
 * [BC BREAK] The method `createBuilder` in FormTypeInterface is not supported anymore for performance reasons
 * [BC BREAK] Removed `setTypes` from FormBuilder
 * deprecated AbstractType methods
   * `getExtensions`
   * `setExtensions`
 * ChoiceType now caches its created choice lists to improve performance
 * [BC BREAK] Rows of a collection field cannot be themed individually anymore. All rows in the collection
   field now have the same block names, which contains "entry" where it previously contained the row index.
 * [BC BREAK] When registering a type through the DI extension, the tag alias has to match the actual type name.
 * added FormRendererInterface, FormRendererEngineInterface and implementations of these interfaces
 * [BC BREAK] removed the following methods from FormUtil:
   * `toArrayKey`
   * `toArrayKeys`
   * `isChoiceGroup`
   * `isChoiceSelected`
 * [BC BREAK] renamed method `renderBlock` in FormHelper to `block` and changed its signature
 * made FormView properties public and deprecated their accessor methods
 * made the normalized data of a form accessible in the template through the variable "form.vars.data"
 * made the original data of a choice accessible in the template through the property "choice.data"
 * added convenience class Forms and FormFactoryBuilderInterface
pear/Form/Symfony/Component/Form/composer.json000064400000002441150431103770015433 0ustar00{
    "name": "symfony/form",
    "type": "library",
    "description": "Symfony Form Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/event-dispatcher": "~2.1",
        "symfony/intl": "~2.3",
        "symfony/options-resolver": "~2.1",
        "symfony/property-access": "~2.3"
    },
    "require-dev": {
        "symfony/validator": "~2.2",
        "symfony/http-foundation": "~2.2",
        "symfony/security-csrf": "~2.4"
    },
    "suggest": {
        "symfony/validator": "For form validation.",
        "symfony/security-csrf": "For protecting forms against CSRF attacks.",
        "symfony/twig-bridge": "For templating with Twig.",
        "symfony/framework-bundle": "For templating with PHP."
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Form\\": "" }
    },
    "target-dir": "Symfony/Component/Form",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Form/Symfony/Component/Form/README.md000064400000001036150431104000014152 0ustar00Form Component
==============

Form provides tools for defining forms, rendering and mapping request data to
related models. Furthermore it provides integration with the Validation
component.

Resources
---------

Silex integration:

https://github.com/fabpot/Silex/blob/master/src/Silex/Provider/FormServiceProvider.php

Documentation:

http://symfony.com/doc/2.4/book/forms.html

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Form/
    $ composer.phar install
    $ phpunit
pear/Form/Symfony/Component/Form/LICENSE000064400000002051150431104000013676 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Security/Symfony/Component/Security/Acl/composer.json000064400000002226150431104040017732 0ustar00{
    "name": "symfony/security-acl",
    "type": "library",
    "description": "Symfony Security Component - ACL (Access Control List)",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/security-core": "~2.4"
    },
    "require-dev": {
        "doctrine/common": "~2.2",
        "doctrine/dbal": "~2.2",
        "psr/log": "~1.0"
    },
    "suggest": {
        "symfony/class-loader": "For using the ACL generateSql script",
        "symfony/finder": "For using the ACL generateSql script",
        "doctrine/dbal": "For using the built-in ACL implementation"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Security\\Acl\\": "" }
    },
    "target-dir": "Symfony/Component/Security/Acl",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Security/Symfony/Component/Security/Acl/README.md000064400000001135150431104040016465 0ustar00Security Component - ACL (Access Control List)
==============================================

Security provides an infrastructure for sophisticated authorization systems,
which makes it possible to easily separate the actual authorization logic from
so called user providers that hold the users credentials. It is inspired by
the Java Spring framework.

Resources
---------

Documentation:

http://symfony.com/doc/2.4/book/security.html

Tests
-----

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Security/Acl/
    $ composer.phar install --dev
    $ phpunit
pear/Security/Symfony/Component/Security/Acl/LICENSE000064400000002051150431104050016212 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Security/Symfony/Component/Security/CHANGELOG.md000064400000005436150431104060016332 0ustar00CHANGELOG
=========

2.4.0
-----

 * The switch user listener now preserves the query string when switching a user
 * The remember-me cookie hashes now use HMAC, which means that current cookies will be invalidated
 * added simpler customization options
 * structured component into three sub-components Acl, Core and Http
 * added Csrf sub-component
 * changed Http sub-component to depend on Csrf sub-component instead of the Form component

2.3.0
-----

 * [BC BREAK] the BCrypt encoder constructor signature has changed (the first argument was removed)
   To use the BCrypt encoder, you now need PHP 5.5 or "ircmaxell/password-compat" as a composer dependency
 * [BC BREAK] return 401 instead of 500 when using use_forward during for form authentication
 * added a `require_previous_session` option to `AbstractAuthenticationListener`

2.2.0
-----

 * `Symfony\Component\Security\Http\Firewall` and
   `Symfony\Component\Security\Http\RememberMe\ResponseListener` now
   implements EventSubscriberInterface
 * added secure random number generator
 * added PBKDF2 Password encoder
 * added BCrypt password encoder

2.1.0
-----

 * [BC BREAK] The signature of ExceptionListener has changed
 * changed the HttpUtils constructor signature to take a UrlGenerator and a UrlMatcher instead of a Router
 * EncoderFactoryInterface::getEncoder() can now also take a class name as an argument
 * allow switching to the user that is already impersonated
 * added support for the remember_me parameter in the query
 * added AccessMapInterface
 * [BC BREAK] moved user comparison logic out of UserInterface
 * made the logout path check configurable
 * after login, the user is now redirected to `default_target_path` if
   `use_referer` is true and the referrer is the `login_path`.
 * added a way to remove a token from a session
 * [BC BREAK] changed `MutableAclInterface::setParentAcl` to accept `null`,
   review your implementation to reflect this change.
 * `ObjectIdentity::fromDomainObject`, `UserSecurityIdentity::fromAccount` and
   `UserSecurityIdentity::fromToken` now return correct identities for proxies
   objects (e.g. Doctrine proxies)
 * [BC BREAK] moved the default authentication success and failure handling to
   separate classes. The order of arguments in the constructor of the
   `AbstractAuthenticationListener` has changed.
 * [BC BREAK] moved the default logout success handling to a separate class. The
   order of arguments in the constructor of `LogoutListener` has changed.
 * [BC BREAK] The constructor of `AuthenticationException` and all child
   classes now matches the constructor of `\Exception`. The extra information
   getters and setters are removed. There are now dedicated getters/setters for
   token (`AuthenticationException'), user (`AccountStatusException`) and
   username (`UsernameNotFoundException`).
pear/Security/Symfony/Component/Security/composer.json000064400000003641150431104060017237 0ustar00{
    "name": "symfony/security",
    "type": "library",
    "description": "Symfony Security Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/event-dispatcher": "~2.1",
        "symfony/http-foundation": "~2.1",
        "symfony/http-kernel": "~2.4"
    },
    "replace": {
        "symfony/security-acl": "self.version",
        "symfony/security-core": "self.version",
        "symfony/security-csrf": "self.version",
        "symfony/security-http": "self.version"
    },
    "require-dev": {
        "symfony/routing": "~2.2",
        "symfony/validator": "~2.2",
        "doctrine/common": "~2.2",
        "doctrine/dbal": "~2.2",
        "psr/log": "~1.0",
        "ircmaxell/password-compat": "1.0.*",
        "symfony/expression-language": "~2.4"
    },
    "suggest": {
        "symfony/class-loader": "For using the ACL generateSql script",
        "symfony/finder": "For using the ACL generateSql script",
        "symfony/validator": "For using the user password constraint",
        "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs",
        "doctrine/dbal": "For using the built-in ACL implementation",
        "symfony/expression-language": "For using the expression voter",
        "ircmaxell/password-compat": "For using the BCrypt password encoder in PHP <5.5"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Security\\": "" }
    },
    "target-dir": "Symfony/Component/Security",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Security/Symfony/Component/Security/README.md000064400000001033150431104070015766 0ustar00Security Component
==================

Security provides an infrastructure for sophisticated authorization systems,
which makes it possible to easily separate the actual authorization logic from
so called user providers that hold the users credentials. It is inspired by
the Java Spring framework.

Resources
---------

Documentation:

http://symfony.com/doc/2.4/book/security.html

Tests
-----

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Security/
    $ composer.phar install
    $ phpunit
pear/Security/Symfony/Component/Security/Http/composer.json000064400000002433150431104100020147 0ustar00{
    "name": "symfony/security-http",
    "type": "library",
    "description": "Symfony Security Component - HTTP Integration",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/security-core": "~2.4",
        "symfony/event-dispatcher": "~2.1",
        "symfony/http-foundation": "~2.4",
        "symfony/http-kernel": "~2.4"
    },
    "require-dev": {
        "symfony/routing": "~2.2",
        "symfony/security-csrf": "~2.4",
        "psr/log": "~1.0"
    },
    "suggest": {
        "symfony/security-csrf": "For using tokens to protect authentication/logout attempts",
        "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Security\\Http\\": "" }
    },
    "target-dir": "Symfony/Component/Security/Http",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Security/Symfony/Component/Security/Http/README.md000064400000001114150431104110016700 0ustar00Security Component - HTTP Integration
=====================================

Security provides an infrastructure for sophisticated authorization systems,
which makes it possible to easily separate the actual authorization logic from
so called user providers that hold the users credentials. It is inspired by
the Java Spring framework.

Resources
---------

Documentation:

http://symfony.com/doc/2.4/book/security.html

Tests
-----

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Security/Http/
    $ composer.phar install --dev
    $ phpunit
pear/Security/Symfony/Component/Security/Http/LICENSE000064400000002051150431104120016430 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Security/Symfony/Component/Security/Csrf/composer.json000064400000001727150431104130020135 0ustar00{
    "name": "symfony/security-csrf",
    "type": "library",
    "description": "Symfony Security Component - CSRF Library",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/security-core": "~2.4"
    },
    "require-dev": {
        "symfony/http-foundation": "~2.1"
    },
    "suggest": {
        "symfony/http-foundation": "For using the class SessionTokenStorage."
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Security\\Csrf\\": "" }
    },
    "target-dir": "Symfony/Component/Security/Csrf",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Security/Symfony/Component/Security/Csrf/README.md000064400000000671150431104140016670 0ustar00Security Component - CSRF
=========================

The Security CSRF (cross-site request forgery) component provides a class
`CsrfTokenManager` for generating and validating CSRF tokens.

Resources
---------

Documentation:

http://symfony.com/doc/2.4/book/security.html

Tests
-----

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Security/Csrf/
    $ composer.phar install --dev
    $ phpunit
pear/Security/Symfony/Component/Security/Csrf/LICENSE000064400000002051150431104150016411 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Security/Symfony/Component/Security/Core/composer.json000064400000002541150431104160020126 0ustar00{
    "name": "symfony/security-core",
    "type": "library",
    "description": "Symfony Security Component - Core Library",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/event-dispatcher": "~2.1",
        "symfony/expression-language": "~2.4",
        "symfony/http-foundation": "~2.4",
        "symfony/validator": "~2.2",
        "psr/log": "~1.0",
        "ircmaxell/password-compat": "1.0.*"
    },
    "suggest": {
        "symfony/event-dispatcher": "",
        "symfony/http-foundation": "",
        "symfony/validator": "For using the user password constraint",
        "symfony/expression-language": "For using the expression voter",
        "ircmaxell/password-compat": "For using the BCrypt password encoder in PHP <5.5"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Security\\Core\\": "" }
    },
    "target-dir": "Symfony/Component/Security/Core",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Security/Symfony/Component/Security/Core/README.md000064400000001064150431104170016663 0ustar00Security Component - Core
=========================

Security provides an infrastructure for sophisticated authorization systems,
which makes it possible to easily separate the actual authorization logic from
so called user providers that hold the users credentials. It is inspired by
the Java Spring framework.

Resources
---------

Documentation:

http://symfony.com/doc/2.4/book/security.html

Tests
-----

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Security/Core/
    $ composer.phar install --dev
    $ phpunit
pear/Security/Symfony/Component/Security/Core/LICENSE000064400000002051150431104200016400 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Security/Symfony/Component/Security/LICENSE000064400000002051150431104210015511 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Validator/Symfony/Component/Validator/CHANGELOG.md000064400000011775150431104240016571 0ustar00CHANGELOG
=========

2.4.0
-----

 * added a constraint the uses the expression language
 * added `minRatio`, `maxRatio`, `allowSquare`, `allowLandscape`, and `allowPortrait` to Image validator

2.3.0
-----

 * added the ISBN, ISSN, and IBAN validators
 * copied the constraints `Optional` and `Required` to the
   `Symfony\Component\Validator\Constraints\` namespace and deprecated the original
   classes.
 * added comparison validators (EqualTo, NotEqualTo, LessThan, LessThanOrEqualTo, GreaterThan, GreaterThanOrEqualTo, IdenticalTo, NotIdenticalTo)

2.2.0
-----

 * added a CardScheme validator
 * added a Luhn validator
 * moved @api-tags from `Validator` to `ValidatorInterface`
 * moved @api-tags from `ConstraintViolation` to the new `ConstraintViolationInterface`
 * moved @api-tags from `ConstraintViolationList` to the new `ConstraintViolationListInterface`
 * moved @api-tags from `ExecutionContext` to the new `ExecutionContextInterface`
 * [BC BREAK] `ConstraintValidatorInterface::initialize` is now type hinted against `ExecutionContextInterface` instead of `ExecutionContext`
 * [BC BREAK] changed the visibility of the properties in `Validator` from protected to private
 * deprecated `ClassMetadataFactoryInterface` in favor of the new `MetadataFactoryInterface`
 * deprecated `ClassMetadataFactory::getClassMetadata` in favor of `getMetadataFor`
 * created `MetadataInterface`, `PropertyMetadataInterface`, `ClassBasedInterface` and `PropertyMetadataContainerInterface`
 * deprecated `GraphWalker` in favor of the new `ValidationVisitorInterface`
 * deprecated `ExecutionContext::addViolationAtPath`
 * deprecated `ExecutionContext::addViolationAtSubPath` in favor of `ExecutionContextInterface::addViolationAt`
 * deprecated `ExecutionContext::getCurrentClass` in favor of `ExecutionContextInterface::getClassName`
 * deprecated `ExecutionContext::getCurrentProperty` in favor of `ExecutionContextInterface::getPropertyName`
 * deprecated `ExecutionContext::getCurrentValue` in favor of `ExecutionContextInterface::getValue`
 * deprecated `ExecutionContext::getGraphWalker` in favor of `ExecutionContextInterface::validate` and `ExecutionContextInterface::validateValue`
 * improved `ValidatorInterface::validateValue` to accept arrays of constraints
 * changed `ValidatorInterface::getMetadataFactory` to return a `MetadataFactoryInterface` instead of a `ClassMetadataFactoryInterface`
 * removed `ClassMetadataFactoryInterface` type hint from `ValidatorBuilderInterface::setMetadataFactory`.
   As of Symfony 2.3, this method will be typed against `MetadataFactoryInterface` instead.
 * [BC BREAK] the switches `traverse` and `deep` in the `Valid` constraint and in `GraphWalker::walkReference`
   are ignored for arrays now. Arrays are always traversed recursively.
 * added dependency to Translation component
 * violation messages are now translated with a TranslatorInterface implementation
 * [BC BREAK] inserted argument `$message` in the constructor of `ConstraintViolation`
 * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ExecutionContext`
 * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `GraphWalker`
 * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ValidationVisitor`
 * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `Validator`
 * [BC BREAK] added `setTranslator()` and `setTranslationDomain()` to `ValidatorBuilderInterface`
 * improved the Validator to support pluralized messages by default
 * [BC BREAK] changed the source of all pluralized messages in the translation files to the pluralized version
 * added ExceptionInterface, BadMethodCallException and InvalidArgumentException

2.1.0
-----

 * added support for `ctype_*` assertions in `TypeValidator`
 * improved the ImageValidator with min width, max width, min height, and max height constraints
 * added support for MIME with wildcard in FileValidator
 * changed Collection validator to add "missing" and "extra" errors to
   individual fields
 * changed default value for `extraFieldsMessage` and `missingFieldsMessage`
   in Collection constraint
 * made ExecutionContext immutable
 * deprecated Constraint methods `setMessage`, `getMessageTemplate` and
   `getMessageParameters`
 * added support for dynamic group sequences with the GroupSequenceProvider pattern
 * [BC BREAK] ConstraintValidatorInterface method `isValid` has been renamed to
   `validate`, its return value was dropped. ConstraintValidator still contains
   `isValid` for BC
 * [BC BREAK] collections in fields annotated with `Valid` are not traversed
   recursively anymore by default. `Valid` contains a new property `deep`
   which enables the BC behavior.
 * added Count constraint
 * added Length constraint
 * added Range constraint
 * deprecated the Min and Max constraints
 * deprecated the MinLength and MaxLength constraints
 * added Validation and ValidatorBuilderInterface
 * deprecated ValidatorContext, ValidatorContextInterface and ValidatorFactory
pear/Validator/Symfony/Component/Validator/composer.json000064400000002563150431104250017476 0ustar00{
    "name": "symfony/validator",
    "type": "library",
    "description": "Symfony Validator Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/translation": "~2.0",
        "symfony/property-access": "~2.2"
    },
    "require-dev": {
        "symfony/http-foundation": "~2.1",
        "symfony/intl": "~2.3",
        "symfony/yaml": "~2.0",
        "symfony/config": "~2.2",
        "doctrine/annotations": "~1.0",
        "doctrine/cache": "~1.0"
    },
    "suggest": {
        "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.",
        "doctrine/cache": "For using the default cached annotation reader",
        "symfony/http-foundation": "",
        "symfony/intl": "",
        "symfony/yaml": "",
        "symfony/config": ""
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Validator\\": "" }
    },
    "target-dir": "Symfony/Component/Validator",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Validator/Symfony/Component/Validator/README.md000064400000007201150431104250016225 0ustar00Validator Component
===================

This component is based on the JSR-303 Bean Validation specification and
enables specifying validation rules for classes using XML, YAML, PHP or
annotations, which can then be checked against instances of these classes.

Usage
-----

The component provides "validation constraints", which are simple objects
containing the rules for the validation. Let's validate a simple string
as an example:

    use Symfony\Component\Validator\Validation;
    use Symfony\Component\Validator\Constraints\Length;

    $validator = Validation::createValidator();

    $violations = $validator->validateValue('Bernhard', new Length(array('min' => 10)));

This validation will fail because the given string is shorter than ten
characters. The precise errors, here called "constraint violations",  are
returned by the validator. You can analyze these or return them to the user.
If the violation list is empty, validation succeeded.

Validation of arrays is possible using the `Collection` constraint:

    use Symfony\Component\Validator\Validation;
    use Symfony\Component\Validator\Constraints as Assert;

    $validator = Validation::createValidator();

    $constraint = new Assert\Collection(array(
        'name' => new Assert\Collection(array(
            'first_name' => new Assert\Length(array('min' => 101)),
            'last_name'  => new Assert\Length(array('min' => 1)),
        )),
        'email'    => new Assert\Email(),
        'simple'   => new Assert\Length(array('min' => 102)),
        'gender'   => new Assert\Choice(array(3, 4)),
        'file'     => new Assert\File(),
        'password' => new Assert\Length(array('min' => 60)),
    ));

    $violations = $validator->validateValue($input, $constraint);

Again, the validator returns the list of violations.

Validation of objects is possible using "constraint mapping". With such
a mapping you can put constraints onto properties and objects of classes.
Whenever an object of this class is validated, its properties and
method results are matched against the constraints.

    use Symfony\Component\Validator\Validation;
    use Symfony\Component\Validator\Constraints as Assert;

    class User
    {
        /**
         * @Assert\Length(min = 3)
         * @Assert\NotBlank
         */
        private $name;

        /**
         * @Assert\Email
         * @Assert\NotBlank
         */
        private $email;

        public function __construct($name, $email)
        {
            $this->name = $name;
            $this->email = $email;
        }

        /**
         * @Assert\True(message = "The user should have a Google Mail account")
         */
        public function isGmailUser()
        {
            return false !== strpos($this->email, '@gmail.com');
        }
    }

    $validator = Validation::createValidatorBuilder()
        ->enableAnnotationMapping()
        ->getValidator();

    $user = new User('John Doe', 'john@example.com');

    $violations = $validator->validate($user);

This example uses the annotation support of Doctrine Common to
map constraints to properties and methods. You can also map constraints
using XML, YAML or plain PHP, if you dislike annotations or don't want
to include Doctrine. Check the documentation for more information about
these drivers.

Resources
---------

Silex integration:

https://github.com/fabpot/Silex/blob/master/src/Silex/Provider/ValidatorServiceProvider.php

Documentation:

http://symfony.com/doc/2.4/book/validation.html

JSR-303 Specification:

http://jcp.org/en/jsr/detail?id=303

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Validator/
    $ composer.phar install
    $ phpunit
pear/Validator/Symfony/Component/Validator/LICENSE000064400000002051150431104260015752 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/DoctrineBridge/Symfony/Bridge/Doctrine/CHANGELOG.md000064400000001353150431104310016571 0ustar00CHANGELOG
=========

2.2.0
-----

 * added an optional PropertyAccessorInterface parameter to DoctrineType,
   EntityType and EntityChoiceList

2.1.0
-----

 * added a default implementation of the ManagerRegistry
 * added a session storage for Doctrine DBAL
 * DoctrineOrmTypeGuesser now guesses "collection" for array Doctrine type
 * DoctrineType now caches its choice lists in order to improve performance
 * DoctrineType now uses ManagerRegistry::getManagerForClass() if the option "em" is not set
 * UniqueEntity validation constraint now accepts a "repositoryMethod" option that will be used to check for uniqueness instead of the default "findBy"
 * [BC BREAK] the DbalLogger::log() visibility has been changed from public to
   protected
pear/DoctrineBridge/Symfony/Bridge/Doctrine/composer.json000064400000002541150431104310017502 0ustar00{
    "name": "symfony/doctrine-bridge",
    "type": "symfony-bridge",
    "description": "Symfony Doctrine Bridge",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "doctrine/common": "~2.2"
    },
    "require-dev": {
        "symfony/stopwatch": "~2.2",
        "symfony/dependency-injection": "~2.0",
        "symfony/form": "~2.2",
        "symfony/http-kernel": "~2.2",
        "symfony/security": "~2.2",
        "symfony/expression-language": "~2.2",
        "symfony/validator": "~2.2",
        "doctrine/data-fixtures": "1.0.*",
        "doctrine/dbal": "~2.2",
        "doctrine/orm": "~2.2,>=2.2.3"
    },
    "suggest": {
        "symfony/form": "",
        "symfony/validator": "",
        "doctrine/data-fixtures": "",
        "doctrine/dbal": "",
        "doctrine/orm": ""
    },
    "autoload": {
        "psr-0": { "Symfony\\Bridge\\Doctrine\\": "" }
    },
    "target-dir": "Symfony/Bridge/Doctrine",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/DoctrineBridge/Symfony/Bridge/Doctrine/README.md000064400000000453150431104310016237 0ustar00Doctrine Bridge
===============

Provides integration for [Doctrine](http://www.doctrine-project.org/) with
various Symfony2 components.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Bridge/Doctrine/
    $ composer.phar install
    $ phpunit
pear/DoctrineBridge/Symfony/Bridge/Doctrine/LICENSE000064400000002051150431104310015761 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/MonologBridge/Symfony/Bridge/Monolog/CHANGELOG.md000064400000000333150431104310016274 0ustar00CHANGELOG
=========

2.4.0
-----

 * added ConsoleHandler and ConsoleFormatter which can be used to show log messages
   in the console output depending on the verbosity settings

2.1.0
-----

 * added ChromePhpHandler
pear/MonologBridge/Symfony/Bridge/Monolog/composer.json000064400000002460150431104310017210 0ustar00{
    "name": "symfony/monolog-bridge",
    "type": "symfony-bridge",
    "description": "Symfony Monolog Bridge",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "monolog/monolog": "~1.3"
    },
    "require-dev": {
        "symfony/http-kernel": "~2.2",
        "symfony/console": "~2.3",
        "symfony/event-dispatcher": "~2.2"
    },
    "suggest": {
        "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.",
        "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings. You need version ~2.3 of the console for it.",
        "symfony/event-dispatcher": "Needed when using log messages in console commands"
     },
    "autoload": {
        "psr-0": { "Symfony\\Bridge\\Monolog\\": "" }
    },
    "target-dir": "Symfony/Bridge/Monolog",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/MonologBridge/Symfony/Bridge/Monolog/README.md000064400000000403150431104310015740 0ustar00Monolog Bridge
==============

Provides integration for Monolog with various Symfony2 components.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Bridge/Monolog/
    $ composer.phar install
    $ phpunit
pear/MonologBridge/Symfony/Bridge/Monolog/LICENSE000064400000002051150431104310015467 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/ConsoleTools/docs/example_output.php000064400000004073150431104330014630 0ustar00<?php
/**
 * Example for the usage of ezcConsoleOutput class.
 *
 * @package ConsoleTools
 * @version 1.6.1
 * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
 * @license http://ez.no/licenses/new_bsd New BSD License
 */

require_once 'Base/src/base.php';

/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}

// Create the output handler
$out = new ezcConsoleOutput();

// Set the verbosity to level 10
$out->options->verbosityLevel = 10;
// Enable auto wrapping of lines after 40 characters
$out->options->autobreak    = 40;

// Set the color of the default output format to green
$out->formats->default->color   = 'green';

// Set the color of the output format named 'success' to white
$out->formats->success->color   = 'white';
// Set the style of the output format named 'success' to bold
$out->formats->success->style   = array( 'bold' );

// Set the color of the output format named 'failure' to red
$out->formats->failure->color   = 'red';
// Set the style of the output format named 'failure' to bold
$out->formats->failure->style   = array( 'bold' );
// Set the background color of the output format named 'failure' to blue
$out->formats->failure->bgcolor = 'blue';

// Output text with default format
$out->outputText( 'This is default text ' );
// Output text with format 'success'
$out->outputText( 'including success message', 'success' );
// Some more output with default output.
$out->outputText( "and a manual linebreak.\n" );

// Manipulate the later output
$out->formats->success->color = 'green';
$out->formats->default->color = 'blue';

// This is visible, since we set verboseLevel to 10, and printed in default format (now blue)
$out->outputText( "Some verbose output.\n", null, 10 );
// This is not visible, since we set verboseLevel to 10
$out->outputText( "Some more verbose output.\n", null, 20 );
// This is visible, since we set verboseLevel to 10, and printed in format 'failure'
$out->outputText( "And some not so verbose, failure output.\n", 'failure', 5 );

?>
pear/ConsoleTools/docs/tutorial_example_13_dialog_question.php000064400000001050150431104330020674 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$question = new ezcConsoleQuestionDialog( $output );
$question->options->text = "Do you want to proceed?";
$question->options->showResults = true;
$question->options->validator = new ezcConsoleQuestionDialogCollectionValidator(
    array( "y", "n" ),
    "y",
    ezcConsoleQuestionDialogCollectionValidator::CONVERT_LOWER
);

do
{
    echo "\nSome action performed...\n\n";
}
while ( ezcConsoleDialogViewer::displayDialog( $question ) !== "n" );

echo "Goodbye!\n";

?>
pear/ConsoleTools/docs/tutorial_example_05_input_advanced.php000064400000002155150431104340020503 0ustar00<?php

require_once 'tutorial_autoload.php';

$input = new ezcConsoleInput();

$helpOption = $input->registerOption( new ezcConsoleOption( 'h', 'help' ) );

$inputOption = $input->registerOption( 
    new ezcConsoleOption( 
        'i',
        'input',
        ezcConsoleInput::TYPE_STRING
    )
);

$outputOption = $input->registerOption(
    new ezcConsoleOption( 
        'o',
        'output'
    )
);
$outputOption->type = ezcConsoleInput::TYPE_STRING;

$inputOption->addDependency( 
    new ezcConsoleOptionRule( $outputOption )
);
$outputOption->addDependency( 
    new ezcConsoleOptionRule( $inputOption )
);

try
{
    $input->process();
}
catch ( ezcConsoleOptionException $e )
{
    die( $e->getMessage() );
}

if ( $helpOption->value === true )
{
    echo $input->getSynopsis() . "\n";
    foreach ( $input->getOptions() as $option )
    {
        echo "-{$option->short}/{$option->long}: {$option->shorthelp}\n";
    }
}
elseif ( $outputOption->value !== false )
{
    echo "Input: {$inputOption->value}, Output: {$outputOption->value}\n";
    echo "Arguments: " . implode( ", ", $input->getArguments() ) . "\n";
}

?>
pear/ConsoleTools/docs/tutorial_example_03_output_options.php000064400000001363150431104350020631 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$output->formats->info->color = 'blue';
$output->formats->info->style = array( 'bold' );

$output->setOptions( 
    array( 
        'autobreak'      => 78,
        'verbosityLevel' => 3
    )
);

$output->outputLine( 'This is a very very long info text. It has so much information in '.
                     'it, that it will definitly not fit into 1 line. Therefore, '.
                     'ezcConsoleOutput will automatically wrap the line for us.', 'info' );

$output->outputLine();

$output->outputLine( 'This verbose information will currently not be displayed.', 'info', 10 );

$output->outputLine( 'But this verbose information will be displayed.', 'info', 2 );

?>
pear/ConsoleTools/docs/example_question_dialog_collection_full.php000064400000001145150431104350021712 0ustar00<?php

require_once "Base/src/base.php";

function __autoload( $className )
{
    ezcBase::autoload( $className );
}

$out = new ezcConsoleOutput();

$opts = new ezcConsoleQuestionDialogOptions();
$opts->text = "Do you want to proceed?";
$opts->showResults = true;
$opts->validator = new ezcConsoleQuestionDialogCollectionValidator(
    array( "y", "n" ),
    "n",
    ezcConsoleQuestionDialogCollectionValidator::CONVERT_LOWER
);

$dialog = new ezcConsoleQuestionDialog( $out, $opts );

echo "The user decided to " . ( ezcConsoleDialogViewer::displayDialog( $dialog ) === "n" ? "not " : "" ) . "proceed.\n";

?>
pear/ConsoleTools/docs/tutorial.txt000064400000057654150431104350013467 0ustar00eZ Components - ConsoleTools
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. contents:: Table of Contents

Introduction
============

The ConsoleTools component provides several useful tools to build
applications that run on a computer console (sometimes also called shell or
command line). For example, eZ Publish includes several shell
scripts that perform tasks like clearing caches.

.. note::
   From version 1.5.2 on, all necessary string operations in ConsoleTools are
   performed using `ext/iconv`__. This makes the component binary safe and
   allows you to use arbitrary unicode characters in your texts. Please make
   sure to convert your text to UTF-8 before submitting it to a method in
   ConsoleTools, if you use a different, non ASCII-compatible encoding.

.. __: http://php.net/iconv

Class overview
==============

The ConsoleTools component offers several (mostly independent) classes to 
perform different tasks. The main classes are:

ezcConsoleOutput
  ezcConsoleOutput is responsible for printing text to the console. It allows 
  you to print text in different colors with different background colors.
  It can also apply other styling information to the text, making
  it bold or underlined for example. It can automatically wrap text
  after a certain number of characters are printed (keeping words
  intact) and handle output of different verbosity levels. ATTENTION: Windows
  does not support the styling of text.

ezcConsoleInput
  Using this little tool, you can handle the options and arguments provided to
  your shell application. It is capable of handling and validating three types of
  option datatypes (string, int and none) and can handle optional and mandatory
  options as well as rules to define relations between them. Rules can include
  dependencies and exclusions between options.

ezcConsoleProgressbar
  Most often you will use a console application in favor of a web application
  when it comes to processing time-consuming tasks. To indicate the
  current progress of a task, a kind of "status 
  indicator" will be used, which is most commonly a progress bar. 
  ezcConsoleProgressbar gives you an easy-to-use interface to display this. 
  It will keep track of re-drawing the bar as needed, showing current 
  and maximum values, as well as percentage completion. It is 
  fully configurable regarding its visual appearance.

ezcConsoleStatusbar
  ezcConsoleStatusbar is the "little brother" of ezcConsoleProgressbar. It
  also allows you to display the progress of a time-consuming action, but does
  not use a fixed bar-like appearance. Instead, it indicates successful
  and failed operations by displaying specific characters and keeps a
  count of successes and failures. This allows you to indicate
  the progress of a process where you don't initially know the number of
  actions to be performed.

ezcConsoleProgressMonitor
  Sometimes you need to display the progress of several actions and don't want
  to use a progress bar to do so. In this case you need the status indicator.
  It allows you to display a status entry for each action and generates the
  percentage completion of the current step.

ezcConsoleTable
  This class lets you easily create tables to be displayed on the
  console. It has a very convenient interface to create a table and manage the
  data it contains. It is highly configurable regarding the table's appearance
  (for example, different color and style information for content
  and borders on a per-cell basis, character selection for borders, variable
  width of the table and so on). ezcConsoleTable will also take care of measuring the 
  best width for table columns (to make your content fit best), automatically
  wrapping content and aligning the content in the cells as indicated.

ezcConsoleDialog
  This interface provides a common API for user interaction elements. A console
  dialog can request information from a user and react on this information
  interactively. For you as a user of ezcConsoleDialog, a dialog is displayed
  to the user and returns a result value to you, which was provided by the user
  of your application in some way. Currently 2 implementations of
  ezcConsoleDialog exist: ezcConsoleQuestionDialog is a dialog for asking a
  simply question and retrieving the answer from the user of an application.
  Instances of the  ezcConsoleMenuDialog class display a menu to the user and
  retrieves his choice of a menu item.

Usage
=====

Printing text to the console
----------------------------

As mentioned, the class ezcConsoleOutput is used to print text to the console.
Let's look at a basic example:

.. include:: tutorial_example_01_output_basic.php
   :literal:

The ezcConsoleOutput object is simply instantiated. You can optionally submit
options and predefined formatting options to its constructor, but this can also 
be done later.

In line 7, you can see how format is defined. Formats are created on the fly,
as soon as you access them (for reading or writing) through the $output->formats
attribute. There, we create a format called "info" and assign the color value
"blue" to it. This will make all text printed with this format blue. In line 9,
you can see how the format is applied to some text at printing time.

The second example shows some more advanced code:

.. include:: tutorial_example_02_output_advanced.php
   :literal:

In this example, two more formats are defined: "error" and "fatal". These formats 
have an additional style attribute set, which makes them both appear bold. The
"fatal" format will also underline the text and give it a black background
color.

The difference between ezcConsoleOutput->outputText() and
ezcConsoleOutput->outputLine() is that the latter automatically adds a
newline value to your text. The newline sequence used here is adjusted based on
the operating system. The use of ezcConsoleOutput->outputLine() is recommended
over the direct output of, for example, "\n".

If you leave the second parameter of ezcConsoleOutput::outputText() and
ezcConsoleOutput::outputLine() out, the "default" format is used. The default
is set to your console's default setting, but you can also change this as
for any other format you define. A third variant to format text is
ezcConsoleOutput->formatText(), which returns the formatted string instead of
printing it.

This example shows some of the options ezcConsoleOutput supports:

.. include:: tutorial_example_03_output_options.php
   :literal:

autobreak
  Will wrap lines automatically after the set amount of characters, keeping
  word boundaries intact.

verbosityLevel
  Allows you to specify a third parameter to ezcConsoleOutput->outputLine() and
  ezcConsoleOutput->outputText() to indicate a verbosity level for when the text
  should be printed. By setting the "verbosityLevel" option for
  ezcConsoleOutput, you define which texts will and will not be printed.

In our example, the call on line 23 would not print out text with the
"verbosityLevel" option set to 3, but the call on line 25 would.

The last example shows how to change the target of a format, which allows you
to print text e.g. to STDERR.

.. include:: tutorial_example_output_targets.php
   :literal:

The error message 'Unable to connect to database' will be printed in bold, with
a red foreground color to STDOUT. The default target is
ezcConsoleOutput::TARGET_OUTPUT, which prints to STDOUT and has standar output
buffering in place. If you want to switch out the standard output bufferung,
use ezcConsoleOutput::TARGET_STDOUT.

Although this feature was originally not designed for that purpose, you can
also use any other arbitrary PHP stream definition as a target. For example
'file:///var/log/my.log' to get the messages redirected to a log file instead
of displaying them.

Mastering options and arguments
-------------------------------

Below is a simple example for ezcConsoleInput:

.. include:: tutorial_example_04_input_basic.php
   :literal:
   
After instantiating a new ezcConsoleInput object to handle the options, an
option is registered on lines 7-12. This option will be available as "-h" and
"--help". The ezcConsoleInput->process() call makes ezcConsoleInput respond to the
options submitted by the user. If any error occurs with the submitted user
data, the method will throw an exception of type ezcConsoleOptionException. By
default, all options are registered with the value type
ezcConsoleInput::TYPE_NONE, which indicates that they don't expect a value
from the user. If a value is submitted anyway, ezcConsoleInput->process() will
throw a ezcConsoleOptionTypeViolationException. 

On line 23, a check is performed to see whether an option was submitted. If an option was not 
submitted, its $value property will contain bool *false*. Depending on the $type
set, it can contain different value types if it was submitted. If you use the 
(not shown here) ezcConsoleOption->$multiple property, the value will be an array 
containing the specified value types.

The next example is more advanced:

.. include:: tutorial_example_05_input_advanced.php
   :literal:

Two options are registered here: "-i" / "--input" and "-o" / "--output". For the
first one, additional properties for the ezcConsoleOption object are submitted
through the constructor. For the second ezcConsoleOption object, you see how to
provide additional properties after construction. We change the type of both
options to expect a string value from the user (lines 13 and 20).

In lines 25 and 28 we make both parameters depend on each other. If one of them
is submitted without the other, ezcConsoleInput->process() will throw an
ezcConsoleOptionDependencyViolationException. Aside from dependency rules, you can
also define exclusion rules using ezcConsoleOption->addExclusion().

On line 43, the method ezcConsoleInput->getSynopsis() is used to retrieve a
synopsis string for the program. The synopsis for our example would look like
this: ::

  $ ./tutorial_example_05_input_advanced.php [-h] [-i <string> [-o <string>] ]  [[--] <args>] 

The synopsis will indicate the option value types, whether they are optional, the
inter-option dependencies and default values (if set). On line 46, the property 
ezcConsoleOption->$shorthelp is accessed, where you can store some short help
information. It has a reasonable default value set.

On line 49, the submission of the "-o" option is checked. Because this has a
dependency on the "-i" option, a check for that is not necessary. Line 52
shows how you can access the arguments submitted to the program.
ezcConsoleInput->getArguments() always returns an array (which is empty if no
arguments are submitted). A more advanced way of handling arguments is
explained further below.

Here is an example of how the defined program would be called: ::

  $ ./tutorial_example_05_input_advanced.php -i /var/www -o /tmp foo bar 

The program would respond by printing the following: ::

  Input: /var/www, Output: /tmp
  Arguments: foo, bar

As you can see, this example does not define, which arguments are expected and
therefore, the program simply accepts any number of arguments and provides them
through the ezcConsoleInput->getArguments() method. The following example
shows, how specific arguments can be defined:

.. include:: tutorial_example_12_input_arguments.php
   :literal:

As seen before, a help option is registered. In addition, 3 arguments are
registered: The first one with the name "source" is a standard argument. It is
mandatory for the user to submit a value here. The second argument,
"destination" is optional and a default value is assigned, which will be used,
if the user does not provide a value for it.

The third one ("iterations") is not of type string, but an integer. Because the
second argument is optional, this third one is automatically optional, too.
Since no default value is assigned, it will be null, if the user does not
submit it. If a value is provided, it must be an integer.

Argument definitions are processed as usual inside the
ezcConsoleInput->process() method, but will throw an
ezcConsoleArgumentException if something goes wrong. If desired, exceptions
about options and arguments can be caught together using ezcConsoleException or
be handled on their own.

The value of an argument can be fetched from its definition, using its value
property. As can be seen at the very end of the example, for reading purpose,
arguments can be accessed by their name. This does not work for writing
purpose, since a specific order must be given there.

If the --help option is set, mandatory arguments don't need to be submitted and
are silently ignored. The help text generated by ezcConsoleInput for this
example looks like this: ::
    
    Usage: $ tutorial_example_12_input_arguments.php [-h] [--] <string:source> [<string:destination>] [<int:iterations>]
    A simple text program

    -h / --help           No help available.
    Arguments:            
    <string:source>       The source directory.
    <string:destination>  No help available.
    <int:iterations>      Number of iterations.


For further information, please refer to the API documentation of
ezcConsoleInput.

Progress indication
-------------------

This example defines a simple progress bar:

.. include:: tutorial_example_06_progressbar_basic.php
   :literal:

The created progressbar will count to a maximum value of 15, submitted to 
ezcConsoleProgressbar->__construct() in line 7. ezcConsoleProgressbar utilizes
ezcConsoleOutput to print the generated progress bar. The call to
ezcConsoleProgressbar->advance() pushes the progress bar one step further on each
call and redraws it (line 11). Calling ezcConsoleProgressbar->finish() will set
the progress bar to 100% immediately.

The progress bar generated by the example will look like this:

.. image:: img/consoletools_tutorial_example_06.png

The next example performs more customization on the progress bar appearance:

.. include:: tutorial_example_07_progressbar_advanced.php
   :literal:

The defined options array demonstrates only a small subset of options. For
detailed information, see the API documentation on
ezcConsoleProgressbarOptions. The "emptyChar" value defines the character to
prefill the bar, the "barChar" option defines the character to fill the bar
with when calling ezcConsoleProgressbar->advance().
Using the "formatString" option, you define the appearance of the whole bar.
Here the substitution of several placeholders (like "%fraction%" and "%bar%")
is permitted. "formatString" must contain the "%bar%" placeholder, while all
other values are optional. Any other printable character is permitted.
Formatting options are allowed in the "formatString" option, but
not in any other option. "redrawFrequency" defines how often the
progressbar will be redrawn. In the example this will be every 50th call to
ezcConsoleProgressbar->advance().

The resulting progress bar looks like this:

.. image:: img/consoletools_tutorial_example_07.png

With ezcConsoleStatusbar, you can indicate the progress of a time-consuming
action in a simpler way. Here is an example:

.. include:: tutorial_example_08_statusbar.php
   :literal:

This variant of indicating progress only displays success or failure indicators
for an action and allows you to run any number of actions, without specifying
in advance how many you will perform. The "successChar" and "failureChar" options
indicate which string to print on a successful or failed action. Lines 11 and
12 format these strings.

Indicating a status is done using ezcConsoleStatusbar->add(), which expects
*true* for a succeeded action and *false* for a failed one (line 20). You can 
access the number of successes and failures through
ezcConsoleStatusbar->getSuccessCount() and
ezcConsoleStatusbar->getFailureCount(). To make ezcConsoleStatusbar
wrap a line after a certain amount of statuses, you can use 
ezcConsoleOutput->$autobreak.

Here the result of the example:

.. image:: img/consoletools_tutorial_example_08.png

Finally, ezcConsoleProgressMonitor can indicate progress, but does not use a
bar-like interface. It simply prints status information about each action you
perform and shows the current progress as a percentage value in relation to the
number of actions you plan to perform overall.

.. include:: tutorial_example_11_progressmonitor.php
   :literal:

Line 7 creates a new status indicator, which will iterate over 7 actions.
Inside the while loop, we simulate some actions. The
call to $status->addEntry() adds a status entry and causes the indicator to
print the entry. Every entry consists of a tag (first parameter) and a message.

The result of the example is as follows:

::

    14.3% ACTION Performed action #1.
    28.6% ACTION Performed action #2.
    42.9% ACTION Performed action #3.
    57.1% ACTION Performed action #4.
    71.4% ACTION Performed action #5.
    85.7% ACTION Performed action #6.
   100.0% ACTION Performed action #7.

More information on these classes can be found in the API documentation of 
ezcConsoleProgressbar, ezcConsoleStatusbar and ezcConsoleProgressMonitor.

Large data served in a table
----------------------------

This is the result of a table generated by ezcConsoleTable:

.. image:: img/consoletools_tutorial_example_09.png

Here is its corresponding source code:

.. include:: tutorial_example_09_table_basic.php
   :literal:

ezcConsoleTable (like ezcConsoleStatusbar and ezcConsoleProgressbar) uses the
ezcConsoleOutput class to print to the console. To create a table, you just
need to submit the maximum width of the table to its constructor:
ezcConsoleTable->__construct(). Options for table formatting are inherited
from the table itself to the table rows and from there to the table cells.
On each inheritance level, options can be overridden individually. The
"defaultBorderFormat" option sets the global format value for all borders (line
24). This is overridden in line 26 for the first row of the table.

Table rows are accessed like an array in PHP (this is achieved by
implementing the ArrayAccess_ interface from SPL_).
ezcConsoleTable implements the Iterator interface (SPL_, too) to allow
iteration over table rows using foreach. Each table row is represented by an
object of type ezcConsoleTableRow, which also implements the ArrayAccess_ and
Iterator interfaces to access cells contained in the rows in the same way. Each
of the named classes allows the access of its properties as usual, in addition
to access to its contained objects through the array interface.

ezcConsoleTableRow and ezcConsoleTableCell have a $format setting to define the
format of the contained text. All cells (as described above) will inherit the
setting of their parent ezcConsoleTableRow, as long as this has not been
explicitly overridden. The same applies to ezcConsoleTableRow->$align and
ezcConsoleTableCell->$align. Possible align values are:

- ezcConsoleTable::ALIGN_DEFAULT (inherit from parent)
- ezcConsoleTable::ALIGN_LEFT
- ezcConsoleTable::ALIGN_RIGHT
- ezcConsoleTable::ALIGN_CENTER

The content of a cell is stored in the ezcConsoleTableCell->$content property
(line 34). The usage of formatted text in a cell is possible, but not recommended. 
If you want to define the format of cell content, use the 
ezcConsoleTableCell->$format property.

.. _SPL:         http://php.net/spl
.. _ArrayAccess: http://www.php.net/~helly/php/ext/spl/interfaceArrayAccess.html

Below is a more advanced (but in a way useless) example to show the handling of
tables:

.. include:: tutorial_example_10_table_advanced.php
   :literal:

The "corner", "lineHorizontal" and "lineVertical" options define which
characters to use for the borders of the table. These options must be
exactly one character long and cannot contain formatting information. To style the
borders, use the ezcConsoleTable->$defaultBorderFormat and
ezcConsoleTableRow->$borderFormat properties. 

The random format and alignment options selected above create the following
table:

.. image:: img/consoletools_tutorial_example_10.png

More information on the handling of tables on the shell can be found in the API
documentation of ezcConsoleTable, ezcConsoleTableRow and ezcConsoleTableCell.

Interacting with the user
-------------------------

Implementations of the interface ezcConsoleDialog are generic building blocks,
which allow to interact with the user of a shell application using STDIN. A
dialog is initialized, displayed and will return a value provided by the user.
What exactly happens inside a specific dialog may vary. Commonly, the dialog
validates and possibly manipulates the provided value before returning it.

The most basic dialog is the ezcConsoleQuestionDialog, which prints out some
text and retrieves a single value back.

.. include:: tutorial_example_13_dialog_question.php
   :literal:

Every dialog expects an instance of ezcConsoleOutput which is used to display
it. The question dialog here will display the text "Do you want to proceed?"
and expects an answer from the user. The $showResults option indicates, that
the possible values the user may provide will be indicated, as well as the
default value, if one is set.

The mechanism for validating the answer is defined by an instance of
ezcConsoleQuestionDialogValidator. In the example, a collection validator is
used, which defines a collection of valid values. Beside that, it performs a
case conversion on the user provided result before validating it, if desired.

Displaying a dialog can either be done directly, by calling
ezcConsoleDialog->display(), or the more convenient way, shown in the example.
The ezcConsoleDialogViewer::displayDialog() method displays the dialog in a
loop, until the user provided a valid value, so that the program can rely on
this. In the example, the user is asked after every performed action, if he
still wants to proceed. If the answer is "n" or "N", the program stops.

An example run of this application could look like this: ::

    Some action performed...

    Do you want to proceed? (y/n) [y] y

    Some action performed...

    Do you want to proceed? (y/n) [y] 

    Some action performed...

    Do you want to proceed? (y/n) [y] n
    Goodbye!


A very similar yes/no question can be created through convenience method very
easily:

.. include:: tutorial_example_14_dialog_yesnoquestion.php
   :literal:

The created yes/no question dialog contains a custom question and defaults to
"y", if nothing is selected. In contrast to the last example, the dialog
created here also accepts "yes" and "no" as answers. Both phrases can be used
in any typing, e.g. like "yEs" or "NO". This is made possibly by the
ezcConsoleQuestionDialogMappingValidator, which extends
ezcConsoleQuestionDialogCollectionValidator. The mapping validator allows to
define an arbitrary mapping between the user typed answers and expected ones.
Therefore the dialog still only returns either "y" or "n".

The second dialog type, provided with ConsoleTools, is the
ezcConsoleMenuDialog. Similar to the ezcConsoleQuestionDialog, it displays a
list of menu items to the user and requires him to choose one of these. An
example for this class looks like this:

.. include:: tutorial_example_15_dialog_menu.php
   :literal:

Again the dialog is instantiated and some options are tweaked to get the
desired behaviour. The validator in this case receives an array of possible
menu items, while the key represents the identifier and the value contains the
text to be displayed for the item. The second argument is the default value,
chosen if the user simply presses <return>.

An example run of this program could look like this: ::

    Please choose a possibility:

      1) Perform some more actions
      2) Perform another action
      0) Quit

    Select: [0] 1
    Performing some more actions...
    Please choose a possibility:

      1) Perform some more actions
      2) Perform another action
      0) Quit

    Select: [0] 2
    Performing some other actions!
    Please choose a possibility:

      1) Perform some more actions
      2) Perform another action
      0) Quit

    Select: [0] 

The character used to divide the identifier and text, as well as the text
indicating that a selection must be done, can be tweaked, too.

Further information about dialogs can be found in the API documentation of
ezcConsoleDialog, ezcConsoleQuestionDialog and ezcConsoleMenuDialog.


..
   Local Variables:
   mode: rst
   fill-column: 79
   End: 
   vim: et syn=rst tw=79
pear/ConsoleTools/docs/example_table_2.php000064400000003322150431104350014576 0ustar00<?php
/**
 * Example for the usage of ezcConsoleTable class.
 *
 * @package ConsoleTools
 * @version 1.6.1
 * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
 * @license http://ez.no/licenses/new_bsd New BSD License
 */

require_once 'Base/src/base.php';
/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}

// Initialize the console output handler
$out = new ezcConsoleOutput();

// Define format schemes for even and odd rows
$out->formats->evenRow->color = 'red';
$out->formats->evenRow->style = array( 'bold' );

$out->formats->oddRow->color = 'blue';
$out->formats->oddRow->style = array( 'bold' );

// Define format schemes for even and odd cells
$out->formats->evenCell->color = 'red';
$out->formats->evenCell->style = array( 'negative' );

$out->formats->oddCell->color = 'blue';
$out->formats->oddCell->style = array( 'negative' );

// Create a new table with a width of 60 chars
$table = new ezcConsoleTable( $out, 60 );
    
// Set global cell content align
$table->options->defaultAlign = ezcConsoleTable::ALIGN_CENTER;

for ( $i = 0; $i < 5; $i ++ )
{
    for ( $j = 0; $j < 5; $j++ )
    {
        // Fill each table cell with ##
        $table[$i][$j]->content = '##';
        if ( $i === $j )
        {
            // On diagonal line set explicit cell format for even/odd
            $table[$i][$j]->format = $j % 2 == 0 ? 'evenCell' : 'oddCell';
        }
    }
    // Set global format for even/odd rows
    $table[$i]->format = $i % 2 == 0 ? 'evenRow' : 'oddRow';
    // Set border format for even/odd rows
    $table[$i]->borderFormat = $i % 2 == 0 ? 'evenRow' : 'oddRow';
}

$table->outputTable();
echo "\n";
?>
pear/ConsoleTools/docs/tutorial_example_06_progressbar_basic.php000064400000000417150431104350021212 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$bar = new ezcConsoleProgressbar( $output, 15 );

for ( $i = 0; $i < 15; $i++ )
{
    $bar->advance();
    usleep(  mt_rand( 2000, 200000 ) );
}

$bar->finish();

$output->outputLine();

?>
pear/ConsoleTools/docs/tutorial_autoload.php000064400000000757150431104350015317 0ustar00<?php
$dir = dirname( __FILE__ );
$dirParts = explode( DIRECTORY_SEPARATOR, $dir );
switch ( $dirParts[count( $dirParts ) - 3] )
{
    case 'doc': require_once 'ezc/Base/base.php'; break; // pear
    case 'trunk': require_once "$dir/../../Base/src/base.php"; break; // svn
    default: require_once "$dir/../../Base/src/base.php"; break; // bundle
}

/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}
?>
pear/ConsoleTools/docs/tutorial_example_01_output_basic.php000064400000000270150431104350020211 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$output->formats->info->color = 'blue';

$output->outputText( 'Test text in color blue', 'info' );

?>
pear/ConsoleTools/docs/tutorial_example_08_statusbar.php000064400000001220150431104350017523 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$output->formats->success->color = 'green';
$output->formats->failure->color = 'red';

$options = array( 
    'successChar' => $output->formatText( '+', 'success' ),
    'failureChar' => $output->formatText( '-', 'failure' ),
);

$status = new ezcConsoleStatusbar( $output, $options );

for ( $i = 0; $i < 120; $i++ )
{
    $nextStatus = ( bool )mt_rand( 0,1 );
    $status->add( $nextStatus );
    usleep(  mt_rand( 200, 2000 ) );
}

$output->outputLine();
$output->outputLine( 'Successes: ' . $status->getSuccessCount() . ', Failures: ' . $status->getFailureCount() );

?>
pear/ConsoleTools/docs/CREDITS000064400000000345150431104360012065 0ustar00CREDITS
=======

eZ Components team
------------------

- Sergey Alexeev
- Sebastian Bergmann
- Jan Borsodi
- Raymond Bosman
- Frederik Holljen
- Kore Nordmann
- Derick Rethans
- Vadym Savchuk
- Tobias Schlitt
- Alexandru Stanoi
pear/ConsoleTools/docs/tutorial_example_02_output_advanced.php000064400000001221150431104360020674 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$output->formats->info->color = 'blue';

$output->formats->error->color = 'red';
$output->formats->error->style = array( 'bold' );

$output->formats->fatal->color = 'red';
$output->formats->fatal->style = array( 'bold', 'underlined' );
$output->formats->fatal->bgcolor = 'black';

$output->outputText( 'This is some standard text ' );
$output->outputText( 'including some error', 'error' );
$output->outputText( ' wrapped in standard text.' );
$output->outputText( "\n" );

$output->outputLine( 'This is a fatal error message.', 'fatal' );

$output->outputText( 'Test' );

?>
pear/ConsoleTools/docs/example_statusbar.php000064400000001733150431104360015303 0ustar00<?php
/**
 * Example for the usage of ezcConsoleStatusbar class.
 *
 * @package ConsoleTools
 * @version 1.6.1
 * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
 * @license http://ez.no/licenses/new_bsd New BSD License
 */

require_once 'Base/src/base.php';

/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}

$out = new ezcConsoleOutput();

// Create status bar itself
$status = new ezcConsoleStatusbar( $out );

// Perform actions
$i = 0;
while( $i++ < 20 ) 
{
    // Do whatever you want to indicate progress for
    usleep( mt_rand( 20000, 2000000 ) );
    // Indicate success or failure
    $status->add( (bool)mt_rand( 0, 1 ) );
}

$out->outputLine();
// Print statistics
$out->outputLine( $status->getSuccessCount() . ' operations succeeded, ' . $status->getFailureCount() . ' failed.' );

/*
OUTPUT:

+-++++-++++-++-+--+-
13 operations succeeded, 7 failed.

*/
?>
pear/ConsoleTools/docs/example_question_dialog_factory_yesno.php000064400000000715150431104360021424 0ustar00<?php

require_once "Base/src/base.php";

function __autoload( $className )
{
    ezcBase::autoload( $className );
}

$out = new ezcConsoleOutput();

$dialog = ezcConsoleQuestionDialog::YesNoQuestion( $out, "Is the answer to everything 42?", "y" );

if ( ( $res = ezcConsoleDialogViewer::displayDialog( $dialog ) ) === "y" )
{
    echo "You are so right! Don't forget your towel! :)\n";
}
else
{
    echo "You should better read some Douglas Adams!\n";
}



?>
pear/ConsoleTools/docs/example_question_dialog_type_full.php000064400000001166150431104360020544 0ustar00<?php

require_once "Base/src/base.php";

function __autoload( $className )
{
    ezcBase::autoload( $className );
}

$out = new ezcConsoleOutput();

$opts = new ezcConsoleQuestionDialogOptions();
$opts->text = "How old are you?";
$opts->showResults = true;
$opts->validator = new ezcConsoleQuestionDialogTypeValidator(
    ezcConsoleQuestionDialogTypeValidator::TYPE_INT
);

$dialog = new ezcConsoleQuestionDialog( $out, $opts );

if ( ( $res = ezcConsoleDialogViewer::displayDialog( $dialog ) ) < 8 )
{
    echo "Sorry, I can not believe that you are $res years old!\n";
}
else
{
    echo "Hey, you're still young! :)\n";
}

?>
pear/ConsoleTools/docs/example_menu_dialog_full.php000064400000001160150431104360016572 0ustar00<?php

require_once "Base/src/base.php";

function __autoload( $className )
{
    ezcBase::autoload( $className );
}

$out = new ezcConsoleOutput();

$opts = new ezcConsoleMenuDialogOptions();
$opts->text = "Please choose a possibility:\n";
$opts->validator = new ezcConsoleMenuDialogDefaultValidator(
    array(
        "A" => "Selection A",
        "B" => "Selection B",
        "C" => "Selection C",
        "D" => "Selection D",
        "Z" => "Selection Z",
    ),
    "Z"
);

$dialog = new ezcConsoleMenuDialog( $out, $opts );

$res = ezcConsoleDialogViewer::displayDialog( $dialog );
echo "User seletced $res\n";

?>
pear/ConsoleTools/docs/tutorial_example_07_progressbar_advanced.php000064400000001124150431104360021674 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$output->formats->bar->color = 'blue';
$output->formats->bar->style = array( 'bold' );

$options = array( 
    'emptyChar'       => ' ',
    'barChar'         => '-',
    'formatString'    => '%fraction%% <' . $output->formatText( '%bar%', 'bar' ) . '> Uploaded %act% / %max% kb',
    'redrawFrequency' => 50,
);

$bar = new ezcConsoleProgressbar( $output, 1024, $options );

for ( $i = 0; $i < 1024; $i++ )
{
    $bar->advance();
    usleep(  mt_rand( 200, 2000 ) );
}

$bar->finish();

$output->outputLine();

?>
pear/ConsoleTools/docs/example_table.php000064400000004136150431104360014362 0ustar00<?php
/**
 * Example for the usage of ezcConsoleTable class.
 *
 * @package ConsoleTools
 * @version 1.6.1
 * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
 * @license http://ez.no/licenses/new_bsd New BSD License
 */

require_once 'Base/src/base.php';
/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}

// Initialize the console output handler
$out = new ezcConsoleOutput();
// Define a new format "headline"
$out->formats->headline->color = 'red';
$out->formats->headline->style = array( 'bold' );
// Define a new format "sum"
$out->formats->sum->color = 'blue';
$out->formats->sum->style = array( 'negative' );

// Create a new table
$table = new ezcConsoleTable( $out, 60 );

// Create first row and in it the first cell
$table[0][0]->content = 'Headline 1';

// Create 3 more cells in row 0
for ( $i = 2; $i < 5; $i++ )
{
     $table[0][]->content = "Headline $i";
}

$data = array( 1, 2, 3, 4 );

// Create some more data in the table...
foreach ( $data as $value )
{
     // Create a new row each time and set it's contents to the actual value
     $table[][0]->content = "$value";
}

// Set another border format for our headline row
$table[0]->borderFormat = 'headline';

// Set the content format for all cells of the 3rd row to "sum"
$table[2]->format = 'sum';

$table->outputTable();
echo "\n";
/*

RESULT (without color):

+------------+------------+------------+------------+       // 
| Headline 1 | Headline 2 | Headline 3 | Headline 4 |       // Red bordered line
+------------+------------+------------+------------+       // 
| 1          |            |            |            |
+------------+------------+------------+------------+
| 2          |            |            |            |       // Content printed in white on blue
+------------+------------+------------+------------+
| 3          |            |            |            |
+------------+------------+------------+------------+
| 4          |            |            |            |
+------------+------------+------------+------------+

*/
?>
pear/ConsoleTools/docs/tutorial_example_output_targets.php000064400000000464150431104360020307 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$output->formats->error->color = 'red';
$output->formats->error->style = array( 'bold' );
$output->formats->error->target = ezcConsoleOutput::TARGET_STDERR;

$output->outputLine( 'Unable to connect to database', 'error' );

?>
pear/ConsoleTools/docs/example_progressbar.php000064400000006562150431104360015631 0ustar00<?php
/**
 * Example for the usage of ezcConsoleProgressbar class.
 *
 * @package ConsoleTools
 * @version 1.6.1
 * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
 * @license http://ez.no/licenses/new_bsd New BSD License
 */

require_once 'Base/src/base.php';

/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}

$out = new ezcConsoleOutput();

$out->formats->red->color = "red";

// Create progress bar itself
$progress = new ezcConsoleProgressbar( $out, 100, array( 'step' => 5 ) );

$progress->options->emptyChar = '-';
$progress->options->progressChar = $out->formatText('>', "red");
$progress->options->formatString = "Uploading file </tmp/foobar.tar.bz2>: %act%/%max% kb [%bar%]";

// Perform actions
$i = 0;
while( $i++ < 20 ) 
{
    // Do whatever you want to indicate progress for
    usleep( mt_rand( 20000, 2000000 ) );
    // Advance the progressbar by one step ( uploading 5k per run )
    $progress->advance();
}

// Finish progress bar and jump to next line.
$progress->finish();

$out->outputText( "Successfully uploaded </tmp/foobar.tar.bz2>.\n", 'success' );

/*
OUTPUT: (sequential, will be printed into 1 line and updated in reallife)

Uploading file </tmp/foobar.tar.bz2>:   5/100 kb [++#----------------------------------------------]
Uploading file </tmp/foobar.tar.bz2>:  10/100 kb [+++++#-------------------------------------------]
Uploading file </tmp/foobar.tar.bz2>:  15/100 kb [++++++++#----------------------------------------]
Uploading file </tmp/foobar.tar.bz2>:  20/100 kb [+++++++++++#-------------------------------------]
Uploading file </tmp/foobar.tar.bz2>:  25/100 kb [++++++++++++++#----------------------------------]
Uploading file </tmp/foobar.tar.bz2>:  30/100 kb [+++++++++++++++++#-------------------------------]
Uploading file </tmp/foobar.tar.bz2>:  35/100 kb [++++++++++++++++++++#----------------------------]
Uploading file </tmp/foobar.tar.bz2>:  40/100 kb [+++++++++++++++++++++++#-------------------------]
Uploading file </tmp/foobar.tar.bz2>:  45/100 kb [++++++++++++++++++++++++++#----------------------]
Uploading file </tmp/foobar.tar.bz2>:  50/100 kb [+++++++++++++++++++++++++++++#-------------------]
Uploading file </tmp/foobar.tar.bz2>:  55/100 kb [++++++++++++++++++++++++++++++++#----------------]
Uploading file </tmp/foobar.tar.bz2>:  60/100 kb [+++++++++++++++++++++++++++++++++++#-------------]
Uploading file </tmp/foobar.tar.bz2>:  65/100 kb [++++++++++++++++++++++++++++++++++++++#----------]
Uploading file </tmp/foobar.tar.bz2>:  70/100 kb [+++++++++++++++++++++++++++++++++++++++++#-------]
Uploading file </tmp/foobar.tar.bz2>:  75/100 kb [++++++++++++++++++++++++++++++++++++++++++++#----]
Uploading file </tmp/foobar.tar.bz2>:  80/100 kb [+++++++++++++++++++++++++++++++++++++++++++++++#-]
Uploading file </tmp/foobar.tar.bz2>:  85/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#]
Uploading file </tmp/foobar.tar.bz2>:  90/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#]
Uploading file </tmp/foobar.tar.bz2>:  95/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#]
Uploading file </tmp/foobar.tar.bz2>: 100/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#]
Uploading file </tmp/foobar.tar.bz2>: 100/100 kb [++++++++++++++++++++++++++++++++++++++++++++++++#]Successfully uploaded </tmp/foobar.tar.bz2>.

*/
?>
pear/ConsoleTools/docs/LICENSE000064400000003042150431104360012047 0ustar00eZ Components Licence
=====================

New BSD Licence
---------------

Copyright (c) 2005-2008, eZ Systems A.S.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials provided
  with the distribution.
* Neither the name of eZ Systems A.S. nor the names of its
  contributors may be used to endorse or promote products derived
  from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pear/ConsoleTools/docs/tutorial_example_04_input_basic.php000064400000000617150431104360020021 0ustar00<?php

require_once 'tutorial_autoload.php';

$input = new ezcConsoleInput();

$helpOption = $input->registerOption( 
    new ezcConsoleOption( 
        'h',
        'help'
    )
);

try
{
    $input->process();
}
catch ( ezcConsoleOptionException $e )
{
    die( $e->getMessage() );
}

if ( $helpOption->value !== false )
{
    echo "Help requested.";
}
else
{
    echo "No help requested.";
}

?>
pear/ConsoleTools/docs/tutorial_example_14_dialog_yesnoquestion.php000064400000000516150431104370021765 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$question = ezcConsoleQuestionDialog::YesNoQuestion(
    $output,
    "Do you want to proceed?",
    "y"
);

do
{
    echo "\nSome action performed...\n\n";
}
while ( ezcConsoleDialogViewer::displayDialog( $question ) !== "n" );

echo "Goodbye!\n";

?>
pear/ConsoleTools/docs/tutorial_example_11_progressmonitor.php000064400000000453150431104370020772 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$status = new ezcConsoleProgressMonitor( $output, 7 );

$i = 0;
while( $i++ < 7 ) 
{
    usleep( mt_rand( 20000, 2000000 ) );
    $status->addEntry( 'ACTION', "Performed action #{$i}." );
}

$output->outputLine();

?>
pear/ConsoleTools/docs/img/consoletools_tutorial_example_08.png000064400000001514150431104400021011 0ustar00�PNG


IHDR�'1gPibKGD�������	pHYs��tIME�%
qJ��IDATx���=r�0``��I�����&E��)vgr�ʎ�ZȂ',���$(B��{����w��I:H�/�o��׷�
��/m���v?����q�e{��?������q�K�v��?�)@C�?W_���e�xc��T�d�������^b�Y:ި8G�����]?j��������m��Ok����������<�V�+��%�K�)-��ϨqEšv�{�^���ħ�8�r\�ҟ�/��ϻ��kh���C�
f� )�2H����2 )@�I��R��_�������(k�}K�̔`Ӛ} E�"D��
K=@���/�k��Ͼ�;P9)�h����*�=���G�?ʚoD��x�eX��Vg���2H���H� )~
_O��~�o6(Sq�=��v�m���R㍌����t�:)�_o)!���{���}��֚�x%a�k������v}fb�-�̘)�3sL-w�Z1���d�����^ßK�35�������K���d���J�pl�	d*
?�<�]�\�#����ϊ�Tܢ�	�ʙ�#�)��0w����d"���3�CF.�	#�V�%�[j���w&��r'���\��vz053mu�Pǡ$	ܪ��[�|���+/m'*���<����Ddzt�ز��D͹Ш��n�
S	cn;sg���E�y|�לe�V�	����f5�`���kI@R���O�,��IEND�B`�pear/ConsoleTools/docs/img/consoletools_tutorial_example_09.png000064400000006771150431104410021025 0ustar00�PNG


IHDRU�i��bKGD�������	pHYs��tIME�	2,��N
�IDATx�흿n�8�7�W�0�.\�᮸'I��s�¥�p���=��!g��Q��-E͐?�PZ����ǿ'p��q���rS�����J"���?~�@l"Y,��?=��.:�߶7��4&�ZQ�ꉕ_���^��?M=�:j���W+v�z,���:�jl����F�[�J�K�Z�D�r�t�%����j���&���=�t.�,m���Rv�پ`�U��u�"���R{�w�h�V@j�����%��l��Z[D���_�I#�P(RQSJ�zR�KuJe�4��c�~�z�c56�����o�~M��NK���T"U"U@TU�eD���/����'c�F�
���Ly�>SN9�S�)���6�
�}�'��'��F��"��z�TUDQD`�`�ϭ�����t:���+��јŏ�~i��Kݱ�W�O��dk���z�����j�ɰ/����!~��Q휉��‰����`�3��:��p^���N����+��Ď��~���3VO�{�c���2��n��R6��6�Z��7�~��u�I�'��Cs<��%L'c�4�$��
$�c�M�����)��~��3<^���*j."*��`�x������C�L�E;���"]�N����Ds�eO�E���W���d�/	"�|~iyGس�0B�Dkpr�{j9/�{=�rw��,SZ��8!���fB�&���C�R
)�.��Hk����qd���Z�M��~���O���Qh�����/�*�#�PQ@T�'��}�a�G�����*�#׻�1��M9�SNy�<*�۰v�o����?����H�Z��P�*�
�� ����f��������G��O�/����ڥ�O�/�sy��z����ǽ��hh�Iʟ�>t���_I�����j���x��������kO�0w�#	A��cʰ/\��P:���>{���=�I��s�,o����b!�ef��okx�K�I�M��As�3O&���b���a?�L絶ǫ�!��
��߷�U�[5%z��E�;�~�H7F.��Y>��Ax�f
֢9�z4�{�HU�����z�)!��4��T���#D�8QlnLi�`K���������{FK��x�3�I��!j��iݿK�j-��S�U�hP[O.�*���c����>�|�a7طp�A�{	jU�*ݰ��L�uY�)�Xsk;�][�F$K��cP��k���a��._Y�n=^:�hY��zr��?G��*�
�� ����!�<_���'c�F�
��9U�E�SN9唧ˣ��
k�6��	~�I����H��"UDQ@TQ�CT�U|z~���ks�b��jm�-�֏�/[3r�
o�����Hv����>��7�m{b~.ѱ�qU��������\z�i���g|~6�h���sqIk%��tl��O����#&�#���H�
[|�k��[?�q���f&
�uN�/�ְ��i퓺ޞ���V�JQMo;HIZړ��4�����%��y���F��y�t��묩rM��ۂZk0K��dPr�=;��Z��M���1�z���s�y�~b]�vSռ��t�j��nM�TC#�\i1�j��f52J�����J�J�f�qM?�E�+��xѮ����[��<�=/XJ�X?�u~��[׳��d����n��[_���!g9oo_y�S3�{�<�˒G�f��{��Z��[�*��hGҦ��U��ړZ֮ٔ\o/�h&$��:wh�yG�G���G5Kd3�'֮K�^b���y��������D� F?'� �S�Q}Q�
�PQ@T�'�Gy����G�����*�#׻����RN9�S�yTT�a-�ʭ���G����?@���!R@TUDU�!ܼ��������ջ ÇlGn~���~�%�Ǧd�k���><o�����v3���TZm��;�`_Qtf�&�}�~���%�-�a6��e��z���@�;QPK}Rej>�٫��\���F�[�X��mؗ*�̶+�%���9��Pj�������6��2�skCH)�5d���`�o)ϭ	!2)���);{�+�k��ҵ͒_��n"�Z#YKl��0�a��
���S��k"��W�.��9"��ӈ�f�t�����3�+���E�=#w5�8��c�������9O�/����ר̪�&�7g��
�p��\lx��N͒@�xmy˵�=-h�����"Ϙ���ԋg����Y��y�>7S�y�L��4������
�*�7�UD�x�ʣ*k��~2�nD��\�[_*K9�SN���7�T��:�	~�I����H��"UDQ@TQ�͛��O_�������f�ϙ�_�,~�9�5�Iʟ���!�-�-��5U:��WS�Vm���7��[1u���<&1!�vp���d�i��\�4�$��)3����&�!��/��k�p�̰�ۙ+��OSOl���95�O�ǫ�3G%�5Z�?���>+]���Q��k�v�,ى3��~/�>ܡQ:o�=��D����r�&�b�e��#�`���!/Ykm�ϭ�^fM�`�H�n��Ҭo�"z_k�~�x�>b��B`���D��Ҟ:O��R_8�#Bk�����\m�]�T5!�嘽��k)��^����D�#�-�ߎ�7�.Y��T��H5�&k�I������鼹���omۈA��C�ڵv���3\���~"-3�N��h�W��|N`]ߧJ$�*��U�*�
p<Q��5��@?c7"UG�w��PN9�S�.���6���5���v#�h��@=D��*�
���
0��7��?<��>?���~8�y8�{\S��ޤ�%Z?Z�ka�'���O�_��/�ji�O��x;�-�[����mQ4�6�0�������uKw�\�mwݪ�K���r��"D*�z��h�n�?C�|n�K: ��%i�ײ�%Տ+m�'���Ģ��uIQ��`�-飚
{qnq�R8�*ϭ�h�
M�.-[���k���x�9rY@�}{m�[�s����#�{V!��,����<��Na�_�v�J�}�X�>km��ֈb���5��K�T��2�jI!�M���$/E����s�ہz�BwiT�:�ޓ�x�A]7�)���Kka�?K�n����\���*������K��Tj+�n��t���>��R��}�g��f�?�
��T�k��������� ��* ��*�D�G^�?�d�݈T�>��y)�SN9��QQ݆�|�~��?����H�Z��P�*�
��,��D�����IEND�B`�pear/ConsoleTools/docs/img/consoletools_tutorial_example_06.png000064400000000751150431104410021012 0ustar00�PNG


IHDR�
u�m@bKGD�������	pHYs��tIME�

�2A�vIDATx���1r�0��p.|�äH�2E�!��h����|��;��}Z?�_�o��U�v�o~��g@�~}!�T�����+��Y��s��쵚_#�r�~�K����#l����
�Tl�1�w���1�������լ>���{v���s�8�Η6wk��f�"|T�ƞ�Kj�W���~�E�RRVM��.	�Y�]�t&���sU|��E!]�L��hH�>֘T⒝ʽv��@v���3w�ml�T�{�{�^�|[�\�ȭp�ٹ{t�ݎ�u7\:Q�@�������
�X�5��r{^.�Ao(2J�ґ�#H{�)����*��$��n��y�i����[����/IEND�B`�pear/ConsoleTools/docs/img/consoletools_tutorial_example_07.png000064400000001237150431104410021013 0ustar00�PNG


IHDR�j��[bKGD�������	pHYs��tIME��#R,IDATx�휱��0��!Xx8��{8�;�{��)(���N�b�ITR;u*�q��|�M�8O�v��c��\��ƛ��+[B�@t���9^�!�ʝS����/��|�X%�yŒ�<��r�5o���i'�Hi�c8Zg�%g���
N��q��7�`+Y��R�����C|�Fk���x�X�vo��\IG�:�ҝ#ha��qP���Ex^Qx�eU�����r�Ԧ��3�}��,�"�V�n��� �k���&o��������Βy�ӪA�}kE��B��莘M����r��Q��\��>�M�&�K�5'�D/�)	C�bN�]B�G��ٰ��It5�Fޔ-Uq�=�'LP��/՜�M����Yp[|�����ͨ��;SEp\@p=��Z̀~ls��ԗmO�5�/���#|�L��ͱ)�x���Meo�sZ�i6O�^���}i�W�>ޑm]Q��D������%��Z��a)�@p�<V�Ӛ'��Jڬ��H5b�X-o[����R��Y)�^�F�zb<�1�� �y��O� �?7`(����IEND�B`�pear/ConsoleTools/docs/img/consoletools_tutorial_example_10.png000064400000005624150431104410021011 0ustar00�PNG


IHDR���VbKGD�������	pHYs��tIME�
-5q�I!IDATx���A��H`�O��&rH���A�j�:c��{�};X�^�_�G�6_��J�+V@��`�
V� X@��+V@��`�5�PW�C]|^�ݱ�vǺ�l�۪竢��ϵ_E����S��k��W�;�=�U�<���6ƿ�z�f3��^���r=���_�Zz��P-�3�m�����E��t7�H���:��c��5�X�N-�N��Ɵ�����^�?�~m�ֺ�OQ�_�X�G�t7�g���xc�2���	?�zQ��7�(���:��+�+ X@��`�
V� X�
�+ X@��`�
V� X�
�������stS��|9U�˩����d�;���X���ޟ�ꟽ�Y�?ž�ѵ�W���M��q��o���>+סg��>�3Z���3�߽/}F��һ,������X3��ܛz�]�M4[F��zf��R�`;%d��L=���^�l������(Ӎ5{F��zf��R�k�h��xc�j����n�{ߠo�Y�w�ӳm�
=�5kF��zf��R��X 3��
�+ X@��`+V� X�
�+ X@��`�
V� X'�;���X��v�����T|�x^�?��P���֟�D���}�g��)�G�6_�6��g�,>�C���x���
u�&���g��1Rf���=��{]�����wKMr��V���M��.K�.ݟ�7ť�3{�e_�Y�w�u*X�N	K��NKK����Uc��L7�h�M����o��{��b]���>ۦ��7���Op�k���=�~��xc�ҟQoQ�3{�e_�Y�w�u�7V���m@��`�
V� X�
�+V@��`�
V� X@��+l<X���������u�;���e�/���|9U�˩����D���3�|tm��f1�=��m�����>_Ɵ/\�n׻����3�|�e�(��?�[jS�6_Ɵ;TK�:�h�C�zF����u����)g�i��2�\�n/K�h��'�������W7������O9϶�'&5�|���z�7�7�(㉶?d�g�yy�7V�M7V@��`�
�� X@��+V@��`�
�� X@��+�/XϗSu������u�;�����j���[���_7�k?�\���m�^m����j�|/سm�(��P�h�_�o*\�o��$j�>��t�wY���N���n����
U�{?�\���u���D7v
qb��4��f���u3�����u�Ս�v��
��D�l��pN�=Mv��_S�X��_�o��j~s�'���o���n��`�
�+ X@��`+V��`�
�+ X@��`+V��c]�u�yn�˩:_N����j����+w�[/���x�Ǐ�m�����g�,�x�n׻D��C��|�����\�k<9���Qz�TS��	՟ߙ���o��^�ɻ'
ֱ��'��ӕ�Ϸ�%o���+Z�[/���x��Yn�϶�? �v��
����i�h�@�pc�:_��z��Ɠw=N�+l����`�
�� X@��+V��`�
�� X@��`+V�/9_N�r*>�m����.>���XW�c]|^���m�D����e�?g}>�����XC��}��?�=�U/��A�l����7�z�V���?ˎ��|�Y�һ�}��ZC��n���m~���h��^����Ϥ�:vX�5vz^�u�v��k����^��?{}�ϲ㟳>��Xo�{�n�ݣ��n�϶�u7֬�m�D����e�?g}&�����m@��`�
V� X�
�+V@��`�
V� X@��+�I�u�;����Y�C]�u�yn�˩:_N��袍?{f���;g�|tm���C϶I�ƿl�u�e�}�]��m��3{?d�߹��3rQK�4��/��wKm��wYB`��g���}~��P�:vz�t"5�e��N�����F2�P��?{f���;g����>ۦ��7>�_���=�>P#�Xo�{��f��F������w�	�+d��6 X@��`+V��`�
�+ X@��`+V� X�
�6��˩:_N�絉���c]�u�9:���k:�C]�u�y�0u}�>���z��C��}�'�h�}cx�M�z��7_ӆ�P�h�Ì�������[릲�����_���yB��n��0u}~�c��5�X�}��i;�	���������7��0u}�|c�]�}A�pc����m�oo|Ư���t7����1ō5k?L]���c�tc+V� X�
�+ X@��`+V� X�
�+ X@��`}��XW�c]|����T�/��stS�'�����������?��k��Z=#�G�6_��гm�^ġ���	����u�{�-�O����?�VϨ�yї޽�x�wY6�w�gm�Zz���?��k��Z=#W�`;=��D=v
�t⚺>ٍ���y#�?�D����sk���]!o�϶��7���.�c������=�~Ú�ƪr�D������zF��p��@f�n�+V@��`�
V� X@��+V@��`�,���(h7�$IEND�B`�pear/ConsoleTools/docs/example_input.php000064400000005221150431104410014422 0ustar00<?php
/**
 * Example for the usage of ezcConsoleParameter class.
 *
 * @package ConsoleTools
 * @version 1.6.1
 * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
 * @license http://ez.no/licenses/new_bsd New BSD License
 */

require_once 'Base/src/base.php';
/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}

$optionHandler = new ezcConsoleInput();

// Register simple parameter -h/--help
$optionHandler->registerOption( new ezcConsoleOption( 'h', 'help' ) );

// Register complex parameter -f/--file
$file = new ezcConsoleOption(
 'f',
 'file',
 ezcConsoleInput::TYPE_STRING,
 null,
 false,
 'Process a file.',
 'Processes a single file.'
);
$optionHandler->registerOption( $file );

// Manipulate parameter -f/--file after registration
$file->multiple = true;

// Register another complex parameter that depends on -f and excludes -h
$dir = new ezcConsoleOption(
 'd',
 'dir',
 ezcConsoleInput::TYPE_STRING,
 null,
 true,
 'Process a directory.',
 'Processes a complete directory.',
 array( new ezcConsoleOptionRule( $optionHandler->getOption( 'f' ) ) ),
 array( new ezcConsoleOptionRule( $optionHandler->getOption( 'h' ) ) )
);
$optionHandler->registerOption( $dir );

// Register an alias for this parameter
$optionHandler->registerAlias( 'e', 'extended-dir', $dir );

// Process registered parameters and handle errors
try
{
     $optionHandler->process( array( 'example_input.php', '-h' ) );
}
catch ( ezcConsoleOptionException $e )
{
     echo $e->getMessage();
     exit( 1 );
}

// Process a single parameter
$file = $optionHandler->getOption( 'f' );
if ( $file->value === false )
{
     echo "Parameter -{$file->short}/--{$file->long} was not submitted.\n";
}
elseif ( $file->value === true )
{
     echo "Parameter -{$file->short}/--{$file->long} was submitted without value.\n";
}
else
{
     echo "Parameter -{$file->short}/--{$file->long} was submitted with value <".var_export($file->value, true).">.\n";
}

// Process all parameters at once:
foreach ( $optionHandler->getOptionValues() as $paramShort => $val )
{
     switch ( true )
     {
         case $val === false:
             echo "Parameter $paramShort was not submitted.\n";
             break;
         case $val === true:
             echo "Parameter $paramShort was submitted without a value.\n";
             break;
         case is_array( $val ):
             echo "Parameter $paramShort was submitted multiple times with value: <".implode(', ', $val).">.\n";
             break;
         default:
             echo "Parameter $paramShort was submitted with value: <$val>.\n";
             break;
     }
}
?>
pear/ConsoleTools/docs/tutorial_example_15_dialog_menu.php000064400000001343150431104410017777 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$menu = new ezcConsoleMenuDialog( $output );
$menu->options = new ezcConsoleMenuDialogOptions();
$menu->options->text = "Please choose a possibility:\n";
$menu->options->validator = new ezcConsoleMenuDialogDefaultValidator(
    array(
        "1" => "Perform some more actions",
        "2" => "Perform another action",
        "0" => "Quit",
    ),
    "0"
);

while ( ( $choice = ezcConsoleDialogViewer::displayDialog( $menu ) ) != 0 )
{
    switch ( $choice )
    {
        case 1:
            echo "Performing some more actions...\n";
            break;
        case 2:
            echo "Performing some other actions!\n";
            break;
    }
}

?>
pear/ConsoleTools/docs/example_progressmonitor.php000064400000002113150431104410016534 0ustar00<?php
/**
 * Example for the usage of ezcConsoleProgressMonitor class.
 *
 * @package ConsoleTools
 * @version 1.6.1
 * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
 * @license http://ez.no/licenses/new_bsd New BSD License
 */

require_once 'Base/src/base.php';

/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}

$out = new ezcConsoleOutput();

// Create a progress monitor
$status = new ezcConsoleProgressMonitor( $out, 7 );

// Perform actions
$i = 0;
while( $i++ < 7 ) 
{
    // Do whatever you want to indicate progress for
    usleep( mt_rand( 20000, 2000000 ) );
    // Advance the statusbar by one step
    $status->addEntry( 'ACTION', "Performed action #{$i}." );
}

$out->outputLine();

/*
OUTPUT:

    14.3% ACTION Performed action #1.
    28.6% ACTION Performed action #2.
    42.9% ACTION Performed action #3.
    57.1% ACTION Performed action #4.
    71.4% ACTION Performed action #5.
    85.7% ACTION Performed action #6.
   100.0% ACTION Performed action #7.

*/
?>
pear/ConsoleTools/docs/tutorial_example_10_table_advanced.php000064400000002000150431104410020412 0ustar00<?php

require_once 'tutorial_autoload.php';

$output = new ezcConsoleOutput();

$output->formats->blue->color  = 'blue';
$output->formats->blue->style = array(  'bold' );
$output->formats->red->color   = 'red';
$output->formats->red->style = array(  'bold' );
$output->formats->green->color = 'green';
$output->formats->green->style = array(  'bold' );

$colors = array( 'red', 'blue', 'green' );
$aligns = array( ezcConsoleTable::ALIGN_LEFT, ezcConsoleTable::ALIGN_CENTER, ezcConsoleTable::ALIGN_RIGHT );

$table = new ezcConsoleTable( $output, 78 );

$table->options->corner = ' ';
$table->options->lineHorizontal = ' ';
$table->options->lineVertical = ' ';
$table->options->widthType = ezcConsoleTable::WIDTH_FIXED;

for ( $i = 0; $i < 10; $i++ )
{
    for ( $j = 0; $j < 10; $j++ )
    {
        $table[$i][$j]->content = '*';
        $table[$i][$j]->format  = $colors[array_rand( $colors )];
        $table[$i][$j]->align   = $aligns[array_rand( $aligns )];
    }
}

$table->outputTable();
$output->outputLine();


?>
pear/ConsoleTools/docs/tutorial_example_12_input_arguments.php000064400000002642150431104410020740 0ustar00<?php

require_once 'tutorial_autoload.php';

$input = new ezcConsoleInput();

$helpOption = $input->registerOption( new ezcConsoleOption( 'h', 'help' ) );
$helpOption->isHelpOption = true;

$input->argumentDefinition = new ezcConsoleArguments();

$input->argumentDefinition[0] = new ezcConsoleArgument( "source" );
$input->argumentDefinition[0]->shorthelp = "The source directory.";

$input->argumentDefinition[1] = new ezcConsoleArgument( "destination" );
$input->argumentDefinition[1]->mandatory = false;
$input->argumentDefinition[1]->default   = './';

$input->argumentDefinition[2] = new ezcConsoleArgument( "iterations" );
$input->argumentDefinition[2]->type = ezcConsoleInput::TYPE_INT;
$input->argumentDefinition[2]->shorthelp = "Number of iterations.";
$input->argumentDefinition[2]->longhelp  = "The number of iterations to perform.";


try
{
    $input->process();
}
catch ( ezcConsoleException $e )
{
    die( $e->getMessage() );
}

if ( $helpOption->value === true )
{
    echo $input->getHelpText( "A simple text program" );
}
else
{
    echo "Source:      {$input->argumentDefinition["source"]->value}\n";
    echo "Destination: {$input->argumentDefinition["destination"]->value}\n";
    echo "Iterations:  " . ( $input->argumentDefinition["iterations"]->value === null
                             ? "not set"
                             : $input->argumentDefinition["iterations"]->value
                           );
}

?>
pear/ConsoleTools/docs/tutorial_example_09_table_basic.php000064400000002100150431104410017737 0ustar00<?php

require_once 'tutorial_autoload.php';

$data = array( 
    array( 'Name', 'Nationality', 'Birthday' ),
    array( 'Derick Rethans', 'Dutch', '1978-12-22' ),
    array( 'Frederik Holljen', 'Canadian / Norwegian', '1978-11-15' ),
    array( 'Jan Borsodi', 'Norwegian', '1977-10-13' ),
    array( 'Raymond Bosman', 'Dutch', '1979-07-24' ),
    array( 'Tobias Schlitt', 'German', '1980-05-19' ),
);

$output = new ezcConsoleOutput();

$output->formats->headBorder->color = 'blue';
$output->formats->normalBorder->color = 'gray';

$output->formats->headContent->color = 'blue';
$output->formats->headContent->style = array( 'bold' );

$table = new ezcConsoleTable( $output, 78 );

$table->options->defaultBorderFormat = 'normalBorder';

$table[0]->borderFormat = 'headBorder';
$table[0]->format = 'headContent';
$table[0]->align = ezcConsoleTable::ALIGN_CENTER;

foreach ( $data as $row => $cells )
{
    foreach ( $cells as $cell )
    {
        $table[$row][]->content = $cell;
    }
}

$output->outputLine( 'eZ components team:' );
$table->outputTable();
$output->outputLine();


?>
pear/Templating/Symfony/Component/Templating/CHANGELOG.md000064400000000161150431104410017111 0ustar00CHANGELOG
=========

2.1.0
-----

 * added StreamingEngineInterface
 * added ENT_SUBSTITUTE for the HTML escaper
pear/Templating/Symfony/Component/Templating/composer.json000064400000001561150431104410020027 0ustar00{
    "name": "symfony/templating",
    "type": "library",
    "description": "Symfony Templating Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "psr/log": "~1.0"
    },
    "suggest": {
        "psr/log": "For using debug logging in loaders"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Templating\\": "" }
    },
    "target-dir": "Symfony/Component/Templating",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Templating/Symfony/Component/Templating/README.md000064400000001032150431104410016555 0ustar00Templating Component
====================

Templating provides all the tools needed to build any kind of template system.

It provides an infrastructure to load template files and optionally monitor
them for changes. It also provides a concrete template engine implementation
using PHP with additional tools for escaping and separating templates into
blocks and layouts.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Templating/
    $ composer.phar install
    $ phpunit
pear/Templating/Symfony/Component/Templating/LICENSE000064400000002051150431104410016305 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Yaml/Symfony/Component/Yaml/CHANGELOG.md000064400000000262150431104410014507 0ustar00CHANGELOG
=========

2.1.0
-----

 * Yaml::parse() does not evaluate loaded files as PHP files by default
   anymore (call Yaml::enablePhpParsing() to get back the old behavior)
pear/Yaml/Symfony/Component/Yaml/composer.json000064400000001323150431104410015417 0ustar00{
    "name": "symfony/yaml",
    "type": "library",
    "description": "Symfony Yaml Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Yaml\\": "" }
    },
    "target-dir": "Symfony/Component/Yaml",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Yaml/Symfony/Component/Yaml/README.md000064400000000533150431104410014156 0ustar00Yaml Component
==============

YAML implements most of the YAML 1.2 specification.

    use Symfony\Component\Yaml\Yaml;

    $array = Yaml::parse($file);

    print Yaml::dump($array);

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Yaml/
    $ composer.phar install
    $ phpunit
pear/Yaml/Symfony/Component/Yaml/LICENSE000064400000002051150431104410013701 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/HttpFoundation/Symfony/Component/HttpFoundation/CHANGELOG.md000064400000013620150431104430020623 0ustar00CHANGELOG
=========

2.4.0
-----

 * added RequestStack
 * added Request::getEncodings()
 * added accessors methods to session handlers

2.3.0
-----

 * added support for ranges of IPs in trusted proxies
 * `UploadedFile::isValid` now returns false if the file was not uploaded via HTTP (in a non-test mode)
 * Improved error-handling of `\Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler`
   to ensure the supplied PDO handler throws Exceptions on error (as the class expects). Added related test cases
   to verify that Exceptions are properly thrown when the PDO queries fail.

2.2.0
-----

 * fixed the Request::create() precedence (URI information always take precedence now)
 * added Request::getTrustedProxies()
 * deprecated Request::isProxyTrusted()
 * [BC BREAK] JsonResponse does not turn a top level empty array to an object anymore, use an ArrayObject to enforce objects
 * added a IpUtils class to check if an IP belongs to a CIDR
 * added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method)
 * disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to
   enable it, and Request::getHttpMethodParameterOverride() to check if it is supported)
 * Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3
 * Deprecated Flashbag::count() and \Countable interface, will be removed in 2.3

2.1.0
-----

 * added Request::getSchemeAndHttpHost() and Request::getUserInfo()
 * added a fluent interface to the Response class
 * added Request::isProxyTrusted()
 * added JsonResponse
 * added a getTargetUrl method to RedirectResponse
 * added support for streamed responses
 * made Response::prepare() method the place to enforce HTTP specification
 * [BC BREAK] moved management of the locale from the Session class to the Request class
 * added a generic access to the PHP built-in filter mechanism: ParameterBag::filter()
 * made FileBinaryMimeTypeGuesser command configurable
 * added Request::getUser() and Request::getPassword()
 * added support for the PATCH method in Request
 * removed the ContentTypeMimeTypeGuesser class as it is deprecated and never used on PHP 5.3
 * added ResponseHeaderBag::makeDisposition() (implements RFC 6266)
 * made mimetype to extension conversion configurable
 * [BC BREAK] Moved all session related classes and interfaces into own namespace, as
   `Symfony\Component\HttpFoundation\Session` and renamed classes accordingly.
   Session handlers are located in the subnamespace `Symfony\Component\HttpFoundation\Session\Handler`.
 * SessionHandlers must implement `\SessionHandlerInterface` or extend from the
   `Symfony\Component\HttpFoundation\Storage\Handler\NativeSessionHandler` base class.
 * Added internal storage driver proxy mechanism for forward compatibility with
   PHP 5.4 `\SessionHandler` class.
 * Added session handlers for custom Memcache, Memcached and Null session save handlers.
 * [BC BREAK] Removed `NativeSessionStorage` and replaced with `NativeFileSessionHandler`.
 * [BC BREAK] `SessionStorageInterface` methods removed: `write()`, `read()` and
   `remove()`.  Added `getBag()`, `registerBag()`.  The `NativeSessionStorage` class
   is a mediator for the session storage internals including the session handlers
   which do the real work of participating in the internal PHP session workflow.
 * [BC BREAK] Introduced mock implementations of `SessionStorage` to enable unit
   and functional testing without starting real PHP sessions.  Removed
   `ArraySessionStorage`, and replaced with `MockArraySessionStorage` for unit
   tests; removed `FilesystemSessionStorage`, and replaced with`MockFileSessionStorage`
   for functional tests.  These do not interact with global session ini
   configuration values, session functions or `$_SESSION` superglobal. This means
   they can be configured directly allowing multiple instances to work without
   conflicting in the same PHP process.
 * [BC BREAK] Removed the `close()` method from the `Session` class, as this is
   now redundant.
 * Deprecated the following methods from the Session class: `setFlash()`, `setFlashes()`
   `getFlash()`, `hasFlash()`, and `removeFlash()`. Use `getFlashBag()` instead
   which returns a `FlashBagInterface`.
 * `Session->clear()` now only clears session attributes as before it cleared
   flash messages and attributes. `Session->getFlashBag()->all()` clears flashes now.
 * Session data is now managed by `SessionBagInterface` to better encapsulate
   session data.
 * Refactored session attribute and flash messages system to their own
  `SessionBagInterface` implementations.
 * Added `FlashBag`. Flashes expire when retrieved by `get()` or `all()`. This
   implementation is ESI compatible.
 * Added `AutoExpireFlashBag` (default) to replicate Symfony 2.0.x auto expire
   behaviour of messages auto expiring after one page page load.  Messages must
   be retrieved by `get()` or `all()`.
 * Added `Symfony\Component\HttpFoundation\Attribute\AttributeBag` to replicate
   attributes storage behaviour from 2.0.x (default).
 * Added `Symfony\Component\HttpFoundation\Attribute\NamespacedAttributeBag` for
   namespace session attributes.
 * Flash API can stores messages in an array so there may be multiple messages
   per flash type.  The old `Session` class API remains without BC break as it
   will allow single messages as before.
 * Added basic session meta-data to the session to record session create time,
   last updated time, and the lifetime of the session cookie that was provided
   to the client.
 * Request::getClientIp() method doesn't take a parameter anymore but bases
   itself on the trustProxy parameter.
 * Added isMethod() to Request object.
 * [BC BREAK] The methods `getPathInfo()`, `getBaseUrl()` and `getBasePath()` of
   a `Request` now all return a raw value (vs a urldecoded value before). Any call
   to one of these methods must be checked and wrapped in a `rawurldecode()` if
   needed.
pear/HttpFoundation/Symfony/Component/HttpFoundation/composer.json000064400000001622150431104440021534 0ustar00{
    "name": "symfony/http-foundation",
    "type": "library",
    "description": "Symfony HttpFoundation Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/expression-language": "~2.4"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\HttpFoundation\\": "" },
        "classmap": [ "Symfony/Component/HttpFoundation/Resources/stubs" ]
    },
    "target-dir": "Symfony/Component/HttpFoundation",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/HttpFoundation/Symfony/Component/HttpFoundation/README.md000064400000002612150431104450020272 0ustar00HttpFoundation Component
========================

HttpFoundation defines an object-oriented layer for the HTTP specification.

It provides an abstraction for requests, responses, uploaded files, cookies,
sessions, ...

In this example, we get a Request object from the current PHP global
variables:

    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;

    $request = Request::createFromGlobals();
    echo $request->getPathInfo();

You can also create a Request directly -- that's interesting for unit testing:

    $request = Request::create('/?foo=bar', 'GET');
    echo $request->getPathInfo();

And here is how to create and send a Response:

    $response = new Response('Not Found', 404, array('Content-Type' => 'text/plain'));
    $response->send();

The Request and the Response classes have many other methods that implement
the HTTP specification.

Loading
-------

If you are not using Composer but are using PHP 5.3.x, you must add the following to your autoloader:

    // SessionHandlerInterface
    if (!interface_exists('SessionHandlerInterface')) {
        $loader->registerPrefixFallback(__DIR__.'/../vendor/symfony/src/Symfony/Component/HttpFoundation/Resources/stubs');
    }

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/HttpFoundation/
    $ composer.phar install
    $ phpunit
pear/HttpFoundation/Symfony/Component/HttpFoundation/LICENSE000064400000002051150431104450020015 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Archive/docs/tutorial_extract.php000064400000001024150431104500014100 0ustar00<?php

require_once 'tutorial_autoload.php';
date_default_timezone_set( "UTC" );

// Open the gzipped TAR archive.
$archive = ezcArchive::open( "compress.zlib:///tmp/my_archive.tar.gz" );

while( $archive->valid() )
{
    // Returns the current entry (ezcArchiveEntry).
    $entry = $archive->current();

    // ezcArchiveEntry has an __toString() method.
    echo $entry, "\n";

    // Extract the current archive entry to /tmp/target_location/
    $archive->extractCurrent( "/tmp/target_location/" );

    $archive->next();
}

?>
pear/Archive/docs/tutorial.txt000064400000011726150431104510012411 0ustar00eZ Components - Archive
~~~~~~~~~~~~~~~~~~~~~~~

.. contents:: Table of Contents

Introduction
============

The Archive component provides a generic API for creating and extracting
archives.  Currently, the Archive component supports the Tar and Zip formats.
Compression algorithms, such as GZip or BZip2, are indirectly supported.
The stream wrappers from PHP should be used to handle compressed archives.


Class overview
==============

The following list sums up the most important classes:

ezcArchive
  This class provides the main API for accessing or creating a
  Tar or Zip archive. ezcArchive provides methods for
  extracting entries (files, directories, symbolic links and so on), appending
  entries and removing entries. 

ezcArchiveEntry
  The ezcArchiveEntry class is returned when an entry (such as a file or
  directory) is requested from the opened archive. ezcArchiveEntry provides
  entry information about the path, its access rights and whether the entry is
  a directory, a symbolic link, a hard link, a block-file and so on. The owner name, the
  group name and the last access time are also available. 
 
More information about these classes can be found in the documentation of the
class itself. 


Usage
=====

The following examples demonstrate how to use the Archive component.

Extracting a Tar-archive
------------------------

The Tar format has more than one standard. The most common formats are:

- Gnu
- POSIX
- Unix V7
- Ustar (The default when creating a tar archive)

The Archive component can extract from any of these formats. Appending entries
to the archive is only available for the Unix V7 and Ustar formats. 

Extracting entries can occur in two ways: 

- ezcArchive->extract(), extracts all entries from the archive.
- ezcArchive->extractCurrent(), extracts only the current entry.

An ezcArchive object can be used like an iterator. After opening the file, it
points to the first entry. The iterator can be moved using ezcArchive->next()
and ezcArchive->rewind() to move to the next entry or go back to the first
entry.

The next example demonstrates how to extract an entire archive file-by-file:

.. include:: tutorial_extract.php
   :literal:

First, tutorial_autoload.php is included. The included file loads the
correct php files for the Archive package. Hereafter the time zone is set to
"UTC". The Archive component uses some date functions and might therefore
produce warnings if the time zone is not specified.

The gzipped Tar archive is opened using the zlib stream. The while() method
iterates over each entry, showing the name and extracting the entry itself. 

The Archive component extends from the PHP Iterator class, thus the above
example can be rewritten as follows:

.. include:: tutorial_iterator.php
   :literal:

Please be aware that by default archive files are opened in read/write mode. In
order to prevent that, you can set an option to open the archive in read-only
mode. This also prevents the modify and create timestamps of the file to be
preserved. The following example shows that:

.. include:: tutorial_read_only.php
   :literal:


Appending files to an archive
-----------------------------

Unfortunately, it is not yet possible to directly append files to a gzipped or
bzipped Tar archive. The ZLib and BZip2 libraries do not support opening a file
for reading and writing.

ezcArchive has two methods for appending files:

- ezcArchive->append(), appends entries to the end of the archive.
- ezcArchive->appendCurrent(), appends entries after the current entry and
  removes the rest of the files from the archive.

To replace the first file as well, use ezcArchive->truncate().  The 
next example replaces all entries from an existing Zip archive with the files
file1.txt and file2.txt:

.. include:: tutorial_replacing.php
   :literal:

Appending directories to an archive
-----------------------------------

You need to append a slash '/' to the end of the directory name that is added
to an archive.

The next example replaces all entries from an existing Zip archive with the
'directory' folder and the 'file.txt' file:

.. include:: tutorial_directories.php
   :literal:

Appending a directory tree to an archive
----------------------------------------

Using the function ezcBase::walkRecursive() a directory tree can be added to
an archive.

The next example shows how to browse a directory tree and add all the files
and directories inside to an archive:

.. include:: tutorial_recursive.php
   :literal:

The **ArchiveContext** class will hold the archive object which is passed to
the callback function *findRecursiveCallback*. The *appendRecursive* function
sets up the context object (of class **ArchiveContext**) and calls the
*findRecursiveCallback* function. In the *findRecursiveCallback* function the
current file or directory is appended to the archive object inside the
context.

More Information
================

For more information, see the ezcArchive API documentation.


..
   Local Variables:
   mode: rst
   fill-column: 79
   End: 
   vim: et syn=rst tw=79
pear/Archive/docs/tutorial_replacing.php000064400000000606150431104520014401 0ustar00<?php

require_once 'tutorial_autoload.php';
date_default_timezone_set( "UTC" );

$archive = ezcArchive::open( "/tmp/my_archive.zip" );
$archive->truncate();

$filesToAppend[] = "/tmp/file1.txt";
$filesToAppend[] = "/tmp/file2.txt";

// The second parameter specifies prefix. The prefix is normally not included 
// in the archive.
$archive->appendToCurrent( $filesToAppend, "/tmp/" );

?>
pear/Archive/docs/tutorial_autoload.php000064400000000757150431104520014254 0ustar00<?php
$dir = dirname( __FILE__ );
$dirParts = explode( DIRECTORY_SEPARATOR, $dir );
switch ( $dirParts[count( $dirParts ) - 3] )
{
    case 'doc': require_once 'ezc/Base/base.php'; break; // pear
    case 'trunk': require_once "$dir/../../Base/src/base.php"; break; // svn
    default: require_once "$dir/../../Base/src/base.php"; break; // bundle
}

/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}
?>
pear/Archive/docs/example.php000064400000002701150431104520012143 0ustar00<?php
/**
 * @package Archive
 */

// Add "MyDirectory" to a new archive: myArchive.tar
// [ tar -cf myArchive.tar MyDirectory ]

$ar = new Tar( "myArchive.tar" );
$ar->append( "MyDirectory" );

// Show the files in the archive.
// [ tar -tf myArchive.tar ]
$fileListing = $ar->getList();
foreach( $fileListing as $file )
{
    print( "Archived file: $file\n" );
}

// Append the file /etc/passwd
// [ tar -rf myArchive.tar /etc/passwd ]
$ar->append( "/etc/passwd" );

// Delete the directory and it's contents
// [ tar -f myArchive.tar --delete MyDirectory ]
$ar->delete( "MyDirectory" );

// Append another directory .. 
$ar->append( "AnotherDirectory" );

// .. and show detailed file permissions plus the file or directory path.
$fileListing = $ar->getList();
foreach( $fileListing as $file )
{
    $entry = $ar->getArchivedEntry( $file );

    print( $entry->getPermissionsString() );

    if ( $entry->isDirectory() )
    {
        print( " [ ".$entry->getPath()." ]\n" );
    }
    else
    {
        print( "   ".$entry->getPath()."\n" );
    }
}


// Extract the whole archive to the tmp directory
$ar->extractTo( "/tmp/" );

// Extract the passwd file to the file: /tmp/passwd-backup
$ar->extractTo( "/tmp/passwd-backup", "passwd" );



// Extracting the gzipped archive: compressedTar.tgz to the tmp directory:
$ar = new Tar( "compress.zlib://compressedTar.tgz" );
$ar->extractTo( "/tmp/" );

// .. and append the password file.
$ar->append( "/etc/passwd" );
?>
pear/Archive/docs/tutorial_directories.php000064400000000606150431104520014751 0ustar00<?php

require_once 'tutorial_autoload.php';
date_default_timezone_set( "UTC" );

$archive = ezcArchive::open( "/tmp/my_archive.zip" );
$archive->truncate();

$filesToAppend[] = "/tmp/directory/";
$filesToAppend[] = "/tmp/file.txt";

// The second parameter specifies prefix. The prefix is normally not included 
// in the archive.
$archive->appendToCurrent( $filesToAppend, "/tmp/" );

?>
pear/Archive/docs/CREDITS000064400000000345150431104530011022 0ustar00CREDITS
=======

eZ Components team
------------------

- Sergey Alexeev
- Sebastian Bergmann
- Jan Borsodi
- Raymond Bosman
- Frederik Holljen
- Kore Nordmann
- Derick Rethans
- Vadym Savchuk
- Tobias Schlitt
- Alexandru Stanoi
pear/Archive/docs/tutorial_iterator.php000064400000000452150431104530014266 0ustar00<?php
require_once 'tutorial_autoload.php';

$archive = ezcArchive::open( "compress.zlib:///tmp/my_archive.tar.gz" );

// The foreach method calls internally the iterator methods.
foreach( $archive as $entry )
{
    echo $entry, "\n";

    $archive->extractCurrent( "/tmp/target_location/" );
}
?>
pear/Archive/docs/LICENSE000064400000003042150431104530011004 0ustar00eZ Components Licence
=====================

New BSD Licence
---------------

Copyright (c) 2005-2008, eZ Systems A.S.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials provided
  with the distribution.
* Neither the name of eZ Systems A.S. nor the names of its
  contributors may be used to endorse or promote products derived
  from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pear/Archive/docs/tutorial_recursive.php000064400000001665150431104530014453 0ustar00<?php

require_once 'tutorial_autoload.php';
date_default_timezone_set( "UTC" );

class ArchiveContext extends ezcBaseFileFindContext
{
    public $archive;
    public $prefix;
}

function findRecursiveCallback( ezcBaseFileFindContext $context, $sourceDir, $fileName, $fileInfo )
{
    $path = "{$sourceDir}/{$fileName}";
    if ( is_dir( $path ) )
    {
        $path .= '/';
    }
    $context->archive->append( array( $path ), $context->prefix );
}

function appendRecursive( $archive, $sourceDir, $prefix )
{
    $context = new ArchiveContext();
    $context->archive = $archive;
    $context->prefix = $prefix;
    ezcBaseFile::walkRecursive( $sourceDir, array(), array(), 'findRecursiveCallback', $context );
}

$archive = ezcArchive::open( "my_archive.zip", ezcArchive::ZIP );
$archive->truncate();

// the 2nd parameter is the directory, the 3rd parameter is the prefix
appendRecursive( $archive, '/tmp/directory/', '/tmp/directory/' );

?>
pear/Archive/docs/tutorial_read_only.php000064400000000577150431104530014421 0ustar00<?php
require_once 'tutorial_autoload.php';

$options = new ezcArchiveOptions( array( 'readOnly' => true ) );
$archive = ezcArchive::open(
    "compress.zlib:///tmp/my_archive.tar.gz", null, $options );

// The foreach method calls internally the iterator methods.
foreach( $archive as $entry )
{
    echo $entry, "\n";

    $archive->extractCurrent( "/tmp/target_location/" );
}
?>
pear/File/docs/tutorial.txt000064400000001102150431104530011674 0ustar00eZ Components - File
~~~~~~~~~~~~~~~~~~~~

.. contents:: Table of Contents

Introduction
============

The File component is now **deprecated**. Instead use the ezcBaseFile class
from the Base package. Please refer to the Base_ component introduction
for the tutorial. The classes in this component still exist because
of backwards compatibility reasons.

.. _Base: introduction_Base.html

More information
================

For more information, see the ezcBaseFile API documentation.


..
   Local Variables:
   mode: rst
   fill-column: 79
   End: 
   vim: et syn=rst tw=79
pear/File/docs/tutorial_autoload.php000064400000000737150431104530013551 0ustar00<?php
$dir = dirname( __FILE__ );
$dirParts = explode( '/', $dir );
switch ( $dirParts[count( $dirParts ) - 3] )
{
    case 'doc': require_once 'ezc/Base/base.php'; break; // pear
    case 'trunk': require_once "$dir/../../Base/src/base.php"; break; // svn
    default: require_once "$dir/../../Base/src/base.php"; break; // bundle
}

/**
 * Autoload ezc classes 
 * 
 * @param string $className 
 */
function __autoload( $className )
{
    ezcBase::autoload( $className );
}
?>
pear/File/docs/CREDITS000064400000000345150431104530010320 0ustar00CREDITS
=======

eZ Components team
------------------

- Sergey Alexeev
- Sebastian Bergmann
- Jan Borsodi
- Raymond Bosman
- Frederik Holljen
- Kore Nordmann
- Derick Rethans
- Vadym Savchuk
- Tobias Schlitt
- Alexandru Stanoi
pear/File/docs/LICENSE000064400000003010150431104530010275 0ustar00eZ Components Licence
=====================

Copyright (c) 2005, 2006, 2007, eZ Systems A.S.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials provided
  with the distribution.
* Neither the name of eZ Systems A.S. nor the names of its
  contributors may be used to endorse or promote products derived
  from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pear/BrowserKit/Symfony/Component/BrowserKit/CHANGELOG.md000064400000000777150431104530017107 0ustar00CHANGELOG
=========

2.3.0
-----

 * [BC BREAK] `Client::followRedirect()` won't redirect responses with
   a non-3xx Status Code and `Location` header anymore, as per 
   http://tools.ietf.org/html/rfc2616#section-14.30

 * added `Client::getInternalRequest()` and `Client::getInternalResponse()` to
   have access to the BrowserKit internal request and response objects

2.1.0
-----

 * [BC BREAK] The CookieJar internals have changed to allow cookies with the
   same name on different sub-domains/sub-paths
pear/BrowserKit/Symfony/Component/BrowserKit/composer.json000064400000001657150431104540020017 0ustar00{
    "name": "symfony/browser-kit",
    "type": "library",
    "description": "Symfony BrowserKit Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/dom-crawler": "~2.0"
    },
    "require-dev": {
        "symfony/process": "~2.0",
        "symfony/css-selector": "~2.0"
    },
    "suggest": {
        "symfony/process": ""
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\BrowserKit\\": "" }
    },
    "target-dir": "Symfony/Component/BrowserKit",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/BrowserKit/Symfony/Component/BrowserKit/README.md000064400000001304150431104540016541 0ustar00BrowserKit Component
====================

BrowserKit simulates the behavior of a web browser.

The component only provide an abstract client and does not provide any
"default" backend for the HTTP layer.

Resources
---------

For a simple implementation of a browser based on an HTTP layer, have a look
at [Goutte](https://github.com/fabpot/Goutte).

For an implementation based on HttpKernelInterface, have a look at the
[Client](https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/Client.php)
provided by the HttpKernel component.

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/BrowserKit/
    $ composer.phar install
    $ phpunit
pear/BrowserKit/Symfony/Component/BrowserKit/LICENSE000064400000002051150431104540016267 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/DomCrawler/Symfony/Component/DomCrawler/CHANGELOG.md000064400000002202150431104550017002 0ustar00CHANGELOG
=========

2.4.0
-----

 * `Crawler::addXmlContent()` removes the default document namespace again if it's an only namespace.
 * added support for automatic discovery and explicit registration of document
   namespaces for `Crawler::filterXPath()` and `Crawler::filter()`
 * improved content type guessing in `Crawler::addContent()`
 * [BC BREAK] `Crawler::addXmlContent()` no longer removes the default document
   namespace

2.3.0
-----

 * added Crawler::html()
 * [BC BREAK] Crawler::each() and Crawler::reduce() now return Crawler instances instead of DomElement instances
 * added schema relative URL support to links
 * added support for HTML5 'form' attribute

2.2.0
-----

 * added a way to set raw path to the file in FileFormField - necessary for
   simulating HTTP requests

2.1.0
-----

 * added support for the HTTP PATCH method
 * refactored the Form class internals to support multi-dimensional fields
   (the public API is backward compatible)
 * added a way to get parsing errors for Crawler::addHtmlContent() and
   Crawler::addXmlContent() via libxml functions
 * added support for submitting a form without a submit button
pear/DomCrawler/Symfony/Component/DomCrawler/composer.json000064400000001552150431104560017723 0ustar00{
    "name": "symfony/dom-crawler",
    "type": "library",
    "description": "Symfony DomCrawler Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/css-selector": "~2.0"
    },
    "suggest": {
        "symfony/css-selector": ""
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\DomCrawler\\": "" }
    },
    "target-dir": "Symfony/Component/DomCrawler",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/DomCrawler/Symfony/Component/DomCrawler/README.md000064400000001545150431104560016462 0ustar00DomCrawler Component
====================

DomCrawler eases DOM navigation for HTML and XML documents.

If you are familiar with jQuery, DomCrawler is a PHP equivalent:

    use Symfony\Component\DomCrawler\Crawler;

    $crawler = new Crawler();
    $crawler->addContent('<html><body><p>Hello World!</p></body></html>');

    print $crawler->filterXPath('descendant-or-self::body/p')->text();

If you are also using the CssSelector component, you can use CSS Selectors
instead of XPath expressions:

    use Symfony\Component\DomCrawler\Crawler;

    $crawler = new Crawler();
    $crawler->addContent('<html><body><p>Hello World!</p></body></html>');

    print $crawler->filter('body > p')->text();

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/DomCrawler/
    $ composer.phar install
    $ phpunit
pear/DomCrawler/Symfony/Component/DomCrawler/LICENSE000064400000002051150431104570016202 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/CssSelector/Symfony/Component/CssSelector/CHANGELOG.md000064400000000052150431104600017363 0ustar00CHANGELOG
=========

2.1.0
-----

 * none
pear/CssSelector/Symfony/Component/CssSelector/composer.json000064400000001552150431104600020302 0ustar00{
    "name": "symfony/css-selector",
    "type": "library",
    "description": "Symfony CssSelector Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Jean-François Simon",
            "email": "jeanfrancois.simon@sensiolabs.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\CssSelector\\": "" }
    },
    "target-dir": "Symfony/Component/CssSelector",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/CssSelector/Symfony/Component/CssSelector/README.md000064400000002611150431104610017035 0ustar00CssSelector Component
=====================

CssSelector converts CSS selectors to XPath expressions.

The component only goal is to convert CSS selectors to their XPath
equivalents:

    use Symfony\Component\CssSelector\CssSelector;

    print CssSelector::toXPath('div.item > h4 > a');

HTML and XML are different
--------------------------

The `CssSelector` component comes with an `HTML` extension which is enabled by
default. If you need to use this component with `XML` documents, you have to
disable this `HTML` extension. That's because, `HTML` tag & attribute names
are always lower-cased, but case-sensitive in `XML`:

    // disable `HTML` extension:
    CssSelector::disableHtmlExtension();

    // re-enable `HTML` extension:
    CssSelector::enableHtmlExtension();

When the `HTML` extension is enabled, tag names are lower-cased, attribute
names are lower-cased, the following extra pseudo-classes are supported:
`checked`, `link`, `disabled`, `enabled`, `selected`, `invalid`, `hover`,
`visited`, and the `lang()` function is also added.

Resources
---------

This component is a port of the Python lxml library, which is copyright Infrae
and distributed under the BSD license.

Current code is a port of https://github.com/SimonSapin/cssselect@v0.7.1

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/CssSelector/
    $ composer.phar install
    $ phpunit
pear/CssSelector/Symfony/Component/CssSelector/LICENSE000064400000002051150431104610016561 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/EventDispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md000064400000000727150431104630021075 0ustar00CHANGELOG
=========

2.1.0
-----

 * added TraceableEventDispatcherInterface
 * added ContainerAwareEventDispatcher
 * added a reference to the EventDispatcher on the Event
 * added a reference to the Event name on the event
 * added fluid interface to the dispatch() method which now returns the Event
   object
 * added GenericEvent event class
 * added the possibility for subscribers to subscribe several times for the
   same event
 * added ImmutableEventDispatcher
pear/EventDispatcher/Symfony/Component/EventDispatcher/composer.json000064400000001661150431104630022004 0ustar00{
    "name": "symfony/event-dispatcher",
    "type": "library",
    "description": "Symfony EventDispatcher Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/dependency-injection": "~2.0"
    },
    "suggest": {
        "symfony/dependency-injection": "",
        "symfony/http-kernel": ""
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\EventDispatcher\\": "" }
    },
    "target-dir": "Symfony/Component/EventDispatcher",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/EventDispatcher/Symfony/Component/EventDispatcher/README.md000064400000001214150431104630020533 0ustar00EventDispatcher Component
=========================

The Symfony2 EventDispatcher component implements the Mediator pattern in a
simple and effective way to make your projects truly extensible.

    use Symfony\Component\EventDispatcher\EventDispatcher;
    use Symfony\Component\EventDispatcher\Event;

    $dispatcher = new EventDispatcher();

    $dispatcher->addListener('event_name', function (Event $event) {
        // ...
    });

    $dispatcher->dispatch('event_name');

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/EventDispatcher/
    $ composer.phar install
    $ phpunit
pear/EventDispatcher/Symfony/Component/EventDispatcher/LICENSE000064400000002051150431104630020261 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Console/Symfony/Component/Console/CHANGELOG.md000064400000003222150431104650015714 0ustar00CHANGELOG
=========

2.4.0
-----

 * added a way to force terminal dimensions
 * added a convenient method to detect verbosity level
 * [BC BREAK] made descriptors use output instead of returning a string

2.3.0
-----

 * added multiselect support to the select dialog helper
 * added Table Helper for tabular data rendering
 * added support for events in `Application`
 * added a way to normalize EOLs in `ApplicationTester::getDisplay()` and `CommandTester::getDisplay()`
 * added a way to set the progress bar progress via the `setCurrent` method
 * added support for multiple InputOption shortcuts, written as `'-a|-b|-c'`
 * added two additional verbosity levels, VERBOSITY_VERY_VERBOSE and VERBOSITY_DEBUG

2.2.0
-----

 * added support for colorization on Windows via ConEmu
 * add a method to Dialog Helper to ask for a question and hide the response
 * added support for interactive selections in console (DialogHelper::select())
 * added support for autocompletion as you type in Dialog Helper

2.1.0
-----

 * added ConsoleOutputInterface
 * added the possibility to disable a command (Command::isEnabled())
 * added suggestions when a command does not exist
 * added a --raw option to the list command
 * added support for STDERR in the console output class (errors are now sent
   to STDERR)
 * made the defaults (helper set, commands, input definition) in Application
   more easily customizable
 * added support for the shell even if readline is not available
 * added support for process isolation in Symfony shell via
   `--process-isolation` switch
 * added support for `--`, which disables options parsing after that point
   (tokens will be parsed as arguments)
pear/Console/Symfony/Component/Console/composer.json000064400000001545150431104650016633 0ustar00{
    "name": "symfony/console",
    "type": "library",
    "description": "Symfony Console Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/event-dispatcher": "~2.1"
    },
    "suggest": {
        "symfony/event-dispatcher": ""
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Console\\": "" }
    },
    "target-dir": "Symfony/Component/Console",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Console/Symfony/Component/Console/README.md000064400000003647150431104650015375 0ustar00Console Component
=================

Console eases the creation of beautiful and testable command line interfaces.

The Application object manages the CLI application:

    use Symfony\Component\Console\Application;

    $console = new Application();
    $console->run();

The ``run()`` method parses the arguments and options passed on the command
line and executes the right command.

Registering a new command can easily be done via the ``register()`` method,
which returns a ``Command`` instance:

    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Input\InputArgument;
    use Symfony\Component\Console\Input\InputOption;
    use Symfony\Component\Console\Output\OutputInterface;

    $console
        ->register('ls')
        ->setDefinition(array(
            new InputArgument('dir', InputArgument::REQUIRED, 'Directory name'),
        ))
        ->setDescription('Displays the files in the given directory')
        ->setCode(function (InputInterface $input, OutputInterface $output) {
            $dir = $input->getArgument('dir');

            $output->writeln(sprintf('Dir listing for <info>%s</info>', $dir));
        })
    ;

You can also register new commands via classes.

The component provides a lot of features like output coloring, input and
output abstractions (so that you can easily unit-test your commands),
validation, automatic help messages, ...

Tests
-----

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Console/
    $ composer.phar install
    $ phpunit

Third Party
-----------

`Resources/bin/hiddeninput.exe` is a third party binary provided within this
component. Find sources and license at https://github.com/Seldaek/hidden-input.

Resources
---------

[The Console Component](http://symfony.com/doc/current/components/console.html)

[How to create a Console Command](http://symfony.com/doc/current/cookbook/console/console_command.html)
pear/Console/Symfony/Component/Console/LICENSE000064400000002051150431104650015107 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/OptionsResolver/Symfony/Component/OptionsResolver/composer.json000064400000001444150431104650022157 0ustar00{
    "name": "symfony/options-resolver",
    "type": "library",
    "description": "Symfony OptionsResolver Component",
    "keywords": ["options", "config", "configuration"],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\OptionsResolver\\": "" }
    },
    "target-dir": "Symfony/Component/OptionsResolver",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/OptionsResolver/Symfony/Component/OptionsResolver/README.md000064400000006140150431104660020713 0ustar00OptionsResolver Component
=========================

OptionsResolver helps at configuring objects with option arrays.

It supports default values on different levels of your class hierarchy,
option constraints (required vs. optional, allowed values) and lazy options
whose default value depends on the value of another option.

The following example demonstrates a Person class with two required options
"firstName" and "lastName" and two optional options "age" and "gender", where
the default value of "gender" is derived from the passed first name, if
possible, and may only be one of "male" and "female".

    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    use Symfony\Component\OptionsResolver\Options;

    class Person
    {
        protected $options;

        public function __construct(array $options = array())
        {
            $resolver = new OptionsResolver();
            $this->setDefaultOptions($resolver);

            $this->options = $resolver->resolve($options);
        }

        protected function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->setRequired(array(
                'firstName',
                'lastName',
            ));

            $resolver->setDefaults(array(
                'age' => null,
                'gender' => function (Options $options) {
                    if (self::isKnownMaleName($options['firstName'])) {
                        return 'male';
                    }

                    return 'female';
                },
            ));

            $resolver->setAllowedValues(array(
                'gender' => array('male', 'female'),
            ));
        }
    }

We can now easily instantiate a Person object:

    // 'gender' is implicitly set to 'female'
    $person = new Person(array(
        'firstName' => 'Jane',
        'lastName' => 'Doe',
    ));

We can also override the default values of the optional options:

    $person = new Person(array(
        'firstName' => 'Abdullah',
        'lastName' => 'Mogashi',
        'gender' => 'male',
        'age' => 30,
    ));

Options can be added or changed in subclasses by overriding the `setDefaultOptions`
method:

    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\OptionsResolver\Options;

    class Employee extends Person
    {
        protected function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            parent::setDefaultOptions($resolver);

            $resolver->setRequired(array(
                'birthDate',
            ));

            $resolver->setDefaults(array(
                // $previousValue contains the default value configured in the
                // parent class
                'age' => function (Options $options, $previousValue) {
                    return self::calculateAge($options['birthDate']);
                }
            ));
        }
    }



Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/OptionsResolver/
    $ composer.phar install
    $ phpunit
pear/OptionsResolver/Symfony/Component/OptionsResolver/LICENSE000064400000002051150431104660020436 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/Config/Symfony/Component/Config/CHANGELOG.md000064400000001250150431104670015323 0ustar00CHANGELOG
=========

2.2.0
-----

 * added ArrayNodeDefinition::canBeEnabled() and ArrayNodeDefinition::canBeDisabled()
   to ease configuration when some sections are respectively disabled / enabled
   by default.
 * added a `normalizeKeys()` method for array nodes (to avoid key normalization)
 * added numerical type handling for config definitions
 * added convenience methods for optional configuration sections to ArrayNodeDefinition
 * added a utils class for XML manipulations

2.1.0
-----

 * added a way to add documentation on configuration
 * implemented `Serializable` on resources
 * LoaderResolverInterface is now used instead of LoaderResolver for type
   hinting
pear/Config/Symfony/Component/Config/composer.json000064400000001401150431104670016232 0ustar00{
    "name": "symfony/config",
    "type": "library",
    "description": "Symfony Config Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/filesystem": "~2.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Config\\": "" }
    },
    "target-dir": "Symfony/Component/Config",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/Config/Symfony/Component/Config/README.md000064400000000764150431104670015002 0ustar00Config Component
================

Config provides the infrastructure for loading configurations from different
data sources and optionally monitoring these data sources for changes. There
are additional tools for validating, normalizing and handling of defaults that
can optionally be used to convert from different formats to arrays.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Config/
    $ composer.phar install
    $ phpunit

pear/Config/Symfony/Component/Config/LICENSE000064400000002051150431104670014517 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/HttpKernel/Symfony/Component/HttpKernel/CHANGELOG.md000064400000005363150431104670017062 0ustar00CHANGELOG
=========

2.4.0
-----

 * added event listeners for the session
 * added the KernelEvents::FINISH_REQUEST event

2.3.0
-----

 * [BC BREAK] renamed `Symfony\Component\HttpKernel\EventListener\DeprecationLoggerListener` to `Symfony\Component\HttpKernel\EventListener\ErrorsLoggerListener` and changed its constructor
 * deprecated `Symfony\Component\HttpKernel\Debug\ErrorHandler`, `Symfony\Component\HttpKernel\Debug\ExceptionHandler`,
   `Symfony\Component\HttpKernel\Exception\FatalErrorException`, and `Symfony\Component\HttpKernel\Exception\FlattenException`
 * deprecated `Symfony\Component\HttpKernel\Kernel::init()``
 * added the possibility to specify an id an extra attributes to hinclude tags
 * added the collect of data if a controller is a Closure in the Request collector
 * pass exceptions from the ExceptionListener to the logger using the logging context to allow for more
   detailed messages

2.2.0
-----

 * [BC BREAK] the path info for sub-request is now always _fragment (or whatever you configured instead of the default)
 * added Symfony\Component\HttpKernel\EventListener\FragmentListener
 * added Symfony\Component\HttpKernel\UriSigner
 * added Symfony\Component\HttpKernel\FragmentRenderer and rendering strategies (in Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface)
 * added Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel
 * added ControllerReference to create reference of Controllers (used in the FragmentRenderer class)
 * [BC BREAK] renamed TimeDataCollector::getTotalTime() to
   TimeDataCollector::getDuration()
 * updated the MemoryDataCollector to include the memory used in the
   kernel.terminate event listeners
 * moved the Stopwatch classes to a new component
 * added TraceableControllerResolver
 * added TraceableEventDispatcher (removed ContainerAwareTraceableEventDispatcher)
 * added support for WinCache opcode cache in ConfigDataCollector

2.1.0
-----

 * [BC BREAK] the charset is now configured via the Kernel::getCharset() method
 * [BC BREAK] the current locale for the user is not stored anymore in the session
 * added the HTTP method to the profiler storage
 * updated all listeners to implement EventSubscriberInterface
 * added TimeDataCollector
 * added ContainerAwareTraceableEventDispatcher
 * moved TraceableEventDispatcherInterface to the EventDispatcher component
 * added RouterListener, LocaleListener, and StreamedResponseListener
 * added CacheClearerInterface (and ChainCacheClearer)
 * added a kernel.terminate event (via TerminableInterface and PostResponseEvent)
 * added a Stopwatch class
 * added WarmableInterface
 * improved extensibility between bundles
 * added profiler storages for Memcache(d), File-based, MongoDB, Redis
 * moved Filesystem class to its own component
pear/HttpKernel/Symfony/Component/HttpKernel/composer.json000064400000002766150431104700017771 0ustar00{
    "name": "symfony/http-kernel",
    "type": "library",
    "description": "Symfony HttpKernel Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/event-dispatcher": "~2.1",
        "symfony/http-foundation": "~2.4",
        "symfony/debug": "~2.3",
        "psr/log": "~1.0"
    },
    "require-dev": {
        "symfony/browser-kit": "~2.2",
        "symfony/class-loader": "~2.1",
        "symfony/config": "~2.0",
        "symfony/console": "~2.2",
        "symfony/dependency-injection": "~2.0",
        "symfony/finder": "~2.0",
        "symfony/process": "~2.0",
        "symfony/routing": "~2.2",
        "symfony/stopwatch": "~2.2",
        "symfony/templating": "~2.2"
    },
    "suggest": {
        "symfony/browser-kit": "",
        "symfony/class-loader": "",
        "symfony/config": "",
        "symfony/console": "",
        "symfony/dependency-injection": "",
        "symfony/finder": ""
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\HttpKernel\\": "" }
    },
    "target-dir": "Symfony/Component/HttpKernel",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/HttpKernel/Symfony/Component/HttpKernel/README.md000064400000005253150431104710016521 0ustar00HttpKernel Component
====================

HttpKernel provides the building blocks to create flexible and fast HTTP-based
frameworks.

``HttpKernelInterface`` is the core interface of the Symfony2 full-stack
framework:

    interface HttpKernelInterface
    {
        /**
         * Handles a Request to convert it to a Response.
         *
         * @param  Request $request A Request instance
         *
         * @return Response A Response instance
         */
        function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true);
    }

It takes a ``Request`` as an input and should return a ``Response`` as an
output. Using this interface makes your code compatible with all frameworks
using the Symfony2 components. And this will give you many cool features for
free.

Creating a framework based on the Symfony2 components is really easy. Here is
a very simple, but fully-featured framework based on the Symfony2 components:

    $routes = new RouteCollection();
    $routes->add('hello', new Route('/hello', array('_controller' =>
        function (Request $request) {
            return new Response(sprintf("Hello %s", $request->get('name')));
        }
    )));

    $request = Request::createFromGlobals();

    $context = new RequestContext();
    $context->fromRequest($request);

    $matcher = new UrlMatcher($routes, $context);

    $dispatcher = new EventDispatcher();
    $dispatcher->addSubscriber(new RouterListener($matcher));

    $resolver = new ControllerResolver();

    $kernel = new HttpKernel($dispatcher, $resolver);

    $kernel->handle($request)->send();

This is all you need to create a flexible framework with the Symfony2
components.

Want to add an HTTP reverse proxy and benefit from HTTP caching and Edge Side
Includes?

    $kernel = new HttpKernel($dispatcher, $resolver);

    $kernel = new HttpCache($kernel, new Store(__DIR__.'/cache'));

Want to functional test this small framework?

    $client = new Client($kernel);
    $crawler = $client->request('GET', '/hello/Fabien');

    $this->assertEquals('Fabien', $crawler->filter('p > span')->text());

Want nice error pages instead of ugly PHP exceptions?

    $dispatcher->addSubscriber(new ExceptionListener(function (Request $request) {
        $msg = 'Something went wrong! ('.$request->get('exception')->getMessage().')';

        return new Response($msg, 500);
    }));

And that's why the simple looking ``HttpKernelInterface`` is so powerful. It
gives you access to a lot of cool features, ready to be used out of the box,
with no efforts.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/HttpKernel/
    $ composer.phar install
    $ phpunit
pear/HttpKernel/Symfony/Component/HttpKernel/LICENSE000064400000002051150431104720016241 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/ClassLoader/Symfony/Component/ClassLoader/CHANGELOG.md000064400000001224150431104750017301 0ustar00CHANGELOG
=========

2.4.0
-----

 * deprecated the DebugClassLoader as it has been moved to the Debug component instead

2.3.0
-----

 * added a WinCacheClassLoader for WinCache

2.1.0
-----

 * added a DebugClassLoader able to wrap any autoloader providing a findFile
   method
 * added a new ApcClassLoader and XcacheClassLoader using composition to wrap
   other loaders
 * added a new ClassLoader which does not distinguish between namespaced and
   pear-like classes (as the PEAR convention is a subset of PSR-0) and
   supports using Composer's namespace maps
 * added a class map generator
 * added support for loading globally-installed PEAR packages
pear/ClassLoader/Symfony/Component/ClassLoader/composer.json000064400000001455150431104750020220 0ustar00{
    "name": "symfony/class-loader",
    "type": "library",
    "description": "Symfony ClassLoader Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "minimum-stability": "dev",
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/finder": "~2.0"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\ClassLoader\\": "" }
    },
    "target-dir": "Symfony/Component/ClassLoader",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/ClassLoader/Symfony/Component/ClassLoader/README.md000064400000004547150431104750016762 0ustar00ClassLoader Component
=====================

ClassLoader loads your project classes automatically if they follow some
standard PHP conventions.

The Universal ClassLoader is able to autoload classes that implement the PSR-0
standard or the PEAR naming convention.

First, register the autoloader:

    require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';

    use Symfony\Component\ClassLoader\UniversalClassLoader;

    $loader = new UniversalClassLoader();
    $loader->register();

Then, register some namespaces with the `registerNamespace()` method:

    $loader->registerNamespace('Symfony', __DIR__.'/src');
    $loader->registerNamespace('Monolog', __DIR__.'/vendor/monolog/src');

The `registerNamespace()` method takes a namespace prefix and a path where to
look for the classes as arguments.

You can also register a sub-namespaces:

    $loader->registerNamespace('Doctrine\\Common', __DIR__.'/vendor/doctrine-common/lib');

The order of registration is significant and the first registered namespace
takes precedence over later registered one.

You can also register more than one path for a given namespace:

    $loader->registerNamespace('Symfony', array(__DIR__.'/src', __DIR__.'/symfony/src'));

Alternatively, you can use the `registerNamespaces()` method to register more
than one namespace at once:

    $loader->registerNamespaces(array(
        'Symfony'          => array(__DIR__.'/src', __DIR__.'/symfony/src'),
        'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib',
        'Doctrine'         => __DIR__.'/vendor/doctrine/lib',
        'Monolog'          => __DIR__.'/vendor/monolog/src',
    ));

For better performance, you can use the APC based version of the universal
class loader:

    require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
    require_once __DIR__.'/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php';

    use Symfony\Component\ClassLoader\ApcUniversalClassLoader;

    $loader = new ApcUniversalClassLoader('apc.prefix.');

Furthermore, the component provides tools to aggregate classes into a single
file, which is especially useful to improve performance on servers that do not
provide byte caches.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/ClassLoader/
    $ composer.phar install
    $ phpunit
pear/ClassLoader/Symfony/Component/ClassLoader/LICENSE000064400000002051150431104760016475 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
pear/DependencyInjection/Symfony/Component/DependencyInjection/CHANGELOG.md000064400000001643150431104760022561 0ustar00CHANGELOG
=========

2.4.0
-----

 * added support for expressions in service definitions
 * added ContainerAwareTrait to add default container aware behavior to a class

2.2.0
-----

 * added Extension::isConfigEnabled() to ease working with enableable configurations
 * added an Extension base class with sensible defaults to be used in conjunction
   with the Config component.
 * added PrependExtensionInterface (to be able to allow extensions to prepend
   application configuration settings for any Bundle)

2.1.0
-----

 * added IntrospectableContainerInterface (to be able to check if a service
   has been initialized or not)
 * added ConfigurationExtensionInterface
 * added Definition::clearTag()
 * component exceptions that inherit base SPL classes are now used exclusively
   (this includes dumped containers)
 * [BC BREAK] fixed unescaping of class arguments, method
   ParameterBag::unescapeValue() was made public
pear/DependencyInjection/Symfony/Component/DependencyInjection/composer.json000064400000002103150431104760023462 0ustar00{
    "name": "symfony/dependency-injection",
    "type": "library",
    "description": "Symfony DependencyInjection Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/yaml": "~2.0",
        "symfony/config": "~2.2",
        "symfony/expression-language": "~2.4"
    },
    "suggest": {
        "symfony/yaml": "",
        "symfony/config": "",
        "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\DependencyInjection\\": "" }
    },
    "target-dir": "Symfony/Component/DependencyInjection",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.4-dev"
        }
    }
}
pear/DependencyInjection/Symfony/Component/DependencyInjection/README.md000064400000003311150431104760022221 0ustar00DependencyInjection Component
=============================

DependencyInjection manages your services via a robust and flexible Dependency
Injection Container.

Here is a simple example that shows how to register services and parameters:

    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\DependencyInjection\Reference;

    $sc = new ContainerBuilder();
    $sc
        ->register('foo', '%foo.class%')
        ->addArgument(new Reference('bar'))
    ;
    $sc->setParameter('foo.class', 'Foo');

    $sc->get('foo');

Method Calls (Setter Injection):

    $sc = new ContainerBuilder();

    $sc
        ->register('bar', '%bar.class%')
        ->addMethodCall('setFoo', array(new Reference('foo')))
    ;
    $sc->setParameter('bar.class', 'Bar');

    $sc->get('bar');

Factory Class:

If your service is retrieved by calling a static method:

    $sc = new ContainerBuilder();

    $sc
        ->register('bar', '%bar.class%')
        ->setFactoryClass('%bar.class%')
        ->setFactoryMethod('getInstance')
        ->addArgument('Aarrg!!!')
    ;
    $sc->setParameter('bar.class', 'Bar');

    $sc->get('bar');

File Include:

For some services, especially those that are difficult or impossible to
autoload, you may need the container to include a file before
instantiating your class.

    $sc = new ContainerBuilder();

    $sc
        ->register('bar', '%bar.class%')
        ->setFile('/path/to/file')
        ->addArgument('Aarrg!!!')
    ;
    $sc->setParameter('bar.class', 'Bar');

    $sc->get('bar');

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/DependencyInjection/
    $ composer.phar install
    $ phpunit
pear/DependencyInjection/Symfony/Component/DependencyInjection/LICENSE000064400000002051150431104760021747 0ustar00Copyright (c) 2004-2014 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
alt-php73-snuffleupagus/README.md000064400000014667150464067770012465 0ustar00<h1 align="center">
  <br>
  <a href="https://snuffleupagus.readthedocs.io/">
    <img src="https://github.com/jvoisin/snuffleupagus/raw/master/doc/source/_static/sp.png" alt="Snuffleupagus' logo" width="200"></a>
  <br>
  Snuffleupagus
  <br>
</h1>

<h4 align="center">Security module for php7 and php8 - Killing bugclasses and virtual-patching the rest!</h4>

<p align="center">
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml/badge.svg"
         alt="Testing PHP7 on various Linux distributions" />
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml/badge.svg"
         alt="Testing PHP8 on various Linux distributions" />
  </a>
  <a href="https://scan.coverity.com/projects/jvoisin-snuffleupagus">
    <img src="https://scan.coverity.com/projects/13821/badge.svg?flat=1"
         alt="Coverity">
  </a>
  <a href="https://bestpractices.coreinfrastructure.org/projects/1267">
      <img src="https://bestpractices.coreinfrastructure.org/projects/1267/badge"
           alt="CII Best Practises">
  </a>
  <a href="http://snuffleupagus.readthedocs.io/?badge=latest">
    <img src="https://readthedocs.org/projects/snuffleupagus/badge/?version=latest"
         alt="readthedocs.org">
  </a>
  <a href="https://coveralls.io/github/jvoisin/snuffleupagus?branch=master">
    <img src="https://coveralls.io/repos/github/jvoisin/snuffleupagus/badge.svg?branch=master"
         alt="coveralls">
  </a>
  <a href="https://twitter.com/dustriorg">
    <img src="https://img.shields.io/badge/twitter-follow-blue.svg"
         alt="twitter">
  </a>
  <a href="https://repology.org/project/php:snuffleupagus/versions">
    <img src="https://repology.org/badge/tiny-repos/php:snuffleupagus.svg"
         alt="Packaging status">
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/codeql-analysis.yml/badge.svg"
         alt="CodeQL">
  </a>
</p>

<p align="center">
  <a href="#key-features">Key Features</a> •
  <a href="#download">Download</a> •
  <a href="#examples">Examples</a> •
  <a href="https://snuffleupagus.readthedocs.io/">Documentation</a> •
  <a href="https://github.com/jvoisin/snuffleupagus/blob/master/LICENSE">License</a> •
  <a href="#thanks">Thanks</a>
</p>

Snuffleupagus is a [PHP 7+ and 8+](https://secure.php.net/) module designed to
drastically raise the cost of attacks against websites, by killing entire bug
classes. It also provides a powerful virtual-patching system, allowing
administrator to fix specific vulnerabilities and audit suspicious behaviours
without having to touch the PHP code.

## Key Features

* No [noticeable performance impact](https://dustri.org/b/snuffleupagus-030-dentalium-elephantinum.html)
* Powerful yet simple to write virtual-patching rules
* Killing several classes of vulnerabilities
  * [Unserialize-based](https://www.owasp.org/images/9/9e/Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits.pdf) code execution
  * [`mail`-based]( https://blog.ripstech.com/2016/roundcube-command-execution-via-email/ ) code execution
  * Cookie-stealing [XSS]( https://en.wikipedia.org/wiki/Cross-site_scripting )
  * File-upload based code execution
  * Weak PRNG
  * [XXE]( https://en.wikipedia.org/wiki/XML_external_entity_attack )
  * Filter based remote code execution and assorted shenanigans
* Several hardening features
  * Automatic `secure` and `samesite` flag for cookies
  * Bundled set of rules to detect post-compromissions behaviours
  * Global [strict mode]( https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations) and type-juggling prevention
  * Whitelisting of [stream wrappers](https://secure.php.net/manual/en/intro.stream.php)
  * Preventing writeable files execution
  * Whitelist/blacklist for `eval`
  * Enforcing TLS certificate validation when using [curl](https://secure.php.net/manual/en/book.curl.php)
  * Request dumping capability
* A relatively sane code base:
  * A [comprehensive](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master) test suite close to 100% coverage
  * Every commit is tested on [several distributions](https://gitlab.com/jvoisin/snuffleupagus/pipelines)
  * An `clang-format`-enforced code style
  * A [comprehensive documentation](https://snuffleupagus.rtfd.io)
  * Usage of [coverity](https://scan.coverity.com/projects/jvoisin-snuffleupagus), codeql, [scan-build](https://clang-analyzer.llvm.org/scan-build.html), …

## Download

We've got a [download
page](https://snuffleupagus.readthedocs.io/download.html), where you can find
packages for your distribution, but you can of course just `git clone` this
repo, or check the releases on [github](https://github.com/jvoisin/snuffleupagus/releases).

## Examples

We're providing [various example rules](https://github.com/jvoisin/snuffleupagus/tree/master/config),
that are looking like this:

```python
# Harden the `chmod` function
sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop();

# Mitigate command injection in `system`
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n]").drop();
```

Upon violation of a rule, you should see lines like this in your logs:

```python
[snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in /var/www/index.php:2, because the return value (0) of the function 'strpos' matched a rule.
```

## Documentation

We've got a [comprehensive website](https://snuffleupagus.readthedocs.io/) with
all the documentation that you could possibly wish for. You can of course
[build it yourself](https://github.com/jvoisin/snuffleupagus/tree/master/doc).

## Thanks

Many thanks to:

- The [Suhosin project](https://suhosin.org) for being a __huge__ source of inspiration
- [NBS System](https://www.nbs-system.com) for initially sponsoring the development
- [Suhosin-ng](https://github.com/sektioneins/suhosin-ng) for their
  [experimentations](https://github.com/sektioneins/suhosin-ng/wiki/News)
  and [contributions](https://github.com/jvoisin/snuffleupagus/commits?author=bef),
  as well as [NLNet](https://nlnet.nl/project/Suhosin-NG/) for sponsoring it
- All [our contributors](https://github.com/jvoisin/snuffleupagus/graphs/contributors)

alt-php73-snuffleupagus/CONTRIBUTING.md000064400000013046150464067770013425 0ustar00## Contributing

First off, thank you for considering contributing to snuffleupagus.

### 1. Where do I go from here?

If you've noticed a bug or have a question,
look at the [faq](https://snuffleupagus.readthedocs.io/faq.html) and
[search the issue tracker](https://github.com/jvoisin/snuffleupagus/issues)
to see if someone else has already created a ticket. If not, go ahead and
[make one](https://github.com/jvoisin/snuffleupagus/issues/new)!

### 2. Fork & create a branch

If this is something you think you can fix,
then [fork snuffleupagus](https://help.github.com/articles/fork-a-repo) and
create a branch with a descriptive name.

A good branch name would be (where issue #325 is the ticket you're working on):

```sh
git checkout -b 325-kill-sql-injections
```

### 3. Get the test suite running

Just type `make coverage` or `make debug`, the testsuite should be run
automatically.

Please add tests if you're fixing a bug or adding a new feature: we do have a
[high coverage](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master)
(functions, lines and branches), and intend to keep it that way.

#### 3.3 Debugging failures in the test suite

If your changes have introduced run-time failures in the test-suite, you can
easily troubleshoot them by inspecting the files that
[php has generated](https://qa.php.net/write-test.php#analyzing-failing-tests)
for this purpose.

A nice trick is to edit the `.sh` file to prepend `gdb --args` to it before
launching it, in order to run the failing test inside GDB.


### 4. Did you find a bug?

* **Ensure the bug was not already reported** by
  [searching all issues](https://github.com/jvoisin/snuffleupagus/issues?q=).
* If you're unable to find an open issue addressing the problem,
  [open a new one](https://github.com/jvoisin/snuffleupagus/issues/new).
  Be sure to include a **title and clear description**,
  as much relevant information as possible, and a **code sample**
  or an **executable test case** demonstrating the expected behavior that is not
  occurring.


### 5. Get the style right

Your patch should follow the same conventions & pass the same code quality
checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to
ensure a consistent code-style. Please run it with `clang-format --style="{BasedOnStyle: google, SortIncludes: false}"`
before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format).

### 6. Make a Pull Request

At this point, you should switch back to your master branch and make sure it's
up to date with our upstream master branch:

```sh
git remote add upstream git@github.com:jvoisin/snuffleupagus.git
git checkout master
git pull upstream master
```

Then update your feature branch from your local copy of master, and push it!

```sh
git checkout 325-kill-sql-injections
git rebase master
git push --set-upstream origin 325-kill-sql-injections
```

Finally, go to GitHub and [make a Pull Request](https://help.github.com/articles/creating-a-pull-request) :D

Travis CI will [run our test suite](https://travis-ci.org/jvoisin/snuffleupagus)
against all supported PHP versions. We care about quality, so your PR won't be
merged until all tests pass. It's unlikely, but it's possible that your changes
pass tests in one PHP version but fail in another. In that case, you'll have to
setup your development environment to use the problematic PHP version, and
investigate what's going on!

### 7. Keeping your Pull Request updated

If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
has changed, and that you need to update your branch so it's easier to merge.

To learn more about rebasing in Git, there are a lot of [good](http://git-scm.com/book/en/Git-Branching-Rebasing)
[resources](https://help.github.com/articles/interactive-rebase) but here's the suggested workflow:

```sh
git checkout 325-kill-sql-injections
git pull --rebase upstream master
git push --force-with-lease 325-kill-sql-injections
```

### 8. Merging a PR (maintainers only)

A PR can only be merged into master by a maintainer if:

1. It is passing CI.
2. It has been approved by at least one maintainer. If it was a maintainer who
   opened the PR, only one extra approval is needed.
3. It has no requested changes.
4. It is up to date with current master.

Any maintainer is allowed to merge a PR if all of these conditions are met.

### 9. Shipping a release (maintainers only)

Maintainers need to do the following to push out a release:

1. Make sure that all pending and mergeable pull requests are in
2. Close the corresponding
	 [milestone](https://github.com/jvoisin/snuffleupagus/milestones)
2. Run `valgrind` (by adding a `-m` after the `-q` in the Makefile) and check that everything is ok.
   Don't mind the python-related issues.
2. Run `cd src; phpize; ./configure --enable-snuffleupagus --enable-debug; scan-build make`
   and fix the possible issues.
3. Update the `src/php_snuffleupagus.h` according to [semantic versioning](https://semver.org/)
4. Update the changelog page in the documentation
5. Update the Debian changelog in `./debian/changelog` with `cd debian; dch`
6. Commit the result
7. Clean up the folder `make clean; git clean -xdf`
8. Create a tag for the release:

  ```sh
  git tag -s v$MAJOR.$MINOR.$PATCH -m "v$MAJOR.$MINOR.$PATCH"
  git push --tags
	git push origin master
  ```

9. Wait for the CI on the new tag branch to finish
10. Create the [release on github](https://github.com/jvoisin/snuffleupagus/releases)
11. Add the freshly built Debian packages from the CI to the release
12. Do the *secret release dance*
alt-php73-ioncube-loader/USER-GUIDE.txt000064400000026060150464070010013324 0ustar00ionCube Loader 14.4 User Guide
=====================================

This document describes the available php.ini configuration options of the
ionCube Loader that relate to processing of PHP encoded files, and also the
ionCube24 service. It also describes which encoded files can be run by each
ionCube Loader.

PERFORMANCE OF ENCODED FILES
----------------------------

We recommend that the encoded paths feature (see below) is used 
with encoded files in order to maximise performance.

ENCODED FILES  
-------------

INI entry: ioncube.loader.encoded_paths

Purpose:   Specify the locations of encoded files

  The ionCube Loader will normally examine a PHP file before processing
  to test whether it is encoded, and will run the file itself if necessary.
  Although this checking is very efficient, restricting which files the
  Loader tests for being encoded may give extra performance. If set to 
  a series of paths or files, only files in those locations are tested.

  Entries should be separated by a : on Unix and ; on Windows. 
  A path may be prefixed with + or - to add or remove that path from
  the possible locations. + is assumed if no character is given.


Examples: (... means ioncube.loader.encoded_paths)

  * Site with a single encoded module in /var/www/html/modules/RSS

... = "/var/www/html/modules/RSS"


  * As above, with a site configuration file encoded too.

... = "/var/www/html/modules/RSS:/var/www/html/config/config.php"


  * Encoded files may be anywhere except for /var/www/html/framework

... = "/:-/var/www/html/framework"


  * Site with most modules encoded except for one

... = "/var/www/html/modules:-/var/www/html/modules/plain"


  * As above, with an encoded config file in the plain directory

... = "/site/modules:-/site/modules/plain:/site/modules/plain/config.php"


Locations:

  The ioncube.loader.encoded_paths property can be set in a php.ini
  file, in a .htaccess file (when using Apache), in a .user.ini file
  (when using CGI PHP 5.3+) or using ini_set within a PHP script. In ini
  files only the last value will be used for the encoded_paths property. If
  you wish to build up the value in several lines then, for PHP 5.1+, you
  can use the following syntax:

ioncube.loader.encoded_paths = "/path1"  
ioncube.loader.encoded_paths = ${ioncube.loader.encoded_paths}":/path2"  
; etc...

LIMITATIONS OF LOADERS AND ENCODED FILES
----------------------------------------

Encoded files can, in general, run on versions of PHP equal to
or greater than the source language of the Encoder used to
produce them. So a file produced by the Encoder for PHP 7.2
can be run by the Loaders for PHP 7.2, 7.3 and 7.4, but 7.1. This 
means that the Loaders offer good backwards compatibility, 
however there are the following limitations:

  * The Loader for PHP 8.3 can run files produced by the PHP 8.2 and
    8.3 Encoders.

  * The Loader for PHP 8.2 can only run files produced for
    PHP 8.2. Updates for files produced for PHP 8.1 should
    be obtained to use them with PHP 8.2.

  * The Loader for PHP 8.1 can only run files produced for
    PHP 8.1.

  * The Loaders for PHP 7.1 through 7.4 can only run files 
    produced by the Encoders for PHP 7. 

  * The Loader for PHP 7.0 can only run files produced by the
    Encoder for PHP 5.6.

  * The Loaders for PHP 5.5 and PHP 5.6 cannot run files 
    produced by the PHP 4 Encoder.


IONCUBE24 : real-time intrusion protection and PHP error reporting
---------
### (Available for Linux 32 and 64 bit x86 servers using PHP 7)

ionCube24 (https://ioncube24.com) is an ionCube service that uses the
ionCube Loader to provide both real-time protection against the exploit of
website vulnerabilities and alerting of website errors.

Vulnerabilities in PHP applications are common, particularly in sites using 
Wordpress and other plugin based systems. Exploits result in website
defacement or customer data being compromised, and ionCube24 provides a 
uniquely powerful defense. 

PHP errors can cause intermittent or even persistent blank pages or errors for
visitors until discovered, and without active monitoring this could go
undetected indefinitely. ionCube24 active monitoring ensures you are always
aware of problems in your website code.

ionCube24 is free to try, with the server side support built into the Linux
Loaders as standard. With the Loader installed, ionCube24 can be activated
at any time to give active intrusion protection and error reporting.

## php.ini settings

ionCube24 has a powerful real-time web interface to configure, monitor and
manage things, and there are also settings that can be used in a php.ini
file as summarised below.

The setup process at https://ioncube24.com automatically gives the settings
that you need to get started, but you may wish to make changes yourself
once setup. The default values are given with each example.

### Global settings

INI entry: ic24.enable ; default 0

Purpose: Enable or disable all ionCube24 features. 

This defaults to 0 (off), and in this case no ionCube24 behaviour is
activated.

Example:

  ic24.enable = 1

----------

INI entry: ic24.api_access_key ; provided during setup

Purpose: An authentication key for adminstration requests. 

  This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.api_check_ip ; default 1

Purpose: Specify whether the IP for admin requests should be validated

  If set, ionCube24 refuses access to API functions unless the calling IP
  is a known ionCube IP address. This option should be left with the
  default setting unless web requests pass through a proxy and your site
  appears to be accessed from the IP of the proxy instead of ionCube. Note
  that access to API functions will still be authenticated by access key.

----------

INI entry: ic24.api_max_timeout ; default 7

Purpose: Maximum timeout period when sending notifications to ionCube24.

  The actual period is adaptive so that a brief increase in typical latency
  will favour a timeout followed by a retry rather than a longer than usual
  timeout.

----------

INI entry: ic24.home_dir ; no default

Purpose: The home directory for ionCube24 related system files. 

  A location outside of the web root is recommended.  It should be writable
  by the web server during startup.

Example:

ic24.home_dir = /var/www/ic24_home

----------

INI entry: ic24.update_domains_retry_interval ; default 30

Purpose: The number of seconds to wait before retrying a fetch of the set
of domains being managed.


### Security related settings

INI entry: ic24.sec.enable ; default "auto"

Purpose: Enable the intrusion protection feature of ionCube24.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

INI entry: ic24.sec.initial_state ; default 1

Purpose: The default for whether security should be enabled or
disabled. The default is to enable protection. Any files on a protected
domain will become blocked if they are changed, so setting this to 0 will
avoid accidental blocking when using ionCube24 for the first time.
Protection may be enabled and disabled using the ionCube24 control panel and
also via the User API.

Accepted values:

   * 1 : protection will be active when ionCube24 initialises.
   * 0 : protection will be disabled.

----------

INI entry: ic24.sec.initial_action ; default "block"

Purpose: The initial setting for how new and modified files should be
treated when about to execute. The default is to block. The action is taken
only if protection is enabled, and the setting may be changed via the
ionCube24 control panel.

Accepted values:

   * "block" : prevent execution of new or modified files
   * "allow" : allow execution of new or modified files

Note that depending on the notification settings, a notification may still
be generated when a new or modified file is about to execute even if it is
not blocked.

----------

INI entry: ic24.sec.initial_notify ; default "always"

Purpose: The initial setting for whether a notification is generated the 
first time an unacknowledged new or modified file is attempted to be
executed. This setting can be changed via the ionCube24 control panel.

Accepted values:

   * "always" : always notify of a new modification 
   * "once"   : only the first detected modification is reported
   * "never"  : never notify of new and modified files

----------

INI entry: ic24.sec.exclusion_key ; provided during setup

Purpose: A key that if present at the start of a file, will identify the
file as trusted. This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.sec.trusted_include_paths ; no default

Purpose: List paths from where files can be included and automatically
trusted.

Example:

ic24.sec.trusted_include_paths = "/var/cache:/var/cache2"

Directories can be excluded from the list by prefixing with a minus
character -. e.g.

"/var/cache:-/var/cache/subdir"

This is useful if your site creates and/or modifies files by itself from
time to time, e.g. in a cache directory. Requests that *directly* access
files on a trusted include path will be blocked but the file itself will
not be blocked, so requests that use the file as intended will still work.
See ioncube24.com for more details once signed up.  As an alternative, if
possible we recommend producing files that include the exclusion key.

----------

INI entry: ic24.sec.block_uploaded_files ; default 1

Purpose: If set, block any uploaded files in ionCube24 that are processed
using the standard PHP mechanism for uploaded files. This applies even if
the file is subsequently included and where included files being
automatically approved with the previous setting.

----------

INI entry: ic24.sec.block_stdin ; default 1

Purpose: Refuse code that PHP sees via stdin.  If disabled, code via
stdin will run without security checking as there is no filepath. This
setting should be left on as PHP would normally never receive a script via
stdin.

### PHP Error reporting settings

INI entry: ic24.phperr.enable ; default "auto"

Purpose: Enable reporting of PHP errors to ionCube24.  When enabled, any
non-ignored errors are reported to ionCube24 in realtime, triggering
alerting so errors can be investigated as necessary.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

### Deprecated settings

Deprecated settings are subject to removal in a future
release.

INI entry: ic24.phperr.ignore ; default 0

Purpose: Specify default error levels to always ignore for all domains.

Note that default and per-domain errors to ignore can also be set via the
web interface, and are combined with this setting. Leaving this unset and
using the web interface is recommended for maximum flexibility.

Example: 

ic24.phperr.ignore = E_NOTICE | E_DEPRECATED

(c) ionCube Ltd. 2025
alt-php73-ioncube-loader/USER-GUIDE.pdf000064400000115466150464070010013267 0ustar00%PDF-1.4
1 0 obj
<<
/Title (��Markdown To PDF)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20250130155421Z)
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 33  
813.500000  0]
endobj
9 0 obj
[0 /XYZ 33  
749.750000  0]
endobj
10 0 obj
[0 /XYZ 33  
700.250000  0]
endobj
11 0 obj
[0 /XYZ 33  
131.750000  0]
endobj
12 0 obj
[0 /XYZ 33  
296  0]
endobj
13 0 obj
[0 /XYZ 33  
97.2500000  0]
endobj
14 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [71.2500000  66.5000000  144.750000  75.5000000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 15 0 R
/Resources 17 0 R
/Annots 18 0 R
/MediaBox [0 0 595 842]
>>
endobj
17 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
18 0 obj
[ 14 0 R ]
endobj
15 0 obj
<<
/Length 16 0 R
/Filter /FlateDecode
>>
stream
x��][��8v~�_��FI���@w� �0l A�l���8;��Ϗ.TU�򱪾�(���H�\lR���_�ۗo��#y����|�r�RSd�I���ej�'�P�{��Ï�����s�����~�n�|���{ޡ������/�ɿ��{�_�]��.���#L�,/������Sd�Nu%���=������O�o�>���2)�T������魞�eZ	�s�e�]y��J7ߕ�5X��}�I.����/�ߟ���ㄪ�>Oʰ�WVEXx
=��12����E��?�fy���C���}�5eH��5�^���k���N��%y����׿tjJ!����َ�"�t��ӈ�Gre�s�n�L��)�s��ӈ�GL��=�FL7���,�#��u5yNկ�������|�[�k��ҎTi�=�]<>g<�
G>�#&UE���w ���D�o*D����
aϧ�����Ont)�}���o��ɻ�����/_���ɇ��Ǘ���xy��y�������sf}��6��&-��.#�wV�-�Ϡ��7��t�w�i5����Av
u٣�N5����}�i9>wQ�9�z�v-�-�Ң{��y�TM�K�պ9j
�M�0D0�p?O�|Lg��Y�����a`�9�
�����SL�I7�H˞]��
B�a�X���x�ρ��s,�WSJ�*xs�`����q���-��}���;�ۈqS7���i/ƪ@���~��S1���[^o&�'�^�/8ާ�s�B�+y�����q��6s�1��1w&8�co�����&��:���b�"��eBѷ��R�)g#�fW���x�c׌��H��s0�������ɮ�EVv�:�a�Y
�|��>2��ءӜ�ַ֊��El��|�_w�{�N��A<����v�V)a��-�ë��lr
�E
��Z��-e�`�->S��Y��xݵT�^k�;�
�1M�{�v��w��:I#�(@�(Yw\-t�9]�����4b�Tr:��9cG�<:�&� ^�CQ�j�t�U��	S|�3A�8g��M�^���c�@8Vðf���c��5;�s��@�9�>!�ٽ�5{�����%)�&ěpW7aMW�g7c�R��<����&M��o�ףO��{�Y��Ms���|�tFs�Z-��`�b|����~��z�?��^���{��G~�����o���bN�ҝ[�V���5t��8�q�f5*؈p�:H��a��K�u���–n_��99��F���] p�9��\rSݟ�LfG��Օ�6��` 1|���=ę0 <dz���#��ص�.�#��1J���*K�|�ɔU��T}���=��(��DT��?6��3��)Z���1��xG69Qp$�#�p���T�<��gbo/Į�j��2��|�#��?����������8*I�d�.6��u4r��Y&iRqC�
c���
��PF\Ƥń�<N"H�����,�U�щ�d�>L��N���L����4�шy��w�!�5a<t��k���2���g?�W�g��e�-镫��� @'-��~�7�?�$�h0W�.��-��m@$
�XL�^�3�
��ǁ��L�T(A����e�n����v�W��7����U��\KL�q,����j�^Y!��D���a�M����`p	n��$N&$0�J5��?",�~}�����3��d츮�M���rb�#�($fR��>m��~��E�ofw(n�K�ox,��ŰƄ�H�Z�)&�X�c�n�
3L]0�|�5���x� �b�X�Zڈ��׏��r�_��TK�WL$�W��p���,�9�&F�Q6ܾ����*u��կ9���?���{Z�ߙ���5� �u�_�9��L�O�!h��IH�˴{UN=K�$���ue��B&Bm?ץ��9���b$k�<Я��l���t�!:98"�D�Ah��� ���i㣗4J�r
�v�<b�x�U���9ۊ����E*��__�_ߚ�Y�a�T��[�b{h�l	������"���/MV
��L�/Y����1��1�s~�1�
��Ռ"�׿�Pu�ٰQΫ�p5ח/0oe2J�.�)�^��i�9�TM�&��cE�JkY�?��~��2/Êaeq��r4n).c<C��fD�P�L���ע��φʋc<8�½0�p��Y�k���7�х�k �Ţ7s֍�ni��;�%�҉���vF�c���ե����t��Y��oZ�Se�f��L'r18�X�.��s��K�)Y
8�\�`��v+�i+�$�RɯݗZ���BW��[^��(i���RiY�ʺ��T�V�W�a�2��Z����gԿ��$c���OA����cp�TG�_ ����7N�k����I�a��ğ�-�v)� P�H��\�0;�d��"h�2�W�� �x1��Ȓl�fpıF�âO�s�
(T;�⁀��#�L�I^�l��֯�hT�߮K��J(;�@A9ҒHKV�%Gߪ�T��<���y*��)��<��j0I�ku:OY��<eծUu��w3�d�ZK�<U�k�<��|�5�ɡ{�˯�JiCX�b��dži����~�,�җ��6<rf� �"Kr�7R#��,�(�F�7����aq4�R�.�7p��*�j��vPL��jx�ձ�M�:y9�:��Q��������T�V�:y1�:m|d�1P���`��k-�:���L���
2�g�C�w��߮T�6��5��cr3����-gtR4�7�r�J�4�9ጲZ8Y�!��(,�3Z�m���&E�KV&�n�������)�;����L�2o�2�iP�Vm~��
Jg��z������T�V�A�L�hP�M�o?T��L2v��5�ZH��i��¶8�8
��n�q)p����e!R�<i�B��*�iE�����Y���U��
;�p���� ��U~�m#���ԺS4�(b��]
&�v�Ni)�"�_۵�Q�`��L2v���#O#�MT�ՇQ6���r��֧r@��0p`/~Sj���B(��pձ��0�}�����9b��`�8/�M(��j�S�?Մ��xpx�6���|�v�E3R���.��,�Bԇ4y_�ƶ�03��؝yqY��f�Njj��豤��XǒZ^RK6U�Ϯ�ߖ�a�m�Y	�ӓ`f�ud��s�k߳�hޚ*�
�k�qo�����z�5$�����W��3�k���L*m��|�75/:QT��QS�i����T��bANx��(,~��VLW	'�;�l%�Z8��fn1WGe*^�v�3�s��ֶ�l�Uc�1�cKR��vC�u9��ܤ�;��~��M
[&��g��%_Y8P������IM5V�;��Sk�pT�3]��ϱxw6�j�SL��F��
|� S=`�=��k��T*GsT��b��i�V2T7��j&��G�	#�ln2�R�s�@�i<z����ʉ~����d�0�bB�O��m��"pC0�bN���K=���$���"m���F�{�|��C�P�	�8*��W6
����u��C�����W�2��gn����׳B�
��2_��a�*B\칺 k�@Fv�2FpL���g̼��L�C�1ta��3�Y�H���-�Ӊ��"!�*O>�9�.�[�J��c�p@���K��:u�%�ʑ]�E.j�4�WaY�W�R(�j����׃O�q)��1WF:����i*��=�ƛ��X�-��g1f޽����ύ��J
'V�%����ȓ��UO)���"�0R�s$<�O!ެx���fI3����A0	�?��^뵽�f��i��'�}���a�&lM�42,��
]ji��2�>t���ˠ��`�j�S�c)����;���&U�ݑ�2U���c�慜T���B����֡��ӉM��Y��ϱ���Y�XA�st�bނ6����s ��s?b]Gc�^?����)zLF���S��v<�|�����ݦ0��2�qc�w��왎(û/��-y�>y��~�����#y�!��!y��r0in-���D
)H� ��?�\_�سtY�b����1@ԭ_��)����($����Y3�`���D29K^˕1p�5�b����Mo����7��I~����`�ôue
�1��op��0�`�!�n3QA�V
���P!%��fxp(:�6-Æ��+E{��~���{~�W�v4 d�'pSI�o3ɳ��"�)�1I0�"pN�ΰ*�WRw!�}4�
!����9wV�4�a+d�6�u���S�x�w�1�1;���(��F�}3�s��Q&#�)�@�)LUbc���e�oQ��D���y����lQ�7"�
fQw0<�B3�yaX3�>C6�Ҭ��[fF%`�lw0D�z�fb܁��o]�G
�c� 
�a�"_��gS���`��d^����7#m^z��f��X|1}�sa�HP���,㛹W�욹W��i�^�YӀ��4soW�I�]�m�^=�̽��]��4so7�IƮ�p3��T�`��l;��~s��������n:�0��6m����f�.�,��h�>��J1�vw�x$���G�7+���G���j�ρ�ԍ��<խ��H�7���p��멡�ԍ��<ӯ���T?�/�((�'���ի}GQ�D�H��q^fv�f��
c>9����� ҃M�G0�-��gxැ�ߐ9�>�9�e�o��c�YX���*|��T��;�7�
��M�F?c*Py��ן#SA3��T��5�l�T�2�^66t>��y�_oqS��+'FSA�� �
�j�h��.��E�l�Ekѱ�sĢ�5����,�.��.�w�0c݌��<ӯ�8��}٭Ȣ7n��pBżm�!��84F����z\UjD�F��g��݅`D��Mp-u/��fNp-�N�,˱�ڌ��<խg�2�\Kk�*��ڌ��<ӯ���Z)
��z9�,��D1��Ĭ��-Eq(�8�@T�h��^.�y��$�������$D�
6��PPjG�`�������A��Ϯ'F�R;b�L��҂�&
Joc�欞�i�a"J��#8{��)�pb��:=��Q<ݴx�6:�/ة�|���jѲ��~[�&26N���ĝ>�#CnԒ�#�<;�F��&�rA1���d}5����w0���~$���
�t5�ڟ�$����r�PI��(�2U5�f��9�V7
{̰�c���q�1�v ����r�M�j��p��	�~�t�X:)�v��f1�:��=�#�3ŧp�!R�`�h��x|K�ix��"9����o�R���_ds��E6�\ds��m��{N��0
�Fy,�!{J�O��������I���ޜr�gK�Z�p���jڎ��~s�;g�;UZ���0XLM-Y�g�s�i5D��s�9ֽQ���s��Kp&����gT��nE�k�f���=���33#�7�g�����z�x�w���J�����	JR����zB�v�)�ka���
Ʒⵃ0�����X��Y����Ǟ�NL�G���9ܩ�O��e!�E�Fd�aD��X��\0�$�����S�kk�qo�"��Ҋ��q��|�5�������Yϭ��T59(j�p仼��W���=��A;�Nw<.=�A5�]�<���kF<�j��+��y�*�GT�'e���w�����7bo[&�L�.*���SN[����k#/���53c����.l9H:T96�a�=����#Bm�"T&L�`ج��T��M�p�f����)�
�L�VA���h��@����[Y�9֬SLu
�VC4ᢚVy��{��$�5.U��!�������Sl�)����ɫ��t��k��$��RzQ����x��{ʤ���3΂��������'��H�@����EaJ�%0F6c�JnJ�H�]~=���z$�K��o�=	�R�4�yp`<�k��i�R�@�u�[�ނ�@���< ��p�g��XL���Nل��ݴ>���׮�pc���_j�1�g|`LQ�L�)�Ѷ�>rS0��e�E)��*F�,�^���Y�ê����2X��j��wai�EU]�!�1~T�4^�E"�n���4��ӳ���W�1��r"�Fg&��2��oh�>#.<kU˗��ŀwP�ptk��]�s0l�Zk�����	�F��+����S�>��K~8�|z;�*�~N>�I�˙
endstream
endobj
16 0 obj
6379
endobj
20 0 obj
[1 /XYZ 33  
760.250000  0]
endobj
21 0 obj
[1 /XYZ 33  
672.500000  0]
endobj
22 0 obj
[1 /XYZ 33  
158.750000  0]
endobj
23 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [102  696.500000  175.500000  705.500000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
19 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 24 0 R
/Resources 26 0 R
/Annots 27 0 R
/MediaBox [0 0 595 842]
>>
endobj
26 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
27 0 obj
[ 23 0 R ]
endobj
24 0 obj
<<
/Length 25 0 R
/Filter /FlateDecode
>>
stream
x��][k�H~�_��Ȫ*�.`�maaL���C�dv���d��+�JmK꯺��QIrk㶫���:��\��o>F��#����-zr?o>l�8�I�_T�{������P�}���l�G�7����7���x���h��4�p���"�����_��~�����e��<�_�l��痿�$��TeQ�=�Z���?��V�H�"I�6ڨf,��߽x��=��K�gi�آ��mZ&����&o~���JuE5�迟6�V�?w]�X]���\�؎��:)�Ĕ��]�&�vm�w]X=Q�:Iҩ�V:��k3ݬm�w�~� ���c[׏���,R:z�5j���X��2���KtYq�۫��M�L[�C]�ݶ�b�iV�5:�LRl[t\6��hɷ-YlR�k�ٶ�q���Ӣ�ۊ�ߦ�{F5C;f�ʺgt�t����Ūf�[�kɒ�tG-ۏE�xf�w�j[��768S��c�<CЁʶ-*iሱ�Pccf�W��^�d��;�z�L=���h�N��z�n�gf��ZU“Ep�RU�7�����#P7��6�{C��Y˟k�6�	c���Sg��ʡVKM���ⳍ�vݞ���·u
�֔�􆟁3U�n��h(�.�����u+�d����pl�,`���L��Cڡ�CU�Wam���@��Ң��ū����[��k�G��YQ<6QY�5֞�:�������aLT��W�je�~Ō��%xl��q�4sd���{��p>�}��ӆ��q^�9 >-�B«������lY%�IBʾ��S/��2r�s�	�Jiӌ�Ϝ9��߆׍�q?�؄W�uX�1���0(>?��Q{��P�@s<���
�,���9Ƣ �A�=���fzռ��!Y����2��68��#��`��,����5�ش,�ʌs�72#���-<Z�!��y�(���&��H��1)�3�5�H�㑍p�L��i�׎
�(���(�Ö#�_�������LM߶�I�&��X��Ԝ�Y棢t��=,�O]�`��Lg�c��~��||�Dc<c��]����+F�y����L���M���*y,+S��<�V'T���і��1��P���o������"�yZK𹓃r���;u�Z+ĩS�wwF����윪�o��g܊�=�C�������i^w�3-������-o���
��ma�s�=-�|��[k7��V]|���kty]�����Ϗ���]^EWW��Me��Ԭ[:�-�����@z�x
Yj��$�S����x%�Q��Pnj,T��	.U��9%A�itzSQ6�`֩���qf9J�ך�����!v�Ѐ���=Ϻ1#M=�*�h�ŒӠ�]K��J�^��b''�U���@/Lo�N��:�dD00�h`��]�i�c��P�t!*��IE��|1�I���a*Ɣ���Hr	v�^�ƊNmՎ�9i��lL(�:D�d0�a�ztZ�дCr��H��uW}N�_]��.f�"�=���i�zi]iӥv,�-�#'���̽��AP%n�Ex=�;=���dG���lt��ӬC���Ɣ�8�'Iq
O%,&�
%#�F(�u���u�Y���%Ťp�"_�!r�* �	k	�L��̙�i�H*�S�h�u��u�OMYf�2�5��L��Z0e����u
_�ܨ�I �F�Dcӈ��Ri���U����х���"!���S�J�T#F�I��c��>ƶ��ƒ�k���-�u��Ze7}խ���q�Ͳ
eh��E�'��QO?E{
�	����`7�8z����6`�;���f\?.�w����:�昬7��M m�z���k�۽�た��'Z��^:~z�5����6*���06{�-0��S6/+ΚD�[�vL�'SJZM��RԢ3ؒ÷�?c`�{�Ƕ+Yp�v���
?��CN�=��X���~q��cv��Q�������>;�={C{����-����kf�:�EA�2\�c�(�py� �\}E^G���̉�t\&f'��e| ��Ӣ�ZZhDiaܢ�( %Q�2XQ�h�Y_��2��s�*︨_&N���.����?ӗ
UR+�n���Ƕ͜��"�! �TD*+�H%��0&UcLy�bLnj��1ݞ���0�|��б�ɔtn�H�zI�a@?��>�w��ZO?p���P��p���h��u�?�
����׀���3�����mx>pv�){J�vDxfzD�;��8"J7Ӂ�\8��Ԧ�eo{f��ɫ�2!�TBR�[̙��P�P5��LgL;�[ô���
=�`� �G��n�w�L<
�N�g�O�^��ee�,f��w�2�eW��:���F>���QO�u<gY.N+��
N��Q��xu���g�����5�s�5�iM�2E�y�!���!ѬvFV�t��)X���9'���5�i����j%VPa����%�.����z•���4��D&
��у��PQ��WӔ�K�	D��S�%�S��7f�Dtc(z���c(8���R��#�C�YSl"��S���)�CY��n"���N�}��1o����A�pd���%IJp���T���N�(:ĈR�2��Rr���o���[Ӭ_q��8N�_!��zb��I��b.\�\W5gj��AK�� 2��P9���R�����:5]~��2֣	�)U{}r4P��9㫢!�]�	N���Q:a��H2��ZF�Jx`8c��R�B�<�������L֑��ߕ3k���
ߜߐ��D�R"��rԱ��|��	��Ռ�]�����хSC$�褲�I�59f��]�*�jq�1/�|�cN��#�xl8����*4D�,\�œ�B����6�R���I�3��'զiQI||�OQD��a8���"56,v���f`{�1f�"��)Мq��
 ������E��dZ&\;��:)�:��.�-����I�zc�#X(7��&�J�Ya�sm������5)���r���6�U
�	˘v0T��|�:Õ�3�p4AUA�QSz��l����}���PWN0�o�f&
=P��$p-ҁ$�N-꘠�F��YWa�zeyqJ(�䭭5S@`r�D$�w�eʛ ��ں��k�K��]�ʚH��s-?��eO�C|����`�ū�]��NZ|�^�%�|�f�e{���oCA�L�;%���b\p�q�@�D��Y__q>.+Y�6��dwA��REsj�p�-�Fvi�+���75���g2���t"C��@������iA/L]&&�;ZTa4/J'c¢�u(Cp��"�ra�!,Z��|*Hyx���g�|�!�K��Ҥ���Ɋe^��9��[8P0*e0�D� :ZF�O�+Yu{�4�	�Ǻ7��8,��k�

��֙���%!�F�u�"�{8�؈;N4����\���p��sL�'%�]�G��f��n`竩�ʗ$
��W3���CwӟƼ1�NDY�
<j�?ؕKd=c!�Y��8C�s% vM3��%#v�L�j�|4n��
�3̮���!Z&����C���'�u�>��a`��_E�d��dM�*Ü���C��'�)ܽHת��J�b�	#8��%g��3�e���C�ݭ��$���t��s�;���?����i��fH�MUv�4�2N�~�Y�bE[dg���y�[��u�dE
�pL\���x��5p��_����G�gZ��%-��'�~�q?��i:p>�G{�;<86Ϩ�Z�)E{�Z����Ňo�F�����~������Utu]�����I�Ļ���{��MO(l���>H"=�������.��gڿ�tJ�/~�ǯ�߆Qc�~b&�^`�`�36<S쩹{f1#��<k�;�1��(���*�mN�]*�?�5���P	@�_\!�dR�2LX��%g�$H�&�@#|��
L�B�DR�T-���e��1��r�<Ӄ�#mu}q��O*��d͇2��ZD��S�|ژʒ.mj�c:ϙ�}���Oi��T�ޗ����T����}�m����-q�vY�b0�e�e3!��*u�2bh,�m}ߎ��s�ަ,�)���Z ���w���]�g�z�
S��p"e�0.L��>w$!�S�
�T�����Ϟ�ߊ��s�y����'�Mټ����uK�y.o�7��Ow	0��7�v0����bJcȂ��0��<��Q�;���Ս�Ӎ�@7�N7����tc�W7�N7���:��vtcD7�vd�u�<�=+r��E߽;2��d�=l��S
endstream
endobj
25 0 obj
4362
endobj
29 0 obj
[2 /XYZ 33  
122.750000  0]
endobj
28 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 30 0 R
/Resources 32 0 R
/Annots 33 0 R
/MediaBox [0 0 595 842]
>>
endobj
32 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
33 0 obj
[ ]
endobj
30 0 obj
<<
/Length 31 0 R
/Filter /FlateDecode
>>
stream
x��]߯۶~�_��QDR% ����A�a�C��+��h�
۟?ɢl�G��=�$�-��k]Q$ux~~����}��?��O�>��O7E�l��u��:�B׹�������/����͇͇�߯�a��?>��y�?k�����f:�s��/����������S.�V�����_UQVyը�n�/����߾�~k�Q�uQhm�Q�\F���EcrS��u�'}�޼����)U����\U��sS4ua�F�8�:Ӯ6Y]����������L�6j�U�v��z�-˹]٣G��4�i
�w�6���L���OY?�W��Oݤ_�J�٧�7�����/�k�cd�ʷ�+-+��ck�+��^�y��rp�m�T�)���T����NSTz|��J�'s�G�y���Q��NF�g���}{�iZb)lKC�g�m���>��c��P�mYE�������.�~��J��P����Ŗ芮�G���g�G�s��	���<�|�4��wľ���{�[PO�
�Q|O��RK�����liBQ`�0��R\n{�xf�',3b5����h�>;��\#>.��3��S�˕=�G�p�X�a�7P���]1�z�w�dn{�Tǣ����;�
�
�SL!�9��8^)�~�J��M���k5�S]���&NcO	��J1+
�5���g��A9�U̩'T�نs���;�g;0L���̿o�����$��E!�-�`�_��{��4|����w��s�Ѱ·�~�	֍?����ϡ�)>��,œj��h�,���Jg|^i�]T1l�5o�9�mc
���ŋ�|���kF�3r�
����R/~�hS{?��x^������#�1��+�s���O�!��7�K5Bã�xLU�v��5���`���ю
�C�d���L��L;w�s�<�Hfn�aC�Q
"�,��)d���u�=��D�ak��Q���X�c�/���r����X�a_�����a�8�!4�
a<�8��d�\���!�nʒH�����̬3ұJ��1��v���q4·&�!�:����坨�)�	{K�g�mh|�HD,����vCx�(l�|a�/~��i�*/Ϟ�h�S	O��P��/�DL�c��o���:M&1.Ӯ��T�(m����ДݷMfl���Ƙ�nli
��1��L?^�w�'�q6���l�w�'�W��>7�����7�v�%�R
�b��� v)��:î�����e�?�	̸(0�"f��eR�9�Ue����b�sZs���DZ=�AkΉA[�b��y$�+ft����b��Ġ-�xű쮸�}nor1��ދ4"��`�F�7o^˫��&%��f=G�i��.'~u��{J��$��D�hxw�Y��-����=
����'�m?����+)=Vڙ�R��q��@=Djh����F�ר�D
��$��0f��
f,8
*�<��v�̕#��=&U�EgM�W��:�D���R�wJ���hIK��H�C�T�X�w�J�dV�@� ]SPeF�L!�i�zj_JU���g�0)��l�X�{�q�2%c�)܏�M؟�%���?NȾ1=$��Uy�X���X��-���9F�m���}��G�5�<�k���G(��7��
�M�k��-9��5�I��6L���a��t%�2�0%u���l@1Ʀ	��X5!��	�V�l�F��HuW��>ӏ煐n�	!�gu?��Pwō�s�x��vJ=�:I�'|Xc	��W�J(I��'P�a�[N[���d.��=1Hٸ06>q&��u���O�sc�W���C��J1�2����Ʀ%ƣ�H(��*S�����4Ʉ`��.�:x � 6+�l��`� R"r��k�uJdu�%ci��Ho�Ա�t�3$қ���\۵%�PJ�? �u%��Y��jb�8%]�Y�D���Dz�B�x8Z��͛bo�ԁ��JJ��;��)���Q;����N�Kn�i��o�$x�#��G�:�DG�K��D��z�R�R�BZ���C(=�x�B�����l`bс�K����K��f'�����ޛ]��\OJqN)�aJL)α��M3�CJq��g��o��~:���v����9�.믘�}�o�]�~:���֏w����F��a����ڧUvd��F+�S�İ伳X{�d'6U�F6�l���%;Vdx1�����4�k�mz�|���bF��~<���5����cF�7�;��
�M��w��,��C	��"ӞR���͠d��u��o[p���Od\�L�FYe<I�E����7�(p�xJ|�t�;3�\?��[oF�쯘�}��K�s��o�x'f��f��Q1�	e�0�����dV�;�&J�ξ��Ғ~?�c�#�����0:���=r��VE��\]��~�6�p4�4d�0�"�R|�h�3fp������q�9!��;
��"��Ce��<�յ����N�s�s��J�d��ld����P���'[l��+D�8Z-aѽ��=ӆ�rO-8�("�q��XE�0�%��i��$Yr�E{����ej����A0ώ׊��'۴���2��ފ���_��������HA�̖�hG�
5�&7t1��wZ�zO@��.1��c\�9�33P��)*%�V�ܶx=Li"\	;Zq�!Y�:Q$kՅ��z��x��n�Kkԕ*�p�
"�qkPvk0�d�2���N���iķ���)����1���$�� *���s�E��f�p��:�W�4�Z�p�^��>q��f�w�/!x�a�jD����ڬ�V�\W�Q�Np�&zΚ)6��	�������%�X���v'�a��.��4G�]^۫�Ԉ�d�����i���D���ɋ�i���d!���(`E
�S05��d���0�	�<Z�;���l>�%�Clk�T63�j��U�˥�C�-M��z�D8�8Z�=�B1uK/e�i�*�A�_�C��d��=/i�B{��B؏�W�=<�9�<"Sۮ��
���a�����|�sD�����@t����x���M�E���h��D��<�=8��R�i���X
Y�e=3�G������b5�����Z��8�mw�u�xkd=I҄��0>t&Qg��%hG[��{�|�J��?M�-�N���rs�Ө�M��ȾZ2�_D�Mh�VM1�'&1X����{�e뙊�~Y4���p�q1���l���7�
Y�-07l�0�3eO��=?z`�����pNe+�&~jsK��e�zu��H���$|?�Q7�\S�e�R6��e�D�[`w?X@b0~��9.W7�`٬M٦DK)>s�M4�� ���yͮ���,���5b�p¨�!:FP�.ք������I�{Sp��)pS{��u��|kY�1�@ٜs�$u�U��������&�Z@c�h�jA�{�h��0o�;)�e���'�-b�2�#��E#���/���~I*:gAP�T�]��t�mA�==P9��K��Pxw�zp)�K]z�f��uD{2��T�}�+�	C��~.�P�M������R�C�q�{b�K�L�����`���h�
�>A��ݡ�'�*2�*���K6�R��H&�(T9VP�1�e_� !LX_�l.C�'��OW?�2hiLЖI|`����Zp�<�!��U�uHgL!�DJ��FHe�Dʞ{��%�����e�#tsʏ 
Hf\�E�W�[p˄%�y����C6%���~��@���jx�=p�O`�5�ҿ��0>O�r����lS�/
ܣj��d�s�=�Ze�rmp�=%�G���K��LJ"��Aհ����y��~�`рl����d�쌚|�nRluE�23N�Y����sƸ�rB��+3ZٜY��jFs���Q5�9�'K6�K������qn�\��ŝr�RUc.��JL�A&�ɸ�M�q�1u2���x=Tg5�
��y�@L���ك�Tp��)��0�?��*�P+
50�UYY�)Q�n(��2��F
��s��3����>T�X��H�e�
�@D%*�π�ek��j�8��L�,�Ra,�{�Ehk���u+�Eh[����"t�G+;c�iBUu�]�qY�y��������*+(�w��dmelj�륱RyY�x�?I�Y�fl��r��'�ɟ��<�]d�?�W����y��@��m7���@���u��'�M�gpZy�	�
�?�P�8�X��>&������͛�����������y��}����S#��t�Q����/OGKX-yu'qzO��9q�uQfz]j�W�'��q��PR��8.��g�Qp�
�5~���q�#�F0��v���BLj���ui���#��u� �<Ǫ<L�Lj�x���B��$eG�}S~R��1~s�Q`����]��g�F��A\����2�|&�Ō�JL`��tL�
�c�f��I���!�Ʌ���*��h�B6�?�5�r������9S�N1�_89�-�G;2Z���ឪ���LQ��\�S{b�Q�]�u���T�T�I5,�T�J����N�z(��_�����2�'Y-�WF����6�kO��C����T�}�T���V���M�}�3c���7��ucKS�o��g��k?u���订��k�w������~޼�f�l���U�m-w�c�UG+0�,?�
�i*v�2{@(��y���.���DTIej��Տ�"����s�T��T1,���i{̘ژv���D:����y��נ�;���C�a��l��
endstream
endobj
31 0 obj
4897
endobj
35 0 obj
[3 /XYZ 33  
765.500000  0]
endobj
36 0 obj
<<
/__WKANCHOR_2 8 0 R
/__WKANCHOR_4 9 0 R
/__WKANCHOR_6 10 0 R
/__WKANCHOR_a 11 0 R
/__WKANCHOR_8 12 0 R
/__WKANCHOR_c 13 0 R
/__WKANCHOR_e 20 0 R
/__WKANCHOR_g 21 0 R
/__WKANCHOR_i 22 0 R
/__WKANCHOR_k 29 0 R
/__WKANCHOR_m 35 0 R
>>
endobj
39 0 obj
<</Title (��PERFORMANCE OF ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_4
  /Count 0
  /Next 40 0 R
>>
endobj
40 0 obj
<</Title (��ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_6
  /Count 0
  /Next 41 0 R
  /Prev 39 0 R
>>
endobj
41 0 obj
<</Title (��LIMITATIONS OF LOADERS AND ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_8
  /Count 0
  /Next 42 0 R
  /Prev 40 0 R
>>
endobj
44 0 obj
<</Title (��\(Available for Linux 32 and 64 bit x86 servers using PHP 7\))
  /Parent 42 0 R
  /Dest /__WKANCHOR_c
  /Count 0
>>
endobj
42 0 obj
<</Title (��IONCUBE24 : real-time intrusion protection and PHP error reporting)
  /Parent 38 0 R
  /Dest /__WKANCHOR_a
  /Count 0
  /Next 43 0 R
  /Prev 41 0 R
  /First 44 0 R
  /Last 44 0 R
>>
endobj
45 0 obj
<</Title (��Global settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_g
  /Count 0
  /Next 46 0 R
>>
endobj
46 0 obj
<</Title (��Security related settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_i
  /Count 0
  /Next 47 0 R
  /Prev 45 0 R
>>
endobj
47 0 obj
<</Title (��PHP Error reporting settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_k
  /Count 0
  /Next 48 0 R
  /Prev 46 0 R
>>
endobj
48 0 obj
<</Title (��Deprecated settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_m
  /Count 0
  /Prev 47 0 R
>>
endobj
43 0 obj
<</Title (��php.ini settings)
  /Parent 38 0 R
  /Dest /__WKANCHOR_e
  /Count 0
  /Prev 42 0 R
  /First 45 0 R
  /Last 48 0 R
>>
endobj
38 0 obj
<</Title (��ionCube Loader 14.4 User Guide)
  /Parent 37 0 R
  /Dest /__WKANCHOR_2
  /Count 0
  /First 39 0 R
  /Last 43 0 R
>>
endobj
37 0 obj
<</Type /Outlines /First 38 0 R
/Last 38 0 R>>
endobj
49 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/Outlines 37 0 R
/PageMode /UseOutlines
/Dests 36 0 R
>>
endobj
34 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 50 0 R
/Resources 52 0 R
/Annots 53 0 R
/MediaBox [0 0 595 842]
>>
endobj
52 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
53 0 obj
[ ]
endobj
50 0 obj
<<
/Length 51 0 R
/Filter /FlateDecode
>>
stream
x��[mk�8��_��u�jIP
M��AI�>��d�X�e�����?9gc'��L��^wj'�F�g4�������MLf�/bI�ټ��w��'�g�_�Pҽ�нX��ⱸ-n��Ǣm���|(&M_E��|�{��Gh�k��I��W��%�����+_�M+�>~�����*�����~�c����e�Rk��jl�|>3��Rz]=���-C���hU}�.�W֧�(c�&j�ixO�0��F|}W��=v�a��a�:7:�Lsg��xW	S57��ߦ?��.��H��I���3M{�s��l]-I���NOI�;z�m�c1}�c���:]��J(-�E�γ沸/lHތ����<���B,>U�5u��O5����2Va;k�Q�DV�#�:�qʭ��QkZ�$��}ܚ6+�++�Bg<J�N�0�=�s6$�$��=�A�d�Z���>�X0m[���ܬ$׋Y�	��*6�
h�k/Tj��虦=
�v��uԞ�J-�=߶w�Pq����H��'���i±TU���N�X<�����i�j86���e����
+��=J۟guI�m�h����Zs$1Dt��Op�.����}�~h�w-�
�M]�E��w
�-c�"–�t��6C�@V�'~2�r� ����r���ϋw�~���BL�f�o���	�����f�s�i�9�E�/��3�h�69l�B�-%9~Hk�$��A�Ϸ�%���I�x<ж��8�C�Hە�9�'|Ɯ�<��H1尚���o����:��	ýÊ���4u,P��:r��������kF�Lɣ�2o�9�5JX8��o<ی�o��0w�5;j��V��-7q}�a�q�����U�'7�+�wr��^�t}ﵳ1A��o�qi{����"�� �LSZ�����T� ق��dž[-��
J<l-@�5�(�����l5��V(���H�Q���&��Xpu.��AI����X.�D+[K�h{A�y�4��T���8�7=����T���l�p5R�XX�Dl5&[��a	
��g�8&[X��=�$�A�2�A9[Ƒ�>/�U�F�=�l}8��l�q���kΜ���x��yo��Z�)�`Te���/m�(�%N���b(c�S|=Y
[�WN!��a�a�i�:��x‘|�����̄���.Y��3?��>r��b$�f�8�9ebNfb�-�Xqkx�F-��r=^�Y3�U74�}��GʚG{����ɚo��9��L��É�qW
�	���Ki�������i�G?X��8��3��N������돶*��)#�<��������aX�*N�{<��-2��sh�Q�aU?�T/�T2���F��a���F����g�.����13�ގS������ [�'�Y�����B֬�^:�� ��F�_�U�o��u��|˾V���-W��h�#�D���D��~3���
[�Gj�8�18��<���Lk�o�6��L?��K��]bT[^����'_0��ls��K��[��Y{XE�얞�]�^u�����H��Ȍ��d��}����jz�
endstream
endobj
51 0 obj
1581
endobj
54 0 obj
<< /Type /FontDescriptor
/FontName /QCCAAA+Roboto-Regular
/Flags 4 
/FontBBox [-736.816406 -270.996093 1148.43750 1056.15234 ]
/ItalicAngle 0 
/Ascent 927.734375 
/Descent -244.140625 
/CapHeight 927.734375 
/StemV 48.8281250 
/FontFile2 55 0 R
>>
endobj
55 0 obj
<<
/Length1 6976 
/Length 58 0 R
/Filter /FlateDecode
>>
stream
x�}X	\G����{�F�1+Ȍ�`�P`&�7�)ry" �9ܠ� ry+(*�&��&Fr�I0�$���[s=�xd�M6	0��g0׾���ꪯ���5B�
�L8B����j�=���bI��_�y=�����Н����q!l!���';Ư������삲*���`�B`l�1-���#d~&��UE$�,�v#�U����7�	Bh;��`:Rp����$��V,�-BGb�j���!K�������eD$$S�A�e�x?�4�C��Hm�9"'���B�j��S{5�A�M3ϥ����a����F9QG�5��S��rs���R�*Z9�%M1�_��$���Wq
{��Q�87���K��0Q.�LպA��t�'�蝝���>��y?p��rqQ�r����j���G�J�����J��˴HF���t4x�o��v�\�j��b��͍s�Kv�����}{\,�'�4��Sm��MAA;��Vo���m�����3�((D���'�.�J��^�Q�Y�˱
���˰�3Q�޸* ���5k�z�f����6�~�R��]�}��ȲF�uS��F7�� U
R�)u��Ͽ�c�}��q�C�O}��2��_b��LY9ik�=��W���h:�ցCq�[�x::��ip���V=��m���@��Z��)&���p�
�>�r���ө�͐��O��A����.I�C��dg����i�D���Q�Т�5(	�c^UR�w�h�m*�����x~I™��aT�s��=52b~������Y�%���,\'	���y2�� C.���
(����*����z�����<����zy�Yï\ޒ�]�$~X��Sl�&ž]�O=�ych0���b���4�>m���Ҹ=�GG2u�_8������
��g��_<r�9%���7ȝ+�Dv��4ȡ���	�P���*�����R�t�)lk�9��
[6}s�Ͽ(- z��7-��7/GpZ��->	����W��HNJH�O]pLTĬ�����8~�r�������Ӌq�9��~�-���e�B��ՙ�%�J�ʊ/Mݶ�K/TT� *��'6�(�ˁ�Z�=Hʚu�,7eew�wsr�^@�q��!�-@�,����<��t�[�w�3�Of�05�a���Y�L�{A画�-t�3���kȽ��"C�#e��	����B�5�shk�y�;�����[�}7�K�1�v���*�-�ta@#Q�$u�����;�	�i����s����E�1g�
@5E��c7��
N���7��7�aD�w�M[n�ݱ^Z��c�@85<��k���͟s���:���e�:���d���(%���z�r栱
�o�me�Ĝɀ�Q0��l���N�b�se%��f���[�fN(-?_��a�5�!A%ً�KČi.SfL���ٺz���}zf��5ST3f��Oܓ�`��ؔ$�Gf�`��C	���e�����S��7����h�Qy��j�Fx}CϳM�Qh&����fU�A���P\t!�R��C�.����:���g�C�����R��=0i�/�f�7��96Ԓ��|�8���g
�:Gc0���:���l�ε�!��j�C����_�!Ӻ���@lx�e�@L秅���榦ܬ�C�,���*���М��Q�us�L�O��{�ȎTo��q2_�}��3��-�Ȫpu��Ip)�y�f4��xk-i�O�x�8�e	��&7��Ouv@И��g0�T���� 6�gҁR�y��^��@��7�lc;r�&
��Y7s��R p���Wh�:l�<y��ox`����Bqp�9u��zl�Ĉ�fzt'HrS��{�,6\�75X���/���Ū��C�,k2�&� Β�Y^�I9DL���-9Ē�-�	�Aa�O��⋗�L]�E���	ډ�ا�c�-Y����!�`�^q�?����C�򲑃��܀́�Z���8�\��ҁ��O&%u/\0��{%��m�ɝƧ��ص�z����N@����{�y
�i��J����t��K�4L�Yf�)�e/_2�vU�\+/*�K�8�a�PV�|DĶ����Eb�5��h��um�z��\n܋Ѹ9i�:��s�w�^*e�>�M��8Z���U�8`XG
9}�M���-v���q��q;����|I8�ֿ���28����6:���;��>$i�y��:��yj_��"=nNN�w��,~��#b���bRӱ�r���<�ďCk[��;�b㫑[F'�#��caP�5��%�����f�6GF��n���}q=�h+���X�r��:7��{�{�
������*��l��H��F8-ԞY(3R{{��I�o!m�����.q��o�~��r3p����¹vH�R�V�W��`@;�?|I�ʸ�	�Z��i���an搋�=7��ws�,�g[�C�E����
w��Do�q{��e:�x�S��zE�Ͽ�3��Xc��Ajd�a��^�/�g?6ԇE�B�s!hw$�Ò�v�Ce~V8UT�NSz���m,�&<�f[h��4W��/q�H�`��i��\ø�ܔ��lQo�0I��ѰȲ����AK����	�	����[{N�7�F��5ԟ�i�z���?���A^��73��]�u���ĸ��Wr�?�,!>���w(������w삦ъ�d��9���
{�'��pn��_�&�S��{T��j��j��C��Q��Ć(8K�e�?������2w6]��NP�~s|�3T��x����]��[fa ��_h.^��\��u��,�o��!����Z��r"�s
ӡ��.8�Ҟ�K�钘��_�>p�fK�©���C�'�w���x&�47�$����1)� �.A�X�eV5<@�Q$!��H��$ǣ�?��o�,_��b|����1q�Lv��gs��ں���kSo�]I��s�<U\�矑��.*�-0��7_��7?6��tn�?����>2j���ܹR̟����2�����Ar@�\��;M�_�i.�]����P*��{�c}�F�I��a�S�r_��F��GLs@��t�,�L��Y	��e��Ξr-�
��VUmqۓ�l������%�^}��+d}�#~� ֈ_v���@<��
HqҨm�1����-M������_��N{09���Y�1����y~4��W�:V\��Oࡺz���K�û�z�
R���nc�C��

���?�;������@�|��@��k�M�/�Q
U2m@�Z����������{<�?����v�ֱ��1F���L]���2�)
�~*��w?�׉�22�\	��\s3�ف���ѠF�1�p���a4�bW�IH~%�~c~vVn�k���6|��
v=va!�[�Ö�ԯ��w�K@��O>�Ry�/�,X�b���+���4\��k~A�b��G�$���߁|T>SG���z��@CKmd�Ⱥ�Pl��[����V-^�i�[W6m鍈ظ����{[8/(�EO��^LY�r����1k�g�� $�nS`���d�͟��z+jU�h'����b.��r�zDox�XD�Gr8�'8�;0���koG��y5A��G`�_-�A�5�^�K�������~I��\���a`���Po�,���}F�nS�����1Q
O,[q�aIuٿoK�����mz1�v@n�,
-�킁D\����x���˽/��&`�6���G]��W
��5 �Y�ꖳ�{�5�ؑ�A�kX���.޴��k7â�%k
�Be��}�����O'�au��a ~S�8�ޅ�s���+^,*����k��$&���k����H���P\�
*-


(*	F���yi�C�<�,'&Noga[±Z]��1����3��19��;.������-{�t�)�'Xt�p��qw�s�����]�0/�\��uN���c�s��J���l����G���d���ؗ\~	q4��~�*`��w-eI��Ҙ��a�.�>"l��U[�]�t۶�G����u����/!��ի�ڒV�&�FF�F)�;�S�NB��Q_d���;W���4�.�q�����*��o�����K"A�L샩5Q�!;�/����ˌ��1u՚M��b�]� $h=Ƞc����G}��R:��eŌ��'�Wԥ�}�0R��Y���4��F�_�f��ZO1��]3�m���z0Ƃ�	T��x	9q{���0��0�=�*��7��� F�
��qęat;�T��b�?�����s�ϛ���<Y?��s2�7&^���4�8�yp����P��m��'?<�G�����1CvO�<S�����E����8�PvO���+�k%�����"��\�*�I%��r�!��<�C(�h�ů$|I��a�FҍEO'�]��U$Y(%�Kē�ƶY-�H=Bl�[D��3z�52�)�X�%�!]��8#�$�N��82�{�8��=r���1�I�lߏ'6^X��.��#d}�l������$
�x��Fҁe
�D��Ä��d:�Kƾ(,EXJ���C���+I&J�Dw�F�z��Ë$���,��x�O�D:�.��t#�;�rq\%w�����Z^�g�����`/L��B���p_��"d�&�Q��Z./���$����M�M��36l�ٺ��l�m���4f՘�1c��<6�IKd�#i�/;r�A��b�3�wZ���s�:��oX�<�oY�����u����d�
g�^@�HX?��)�z�Z�Ek��5k] n䶵.#N���Ǔx��IYGJH�"٤��P��o	��F��'�
#�$����"���w�Y�R+�H���8��֕�de���<<=U!FcV~�*�0m�jQ~�*�}*U�f�f�Td��X\o-�2,$ָ�X��H.��㒩H��fd�秖����Cg��V)�k�M�-��
��?�0���c��k�����x6�����x�p��EJ�-b����8�K~��'f��|d'
{
%��bO$�8�!‰ç�Ħ-++�3���rvjQjZv�lcI֜�����Ҍ�9�aA�qA�^�q��G+�
endstream
endobj
58 0 obj
5244
endobj
56 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Roboto-Regular
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 54 0 R
/CIDToGIDMap /Identity
/W [0 [440 241 566 547 646 547 557 526 246 534 540 559 336 557 557 261 643 512 676 592 546 519 869 324 481 241 557 344 557 626 707 195 557 270 745 469 564 611 548 682 866 647 707 651 589 880 339 345 492 240 503 557 557 562 448 210 564 557 557 557 557 618 274 409 631 317 237 ]
]
>>
endobj
57 0 obj
<< /Length 826 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0042> [<0069> <006F> <006E> <0043> <0075> <0062> <0065> <0020> <004C> <0061> <0064> <0072> <0031> <0034> <002E> <0055> <0073> <0047> <0054> <0068> <0063> <006D> <0074> <0076> <006C> <0070> <0066> <0067> <0050> <0048> <002C> <0032> <0049> <0077> <0079> <0045> <0052> <0046> <004F> <004D> <0041> <004E> <0044> <0053> <0057> <0028> <0029> <0078> <003A> <006B> <0035> <0033> <002B> <005F> <003B> <0071> <0037> <0038> <0030> <0036> <0042> <002D> <002F> <0056> <0022> <006A> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
6 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Roboto-Regular
/Encoding /Identity-H
/DescendantFonts [56 0 R]
/ToUnicode 57 0 R>>
endobj
59 0 obj
<< /Type /FontDescriptor
/FontName /QHCAAA+Consolas
/Flags 4 
/FontBBox [-432.128906 -302.246093 677.246093 1011.23046 ]
/ItalicAngle 0 
/Ascent 742.675781 
/Descent -257.324218 
/CapHeight 742.675781 
/StemV 70.3125000 
/FontFile2 60 0 R
>>
endobj
60 0 obj
<<
/Length1 11900 
/Length 63 0 R
/Filter /FlateDecode
>>
stream
x��yytǙgW7�� �H$��M���/�%ID @�hZ�%��x��-;vd[����$���x2Il����;M6;���y��y����Yٱw=~�l�W�
�e�X�+tuu�W���jR����8�P�������`����%Vf�Ux�o������c�hde��e��X�<�L�=<�����}���u<�<�6�����ߚ(ʌ�/.��[�ڨ'(ʢ�g6^��ێ��\MQ�a�͢�(1E��(
�;�kj��

i����E-�J�7��՛@��c�R]TwS���'hZ:E�)�o���bލ2S"j��D��̀�
8EJ�7;��J��:\��`��_G0P���K���f�$��Pe�_���!frMD��*U��@p@���h����.�;�c{��~Ra�K
d�R���D)SH*�*d����5��n��g���x�mv����5FCqQ�`�r����`tnZZ�T�*�R��^�����A6{��*'CN�r��`�>��{�#�3j7��2�L&/S�f���T��j��L=���S�ĔL�R���Xƿ,3�-f�N���(�c��"�Q6����*�uא����w���4j~<��+���wN�[L�M���X���}�d:1>��b���TZgecS��PsyE�R�r9C�};�B�e��[
��8]�a��
<��90��r"�����L
���Zde���[�o��k���}��:u4�&��Rt��k�e�R��ܳR����rW�<32|y�'X+˖;]����
�r��P���ڽ���!T(��ܭk�x��n~¼���sb�
`}h�?�(��üпep���@�}�����������7���V�3�N������4*�щ��	��W:�Ln�hW��~�ď�M!�,e1���NY(��pI6,R��I�y󌤦ʍ�yvx�|��Zv����ݡ�J�ԾW���x��Z���~|�������LTӆo`i]���.~!U�9s�,�o�޽���s�`���XOW�W�}�c���^�pT�ܾ@������Se������� n�x�;�j�[�*�]�������g6�r�F���3hd
�V�x�
b�΂f>O��:���
~B���yv�I�(�IN�cD����oyk�g\Nvpr���[������D|d�)d1��⨫�i�Ֆ;�Z��5ώ�AbF")�>��:��g��Ӄ[����clr����]��ju.w�	�3����_�V��h*l5�kg�:MqQQ�Fge��U�+*F��H��ZQkQ�����q��Vi���7�xt��壍�G�P�:���1?'�F�<�`����(�
�+ǝ��q����o�t+����;���yi|dϤB����~���@����;=�Z�����P���j�vn�xh���.g0������PR�˟S(d�B�!�����1��])*�����`Vi
T�؅�I���9�n�(U>恟���p�Q=�*�#�b�Q��9�/�ռxF24:>3������!�3�u�r��;w���b��^g9�H���G~z�>PQ�ӵ��/�xr_k��*�0[�
d?)hؐ�2�+RG�-(v�y�����3#���*�pEy������\�Ku~������(6Z<�mkG�.�͊f��p
��,���x�}k�7�܀=�T0/�hw(y@�k���PwV�������.?+���X��5L|5���Ţ"nJ����y����~:���k�6X��6�W)��\i���z}�~�}d��~���֦{����%�4>�Z�8R�p?{��$�L��bdU6���|fh�7/{�G�=�.W��eI���$�'��OdZ��3��$7w��Cj)������5�Ȇ��6���F���]��Lks�ɿ����ll��W[W��=911��BPf xO_s�ۣ׫U���ᕖ��;�5�xkL�B.���{&;�+���˂��\�+)�R"��Qc�F�F��hL*��Q�u{�몽����Y��P&/Ui�&�V�Ҫ4P�X�+�5���������OT<�"�V�Y�.V(����ʚ,j�m�B���ػ�c���Xs��-���%��������Kp��r��q��Ľ��V:tZTTR�**)���A��6�����֎�S˨�.r����t���
:�����j�]Q��ZSӾg�Ζ�r�x�"j�j��hJ���W@i�q�/p��k/����p���i�$wg��w�4�ɡ3�v�Gw�T榛�~��ysm�E����]���ij@5S�O�����ןC���;�7�����o���\'�큹e�8�~�5�G��[�,��u��h����Ք�d���х�7��O�(�=��"���)��]�ʆM�_���Fy�-�^j*�L�K
eE��R�J�5؞��EQiY��t�����Qo4����G�Ӛ
v��u��>���N	
����Z;B���aW�H�4��lY;�\�Y��e�C�@
�T��e1�Kp�9�/�&8/9�z�ZL0�r�|N��rhR�ĥ���/tZ��dc]�/��{����2UyECco��t�D]����Xg��Y�Q��~֊�Ck��McuMg���`��g���}�aZ2l�v�Y͞*����5��1xȫV�E�N�$T�	�6�h�p�
�!����`&X�=�����:�\NU)Bf���������3[����2}�	(��.��|��OZ�u���v��jF3�1C��"\��^��(�x2\���jƶd�������:�ƈDi���hktVZ�0�hc��M�`����\e	�\��ru�3���'8���4�%#��
�k�`�g�҉��v��)J3A7:
΂$d���^'2}-r��p�?�^G�}k��wf��K��B�S�cHI���M��Խ�zh3P�]�U'�t�[Q���v��5(WF��)�Ѩ$<�ug�}LƤ,1[�C㝡&���@Ն
��;jk�d��uLM�l<Ԥ7�45`T��
��u���D�I,�`���
G�%֘��'w��)�����q7���H$���bv���X+U�-.wm��6Y�J�i���qgW��Vo,.R��Zi0"SZf����}�m5�F�Z��c�`S(�(S�4z��+�^�5�f����Z0n�W��6{I�Q����Huj�F��i���
6-V��R�����b���#��k	�x�G?"u

 ��\�e�|��ܴq�=���3�\�LJ����v�{���xg�������B�A�W/}㟿8�}#uS�\�M5C����`d6e9��ʅ�NU�q6 ��ñ�R5�8�SƆ`CMS������'�`��r������G�5vn�:����YWoc���ͪ�6�"��@@�PG{Q���t5���DZ({�H.s�F+[�in�ꮩ1�D}$Q�J.�JD�
���q55�h�h���6�S
_��-�'Z^5���&*,f�s�4v��1'�ߥ� =�^G��;��z@�@TK�ԣ�Co�?���5Y�k���Alt�
���P��߼��͢�����:��l�{X!7�+��G�z�>���W?�W�f����6�5��9R�rt�X�w獡S�sTB��ǵ��:0
�������
F�NKꚚ�C�Cm�͵6�w�M���zg��\T��B�7:+��>X�hߧV�ڵk��'�M>���BB^懰+�4��x�v���o�ݻ�
�\VTl4y�[G{��n�9x|bp~�U���!}�ڵ��
�
�j8��U�ʖ��ZBc]����m]�ݽ}#��J��Q�QF�.ɈAP����}y�a��ƻ\�kFo";�.�?̈́W��_Y�~?q�CQ1He�s�P�wɝ�9!A�u�pb�G��M�b��깕/��ї�#���:���XG��B��v�N[n�V5�6�\.�f�d�]����U�@_�	�ҏ<u���^=B��=#Ǐ]~��N�]�=ǎ���ag�X�[
ٹ�n��9p\�ZY3z:�q�Ve)��w���vl��Zf�%U�D
!�ڲp�Cͽ}û"F�ƀ1�頻he��_s���
��_�D:�-Vi�1�Ev[}� .�Μ��{n�aO9�/��0����>�>��Nr��&�6�:Ɲ@��O�Пq�v	���W�ז8�~���7��&+Z��!��y,�8�
�ܕW��o+�{�vÁ��3��T��x�j�@��ׇ�;۷�����P(��궎�'��R��%]W���-��.g��嬘�5l0��[#�z��ҨG��o�j�����\")+-��ڂ�*����Q�,���=�q���\^P {<mm��ݶ��@�wV���K��S�E�o�Kk���_Ҷ��tPlz�;���I��p��
%�"H�T���=��x
z�"S�$kܴش����K��k��%1�y{uwˑ��t�[�ET��<[������juW
���=�������J�\����Ѷ�J�J���\Ύ��=m�J��~��N��r�ښ�G��|���nO��vt�ȑ�dNo��U��S旦ý[�pb��O�!����ƩGT��!w�yU��GE�����k��&������b�-T��P���SO��N�S7���N�\�{�C�Tn>Ư+c�����~���'�tW�؞H|���;��ػ붆�ɂ��ߌ��>X׍��m�w���~���|����g��
w�W�Y��d������������������� �z ~�q��"**������‘/s�G#���S�!���qxW���u�́���Cm�j�^lz�,������
hU���}���~��2��"mX?�0�[��]�p�e��;���ze��o���sc�ûv�j�t�8�ؤ�������]{�����F4E�H*"\<`1�h�{���+��O��yY�߁#�'���~��)ķط�ׅ%m����v��ȳ�K��F��5���D�Ǐ�YB)�/c��^��s��
wܖD�����]�F	�;���`�3p�m�p�@�愶�%h)a-�B�П��S	��C��	h^��Vh[x~��К��o�
<bd�����D����>A���oL#s��>�D�!J�>��.�'��şK�%A�i���NH�)}��t�
�>Q�O�JY�짲��Z�G~^���mE�bX1���⇊�ElQ+�n�z��۟%��멜=�B���B���ӧB_D ��S
�.�%0>%�TzW�PzP�R��q�/��'�&��W���WPy��/Bۋ� �ƒK�	�F	W���R�i�Oì
}������Q��@�)=r}	�	})u�	��C��~!���B_&�M��rj\���WP�J�ѧ�cB��J��Q߃J�j�:*�T��Pi*Ee��RY�^|��a$�$ԉ,�M%�b��06G�ûy��=��oW��c�uvG<�NeR�Y�7�^L���x*�c�	vw|n>�aw�2���X��m0	�6�d&�C�0�~�����R"�۹o����:-�ͻl7N����PJ�@YxKg@6��Ja�+h��0�,Qk�X ��1�<~3�w6�y^��fG��a�)NL��`��g�0�M����p���e��<�̥SK�x8�ZX'㱌�N��c�@�Ѵ�X�PUDh7�������/E��7���T*{7]�A>�P,���g�x���,�s��������~�҄�y�
4��^J�u��ό���%s"D�,Y���`�B��=��]�(�������2�[�'4Ä���=�%c��>9/��b��8���𔀧Cdk,JV����V|�f5�7ssz��ě�9�7)b�X��X�0�:��bLk(#�a��(C�����=*�'ފmrX�����eBiC�Q��E�+dw�;<�_\+C�()�k(����ܕ�3A,�[=}��2M�� c1�>���#���uZ�ܻ{B�;���M_H��$��9�2y�_ ��z��
҄A�	���狷-�	<�1�՘�9�x,ː��9��ab�$p��!F}I�)mX{KB8���;-ț\K�x��%�J+ٛ��y�[5�!���Uy��*�*)�Fn~�{zR���B�`��s��s4#؟�WΧp��lI�ov=��=8A�&�s���2#D���躟�OY�_�̟!=LPae]�9��3dn>�-�q{�/Ģ�l*�.ebl<�.�Ss���B<9�ƒ���Tr!��\NF�d�4��#K�l8�e�e�A6YH%S��p��Kf1��b,��C�&I=2N�#YȒ�|�p���Lx!�.ǣ�j6?cS�(�]Y�-��xf5�>�y�ga��T*
dR�H��3R�p�07���'c��t:�YL%��C;
��@0�$؉x2�Z��<F��Dx�
'�ex�ē��%���<V�.���f"��M��Tzv���˂�$I�q<F7)!��ԛZJ�ci�	V9�,C�_H�� �B?�I����i!��X2
��NPVd"�X���Xr4�����%��I,A�n���4�Ľ��B,NdZ�|>�f��l�
D�?�������$dk0Of>��cB3 ?�5����[�,6��D*�����e����6�
g�1vf�=N�`�lО	�yG[��%�<��E(�j�Z&����[����B���E���8�n�/5��.���.//�r���P���q~�6�%��C��,A�4A���9�x�lx&?��R�^��|�]ɫS��8����G��Wr���@.�1(���P,���pQRje׫�e�W��;���o ���ǕE����r<-���ȸYn���OU��M2�]�?�U�6�~mP�Ȅ|���#�T��r�f��3
���%K�˕˜>/+_�$I~�QIy=�o�i�ߍ�k{�P
�H=|*Erp�[�����_W�g16T���'8��c�l{7���]�dq�X��G�����ш�:�BL/��0!� ����ީ$�^U���������w�L'`	�M�#<P����i��V�]��|I�aWH�D*��)��9ň�2^j)���"vg�3K,n�XmU-1.��%R���/BY��0`���lx)���3���;�	
endstream
endobj
63 0 obj
7274
endobj
61 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Consolas
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 59 0 R
/CIDToGIDMap /Identity
/DW 545 >>
endobj
62 0 obj
<< /Length 742 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0036> [<0069> <006F> <006E> <0063> <0075> <0062> <0065> <002E> <006C> <0061> <0064> <0072> <005F> <0070> <0074> <0068> <0073> <003A> <003B> <002B> <002D> <002F> <0076> <0077> <006D> <0052> <0053> <0020> <003D> <0022> <0066> <0067> <006B> <0031> <0024> <007B> <007D> <0032> <0034> <0030> <0079> <0078> <0037> <0033> <0045> <004E> <004F> <0054> <0049> <0043> <007C> <0044> <0050> <0041> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Consolas
/Encoding /Identity-H
/DescendantFonts [61 0 R]
/ToUnicode 62 0 R>>
endobj
2 0 obj
<<
/Type /Pages
/Kids 
[
5 0 R
19 0 R
28 0 R
34 0 R
]
/Count 4
/ProcSet [/PDF /Text /ImageB /ImageC]
>>
endobj
xref
0 64
0000000000 65535 f 
0000000009 00000 n 
0000038255 00000 n 
0000000187 00000 n 
0000000282 00000 n 
0000000756 00000 n 
0000029337 00000 n 
0000038121 00000 n 
0000000319 00000 n 
0000000362 00000 n 
0000000405 00000 n 
0000000449 00000 n 
0000000493 00000 n 
0000000530 00000 n 
0000000574 00000 n 
0000001080 00000 n 
0000007535 00000 n 
0000000877 00000 n 
0000001053 00000 n 
0000007863 00000 n 
0000007556 00000 n 
0000007600 00000 n 
0000007644 00000 n 
0000007688 00000 n 
0000008188 00000 n 
0000012626 00000 n 
0000007985 00000 n 
0000008161 00000 n 
0000012691 00000 n 
0000012647 00000 n 
0000013009 00000 n 
0000017982 00000 n 
0000012813 00000 n 
0000012989 00000 n 
0000020361 00000 n 
0000018003 00000 n 
0000018047 00000 n 
0000020194 00000 n 
0000020020 00000 n 
0000018298 00000 n 
0000018452 00000 n 
0000018591 00000 n 
0000018987 00000 n 
0000019859 00000 n 
0000018784 00000 n 
0000019263 00000 n 
0000019391 00000 n 
0000019554 00000 n 
0000019723 00000 n 
0000020257 00000 n 
0000020679 00000 n 
0000022336 00000 n 
0000020483 00000 n 
0000020659 00000 n 
0000022357 00000 n 
0000022621 00000 n 
0000027977 00000 n 
0000028459 00000 n 
0000027956 00000 n 
0000029477 00000 n 
0000029735 00000 n 
0000037122 00000 n 
0000037327 00000 n 
0000037101 00000 n 
trailer
<<
/Size 64
/Info 1 0 R
/Root 49 0 R
>>
startxref
38374
%%EOF
alt-php73-ioncube-loader/LICENSE.txt000064400000025020150464070010012770 0ustar00LICENCE AGREEMENT FOR THE IONCUBE PHP LOADER, PROVIDED TO ENABLE THE USE
OF IONCUBE ENCODED FILES AND AS PART OF THE IONCUBE24 SERVICE (ioncube24.com)

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING THE
LOADER SOFTWARE. THE INSTALLATION AND/OR USE OR COPYING OF THE IONCUBE PHP
LOADER SOFTWARE INDICATES YOUR ACCEPTANCE OF THIS LICENCE AGREEMENT.  IF YOU
DO NOT ACCEPT THE TERMS OF THIS LICENCE AGREEMENT, DO NOT INSTALL, COPY
AND/OR USE THE LOADER SOFTWARE.

DEFINITIONS

The following definitions shall apply in this document:

LOADER shall mean the ionCube PHP Loader software package or collection 
of Loaders, including any modifications or upgrades to the software, used for
executing PHP scripts previously encoded with the ionCube PHP Encoder
software to render them non-humanly readable, and any associated
documentation or electronic or online materials relating to the software.

ENCODER shall mean any ionCube PHP Encoder software or service used for the
purpose of producing non-humanly readable encoded files from PHP scripts.

ENCODED FILE shall mean a non-humanly readable file produced by the 
Encoder and being derived from humanly readable PHP script source.

PROVIDER shall mean ionCube Ltd.

USER/YOU shall mean any entity who has downloaded or obtained through any
other means a version of the Loader software.


1 LICENSE ENTITLEMENT 

1.1 The Loader is provided without charge.  Title to the Loader does not pass
to the user in any circumstances.  The Loader is supplied as object code.

1.2 The provider grants a personal, non-transferable, non-exclusive licence to
use the Loader in accordance with the terms and conditions of this Licence
Agreement.

1.3 The installation or downloading and use of the Loader entitles the user
to install and use the Loader for its own internal lawful purposes.


2 DISTRIBUTION 

2.1 The Loader may be freely distributed to third parties alone or as 
part of a distribution containing other items provided that this license
is also included. 

2.2 The Loader may under no circumstances be branded as another product, 
whether distributed or not. 

2.3 Distribution as part of a commercial product is permitted provided such
distribution is in accordance with clauses 2.1 and 2.2 with respect to the 
Loader.


3 ANALYSIS / REVERSE ENGINEERING / MODIFICATION 

Except insofar as the user is permitted to do so in accordance with applicable
law:

3.1 Any analysis of the Loader and embedded data by any means and by
any entity whether human or otherwise and including but without limitation to
discover details of internal operation, to reverse engineer, to de-compile
object code, or to modify for the purposes of modifying behaviour is
forbidden.

3.2 Any analysis of encoded files by any means and by any entity whether human
or otherwise and including but without limitation to discover details of file
format or for the purposes of modifying behaviour or scope of their usage is
forbidden.


4 WARRANTY

THE LOADER SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
WARRANTIES INCLUDING BUT WITHOUT LIMITATION THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE ARE
DISCLAIMED. THE PROVIDER DOES NOT WARRANT THAT THE LOADER IS UNINTERRUPTED
OR ERROR FREE, NOR THAT THE OPERATION OF THE LOADER WILL FUNCTION IN
CONJUNCTION WITH ANY OTHER PRODUCT.  


5 LIMITATION OF LIABILITY 

5.1 IN NO EVENT WILL THE PROVIDER OF THE LOADER BE LIABLE TO THE USER OR ANY
PARTY FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR OTHER
CONSEQUENTIAL DAMAGES ARISING DIRECTLY OR INDIRECTLY FROM THIS LICENCE
AGREEMENT OR ANY USE OF THE LOADER OR ENCODED FILES, EVEN IF THE PROVIDER IS
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

5.2 THE LOADER IS PROVIDED ON AN "AS IS" BASIS.  THE PROVIDER EXCLUDES ALL
WARRANTIES, CONDITIONS, TERMS, UNDERTAKINGS AND REPRESENTATIONS (EXCLUDING
FRAUDULENT MISREPRESENTATION) OF ANY KIND, EXPRESS OR IMPLIED, STATUTORY OR
OTHERWISE IN CONNECTION WITH THE LOADER TO THE FULLEST EXTENT PERMITTED BY
LAW.

5.3 DOWNLOADING THE LOADER IS AT YOUR OWN RISK AND THE PROVIDER DOES NOT
ACCEPT LIABILITY FOR ANY DIRECT OR INDIRECT LOSS OR DAMAGE HOWSOEVER CAUSED AS
A RESULT OF ANY COMPUTER VIRUSES, BUGS, TROJAN HORSES, WORMS, SOFTWARE BOMBS
OR OTHER SIMILAR PROGRAMS ARISING FROM YOUR USE OF THE LOADER.  WHILST THE
PROVIDER WILL DO ITS BEST TO ENSURE THAT THE LOADER IS FREE FROM SUCH
DESTRUCTIVE PROGRAMS, IT IS YOUR RESPONSIBILITY TO TAKE REASONABLE PRECAUTIONS
TO SCAN FOR SUCH DESTRUCTIVE PROGRAMS DOWNLOADED FROM THE INTERNET.

5.4 THE PROVIDER'S MAXIMUM LIABILITY FOR ANY LOSS OR DAMAGE ARISING FROM THIS
LICENCE AGREEMENT SHALL IN ANY EVENT BE LIMITED IN THE SOLE DISCRETION OF THE
PROVIDER TO THE REPLACEMENT OF THE LOADER PRODUCT.

5.5 DUE TO THE NATURE OF THE INTERNET, THE PROVIDER CANNOT GUARANTEE THAT ANY
E-MAILS OR OTHER ELECTRONIC TRANSMISSIONS WILL BE SENT TO YOU OR RECEIVED BY
THE PROVIDER OR THAT THE CONTENT OF SUCH TRANSMISSIONS WILL BE SECURE DURING
TRANSMISSION.


6 BUG FIXING AND PRODUCT SUPPORT 

6.1 The provider will use reasonable endeavours to provide support to users.
The provider will at their discretion only provide support for the latest
release.

6.2 Support comprises of fault reporting via tickets and fault diagnosis,
recommendations on workarounds, and where reasonably possible a timely
resolution.

6.3 The user accepts that on occasion the ability of the provider to meet
anticipated or published support schedules may be impaired due to, but without
limitation, Internet service provider failures or software failures that
affect the ability to communicate for an indeterminate period.

6.4 The provider reserves the right to refuse to provide support at any time.

6.5 The provider wishes to maintain and offer a product of the highest
possible quality, and accordingly may from time to time and at its discretion
make product changes for the purpose of correcting behaviour in variance to
the published specification or the user's reasonable expectations. 

6.6 The provider reserves the right to charge for support where the user does
not have a valid support plan in place, or where the support offered exceeds
the scope of the active support plan.


7 PRODUCT UPGRADES

7.1 The provider may from time to time release product upgrades. These will
be provided free of charge and attempts made to provide a timely notification
to customers of the existence of any new release.


8 ERRORS AND OMISSIONS

Whilst reasonable endeavours are made to ensure the accuracy of documentation
concerning the details of the Loader, the user accepts the possibility of
inaccuracies in information presented in any format, including email
communications and online services. The provider shall under no circumstances
be liable for any events that arise as a result of unintentional inaccuracies
or omissions.


9 USER INDEMNITY

You agree to fully indemnify, defend and hold the provider harmless
immediately upon demand from and against all actions, liability, claims,
losses, damages, costs and expenses (including legal/attorney fees) incurred
by the provider arising directly or indirectly as a result of your breach of
this Licence Agreement.


10 INTELLECTUAL PROPERTY RIGHTS

10.1 The user acknowledges that the Loader and associated documentation and
materials contain proprietary information of the provider and are and shall
remain the exclusive property of the provider and/or its licensors and all
title, copyright, trade marks, trade names, patents and other intellectual
property rights therein of whatever nature shall remain the sole property of
the provider and/or its licensors.

10.2 No title to or rights of ownership, copyright or other intellectual
property in the Loader is transferred to the user (other than the licence
rights expressly granted in this Licence Agreement).


11 TERMINATION

11.1 The provider reserves the right to terminate this Licence Agreement
immediately by notice in writing against the user if the user is in breach of
any terms and conditions of this Licence Agreement.

11.2 Termination of this Licence Agreement for any reason shall be without
prejudice to any other rights or remedies of the provider which may have
arisen on or before the date of termination under this Licence Agreement or in
law.

11.3 The provisions of the following clauses shall survive any termination of
this agreement; clause 3, 5, 10 and 13.


12 GENERAL

12.1 The provider reserves the right to transfer or assign all or any of its
rights and duties and responsibilities set out in this Licence Agreement to
another party.

12.2 Headings have been included for convenience only and will not be used in
construing any provision of this Licence Agreement.

12.3 No delay or failure by the provider to exercise any powers, rights or
remedies under this Licence Agreement will operate as a waiver of them nor
will any single or partial exercise of any such powers, rights or remedies
include any other or further exercise of them.

12.4 If any part of this Licence Agreement is found by a court of competent
jurisdiction or other competent authority to be invalid, unlawful or
unenforceable then such part shall be severed from the remainder of this
Licence Agreement which will continue to be valid and enforceable to the
fullest extent permitted by applicable law.

12.5 This Licence Agreement including the documents or other sources referred
to herein supersede all prior representations, understandings and agreements
between the user and the provider relating to the Loader and sets forth the
entire agreement and understanding between the user and the provider relating
to the Loader.

12.6 Nothing in this Licence Agreement shall be deemed to constitute a
partnership between you and the provider nor constitute either party being an
agent of the other party.

12.7 This Agreement does not create any rights or benefits enforceable by any
person not a party to it (within the meaning of the U.K.Contracts (Rights of
Third Parties) Act 1999) except that a person who under clause 12.1 is a
permitted successor or assignee of the rights or benefits of the provider may
enforce such rights or benefits.


13 GOVERNING LAW AND JURISDICTION

This License Agreement and any issues relating thereto shall be construed and
interpreted in accordance with the laws of England and subject to the
exclusive jurisdiction of the English courts.

Copyright (c) 2002-2024 ionCube Ltd.          Last revised 23-April-2015
alt-php73-ioncube-loader/loader-wizard.php000064400000541746150464070010014444 0ustar00<?php // -*- c++ -*-

/** 
 * ionCube Loader install Wizard
 *
 * ionCube is a registered trademark of ionCube Ltd. 
 *
 * Copyright (c) ionCube Ltd. 2002-2022
 */


 

define ('ERROR_UNKNOWN_OS',1);
define ('ERROR_UNSUPPORTED_OS',2);
define ('ERROR_UNKNOWN_ARCH',3);
define ('ERROR_UNSUPPORTED_ARCH',4);
define ('ERROR_UNSUPPORTED_ARCH_OS',5);
define ('ERROR_WINDOWS_64_BIT',6);
define ('ERROR_PHP_UNSUPPORTED',7);
define ('ERROR_PHP_DEBUG_BUILD',8);
define ('ERROR_RUNTIME_EXT_DIR_NOT_FOUND',101);
define ('ERROR_RUNTIME_LOADER_FILE_NOT_FOUND',102);
define ('ERROR_INI_NOT_FIRST_ZE',201);
define ('ERROR_INI_WRONG_ZE_START',202);
define ('ERROR_INI_ZE_LINE_NOT_FOUND',203);
define ('ERROR_INI_LOADER_FILE_NOT_FOUND',204);
define ('ERROR_INI_NOT_FULL_PATH',205);
define ('ERROR_INI_NO_PATH',206);
define ('ERROR_INI_NOT_FOUND',207);
define ('ERROR_INI_NOT_READABLE',208);
define ('ERROR_INI_MULTIPLE_IC_LOADER_LINES',209);
define ('ERROR_INI_USER_INI_NOT_FOUND',210);
define ('ERROR_INI_USER_CANNOT_CREATE',211);
define ('ERROR_LOADER_UNEXPECTED_NAME',301);
define ('ERROR_LOADER_NOT_READABLE',302);
define ('ERROR_LOADER_PHP_MISMATCH',303);
define ('ERROR_LOADER_NONTS_PHP_TS',304);
define ('ERROR_LOADER_TS_PHP_NONTS',305);
define ('ERROR_LOADER_WRONG_OS',306);
define ('ERROR_LOADER_WRONG_ARCH',307);
define ('ERROR_LOADER_WRONG_GENERAL',308);
define ('ERROR_LOADER_WIN_SERVER_NONWIN',321);
define ('ERROR_LOADER_WIN_NONTS_PHP_TS',322);
define ('ERROR_LOADER_WIN_TS_PHP_NONTS',323);
define ('ERROR_LOADER_WIN_PHP_MISMATCH',324);
define ('ERROR_LOADER_WIN_COMPILER_MISMATCH',325);
define ('ERROR_LOADER_NOT_FOUND',380);
define ('ERROR_LOADER_PHP_VERSION_UNKNOWN',390);


define ('SERVER_UNKNOWN',0);
define ('HAS_PHP_INI',1);
define ('SERVER_SHARED',2); 
define ('SERVER_VPS',5); 
define ('SERVER_DEDICATED',7); 
define ('SERVER_LOCAL',9);

define ('IONCUBE_IP_ADDRESS',
			'94.101.154.134');
define  ('IONCUBE_ACCESS_ADDRESS',
			'lwaccess.ioncube.com');
define ('LOADERS_PAGE',
            'https://loaders.ioncube.com/'); 
define ('SUPPORT_SITE',
            'https://support.ioncube.com/');                                 
define ('WIZARD_SUPPORT_TICKET_DEPARTMENT',
			'3');
define ('LOADER_FORUM_URL',
            'https://forum.ioncube.com/viewforum.php?f=4');                  
define ('LOADERS_FAQ_URL',
            'https://www.ioncube.com/faqs/loaders.php');                     
define ('UNIX_ERRORS_URL',
            'https://www.ioncube.com/loaders/unix_startup_errors.php');      
define ('LOADER_WIZARD_URL',
            LOADERS_PAGE);                                                  
define ('ENCODER_URL',
            'https://www.ioncube.com/sa_encoder.php');                       
define ('LOADER_VERSION_URL',
            'https://www.ioncube.com/feeds/product_info/versions.php');    
define ('WIZARD_LATEST_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-wizard'); 
define ('PHP_COMPILERS_URL',
            LOADER_VERSION_URL . '?item=php-compilers');
define ('LOADER_PLATFORM_URL',
            LOADER_VERSION_URL . '?item=loader-platforms-all');   
define ('LOADER_LATEST_VERSIONS_URL',
            LOADER_VERSION_URL . '?item=loader-versions'); 
define ('LOADER_PHP_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-php-support'); 
define ('WIZARD_STATS_URL',
            'https://www.ioncube.com/feeds/stats/wizard.php');    
define ('IONCUBE_DOWNLOADS_SERVER',
            'https://downloads.ioncube.com/loader_downloads');          
define ('IONCUBE24_URL',
			'https://ioncube24.com');
define ('IONCUBE_CONNECT_TIMEOUT',4);

define ('DEFAULT_SELF','/ioncube/loader-wizard.php');
define ('LOADER_NAME_CHECK',true);
define ('LOADER_EXTENSION_NAME','ionCube Loader');
define ('LOADER_SUBDIR','ioncube');
define ('WINDOWS_IIS_LOADER_DIR', 'system32');
define ('ADDITIONAL_INI_FILE_NAME','00-ioncube.ini');
define ('UNIX_SYSTEM_LOADER_DIR','/usr/local/ioncube');
define ('RECENT_LOADER_VERSION','4.0.7');
define ('LATEST_LOADER_MAJOR_VERSION',12);
define ('LOADERS_PACKAGE_PREFIX','ioncube_loaders_');
define ('SESSION_LIFETIME_MINUTES',360);
define ('WIZARD_EXPIRY_MINUTES',2880);
define ('IONCUBE_WIZARD_EXPIRY_MINUTES',10080);
define ('MIN_INITIALISE_TIME',4);
define ('IC24_ENABLED_INI_PROPERTY',"ic24.enable");

    run();


function php4_http_build_query($formdata, $numeric_prefix = null, $key = null ) {
    $res = array();
    foreach ((array)$formdata as $k=>$v) {
        $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
        if ($key) $tmp_key = $key.'['.$tmp_key.']';
        if ( is_array($v) || is_object($v) ) {
            $res[] = php4_http_build_query($v, null , $tmp_key);
        } else {
            $res[] = $tmp_key."=".urlencode($v);
        }
   }
   $separator = ini_get('arg_separator.output');
   return implode($separator, $res);
}


function script_version()
{
    return "2.73";
}

function retrieve_latest_wizard_version()
{
    $v = false;

    $s = trim(remote_file_contents(WIZARD_LATEST_VERSION_URL));
    if (preg_match('/^\d+([.]\d+)*$/', $s)) {
        $v = $s;
    }

    return $v;
}

function latest_wizard_version()
{
    if (!isset($_SESSION['latest_wizard_version'])) {
        $_SESSION['latest_wizard_version'] = retrieve_latest_wizard_version();
    } 
    return $_SESSION['latest_wizard_version'];
}

function update_is_available($lv)
{
    if (is_numeric($lv)) {
        $lv_parts = explode('.',$lv);
        $script_parts = explode('.',script_version());
        return ($lv_parts[0] > $script_parts[0] || ($lv_parts[0] == $script_parts[0] && $lv_parts[1] > $script_parts[1]));
    } else {
        return null;
    }
}

function check_for_wizard_update($echo_message = false)
{
    $latest_version = latest_wizard_version();
    $update_available = update_is_available($latest_version);

    if ($update_available) {
        if ($echo_message) {
            echo '<p class="alert">An updated version of this Wizard script is available <a href="' . LOADER_WIZARD_URL . '">here</a>.</p>';
        }
        return $latest_version;
    } else {
        return $update_available;
    }
}


function remote_file_contents($url)
{
    $remote_file_opening = ini_get('allow_url_fopen');
    $contents = false;
    if (isset($_SESSION['timing_out']) && $_SESSION['timing_out']) {
        return false;
    }
    @session_write_close();
    $timing_out = 0;
    if ($remote_file_opening) {
        $fh = @fopen($url,'rb');
        if ($fh) {
            stream_set_blocking($fh,0);
            stream_set_timeout($fh,IONCUBE_CONNECT_TIMEOUT);
            while (!feof($fh)) {
                $result = fread($fh, 8192);
                $info = stream_get_meta_data($fh);
                $timing_out = $info['timed_out']?1:0;
                if ($timing_out) {
                    break;
                }
                if ($result !== false) {
                    $contents .= $result;
                } else {
                    break;
                }
            }
            fclose($fh);
        } else {
            $timing_out = 1;
        }
    } elseif (extension_loaded('curl')) {
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,IONCUBE_CONNECT_TIMEOUT);
            $output = curl_exec($ch);
            $info = curl_getinfo($ch);
            $timing_out = ($info['http_code'] >= 400)?1:0;
            curl_close($ch);

            if (is_string($output)) {
                $contents = $output;
            }
    } else {
        $timing_out = 1;
    }
    @session_start();
    $_SESSION['timing_out'] = $timing_out;
    return $contents;
}

function php_version()
{
    $v = explode('.',PHP_VERSION);

    return array(
           'major'      =>  $v[0],
           'minor'      =>  $v[1],
           'release'    =>  $v[2]);
}

function php_version_maj_min()
{
    $vprts = php_version();
    return ($vprts['major'] . '.' . $vprts['minor']);
}

function is_supported_php_version()
{
    $v = php_version(); 

    return ((($v['major'] == 4) && ($v['minor'] >= 1)) ||
      (($v['major'] == 5) && (($v['minor'] >= 1) || ($v['release'] >= 3))) ||
	  $v['major'] == 7 || ($v['major'] == 8 && $v['minor'] >= 1));
}

function is_php_version_or_greater($major,$minor,$release = 0)
{
    $version = php_version();
    return ($version['major'] > $major || 
            ($version['major'] == $major && $version['minor'] > $minor) ||
            ($version['major'] == $major && $version['minor'] == $minor && $version['release'] >= $release));
}

function ini_file_name()
{
    $sysinfo = get_sysinfo();
    return (!empty($sysinfo['PHP_INI'])?$sysinfo['PHP_INI_BASENAME']:'php.ini');
}

function get_remote_session_value($session_var,$remote_url,$default_function)
{
    if (!isset($_SESSION[$session_var])) {
        $serialised_res = remote_file_contents($remote_url);
        $unserialised_res = @unserialize($serialised_res);
        if (empty($unserialised_res)) {
            $unserialised_res = call_user_func($default_function);
        } else {
			$_SESSION['remote_access_successful'] = 1;
		}
        if (false === $unserialised_res) {
            $unserialised_res = '';
        }
        $_SESSION[$session_var] = $unserialised_res;
    }
    return $_SESSION[$session_var];
}

function get_file_contents($file)
{
    if (function_exists('file_get_contents')) {
        $strs = @file_get_contents($file);
    } else {
        $lines = @file($file);
        $strs = join(' ',$lines);
    }
    return $strs;
}

function default_platform_list()
{
    $platforms = array();


    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6', 'is_legacy' => 1,       'os_mod' => '_vc6',     'arch'=>'x86',  'dirname'=>'win32', 'us1-dir'=>'windows_vc6/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6 (Non-TS)',   'is_legacy' => 1,  'os_mod' => '_nonts_vc6',   'arch'=>'x86',  'dirname'=>'win32-nonts', 'us1-dir'=>'windows_vc6/x86-nonts' );

    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9',        'os_mod' => '_vc9',     'arch'=>'x86',  'dirname'=>'win32_vc9', 'us1-dir'=>'windows_vc9/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9 (Non-TS)',   'os_mod' => '_nonts_vc9',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc9', 'us1-dir'=>'windows_vc9/x86-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86',  'dirname'=>'win32_vc11', 'us1-dir'=>'windows_vc11/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc11', 'us1-dir'=>'windows_vc11/x86-nonts' );
	
	$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86-64',  'dirname'=>'win64_vc11', 'us1-dir'=>'windows_vc11/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc11', 'us1-dir'=>'windows_vc11/amd64-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86',  'dirname'=>'win32_vc14', 'us1-dir'=>'windows_vc14/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc14', 'us1-dir'=>'windows_vc14/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86-64',  'dirname'=>'win64_vc14', 'us1-dir'=>'windows_vc14/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc14', 'us1-dir'=>'windows_vc14/amd64-nonts' );
	
		 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86',  'dirname'=>'win32_vc15', 'us1-dir'=>'windows_vc15/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc15', 'us1-dir'=>'windows_vc15/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86-64',  'dirname'=>'win64_vc15', 'us1-dir'=>'windows_vc15/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc15', 'us1-dir'=>'windows_vc15/amd64-nonts' );

    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86',      'dirname'=>'linux_i686-glibc2.3.4', 'us1-dir'=>'linux/x86');
    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86-64',   'dirname'=>'linux_x86_64-glibc2.3.4', 'us1-dir'=>'linux/x86_64');
$platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc',      'dirname'=>'linux_ppc-glibc2.3.4','us1-dir'=>'linux/ppc');
            $platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc64',    'dirname'=>'linux_ppc64-glibc2.5','us1-dir'=>'linux/ppc64');
    

$platforms[] = array('os'=>'dra', 'os_human'=>'DragonFly', 'arch'=>'x86',      'dirname'=>'dragonfly_i386-1.7', 'us1-dir'=>'Dragonfly/x86');

$platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 4', 'os_mod'=>'_4',  'arch'=>'x86',      'dirname'=>'freebsd_i386-4.8', 'us1-dir'=>'FreeBSD/v4');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86',      'dirname'=>'freebsd_i386-6.2', 'us1-dir'=>'FreeBSD/v6/x86');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-6.2', 'us1-dir'=>'FreeBSD/v6/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86',      'dirname'=>'freebsd_i386-7.3', 'us1-dir'=>'FreeBSD/v7/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-7.3', 'us1-dir'=>'FreeBSD/v7/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86',      'dirname'=>'freebsd_i386-8.0', 'us1-dir'=>'FreeBSD/v8/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-8.0', 'us1-dir'=>'FreeBSD/v8/AMD64');
    
    $platforms[] = array('os'=>'bsd', 'os_human'=>'BSDi',     'is_legacy' => 1,           'arch'=>'x86',      'dirname'=>'bsdi_i386-4.3.1');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86',      'dirname'=>'netbsd_i386-2.1','us1-dir'=>'NetBSD/x86');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86-64',   'dirname'=>'netbsd_amd64-2.0','us1-dir'=>'NetBSD/x86_64');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.2', 'os_mod'=>'_4.2',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.2', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.5', 'os_mod'=>'_4.5',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.5', 'us1-dir'=>'OpenBSD/x86');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.6', 'os_mod'=>'_4.6',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.6', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.7', 'os_mod'=>'_4.7',  'arch'=>'x86-64', 'dirname'=>'openbsd_amd64-4.7', 'us1-dir' => 'OpenBSD/x86_64');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',    'is_legacy' => 1, 'arch'=>'ppc',      'dirname'=>'osx_powerpc-8.5','us1-dir'=>'OSX/ppc');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86',      'dirname'=>'osx_i386-8.11','us1-dir'=>'OSX/x86');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86-64',       'dirname'=>'osx_x86-64-10.2','us1-dir'=>'OSX/x86_64');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',  'is_legacy' => 1,          'arch'=>'sparc',    'dirname'=>'solaris_sparc-5.9', 'us1-dir'=>'Solaris/sparc');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',            'arch'=>'x86',      'dirname'=>'solaris_i386-5.10','us1-dir'=>'Solaris/x86');

    return $platforms;
}

function get_loader_platforms()
{
    return get_remote_session_value('loader_platform_info',LOADER_PLATFORM_URL,'default_platform_list');
}

function get_platforminfo()
{
    static $platforminfo;

    if (empty($platforminfo)) {
        $platforminfo = get_loader_platforms();
    }
    return $platforminfo;
}

function default_php_versions()
{
	return array();
}

function get_php_versions()
{
	return get_remote_session_value('php_version_info',LOADER_PHP_VERSION_URL,'default_php_versions');
}


function get_max_php_version_supported()
{
	static $max_php_version;
	
	if (empty($max_php_version)) {
		$php_versions = get_php_versions();
		
		$dirname = calc_dirname();
		
		if (array_key_exists($dirname,$php_versions)) {
			$max_php_version = $php_versions[$dirname];
		} else {
			$max_php_version = NULL;
		}
	}
	
	return $max_php_version;
}

function is_after_max_php_version_supported()
{
	$is_too_recent_php = false;
	
	$supported_php_version = get_max_php_version_supported();
	
	if (!is_null($supported_php_version)) {
		$pversion = php_version();
		
		$supported_parts = explode('.',$supported_php_version);
		$is_too_recent_php = ($supported_parts[0] < $pversion['major'] || ($supported_parts[0] == $pversion['major'] && $supported_parts[1] < $pversion['minor']));
	}
	
	if ($is_too_recent_php) {
		return $supported_php_version;
	} else {
		return false;
	}
}

function supported_os_variants($os_code,$arch_code)
{
    if (empty($os_code)) {
        return ERROR_UNKNOWN_OS;
    }
    if (empty($arch_code)) {
        return ERROR_UNKNOWN_ARCH;
    }

    $os_found = false;
    $arch_found = false;
    $os_arch_matches = array();
    $pinfo = get_platforminfo();

    foreach ($pinfo as $p) {
        if ($p['os'] == $os_code && $p['arch'] == $arch_code) {
            $os_arch_matches[$p['os_human']] = (isset($p['os_mod']))?(0 + (int) str_replace('_','',$p['os_mod'])):'';
        } 
        if ($p['os'] == $os_code) {
            $os_found = true;
        } elseif ($p['arch'] == $arch_code) {
            $arch_found = true;
        }
    }
    if (!empty($os_arch_matches)) {
        asort($os_arch_matches);
        return $os_arch_matches;
    } elseif (!$os_found) {
        return ERROR_UNSUPPORTED_OS;
    } elseif (!$arch_found) {
        return ERROR_UNSUPPORTED_ARCH;
    } else {
        return ERROR_UNSUPPORTED_ARCH_OS;
    }
}

function default_win_compilers()
{
    return array('VC6','VC9','VC11','VC14','VC15', 'VC16');
}

function supported_win_compilers()
{
    static $win_compilers;

    if (empty($win_compilers)) {
        $win_compilers = find_win_compilers();
    }
    return $win_compilers;
}

function find_win_compilers()
{
    return get_remote_session_value('php_compilers_info',PHP_COMPILERS_URL,'default_win_compilers');
}

function server_software_info()
{
    $ss = array('full' => '','short' => '');
    $ss['full'] = $_SERVER['SERVER_SOFTWARE'];

    if (preg_match('/apache/i', $ss['full'])) {
        $ss['short'] = 'Apache';
    } else if (preg_match('/IIS/',$ss['full'])) {
        $ss['short'] = 'IIS';
    } else {
        $ss['short'] = '';
    }
    return $ss;
}

function match_arch_pattern($str)
{
    $arch = null;
    $arch_patterns = array(
             'i.?86'        => 'x86',
             'x86[-_]64'    => 'x86',
             'x86'          => 'x86',
             'amd64'        => 'x86',
             'SMP Tue Jan 01 00:00:00 CEST 2000 all GNU\/Linux' => 'x86',
             'ppc64'        => 'ppc',
             'ppc'          => 'ppc',
             'powerpc'      => 'ppc',
             'sparc'        => 'sparc',
             'sun'          => 'sparc',
			 'armv7l'       => 'armv7l',
             'aarch64'      => 'aarch64'
         );

    foreach ($arch_patterns as $token => $a) {
        if (preg_match("/$token/i", $str)) {
          $arch = $a;
          break;
        }
    }
    return $arch;
}

function required_loader_arch($mach_info,$os_code,$wordsize)
{
    if ($os_code == 'win') {
        $arch = ($wordsize == 32)?'x86':'x86-64';
    } elseif (!empty($os_code)) {
        $arch = match_arch_pattern($mach_info);
        if ($wordsize == 64) {
            if ($arch == 'x86') {
                $arch = 'x86-64';
            } elseif ($arch == 'ppc') {
                $arch = 'ppc64';
            }
        }
    } else {
        $arch = ERROR_UNKNOWN_ARCH;
    }
    return $arch;
}

function uname($part = 'a')
{
    $result = '';
    if (!function_is_disabled('php_uname')) {
        $result = @php_uname($part);
    } elseif (function_exists('posix_uname') && !function_is_disabled('posix_uname')) {
        $posix_equivs = array(
                     'm' => 'machine',
                     'n' => 'nodename',
                     'r' => 'release',
                     's' => 'sysname'
                 );
        $puname = @posix_uname();
        if ($part == 'a' || !array_key_exists($part,$posix_equivs)) {
           $result = join(' ',$puname);
        } else {
           $result = $puname[$posix_equivs[$part]];
        }
    } else {
        if (!function_is_disabled('phpinfo')) {
            ob_start();
            phpinfo(INFO_GENERAL);
            $pinfo = ob_get_contents();
            ob_end_clean();
            if (preg_match('~System.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$match)) {
                $uname = $match[2];
                if ($part == 'r') {
                    if (!empty($uname) && preg_match('/\S+\s+\S+\s+([0-9.]+)/',$uname,$matchver)) {
                        $result = $matchver[1];
                    } else {
                        $result = '';
                    }
                } else {
                    $result = $uname;
                }
            }
        } else {
            $result = '';
        }
    }
    return $result;
}

function calc_word_size($os_code)
{
    $wordsize = null;
    if ('win' === $os_code) {
        ob_start();
        phpinfo(INFO_GENERAL);
        $pinfo = ob_get_contents();
        ob_end_clean();
        if (preg_match('~Compiler.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$compmatch)) {
            if (preg_match("/(VC[0-9]+)/i",$compmatch[2],$vcmatch)) {
                $compiler = strtoupper($vcmatch[1]);
            } elseif (stripos(trim($compmatch[2]),"Visual C++ 2019") === 0) {
                $compiler = 'VC16';
            } else {
                $compiler = 'VC6';
            }
        } else {
            $compiler = 'VC6';
        }
        if ($compiler === 'VC9' || $compiler === 'VC11' || $compiler === 'VC14' 
                || $compiler === 'VC15' || $compiler === 'VC16') {
			if (preg_match('~Architecture.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$archmatch)) {
				if (preg_match("/x64/i",$archmatch[2])) {
					$wordsize = 64;
				} else {
					$wordsize = 32;
				}
            } elseif (isset($_ENV['PROCESSOR_ARCHITECTURE']) && preg_match('~(amd64|x86-64|x86_64)~i',$_ENV['PROCESSOR_ARCHITECTURE'])) {
                if (preg_match('~Configure Command.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$confmatch)) {
                    if (preg_match('~(x64|lib64|system64)~i',$confmatch[2])) {
                        $wordsize = 64;
                    }
                }
            } else {
				$wordsize = 32;
			}
        }
    }
    if (empty($wordsize)) {
        $wordsize = ((-1^0xffffffff)?64:32);
    }
    return $wordsize;
}

function required_loader($unamestr = '')
{
    $un = empty($unamestr)?uname():$unamestr;

    $php_major_version = substr(PHP_VERSION,0,3);

    $os_name = substr($un,0,strpos($un,' '));
    $os_code = empty($os_name)?'':strtolower(substr($os_name,0,3));

    $wordsize = calc_word_size($os_code);

	if ($os_code == 'win' && $wordsize == 64 && $php_major_version < '5.5') {
        $arch = ERROR_WINDOWS_64_BIT;
	} else {
		$arch = required_loader_arch($un,$os_code,$wordsize);
	}
    if (!is_string($arch)) {
        return $arch;
    }
    $os_variants = supported_os_variants($os_code,$arch);
    if (!is_array($os_variants)) {
        return $os_variants;
    }

    $os_ver = '';
    if (preg_match('/([0-9.]+)/',uname('r'),$match)) {
        $os_ver = $match[1];
    }
    $os_ver_parts = preg_split('@\.@',$os_ver);

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $loader_sfix = (($os_code == 'win') ? 'dll' : 'so');
    $file = "ioncube_loader_{$os_code_h}_{$php_major_version}.{$loader_sfix}";

    if ($os_code == 'win') {
        $os_name = 'Windows';
        $file_ts = $file;
        $os_name_qual = 'Windows';
    } else {
        $os_names = array_keys($os_variants);
        if (count($os_variants) > 1) {
            $parts = explode(" ",$os_names[0]); 
            $os_name = $parts[0];
            $os_name_qual = $os_name . ' ' . $os_ver_parts[0] . '.' . $os_ver_parts[1];
        } else {
            $os_name = $os_names[0];
            $os_name_qual = $os_name;
        }
        $file_ts = "ioncube_loader_{$os_code_h}_{$php_major_version}_ts.{$loader_sfix}";
    }

    return array(
           'uname'      =>  $un,
           'arch'       =>  $arch,
           'oscode'     =>  $os_code,
           'oscode_h'   =>  $os_code_h,
           'osname'     =>  $os_name,
           'osnamequal' =>  $os_name_qual,
           'osvariants' =>  $os_variants,
           'osver'      =>  $os_ver,
           'osver2'     =>  $os_ver_parts,
           'file'       =>  $file,
           'file_ts'    =>  $file_ts,
           'wordsize'   =>  $wordsize
       );
}

function ic_system_info()
{
    $thread_safe = null;
    $debug_build = null;
    $cgi_cli = false;
	$is_fpm = false;
    $is_cgi = false;
    $is_cli = false;
    $php_ini_path = '';
    $php_ini_dir = '';
    $php_ini_add = '';
    $is_supported_compiler = true;
    $php_compiler = is_ms_windows()?'VC6':'';

    ob_start();
    phpinfo(INFO_GENERAL);
    $php_info = ob_get_contents();
    ob_end_clean();

    $breaker = (php_sapi_name() == 'cli')?"\n":'</tr>';
    $lines = explode($breaker,$php_info);
    foreach ($lines as $line) {
        if (preg_match('/command/i',$line)) {
          continue;
        }

        if (preg_match('/thread safety/i', $line)) {
          $thread_safe = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('/debug build/i', $line)) {
          $debug_build = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('~configuration file.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
          $php_ini_path = $match[2];

          if (!@file_exists($php_ini_path)) {
                $php_ini_path = '';
          }
        }
        if (preg_match('~dir for additional \.ini files.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_dir = $match[2];
            if (!@file_exists($php_ini_dir)) {
                $php_ini_dir = '';
            }
        }
        if (preg_match('~additional \.ini files parsed.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_add = $match[2];
        }
        if (preg_match('/compiler/i',$line)) {
            $supported_match = join('|',supported_win_compilers());
            $is_supported_compiler = preg_match("/($supported_match)/i",$line);
            if (preg_match("/(VC[0-9]+)/i",$line,$match)) {
                $php_compiler = strtoupper($match[1]);
            } elseif (preg_match("/Visual C\+\+ 2017/i",$line)) {
				$php_compiler = "VC15";
				$is_supported_compiler = true;
            } elseif (preg_match("/Visual C\+\+ 2019/i",$line)) {
				$php_compiler = "VC16";
				$is_supported_compiler = true;
			} else {
                $php_compiler = '';
            }
        }
    }
    $is_cgi = strpos(php_sapi_name(),'cgi') !== false;
    $is_cli = strpos(php_sapi_name(),'cli') !== false;
	$is_fpm = strpos(php_sapi_name(),'fpm-fcgi') !== false;
    $cgi_cli = $is_cgi || $is_cli;

    $ss = server_software_info();
	
	if ($is_fpm) {
		$ss['short'] = 'PHP-FPM';
		$ss['full'] = 'PHP-FPM ' . $ss['full'];
	}

    if (!$php_ini_path && function_exists('php_ini_loaded_file')) {
        $php_ini_path = php_ini_loaded_file();
        if ($php_ini_path === false) {
            $php_ini_path = '';
        }
    }
    if (!empty($php_ini_path)) {
        $real_path = @realpath($php_ini_path);
        if (false !== $real_path) {
            $php_ini_path = $real_path;
        }
    }

    $php_ini_basename = basename($php_ini_path);

    return array(
           'THREAD_SAFE'        => $thread_safe,
           'DEBUG_BUILD'        => $debug_build,
           'PHP_INI'            => $php_ini_path,
           'PHP_INI_BASENAME'   => $php_ini_basename,
           'PHP_INI_DIR'        => $php_ini_dir,
           'PHP_INI_ADDITIONAL' => $php_ini_add,
           'PHPRC'              => getenv('PHPRC'),
           'CGI_CLI'            => $cgi_cli,
           'IS_CGI'             => $is_cgi,
           'IS_CLI'             => $is_cli,
		   'IS_FPM'				=> $is_fpm,
           'PHP_COMPILER'       => $php_compiler,
           'SUPPORTED_COMPILER' => $is_supported_compiler,
           'FULL_SS'            => $ss['full'],
           'SS'                 => $ss['short']);
}

function is_possibly_dedicated_or_local()
{
    $sys = get_sysinfo();

    return (empty($sys['PHP_INI']) || !@file_exists($sys['PHP_INI']) || (is_readable($sys['PHP_INI']) && (0 !== strpos($sys['PHP_INI'],$_SERVER['DOCUMENT_ROOT']))));
}

function is_local()
{
    $ret = false;
    if ($_SERVER["SERVER_NAME"] == 'localhost') {
        $ret = true;
    } else {
        $ip_address = strtolower($_SERVER["REMOTE_ADDR"]);
        if (strpos(':',$ip_address) === false) {
            $ip_parts = explode('.',$ip_address);
            $ret = (($ip_parts[0] == 10) || 
                    ($ip_parts[0] == 172 && $ip_parts[1] >= 16 &&  $ip_parts[1] <= 31) ||
                    ($ip_parts[0] == 192 && $ip_parts[1] == 168));
        } else {
            $ret = ($ip_address == '::1') || (($ip_address[0] == 'f') && ($ip_address[1] >= 'c' && $ip_address[1] <= 'f'));
        }
    }
    return $ret;
}

function is_shared()
{
    return !is_local() && !is_possibly_dedicated_or_local();
}

function find_server_type($chosen_type = '',$type_must_be_chosen = false,$set_session = false)
{
    $server_type = SERVER_UNKNOWN;
    if (empty($chosen_type)) {
        if ($type_must_be_chosen) {
            $server_type = SERVER_UNKNOWN;
        } else {
            if (isset($_SESSION['server_type']) && $_SESSION['server_type'] != SERVER_UNKNOWN) {
                $server_type = $_SESSION['server_type'];
            } elseif (is_local()) {
                $server_type = SERVER_LOCAL;
            } elseif (!is_possibly_dedicated_or_local()) {
                $server_type = SERVER_SHARED;
            } else {
                $server_type = SERVER_UNKNOWN;
            } 
        }
    } else {
        switch ($chosen_type)  {
            case 's':
                $server_type = SERVER_SHARED;
                break;
            case 'd':
                $server_type = SERVER_DEDICATED;
                break;
            case 'l':
                $server_type = SERVER_LOCAL;
                break;
            default:
                $server_type = SERVER_UNKNOWN;
                break;
        }
    }
    if ($set_session) {
        $_SESSION['server_type'] = $server_type;
    }
    return $server_type;
}

function server_type_string()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_string = 'SHARED';
            break;
        case SERVER_LOCAL:
            $server_string = 'LOCAL';
            break;
        case SERVER_DEDICATED:
            $server_string = 'DEDICATED';
            break;
        default:
            $server_string = 'UNKNOWN';
            break;
    }
    return $server_string;
}

function server_type_code()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_char = 's';
            break;
        case SERVER_LOCAL:
            $server_char = 'l';
            break;
        case SERVER_DEDICATED:
            $server_char = 'd';
            break;
        default:
            $server_char = '';
            break;
    }
    return $server_char;
}

function get_sysinfo()
{
    static $sysinfo;

    if (empty($sysinfo)) {
        $sysinfo = ic_system_info();
    }
    return $sysinfo;
}

function get_loaderinfo()
{
    static $loader;

    if (empty($loader)) {
        $loader = required_loader();
    }
    return $loader;
}

function is_ms_windows()
{
    $loader_info = get_loaderinfo();
    return ($loader_info['oscode'] == 'win');
}

function function_is_disabled($fn_name)
{
    $disabled_functions=explode(',',ini_get('disable_functions'));
    return in_array($fn_name, $disabled_functions);
}

function selinux_is_enabled()
{
    $se_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('sestatus');
        $se_enabled = preg_match('/enabled/i',$cmd);
    }

    return $se_enabled;
}

function grsecurity_is_enabled()
{
    $gr_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('gradm -S');
        $gr_enabled = preg_match('/enabled/i',$cmd);
    }

    return $gr_enabled;
}

function threaded_and_not_cgi()
{
    $sys = get_sysinfo();
    return($sys['THREAD_SAFE'] && !$sys['IS_CGI']);
}

function is_restricted_server($only_safe_mode = false)
{
    $disable_functions = ini_get('disable_functions');
    $open_basedir = ini_get('open_basedir');
    $php_restrictions = !empty($disable_functions) || !empty($open_basedir);
    $system_restrictions = selinux_is_enabled() || grsecurity_is_enabled();
    $non_safe_mode_restrictions = $php_restrictions || $system_restrictions;
    return (ini_get('safe_mode') || (!$only_safe_mode && $non_safe_mode_restrictions));
}

function server_restriction_warnings()
{
    $warnings = array();

    if (find_server_type() == SERVER_SHARED) {
        if (is_restricted_server()) {
            $warnings[] = "Server restrictions are in place which might affect the operation of this Loader Wizard or prevent the installation of the Loader.";
        }
    } else {
        $warning_suffix = "This may affect the operation of this Loader Wizard.";
        if (ini_get('safe_mode')) {
            $warnings[] = "Safe mode is in effect on the server. " . $warning_suffix;
        } 
        $disabled_functions = ini_get('disable_functions');
        if (!empty($disabled_functions)) {
            $warnings[] = "Some functions are disabled through disable_functions. " . $warning_suffix;
        }
        $open_basedir = ini_get('open_basedir');
        if (!empty($open_basedir)) {
            $warnings[] = "Open basedir restrictions are in effect. " . $warning_suffix;
        }
    }
    return $warnings;
}

function own_php_ini_possible($only_safe_mode = false)
{
    $sysinfo = get_sysinfo();
    return ($sysinfo['CGI_CLI'] && !is_ms_windows() && !is_restricted_server($only_safe_mode));
}

function extension_dir()
{
    $extdir = ini_get('extension_dir');
    if ($extdir == './' || ($extdir == '.\\' && is_ms_windows())) {
        $extdir = '.';
    }
    return $extdir;
}

function possibly_selinux()
{
    $loaderinfo = get_loaderinfo();
    $se_env = (getenv("SELINUX_INIT"));
    return (strtolower($loaderinfo['osname']) == 'linux' && $se_env && ($se_env == 'Yes' || $se_env == '1'));
}

function ini_same_dir_as_wizard()
{
    $sys = get_sysinfo();
    return dirname($sys['PHP_INI']) == dirname(__FILE__); 
}

function extension_dir_path()
{
    $ext_dir = extension_dir();
    if ($ext_dir == '.' || (dirname($ext_dir) == '.')) {
        $ext_dir_path = @realpath($ext_dir);
    } else {
        $ext_dir_path = $ext_dir;
    }
    return $ext_dir_path;
}

function get_loader_name()
{
    $u = uname();
    $sys = get_sysinfo();
    $os = substr($u,0,strpos($u,' '));
    $os_code = strtolower(substr($u,0,3));

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $php_version = phpversion();
    $php_family = substr($php_version,0,3);

    $loader_sfix = (($os_code == 'win') ? '.dll' : (($sys['THREAD_SAFE'])?'_ts.so':'.so'));
    $loader_name="ioncube_loader_{$os_code_h}_{$php_family}{$loader_sfix}";

    return $loader_name;
}

function get_reqd_version($variants)
{
    $exact_match = false;
    $nearest_version = 0;
    $loader_info = get_loaderinfo();
    $os_version = $loader_info['osver2'][0] . '.' . $loader_info['osver2'][1];
    $os_version_major = $loader_info['osver2'][0];
    foreach ($variants as $v) {
        if ($v == $os_version || (is_int($v) && $v == $os_version_major)) {
            $exact_match = true;
            $nearest_version = $v;
            break;
        } elseif ($v > $os_version) {
            break;
        } else {
            $nearest_version = $v;
        }
    }
    return (array($nearest_version,$exact_match));
}

function get_default_loader_dir_webspace()
{
    return ($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . LOADER_SUBDIR);
}

function get_loader_location($loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = get_default_loader_dir_webspace();
    }
    $loader_name = get_loader_name(); 
    return ($loader_dir . DIRECTORY_SEPARATOR . $loader_name);
}

function get_loader_location_from_ini($php_ini = '')
{
    $errors = array();
    if (empty($php_ini)) {
        $sysinfo = get_sysinfo();
        $php_ini = $sysinfo['PHP_INI'];
    }
    if (!@file_exists($php_ini)) {
        if (empty($php_ini)) {
            $errors[ERROR_INI_NOT_FOUND] = "The configuration file could not be found.";
        } else {
            $errors[ERROR_INI_NOT_FOUND] = "The $php_ini file could not be found.";
        }
    } elseif (!is_readable($php_ini)) {
        $errors[ERROR_INI_NOT_READABLE] = "The $php_ini file could not be read.";
    }
    if (!empty($errors)) {
        return array('location' => '', 'errors' => $errors);
    } 
    $lines = file($php_ini);
    $ext_start = zend_extension_line_start();
    $wrong_ext_start = ($ext_start == 'zend_extension')?'zend_extension_ts':'zend_extension';
    $loader_path = '';
    $loader_name_match = "ioncube_loader";
    foreach ($lines as $l) {
        if (preg_match("/^\s*$ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$corr_matches)) {
            if (preg_match("/$loader_name_match/i",$corr_matches[1])) {
                if (!empty($loader_path)) {
                    $errors[ERROR_INI_MULTIPLE_IC_LOADER_LINES] = "It appears that multiple $ext_start lines for the ionCube Loader have been included in the configuration file, $php_ini.";
                }
                $loader_path = $corr_matches[1];
            } else {
                if (empty($loader_path)) {
                    $errors[ERROR_INI_NOT_FIRST_ZE] = "The ionCube Loader must be the first Zend extension listed in the configuration file, $php_ini.";
                }
            }
        }
        if (empty($loader_path)) {
            if (preg_match("/^\s*$wrong_ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$bad_start_matches)) {
                if (preg_match("/$loader_name_match/i",$bad_start_matches[1])) {
                    $bad_zend_ext_msg = "The line for the ionCube Loader in the configuration file, $php_ini, should start with $ext_start and <b>not</b> $wrong_ext_start.";
                    $errors[ERROR_INI_WRONG_ZE_START] = $bad_zend_ext_msg;
                    $loader_path = $bad_start_matches[1];
                }
            }
        }
    }
    $loader_path = trim($loader_path);
    if ($loader_path === '') {
        $errors[ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration file, $php_ini.";
    } elseif (!@file_exists($loader_path)) {
        $errors[ERROR_INI_LOADER_FILE_NOT_FOUND] = "The loader file  $loader_path, listed in the configuration file, $php_ini, does not exist or is not accessible.";
    } elseif (basename($loader_path) == $loader_path) {
        $errors[ERROR_INI_NOT_FULL_PATH] = "A full path must be specified for the loader file in the configuration file, $php_ini.";
    }
    return array('location' => $loader_path, 'errors' => $errors);
}

function zend_extension_line_missing($ini_path)
{
    $loader_loc = get_loader_location_from_ini($ini_path);
    return (!empty($loader_loc['errors']) && array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$loader_loc['errors']));
}

function find_additional_ioncube_ini()
{
    $sys = get_sysinfo();
    $ioncube_ini = '';

    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
        foreach ($ini_files as $f) {
            $fn = trim($f);
            $bfn = basename($fn);
            if (preg_match('/ioncube/i',$bfn)) {
                $ioncube_ini = $fn;
                break;
            }
        }
    }
    return $ioncube_ini;
}

function get_additional_ini_files()
{
    $sys = get_sysinfo();
    $ini_files = array();
    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
    }
    return (array_map('trim',$ini_files));
}

function all_ini_contents()
{
    $sys = get_sysinfo();
    $output = '';

    $output .= ";;; *MAIN INI FILE AT ${sys['PHP_INI']}* ;;;" . PHP_EOL;
    $output .= get_file_contents($sys['PHP_INI']);
    $other_inis = get_additional_ini_files();
    foreach ($other_inis as $inif) {
        $output .= ";;; *Additional ini file at $inif* ;;;" . PHP_EOL;
        $output .= get_file_contents($inif);
    }
    $here = unix_path_dir();
    $unrec_ini_files = unrecognised_inis_webspace($here);
    foreach ($unrec_ini_files as $urinif) {
        $output .= ";;; *UNRECOGNISED INI FILE at $urinif* ;;;" . PHP_EOL;
        $output .= get_file_contents($urinif);
    }
    return $output;
}

function scan_inis_for_loader()
{
    $ldloc = array('location' => '', 'errors' => array());
    $sysinfo = get_sysinfo();
    if (empty($sysinfo['PHP_INI'])) {
        $ini_files_not_found = array("Main ini file");
        $ini_file_list = get_additional_ini_files();
    } else {
        $ini_files_not_found = array();
        $ini_file_list = array_merge(array($sysinfo['PHP_INI']),get_additional_ini_files());
    }
    $server_type = find_server_type();
    $shared_server = SERVER_SHARED == $server_type;
    foreach ($ini_file_list as $f) {
        $ldloc = get_loader_location_from_ini($f);
        if (array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$ldloc['errors'])) {
            unset($ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND]);
        } 
        if ($shared_server && array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            if (false == user_ini_space_path($f)) {
                $ldloc['errors'][ERROR_INI_NOT_FOUND] = "A system ini file cannot be found or read by the Wizard - you cannot do anything about this on your shared server.";
            } else {
                $ldloc['errors'][ERROR_INI_USER_INI_NOT_FOUND] = $ldloc['errors'][ERROR_INI_NOT_FOUND];
            }
        } elseif (array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            $ini_files_not_found[] = $f;
        }
        if (!empty($ldloc['location'])) {
            break;
        }
    }
    if (!empty($ini_files_not_found)) {
        $plural = (count($ini_files_not_found) > 1)?"s":"";
        $ldloc['errors'][ERROR_INI_NOT_FOUND] = "The following ini file$plural could not be found by the Wizard: " . join(',',$ini_files_not_found);
        if (is_restricted_server()) {
            $ldloc['errors'][ERROR_INI_NOT_FOUND] .= "<br> This may be due to server restrictions in place.";
        }
    }
    if (empty($ldloc['location'])) {
        $ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration.";
    }
    return $ldloc;
}

function find_loader_filesystem()
{
    $ld_inst_dir = loader_install_dir(find_server_type());
    $loader_name = get_loader_name();
    $suggested_loader_path = $ld_inst_dir . DIRECTORY_SEPARATOR . $loader_name;
    if (@file_exists($suggested_loader_path)) {
        $location = $suggested_loader_path;
    } elseif (@file_exists($loader_name)) {
        $location = @realpath($loader_name);
    } else {
        $ld_loc = get_loader_location();
        if (@file_exists($ld_loc)) {
            $location = $ld_loc;
        } else {
            $location = '';
        }
    }
    return $location;
}

function find_loader($search_directories_if_not_ini = false)
{
    $sysinfo = get_sysinfo();
    $php_ini = $sysinfo['PHP_INI'];
    $rtl_path = get_runtime_loading_path_if_applicable();
    $location = '';
    $errors = array();

    if (!empty($rtl_path)) {
        $location = $rtl_path;
    } else {
        $loader_ini = scan_inis_for_loader();
        $location = $loader_ini['location'];
        $errors = $loader_ini['errors'];
    }
    if (empty($location) && (empty($errors) || $search_directories_if_not_ini)) {
        $errors = array(); 
        $location = find_loader_filesystem();
        if (empty($location)) {
            $errors[ERROR_LOADER_NOT_FOUND] = 'The loader file could not be found in standard locations.';
        }
    }
    if (!empty($errors)) {
        return $errors;
    } else {
        return $location;
    }
}

function zend_extension_line_start()
{
    $sysinfo = get_sysinfo();
    $is_53_or_later = is_php_version_or_greater(5,3);
    return (is_bool($sysinfo['THREAD_SAFE']) && $sysinfo['THREAD_SAFE'] && !$is_53_or_later ? 'zend_extension_ts' : 'zend_extension');
}

function ioncube_loader_version_information()
{
    $old_version = true;
    $liv = "";
    $lv = "";
    $mv = 0;
    if (function_exists('ioncube_loader_iversion')) {
        $liv = ioncube_loader_iversion();
        $lv = sprintf("%d.%d.%d", $liv / 10000, ($liv / 100) % 100, $liv % 100);

        $latest_version =  get_latestversion();

        $lat_parts = explode('.',$latest_version);
        $cur_parts = explode('.',$lv);

        if (($cur_parts[0] > $lat_parts[0]) || 
            ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] > $lat_parts[1]) ||
             ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] == $lat_parts[1] && $cur_parts[2] >= $lat_parts[2])) {
            $old_version = false;
        } else {
            $old_version = $latest_version;
        }
        $mv = $cur_parts[0];
    }
    return array($lv,$mv,$old_version);
}

function default_loader_version_info()
{
    return array();
}

function get_loader_version_info()
{
    return get_remote_session_value('loader_version_info',LOADER_LATEST_VERSIONS_URL,'default_loader_version_info');
}

function calc_platform()
{
    $platform = array();
    $platform_info = get_platforminfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($osvar,$exact_match) = get_reqd_version($loader['osvariants']);
    } else {
        $osvar = null;
        if (is_ms_windows()) {
            $sys = get_sysinfo();
            $phpc = (empty($sys['PHP_COMPILER']))?'vc6':strtolower($sys['PHP_COMPILER']); 
            $osvar = ($sys['THREAD_SAFE']?'':'nonts_') . $phpc;
        }
    }
    foreach ($platform_info as $p) {
        if ($p['os'] == $loader['oscode'] && $p['arch'] == $loader['arch'] && (empty($osvar) || $p['os_mod'] == "_" . $osvar)) {
            $platform = $p;
            break;
        }
    }
    return $platform;
}

function get_platform()
{
    static $this_platform;

    if (!isset($this_platform)) {
        $this_platform = calc_platform();
    }

    return $this_platform;
}

function is_legacy_platform()
{
    $platform = get_platform();
    return array_key_exists('is_legacy',$platform);
}

function calc_dirname()
{
    $dirname = '';
    $platform = get_platform();
    if (!empty($platform)) {
        $dirname = $platform['dirname'];
    }
    return $dirname;
}

function calc_loader_latest_version()
{
    $lv_info = get_loader_version_info();
    $latest_version = RECENT_LOADER_VERSION;
    if (!empty($lv_info)) {
        $dirname = calc_dirname();
      
        if (!empty($dirname)) {
            $compiler_specific_version = false;
            if (is_ms_windows()) {
                $sys = get_sysinfo();
                $phpc = strtolower($sys['PHP_COMPILER']);
                if (!empty($phpc)) {
                    $dirname_comp = $dirname . "_" . $phpc;
                    if (array_key_exists($dirname_comp,$lv_info)) {
                        $latest_version = $lv_info[$dirname_comp];
                        $compiler_specific_version = true;
                    }
                }
            }
            if (!$compiler_specific_version && array_key_exists($dirname,$lv_info)) {
                $latest_version = $lv_info[$dirname];
            }
        } 
    }
    return $latest_version;
}

function get_latestversion()
{
    static $latest_version;

    if (empty($latest_version)) {
        $latest_version = calc_loader_latest_version();
    }
    return $latest_version;
}


function runtime_loader_location()
{
    $loader_path = false;
    $ext_path = extension_dir_path();
    if ($ext_path !== false) {
        $id = $ext_path;
        $here = dirname(__FILE__);
        if (isset($id[1]) && $id[1] == ':') {
            $id = str_replace('\\','/',substr($id,2));
            $here = str_replace('\\','/',substr($here,2));
        }
        $rd=str_repeat('/..',substr_count($id,'/')).$here.'/';
        $i=strlen($rd);

        $loader_loc = DIRECTORY_SEPARATOR . basename($here) . DIRECTORY_SEPARATOR . get_loader_name();
        while($i--) {
            if($rd[$i]=='/') {
                $loader_path = runtime_location_exists($ext_path,$rd,$i,$loader_loc);
                if ($loader_path !== false) {
                    break;
                }
            }
        }

        if (!$loader_path && !empty($loader_loc) && @file_exists($loader_loc)) {
            $loader_path = basename($loader_loc);
        }
    }
    return $loader_path;
}

function runtime_location_exists($ext_dir,$path_str,$sep_pos,$loc_name)
{
    $sub_path = substr($path_str,0,$sep_pos);
    $lp = $sub_path . $loc_name;
    $fqlp = $ext_dir.$lp;

    if(@file_exists($fqlp)) {
        return $lp;
    } else {
        return false;
    }
}

function runtime_loading_is_possible() {
    return !((is_php_version_or_greater(5,2,5)) || is_restricted_server() || !ini_get('enable_dl') || !function_exists('dl') || function_is_disabled('dl') || threaded_and_not_cgi());
}

function shared_and_runtime_loading()
{
    return (find_server_type() == SERVER_SHARED && empty($_SESSION['use_ini_method']) && runtime_loading_is_possible());
}

function get_valid_runtime_loading_path($ignore_loading_check = false)
{
    if ($ignore_loading_check || runtime_loading_is_possible()) {
        return runtime_loader_location();
    } else {
        return false;
    }
}

function runtime_loading($rtl_path = null)
{
    if (empty($rtl_path)) {
        $rtl_path = get_valid_runtime_loading_path();
    }
    if (!empty($rtl_path) && @dl($rtl_path)) {
        return $rtl_path;
    } else {
        return false;
    }
}

function get_runtime_loading_path_if_applicable()
{
    $rtl = null;
    if (shared_and_runtime_loading()) {
        $rtl = get_valid_runtime_loading_path();
    }
    return $rtl;
}

function try_runtime_loading_if_applicable()
{
    $rtl_path = get_runtime_loading_path_if_applicable();
    if (!empty($rtl_path)) {
        return runtime_loading($rtl_path);
    } else {
        return $rtl_path;
    }
}

function runtime_loading_instructions()
{
    $default = get_default_address();
    echo '<h4>Runtime Loading Instructions</h4>';
    echo '<div class=panel>';
    echo '<p>On your shared server the Loader can be installed using the runtime loading method.';
    echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";

    if ('.' == extension_dir()) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        echo "Please note that on your system the Loader <em>must</em> be present in the same " . $dirphrase . " as the first encoded file accessed.";
    }
    echo '<ol>';
    loader_download_instructions(); 
    $loader_dir = loader_install_instructions(SERVER_SHARED,dirname(__FILE__));
    shared_test_instructions();
    echo '</ol>';
    echo '</div>';
}

function runtime_loading_errors()
{
    $errors = array();
    $ext_path = extension_dir_path();
    if (false === $ext_path) {
        $errors[ERROR_RUNTIME_EXT_DIR_NOT_FOUND] = "Extensions directory cannot be found.";
    } else {
        $expected_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . get_loader_name();
        if (!@file_exists($expected_file)) {
            $errors[ERROR_RUNTIME_LOADER_FILE_NOT_FOUND] = "The Loader file was expected to be at $expected_file but could not be found.";
        } else {
            $errors = loader_compatibility_test($expected_file);
        }
    }
    return $errors;
}


function windows_package_name()
{
    $sys = get_sysinfo();
	$loader = get_loaderinfo();
    return (LOADERS_PACKAGE_PREFIX . 'win' . '_' . ($sys['THREAD_SAFE']?'':'nonts_') . strtolower($sys['PHP_COMPILER']) .  '_' . $loader['arch']);
}

function unix_package_name()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($reqd_version,$exact_match) = get_reqd_version($loader['osvariants']);
        if ($reqd_version) {
            $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $reqd_version . '_' . $loader['arch'];
        } else {
            $basename = "";
        }
    } else {
        $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $loader['arch'];
    }
    return array($basename,$multiple_os_versions);
}

function loader_download_instructions()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;

    if (is_ms_windows()) {
        if (is_bool($sysinfo['THREAD_SAFE'])) {
            $download_str = '<li>Download the following archive of Windows ' . $sysinfo['PHP_COMPILER'];
            if (!$sysinfo['THREAD_SAFE']) {
                $download_str .= ' non-TS';
            }
            $download_str .= ' ' . $loader['arch'] . ' Loaders:';
            echo $download_str;
            $basename = windows_package_name();
            echo make_archive_list($basename,array('zip'));
            echo 'A Loaders archive can also be downloaded from <a href="' . LOADERS_PAGE . '" target="loaders">' . LOADERS_PAGE . '</a>.';
        } else {
            echo '<li>Download a Windows Loaders archive from <a href="' . LOADERS_PAGE  . '" target=loaders>here</a>. If PHP is built with thread safety disabled, use the Windows non-TS Loaders.';
        }
    } else {
        list($basename,$multiple_os_versions) = unix_package_name(); 
        if ($basename == "") {
            echo '<li>Download a ' . $loader['osname'] . ' ' . $loader['arch'] . ' Loaders archive from <a href="' . LOADERS_PAGE . '" target="loaders">here</a>.';
            echo "<br>Your system appears to be ${loader['osnamequal']} for ${loader['wordsize']} bit. If Loaders are not available for that exact release of ${loader['osname']}, Loaders built for an earlier release should work. Note that you may need to install back compatibility libraries for the operating system.";
            echo '<br>If you cannot find a suitable loader then please raise a ticket at <a href="'. SUPPORT_SITE . '">our support helpdesk</a>.';
        } else {
            echo '<li>Download one of the following archives of Loaders for ' . $loader['osnamequal'] . ' ' . $loader['arch'] . ':'; 
            if (SERVER_SHARED == find_server_type()) {
                $archives = array('zip','tar.gz');
            } else {
                $archives = array('tar.gz','zip');
            }
            echo make_archive_list($basename,$archives);
            echo "</p>";
            if ($multiple_os_versions && !$exact_match) {
                echo "<p>Note that you may need to install back compatibility libraries for  ${loader['osname']}.</p>";
            }
        }
    }

    echo '</li>';
}

function ini_dir()
{
    $sysinfo = get_sysinfo();
    $parent_dir = '';
    if (!empty($sysinfo['PHP_INI'])) {
        $parent_dir = dirname($sysinfo['PHP_INI']);
    } else {
        $parent_dir = $_SERVER["PHPRC"];
        if (@is_file($parent_dir)) {
            $parent_dir = dirname($parent_dir);
        }
    }
    return $parent_dir;
}

function unix_install_dir()
{
    $ext_dir = extension_dir_path();
    $cur_dir = @realpath('.');
    if (empty($ext_dir) || $ext_dir == $cur_dir) {
        $loader_dir = UNIX_SYSTEM_LOADER_DIR;
    } else {
        $loader_dir = $ext_dir;
    }
    return $loader_dir;
}

function windows_install_dir()
{
    $sysinfo = get_sysinfo();
    if ($sysinfo['SS'] == 'IIS') {
        if (false === ($ext_dir = extension_dir_path())) {
            $parent_dir = ini_dir();
            $ext_dir = $parent_dir . '\\ext';
            if (!empty($parent_dir) && @file_exists($ext_dir)) {
                $loader_dir = $ext_dir;
            } else {
                $loader_dir = $_SERVER['windir'] . '\\' . WINDOWS_IIS_LOADER_DIR;
            }
        } else {
            $loader_dir = $ext_dir;
        }
    } else {
        if (false === ($ext_dir = extension_dir_path())) {
			$parent_dir = ini_dir();
			$loader_dir = $parent_dir . '\\' . 'ioncube';
		} else {
			$loader_dir = $ext_dir;
		}
    }
    return $loader_dir;
}

function loader_install_dir($server_type)
{
    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $loader_dir = get_default_loader_dir_webspace();
    } elseif (is_ms_windows()) {
        $loader_dir = windows_install_dir();
    } else {
        $loader_dir = unix_install_dir();
    }
    return $loader_dir;
}

function writeable_directories()
{
    $root_path = @realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    $root_path_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
    $above_root_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/../cgi-bin");

    $paths = array();
    foreach (array($root_path,$above_root_path,$root_path_cgi_bin,$above_root_cgi_bin) as $p) {
        if (@is_writeable($p)) {
            $paths[] = $p;
        }
    }
    return $paths;
}

function loader_install_instructions($server_type,$loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = loader_install_dir($server_type);
    }
    if (SERVER_LOCAL == $server_type) {
        echo "<li>Put the Loader files in <code>$loader_dir</code></li>";
    } else {
        echo "<li>Transfer the Loaders to your web server and install in <code>$loader_dir</code></li>";
    }
    return $loader_dir;
}

function zend_extension_lines($loader_dir)
{
    $zend_extension_lines = array();
    $sysinfo = get_sysinfo();
    $qt = (is_ms_windows()?'"':'');
    $loader = get_loaderinfo();

    if (!is_bool($sysinfo['THREAD_SAFE']) || !$sysinfo['THREAD_SAFE']) {
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file'] . $qt;
        $zend_extension_lines[] = "zend_extension = " . $path;
    }
    if ((!is_bool($sysinfo['THREAD_SAFE']) && !is_php_version_or_greater(5,3)) || $sysinfo['THREAD_SAFE']) {
        $line_start = is_php_version_or_greater(5,3)?'zend_extension':'zend_extension_ts';
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file_ts'] . $qt;
        $zend_extension_lines[] = $line_start . " = " . $path;
    }
    return $zend_extension_lines;
}

function user_ini_base()
{
    $doc_root_path = realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    if (!empty($above_root_path) && @is_writeable($above_root_path)) {
        $start_path = $above_root_path;
    } else {
        $start_path = $doc_root_path;
    }
    return $start_path;
}

function user_ini_space_path($file)
{
    $user_base = user_ini_base();
    $fpath = @realpath($file);
    if (!empty($fpath) && (0 === strpos($fpath,$user_base))) {
        return $fpath;
    } else {
        return false;
    }
}

function default_ini_path()
{
    return (realpath($_SERVER['DOCUMENT_ROOT']));
}

function shared_ini_location()
{
    $phprc = getenv('PHPRC');
    if (!empty($phprc)) {
        $phprc_path = user_ini_space_path($phprc);
        if (false !== $phprc_path) {
            return $phprc_path;
        } else {
            return default_ini_path();
        }
    } else {
        return default_ini_path();
    }
}


function zend_extension_instructions($server_type,$loader_dir)
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();
    $editing_ini = true;

    $php_ini_name = ini_file_name();

    if (isset($sysinfo['PHP_INI']) && @file_exists($sysinfo['PHP_INI'])) {
        $php_ini_path = $sysinfo['PHP_INI'];
    } else {
        $php_ini_path = '';
    }

    if (is_bool($sysinfo['THREAD_SAFE'])) {
        $kwd = zend_extension_line_start();
    } else {
        $kwd = 'zend_extension/zend_extension_ts';
    }

    $server_type_code = server_type_code();

    $zend_extension_lines = zend_extension_lines($loader_dir);

    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $ini_dir = shared_ini_location();
        $php_ini_path = $ini_dir . DIRECTORY_SEPARATOR . $php_ini_name;
        if (@file_exists($php_ini_path)) {
            $edit_line = "<li>Edit the <code>$php_ini_name</code> in the <code>$ini_dir</code> directory";
            if (zend_extension_line_missing($php_ini_path) && @is_writeable($php_ini_path) && @is_writeable($ini_dir)) {
                if (function_exists('file_get_contents')) {
                    $ini_strs = @file_get_contents($php_ini_path);
                } else {
                    $lines = @file($php_ini_path);
                    $ini_strs = join(' ',$lines);
                }
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                        fwrite($fh,$zl . PHP_EOL);
                    }
                    fwrite($fh,$ini_strs);
                    fclose($fh);
                    $editing_ini = false;
                    echo "<li>Your php.ini file at $php_ini_path has been modified to include the necessary line for the ionCube Loader.";
                } else {
                    echo $edit_line;
                }
            } else {
               echo $edit_line;
            }
        } else {
            $download_ini_file = "<li><a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">Save this  <code>$php_ini_name</code> file</a> and upload it to <code>$ini_dir</code> (full path on your server).";
            if (@is_writeable($ini_dir)) {
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                       fwrite($fh,$zl . PHP_EOL);
                    }
                    if (!empty($sysinfo['PHP_INI']) && is_readable($sysinfo['PHP_INI'])) {
                        if (function_exists('file_get_contents')) {
                           $ini_strs = @file_get_contents($sysinfo['PHP_INI']);
                        } else {
                           $lines = @file($sysinfo['PHP_INI']);
                           $ini_strs = join(' ',$lines);
                        }
                        fwrite($fh,$ini_strs);
                    }
                    fclose($fh); 
                    echo "<li>A <code>$php_ini_name</code> file has been created for you in <code>$ini_dir</code>.";
                } else {
                    echo $download_ini_file;
                }
            } else {
                echo $download_ini_file;
            }
            $editing_ini = false;
        }
    } elseif (!empty($sysinfo['PHP_INI'])) {
        if (empty($sysinfo['PHP_INI_DIR'])) {
            echo "<li>Edit the file <code>${sysinfo['PHP_INI']}</code>";
        } else {
            $php_ini_path = find_additional_ioncube_ini();
            if (empty($php_ini_path)) {
                $php_ini_name = ADDITIONAL_INI_FILE_NAME;
                echo "<li><a href=\"$base&amp;page=phpconfig&amp;download=1&amp;newlinesonly=1&amp;ininame=$php_ini_name&amp;stype=$server_type_code\">Save this $php_ini_name file</a> and put it in your ini files directory, <code>${sysinfo['PHP_INI_DIR']}</code>";
                $editing_ini = false;
            } else {
                $php_ini_name = basename($php_ini_path);
                echo "<li>Edit the file <code>$php_ini_path</code>";
            }
        }
    } else {
        echo "<li>Edit the system <code>$php_ini_name</code> file";
    }
    if ($editing_ini) {
        echo " and <b>before</b> any other $kwd lines ensure that the following is included:<br>";
        foreach ($zend_extension_lines as $zl) {
            echo "<code>$zl</code><br>";
        }
        if (!empty($php_ini_path)) {
            if (zend_extension_line_missing($php_ini_path)) {
                echo "<a>Alternatively, replace your current <code>$php_ini_path</code> file with <a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">this new $php_ini_name file</a>."; 
            }
        }
    }
    echo '</li>';
}

function server_restart_instructions()
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();

    if ($sysinfo['SS']) {
		if ($sysinfo['SS'] == 'PHP-FPM') {
			echo "<li>Restart PHP-FPM.</li>";
		} else {
			echo "<li>Restart the ${sysinfo['SS']} server software.</li>";
		}
    } else {
        echo "<li>Restart the server software.</li>";
    }

    echo "<li>When the server software has restarted, <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the Loader</a>.</li>";

	if ($sysinfo['SS'] && $sysinfo['SS'] == 'PHP-FPM') {
		echo '<li>If the Loader installation failed, check the PHP-FPM error log file for errors.</li>';
    } elseif ($sysinfo['SS'] == 'Apache' && !is_ms_windows()) {
        echo '<li>If the Loader installation failed, check the Apache error log file for errors and see our guide to <a target="unix_errors" href="'. UNIX_ERRORS_URL . '">Unix related errors</a>.</li>';
    }
}

function shared_test_instructions()
{
    $base = get_base_address();
    echo "<li><a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">Click here to test the Loader</a>.</li>";
}

function link_to_php_ini_instructions()
{
    $default = get_default_address();
    echo "<p><a href=\"{$default}&amp;stype=s&amp;ini=1\">Please click here for instructions on using the php.ini method instead</a>.</p>";
}

function php_ini_instruction_list($server_type)
{
    echo '<h4>Installation Instructions</h4>';
    echo '<div class=panel>';
    echo '<ol>';

    loader_download_instructions(); 
    $loader_dir = loader_install_instructions($server_type);
    zend_extension_instructions($server_type,$loader_dir);
    if ($server_type != SERVER_SHARED || !own_php_ini_possible()) {
        server_restart_instructions();
    } else {
        shared_test_instructions();
    } 
    echo '</ol>';
    echo '</div>';
}

function php_ini_install_shared($give_preamble = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();
    if ($give_preamble) {
        echo "<p>On your <strong>shared</strong> server, the Loader should be installed using a <code>$php_ini_name</code> configuration file.";
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";
    }

    if (own_php_ini_possible()) {
        echo '<p>With your hosting account, you may be able to use your own PHP configuration file.</p>';
    } else {
        echo "<p>It appears that you cannot install the ionCube Loader using the <code>$php_ini_name</code> file. Your server provider or system administrator should be able to perform the installation for you. Please refer them to the following instructions.</p>";
    }

    php_ini_instruction_list(SERVER_SHARED);
}

function php_ini_install($server_type_desc = null, $server_type = SERVER_DEDICATED, $required = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();

    echo '<p>';
    if ($server_type_desc) {
        echo "For a <strong>$server_type_desc</strong> server ";
    } else {
        echo "For this server ";
    }

    if ($required) {
        echo "you should install the ionCube Loader using the <code>$php_ini_name</code> configuration file.";
    } else {
        echo "installing the ionCube Loader using the <code>$php_ini_name</code> file is recommended.";
    }
    if ($server_type_desc) {
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a $server_type_desc server</a>.)";
    }
    echo '</p>';
      
    php_ini_instruction_list($server_type);
}



function help_resources($error_list = array())
{
	$self = get_self();
    $base = get_base_address();
    $server_type_code = server_type_code();
    $server_type = find_server_type();
    $sysinfo = get_sysinfo();
    $resources = array(
            '<a target="_blank" href="' . LOADERS_FAQ_URL . '">ionCube Loaders FAQ</a>',
            '<a target="_blank" href="' . LOADER_FORUM_URL . '">ionCube Loader Forum</a>'
        );
    if (SERVER_SHARED != $server_type || own_php_ini_possible(true)) {
		$support_info = array ( 
			'department' 		=> WIZARD_SUPPORT_TICKET_DEPARTMENT,
			'subject' 			=> "ionCube Loader installation problem",
			'message' 			=> support_ticket_information()
		   );
		if (SERVER_LOCAL == $server_type && !info_should_be_disabled()) {
			$temp_files = system_info_temporary_files();
		} else {
			$temp_files = NULL;
		}
		if (!empty($temp_files)) {
			$support_info['ini'] = base64_encode(file_get_contents($temp_files['ini']));
			$support_info['phpinfo'] = base64_encode(file_get_contents($temp_files['phpinfo']));
			$support_info['additional'] = base64_encode(file_get_contents($temp_files['additional']));
			
			$loader_path = find_loader(true);
			if (is_string($loader_path)) {		
				$support_info['loader'] = base64_encode(file_get_contents($loader_path));
				$support_info['loader_name'] = basename($loader_path);
			} else {
				$support_info['loader'] = '';
				$support_info['loader_name'] = '';
			}
		} else {
			$support_info['ini'] = '';
			$support_info['phpinfo'] = '';
			$support_info['additional'] = '';
			$support_info['loader'] = '';
			$support_info['loader_name'] = '';
		}
		 
        $resources[2] = '<form action="' . SUPPORT_SITE . 'lw_index.php' .'" method="POST" id="support-ticket"><a href="" onclick="document.getElementById(\'support-ticket\').submit(); return false;">Raise a support ticket through our helpdesk</a>';
		$resources[2] .= '<input type="hidden" name="department" value="' . $support_info['department'] . '"/>';
		$resources[2] .= '<input type="hidden" name="subject" value="' . $support_info['subject'] . '"/>';
		$resources[2] .= '<input type="hidden" name="message" value="' . $support_info['message'] . '"/>';
		if (!empty($temp_files)) {
			$resources[2] .= '<input type="hidden" name="phpinfo" value="' . $support_info['phpinfo'] . '"/>';
			$resources[2] .= '<input type="hidden" name="ini" value="' . $support_info['ini'] . '"/>';
			$resources[2] .= '<input type="hidden" name="additional" value="' . $support_info['additional'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader" value="' . $support_info['loader'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader_name" value="' . $support_info['loader_name'] . '"/>';
		}
		$resources[2] .= '</form>';
    } 
	
    if (SERVER_SHARED == $server_type && own_php_ini_possible(true) && !user_ini_space_path($sysinfo['PHP_INI'])) {
        $resources[3] = '<strong>Please check with your host that you can create php.ini files that will override the system one.</strong>';
    }
    return $resources;
}

function system_info_temporary_files()
{
    $tmpfname_ini = get_tempnam("/tmp", "INI");
    $tmpfname_ini .= ".ini";
    $fh_ini = @fopen($tmpfname_ini,'wb');
    if ($fh_ini) {
        $config = all_ini_contents();
        fwrite($fh_ini,$config);
        fclose($fh_ini);
    } else {
        $tmpfname_ini = '';
    }

    $tmpfname_pinf = get_tempnam("/tmp", "PIN");
    $tmpfname_pinf .= ".html";
    $fh_pinfo = @fopen($tmpfname_pinf,'wb');
    if ($fh_pinfo) {
        ob_start();
        @phpinfo();
        $pinfo = ob_get_contents();
        ob_end_clean();
        fwrite($fh_pinfo,$pinfo);
        fclose($fh_pinfo);
    } else {
        $tmpfname_pinf = '';
    }

    $tmpfname_add = get_tempnam("/tmp", "ADD");
    $tmpfname_add .= ".html";
    $fh_add = @fopen($tmpfname_add,'wb');
    if ($fh_add) {
        ob_start();
        extra_page(false);
        $extra = ob_get_contents();
        ob_end_clean();
        fwrite($fh_add,$extra);
        fclose($fh_add);
    } else {
        $tmpfname_add = '';
    }

    if (empty($tmpfname_ini) || empty($tmpfname_pinf) || empty($tmpfname_add)) {
        return (array());
    } else {
        return (array('ini'           =>   $tmpfname_ini,
                      'phpinfo'       =>   $tmpfname_pinf,
                      'additional'    =>   $tmpfname_add));
    }
}

function get_tempnam($default_tmp_dir = '', $prefix = '')
{
	if (function_exists('sys_get_temp_dir')) {
		return tempnam(sys_get_temp_dir(),$prefix);
	} else {
		return @tempnam($default_tmp_dir, $prefix);
	}
}
function system_info_archive_page()
{
    info_disabled_check();
	$server_type = find_server_type();
	if (SERVER_LOCAL != $server_type) {
		exit;
	}
    $loader = find_loader(true);
    if (is_string($loader)) {
        $loader_file = $loader;
    } else {
        $loader_file = '';
    }
    $all_files = system_info_temporary_files();
    if (!empty($all_files)) {
        if (!empty($loader_file)) {
            $all_files['loader'] = $loader_file;
        }
        $archive_name =  get_tempnam('/tmp',"ARC");
        if (extension_loaded('zip')) {
            $archive_name .= '.zip';
            $zip = @new ZipArchive();
            $mode = @constant("ZIPARCHIVE::OVERWRITE");
            if (!$zip || $zip->open($archive_name, $mode)!==TRUE) {
                $archive_name = '';
            } else {
                foreach($all_files as $f) {
                    $zip->addFile($f,basename($f));
                }
                $zip->close();
            }
        } elseif (extension_loaded('zlib') && !is_ms_windows()) {
            $tar_name = $archive_name . ".tar";
            $all_files_str = join(' ',$all_files);
            $script = "tar -chf $tar_name $all_files_str";
            $result = @system($script,$retval);
            if ($result !== false) {
                $archive_name = $tar_name . '.gz';
                $zp = gzopen($archive_name,"w9");
                $tar_contents = get_file_contents($tar_name);
                gzwrite($zp,$tar_contents);
                gzclose($zp);
            } else {
                $archive_name = '';
            }
        } else {
            $archive_name = '';
        }
    } else {
        $archive_name = '';
    }
    if ($archive_name) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. $archive_name);
        @readfile($archive_name);
    } else {
        $self = get_self();
        $base = get_base_address();
        $server_type_code = server_type_code();
        heading();
        echo "<p>A downloadable archive of system information could not be created.<br> 
            <strong>Please save each of the following and then attach those files to the support ticket:</strong></p>"; 
        echo "<ul>";
        echo "<li><a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo()</a></li>";
        echo "<li><a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a></li>";
        echo "<li><a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional information</a></li>";
        echo "<li><a href=\"$self?page=loaderbin\">loader file</a></li>";
        echo "</ul>";
        footer(true);
    }
}

function support_ticket_information($error_list = array())
{
    $sys = get_sysinfo();
    $ld = get_loaderinfo();

    $ticket_strs = array();
    $ticket_strs[] = "PLEASE DO NOT REMOVE THE FOLLOWING INFORMATION\r\n";
    $ticket_strs[] = "==============\r\n";
    if (!empty($error_list)) {
        $ticket_strs[] = "[hr]";
        $ticket_strs[] = "ERRORS";
        $ticket_strs[] = "[table]";
        $ticket_strs[] = '[tr][td]' . join('[/td][/tr][tr][td]',$error_list) . '[/td][/tr]';
        $ticket_strs[] = "[/table]";
    }
    $ticket_strs[] = "[hr]";
    $ticket_strs[] = "SYSTEM INFORMATION";
    $info_lines = array();
    $info_lines["Wizard version"] = script_version();
    $info_lines["PHP uname"] = $ld['uname'];
    $info_lines["Machine architecture"] = $ld['arch'];
    $info_lines["Word size"] = $ld['wordsize'];
    $info_lines["Operating system"] = $ld['osname'] . ' ' . $ld['osver'];
    if (selinux_is_enabled() || possibly_selinux()) {
        $info_lines["Security enhancements"] = "SELinux";
    } elseif (grsecurity_is_enabled()) {
        $info_lines["Security enhancements"] = "Grsecurity";
    } else {
        $info_lines["Security enhancements"] = "None";
    }
    $info_lines["PHP version"] = PHP_VERSION; 
    if ($sys['DEBUG_BUILD']) {
        $info_lines["DEBUG BUILD"] = "DEBUG BUILD OF PHP";
    }
    if (!$sys['SUPPORTED_COMPILER']) {
        $info_lines["SUPPORTED PHP COMPILER"] = "FALSE";
        $info_lines["PHP COMPILER"] = $sys['PHP_COMPILER'];
    }
    $info_lines["Is CLI?"] = ($sys['IS_CLI']?"Yes":"No");
    $info_lines["Is CGI?"] = ($sys['IS_CGI']?"Yes":"No");
    $info_lines["Is thread-safe?"] = ($sys['THREAD_SAFE']?"Yes":"No");
    $info_lines["Web server"] = $sys['FULL_SS'];
    $info_lines["Server type"] = server_type_string();
    $info_lines["PHP ini file"] = $sys['PHP_INI'];
    if (!@file_exists($sys['PHP_INI'])) {
        $info_lines["Ini file found"] = "INI FILE NOT FOUND";
    } else {
        if (is_readable($sys['PHP_INI'])) {
            $info_lines["Ini file found"] = "INI FILE READABLE";
        } else {
            $fh = @fopen($sys['PHP_INI'],"rb");
            if ($fh === false) {
                $info_lines["Ini file found"] = "INI FILE FOUND BUT POSSIBLY NOT READABLE";
            } else {
                $info_lines["Ini file found"] = "INI FILE READABLE";
            }
        }
    }
    $info_lines["PHPRC"] = $sys['PHPRC'];
    $loader_path = find_loader();
    if (is_string($loader_path)) {
        $info_lines["Loader path"] =  $loader_path;
        $info_lines["Loader file size"] = filesize($loader_path) . " bytes.";
        $info_lines["Loader MD5 sum"] =  md5_file($loader_path);
    } else {
        $info_lines["Loader path"] =  "LOADER PATH NOT FOUND";
    }
    $server_type_code = server_type_code();
    if (!empty($_SESSION['hostprovider'])) {
      $info_lines['Hosting provider'] = $_SESSION['hostprovider'];
      $info_lines['Provider URL'] = $_SESSION['hosturl'];
    }
    $info_lines["Wizard script path"] = '[url]http://' . $_SERVER["HTTP_HOST"] . get_self() . '?stype='. $server_type_code . '[/url]';
    $ticket_strs[] = "[table]";
    foreach ($info_lines as $h => $i) {
        $value = (empty($i))?'EMPTY':$i;
        $ticket_strs[] = '[tr][td]' . $h . '[/td]' . '[td]' . $value . '[/td][/tr]';
    }
    $ticket_strs[] = '[/table]';
    $ticket_strs[] = '[hr]';
    $ticket_strs[] = "\r\n==============\r\n";
    $ticket_strs[] = "PLEASE ENTER ANY ADDITIONAL INFORMATION BELOW\r\n";

    $support_ticket_str = join('',$ticket_strs);
    return urlencode($support_ticket_str);
}

function wizard_stats_data($page_id)
{
    $data = array();

    try_runtime_loading_if_applicable();
    $sysinfo = get_sysinfo();
    $ldinfo = get_loaderinfo();

    $data['sessionid'] = session_id();
    $data['wizard_version'] = script_version();
    $data['server_type'] = server_type_code();
    $data['hostprovider'] = (isset($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $data['hosturl'] = (isset($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $data['page_id'] = $page_id;
    $data['loader_state'] = (extension_loaded(LOADER_EXTENSION_NAME))?'installed':'failure';
    $data['ini_location'] = $sysinfo['PHP_INI'];
    $data['is_cgi'] = ($sysinfo['IS_CGI'])?"yes":"no";
    $data['is_ts'] = ($sysinfo['THREAD_SAFE'])?"yes":"no";
    $data['arch'] = $ldinfo['arch'];
    $data['php_version'] = PHP_VERSION;
    $data['os'] = $ldinfo['osname'];
    $data['word_size'] = $ldinfo['wordsize'];
    $data['referrer'] =  $_SERVER["HTTP_HOST"] . get_self();

    return $data;
}

function send_stats($page_id = 'default')
{
    $server_type = find_server_type();
    $res = false;

    if (SERVER_LOCAL != $server_type) {
        $stats_data = wizard_stats_data($page_id);

        if (!isset($_SESSION['stats_sent'][$page_id][$stats_data['loader_state']])) {
            $url = WIZARD_STATS_URL;

            if (!empty($stats_data)) {
                if(function_exists('http_build_query')) {
                    $qparams = http_build_query($stats_data);
                } else {
                    $qparams = php4_http_build_query($stats_data);
                }
                $url .= '?' . $qparams;
                $res = remote_file_contents($url);
            }
            $_SESSION['stats_sent'][$page_id][$stats_data['loader_state']] = 1;
        } else {
            $res = true;
        }
    } else {
        $res = 'LOCAL';
    }
    return $res;
}

function os_arch_string_check($loader_str)
{
    $errors = array();
    if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_str,$os_matches)) {
        $loader_info = get_loaderinfo();
        $dirname = calc_dirname();
        $packed_osname = preg_replace('/\s/','',strtolower($loader_info['osname']));
        if (strtolower($dirname) != $os_matches[1] && $packed_osname != $os_matches[2]) {
            $errors[ERROR_LOADER_WRONG_OS] = "You have the wrong loader for your operating system, ". $loader_info['osname'] . ".";
        } else {
            $loader_wordsize = (strpos($os_matches[3],'64') === false)?32:64;
            if ($loader_info['arch'] != ($ap = required_loader_arch($os_matches[3],$loader_info['oscode'],$loader_wordsize))) {
                $err_str = "You have the wrong loader for your machine architecture.";
                $err_str .= " Your system is " . $loader_info['arch'];
                $err_str .= " but the loader you are using is for " . $ap . ".";
                $errors[ERROR_LOADER_WRONG_ARCH] = $err_str;
            }
        }
    }
    return $errors;
}

function get_loader_strings($loader_location)
{
    if (function_exists('file_get_contents')) {
        $loader_strs = @file_get_contents($loader_location);
    } else {
        $lines = @file($loader_location);
        $loader_strs = join(' ',$lines);
    }
    return $loader_strs;
}

function loader_system($loader_location)
{
    $loader_system = array();
    $loader_strs = get_loader_strings($loader_location);

    if (!empty($loader_strs)) {

        if (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
            $loader_system['oscode'] = 'win';
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '_nonts')?0:1;
			if (preg_match("/_localtime([0-9][0-9])/i",$loader_strs,$size_matches)) {
				$loader_system['wordsize'] = ($size_matches[1] == '64')?64:32;
			} else {
				$loader_system['wordsize'] = 32;
			}
            $loader_system['arch'] = ($loader_system['wordsize'] == 64)?'x86-64':'x86';
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
			if ($loader_system['php_version_major'] == 8 && $loader_system['php_version_minor'] >= 1) {
				$loader_system['compiler'] = 'VC16';
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] >= 2) {
				$loader_system['compiler'] = 'VC15'; 
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] < 2) {
				$loader_system['compiler'] = 'VC14'; 
			} elseif ($loader_system['php_version_major'] == 5 && $loader_system['php_version_minor'] >= 5) {
				$loader_system['compiler'] = 'VC11'; 
			} elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_system['compiler'] = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_system['compiler'] = 'VC6';
            }
        } elseif (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '-ts')?1:0;
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
            if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_strs,$os_matches)) {
                $loader_system['oscode'] = strtolower(substr($os_matches[2],0,3));
                $loader_system['wordsize'] = (strpos($os_matches[3],'64') === false)?32:64;
                $loader_system['arch'] = required_loader_arch($os_matches[3],$loader_system['oscode'],$loader_system['wordsize']);
                $loader_system['compiler'] = $os_matches[4];
            }
        }
        if (preg_match("/ionCube Loader Version\s+(\S+)/",$loader_strs,$loader_version)) {
            $loader_system['loader_version'] = $loader_version[1];
		} elseif (preg_match("/ioncube_loader_(\d{1,2}\.\d\.\d{1,2})\./",$loader_strs,$loader_version)){
			$loader_system['loader_version'] = $loader_version[1];
        } else {
            $loader_system['loader_version'] = 'UNKNOWN';
        }
        if (isset($loader_system['php_version_major'])) {
            $loader_system['php_version'] = $loader_system['php_version_major'] . '.' . $loader_system['php_version_minor'];
        }
    }
    return $loader_system;
}

function loader_compatibility_test($loader_location)
{
    $errors = array();

    $sysinfo = get_sysinfo();
    if (LOADER_NAME_CHECK) {
        $installed_loader_name = basename($loader_location);
        $expected_loader_name = get_loader_name();
        if ($installed_loader_name != $expected_loader_name) {
            $errors[ERROR_LOADER_UNEXPECTED_NAME] = "The installed loader (<code>$installed_loader_name</code>) does not have the name expected (<code>$expected_loader_name</code>) for your system. Please check that you have the correct loader for your system.";
        }
    }
    if (empty($errors) && !is_readable($loader_location)) {
        $execute_error = "The loader at $loader_location does not appear to be readable.";
        $execute_error .= "<br>Please check that it exists and is readable.";
        $execute_error .= "<br>Please also check the permissions of the containing ";
        $execute_error .= (is_ms_windows()?'folder':'directory') . '.';
		if ($sysinfo['SS'] == 'PHP-FPM') {
			$execute_error .= "<br>Please also check that PHP-FPM has been restarted.";
        } elseif (($sysinfo['SS'] == 'IIS') || !($sysinfo['IS_CGI'] || $sysinfo['IS_CLI'])) {
            $execute_error .= "<br>Please also check that the web server has been restarted.";
        }
        $execute_error .= ".";
        $errors[ERROR_LOADER_NOT_READABLE] = $execute_error;
    }
    $loader_strs = get_loader_strings($loader_location);
    $phpv = php_version(); 
    if (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
        if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
            $loader_php = $version_matches[1] . "." . $version_matches[2];
            $server_php =  $phpv['major'] . "." .  $phpv['minor'];
            $errors[ERROR_LOADER_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
        }
        if (is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'] && !is_ms_windows() && !(isset($version_matches[4]) && $version_matches[4] == '-ts')) {
            $errors[ERROR_LOADER_NONTS_PHP_TS] = "Your server is running a thread-safe version of PHP but the loader is not a thread-safe version.";
        } elseif (isset($version_matches[4]) && $version_matches[4] == '-ts' && !(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'])) {
            $errors[ERROR_LOADER_TS_PHP_NONTS] = "Your server is running a non-thread-safe version of PHP but the loader is a thread-safe version.";
        }
    } elseif (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
        if (!is_ms_windows()) {
            $errors[ERROR_LOADER_WIN_SERVER_NONWIN] = "You have a Windows loader but your server does not appear to be running Windows.";
        } else {
            if (isset($version_matches[4]) && $version_matches[4] == '_nonts' && is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) {
                $errors[ERROR_LOADER_WIN_NONTS_PHP_TS] = "You have the non-thread-safe version of the Windows loader but you need the thread-safe one.";
            } elseif (!(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) && !(isset($version_matches[4]) && $version_matches[4] == '_nonts')) {
                $errors[ERROR_LOADER_WIN_TS_PHP_NONTS] = "You have the thread-safe version of the Windows loader but you need the non-thread-safe one."; 
            }
            if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
                $loader_php = $version_matches[1] . "." . $version_matches[2];
                $server_php =  $phpv['major'] . "." .  $phpv['minor'];
                $errors[ERROR_LOADER_WIN_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
            }
                        
            if ($version_matches[1] == 8 && $version_matches[2] >= 1) {
                $loader_compiler = 'VC16';
            } elseif ($version_matches[1] == 7 && $version_matches[2] >= 2) {
                $loader_compiler = 'VC15'; 
            } elseif ($version_matches[1] == 7) {
                $loader_compiler = 'VC14'; 
            } elseif ($version_matches[1] == 5 && $version_matches[2] >= 5) {
                $loader_compiler = 'VC11'; 
            } elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_compiler = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_compiler = 'VC6';
            }
            if ($loader_compiler != $sysinfo['PHP_COMPILER']) {
                $errors[ERROR_LOADER_WIN_COMPILER_MISMATCH] = "Your loader was built using $loader_compiler but you need the loader built using ${sysinfo['PHP_COMPILER']}.";
            }
        }
    } else {
            $errors[ERROR_LOADER_PHP_VERSION_UNKNOWN] = "The PHP version for the loader cannot be determined - please check that you have a valid ionCube Loader.";
    } 
    $errors += os_arch_string_check($loader_strs);

    return $errors;
}


function shared_server()
{
    if (!$rtl_path = runtime_loading()) {
        if (empty($_SESSION['use_ini_method']) && runtime_loading_is_possible()) {
            runtime_loading_instructions();
        } else {
            php_ini_install_shared();
        }
    } else {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        echo "<p>The ionCube Loader $lv for PHP $phpv has been successfully installed.</p>";
        $is_legacy_loader = loader_major_version_instructions($mv);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,$newer_version);
        }
        successful_install_end_instructions($rtl_path);
    }
}

function dedicated_server()
{
    php_ini_install('dedicated or VPS', SERVER_DEDICATED, true);
}

function local_install()
{
    php_ini_install('local',SERVER_LOCAL, true);
}


function unregister_globals()
{
    if (!ini_get('register_globals')) {
        return;
    }

    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

function clear_session($persist = array())
{
    $persist['not_go_daddy'] = empty($_SESSION['not_go_daddy'])?0:1;
    $persist['use_ini_method'] = empty($_SESSION['use_ini_method'])?0:1;
    $persist['server_type'] = empty($_SESSION['server_type'])?SERVER_UNKNOWN:$_SESSION['server_type'];
    @session_destroy();
    $_SESSION = array();
    $_SESSION['CREATED'] = time();
    $_SESSION = $persist;
}

function can_archive()
{
	return (extension_loaded('zip') || (extension_loaded('zlib') && !is_ms_windows()));
}

function is_ioncube()
{
        return (($_SERVER["REMOTE_ADDR"] == IONCUBE_IP_ADDRESS) || ($_SERVER["REMOTE_ADDR"] == gethostbyname(IONCUBE_ACCESS_ADDRESS)));
}

function can_reach_ioncube()
{
	return (isset($_SESSION['remote_access_successful']));
}

function info_should_be_disabled($only_allow_ioncube = false)
{
    $elapsed = time() - max(filemtime(__FILE__),filectime(__FILE__));
	
	if (is_ioncube()) {
		$cutoff_time = IONCUBE_WIZARD_EXPIRY_MINUTES * 60;
	} else {
		if (!$only_allow_ioncube && !extension_loaded(LOADER_EXTENSION_NAME)) {
			$cutoff_time = WIZARD_EXPIRY_MINUTES * 60;
		} else {
			return true;
		}
	}
	
    return ($elapsed > $cutoff_time);
}

function info_disabled_text()
{
    return "The information you have tried to access has been disabled for security reasons. Please re-install this Loader Wizard script and try again.";
}

function info_disabled_check()
{
    if (info_should_be_disabled()) {
        heading();
        echo info_disabled_text();
        footer(true);
        exit;
    }
}

function run()
{

	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (preg_match('/googlebot/i',$user_agent)) {
		exit;
	}
    unregister_globals();
    if (is_php_version_or_greater(4,3,0)) {
        ini_set('session.use_only_cookies',1);
    }
    $session_ok = @session_start();

    if (!defined('PHP_EOL')) {
        if (is_ms_windows()) {
            define('PHP_EOL',"\r\n");
        } else {
            define('PHP_EOL',"\n");
        }
    }

    if (!isset($_SESSION['CREATED'])) {
        $_SESSION['CREATED'] = time();
    } elseif (time() - $_SESSION['CREATED'] > SESSION_LIFETIME_MINUTES * 60 ) {
        clear_session(); 
    }
    if (!isset($_SERVER)) $_SERVER =& $HTTP_SERVER_VARS;

    (php_sapi_name() == 'cli') && die("This script should only be run by a web server.\n");

    $page = get_request_parameter('page');
    $host = get_request_parameter('host');
    $clear = get_request_parameter('clear');
    $ini = get_request_parameter('ini');
    $timeout = get_request_parameter('timeout');

    if ($timeout) {
        $_SESSION['timing_out'] = 1;
        $_SESSION['initial_run'] = 0;
    }

    if (!empty($host)) {
        if ($host == 'ngd') {
            $_SESSION['not_go_daddy'] = 1;
        }
    }
    if (!empty($ini)) {
        $_SESSION['use_ini_method'] = 1;
    }

    if (!empty($clear)) {
        clear_session();
        unset($_SESSION['not_go_daddy']);
        unset($_SESSION['use_ini_method']);
        unset($_SESSION['server_type']);
    } else {
        $stype = get_request_parameter('stype');
        $hostprovider = get_request_parameter('hostprovider');
        $hosturl = get_request_parameter('hosturl');
        if (!empty($hostprovider)) {
            $_SESSION['hostprovider'] = $hostprovider;
            $_SESSION['hosturl'] = $hosturl;
        }
        $server_type = find_server_type($stype,false,true);
    }
    if ($session_ok && !$timeout && !isset($_SESSION['initial_run']) && empty($page)) {
        $_SESSION['initial_run'] = 1;
        initial_page();
        @session_write_close();
        exit;
    } else {
        $_SESSION['initial_run'] = 0;
    }

    if (empty($_SESSION['server_type'])) {
        $_SESSION['server_type'] = SERVER_UNKNOWN;
    }

    if (empty($page) || !function_exists($page . "_page")) {
        $page = get_default_page();
    } 

    $fn = "{$page}_page";
    $fn();

    @session_write_close();
    exit(0);
}

function wizardversion_page()
{
    $start_time = time();
    $wizard_version_only = get_request_parameter('wizard_only');
    $clear_session_info = get_request_parameter('clear_info');
    if ($clear_session_info) {
        unset($_SESSION['timing_out']);
        unset($_SESSION['latest_wizard_version']);
    }
    $wizard_version = latest_wizard_version();
    $message = '';
    if (false === $wizard_version) {
        $message = "0";
    } elseif (update_is_available($wizard_version)) {
        $message = "$wizard_version";
    } else {
        $message = "1";
    }
    echo $message;
    @session_write_close();
    exit(0);
}

function platforminfo_page()
{
    $message = '';
    $platforms = get_loader_platforms();
    $message = empty($platforms)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function loaderversion_page()
{
    $message = '';
    $loader_versions = get_loader_version_info();
    $message = empty($loader_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function compilerversion_page()
{
    $message = '';
    $compiler_versions = find_win_compilers();
    $message = empty($compiler_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function initial_page()
{
    $self = get_self();
    $start_page = get_default_address(false);
    $stage_timeout = 7000;
    $step_lag = 500;

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <style type="text/css">
        body {
            height: 100%;
            width: 100%;
        }
        </style>
        <script type="text/javascript">
        var timingOut = 0;
        var xmlHttpTimeout;
        var ajax;
        var statusPar;
        var stage_timeout = $stage_timeout;
        var step_lag = $step_lag;

        function checkNextStep(ajax,expected,continuation) {
            if (ajax.readyState==4 && ajax.status==200)
            {
                clearTimeout(xmlHttpTimeout);
                if (ajax.responseText == expected) {
                   setTimeout('',step_lag);
                   continuation();
                } else {
                   statusPar.innerHTML = 'Unable to check for update<br>script continuing';
                   setTimeout("window.location.href = '$start_page&timeout=1'",1000);
                }
            }
        }

        function getXmlHttp() {
            if (window.XMLHttpRequest) {
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xmlhttp;
        }
        var startMainLoaderWizard = function() {
            window.location.href = '$start_page';
        }
        var loaderVersionCheck = function() {
            statusPar.innerHTML = 'Stage 4/4: Getting latest loader versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",startMainLoaderWizard);
            }
            xmlHttp.open("GET","$self?page=loaderversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var platformCheck = function() {
            statusPar.innerHTML = 'Stage 3/4: Getting platform information';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",loaderVersionCheck);
            }
            xmlHttp.open("GET","$self?page=platforminfo",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var compilerVersionCheck = function() {
            statusPar.innerHTML = 'Stage 2/4: Getting compiler versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",platformCheck);
            }
            xmlHttp.open("GET","$self?page=compilerversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var startChecks = function() {
            statusPar = document.getElementById('status');
            statusPar.innerHTML = 'Stage 1/4: Getting Loader Wizard version';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",compilerVersionCheck);
            }
            xmlHttp.open("GET","$self?page=wizardversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        function ajaxTimeout(){
           ajax.abort();
           statusPar.innerHTML = 'Cannot reach server<br>script continuing';
           setTimeout("window.location.href = '$start_page&timeout=1'",1000);
        }
        </script>
    </head>
    <body>

    <div id="loading"><script type="text/javascript">document.write('<p>Initialising<br>ionCube Loader Wizard<br><span id="status"></span></p>');</script><p id="noscript">Your browser does not support JavaScript so the ionCube Loader Wizard initialisation cannot be made now. This script can get the latest loader version information from the ionCube server when you go to the next page.<br>Please choose one of the following. <br>If the script appears to hang please restart the script and choose the "NO" option.<br><br><br><a href="$start_page">YES - my server DOES have internet access</a><br><br><a href="$start_page&timeout=1">NO - my server does NOT have internet access</a></p></div>
    <script type="text/javascript">
        document.getElementById('noscript').style.display = 'none';
        window.onload = startChecks;
    </script>
    </body>
    </html>
EOT;
}

function default_page($loader_extension = LOADER_EXTENSION_NAME)
{
    $self = get_self();
    foreach (array('self') as $vn) {
        if (empty($$vn)) {
			$server_data = print_r($_SERVER,true);
            error("Unable to initialise ($vn)". ' $_SERVER is: ' . $server_data);
        }
    }

    heading();

    $wizard_update = check_for_wizard_update(true);

    $rtl = try_runtime_loading_if_applicable();

    $server_type = find_server_type();

    if (extension_loaded($loader_extension) && $server_type != SERVER_UNKNOWN) {
        loader_already_installed($rtl);
    } else {
        loader_not_installed();
    }
    send_stats('default');

    footer($wizard_update);
}

function uninstall_wizard_instructions()
{
    echo '<p><strong>For security reasons we advise that you remove this Wizard script from your server now that the ionCube Loader is installed.</strong></p>';
}

function contact_script_provider_instructions()
{
    echo '<p>Please contact the script provider if you do experience any problems running encoded files.</p>';
}

function may_need_to_copy_ini()
{
    $sys = get_sysinfo();
    if (ini_same_dir_as_wizard() && $sys['IS_CGI']) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        $ini = ini_file_name();
        echo "<p>Please note that if encoded files in a different $dirphrase from the Wizard fail then you should attempt to copy the $ini file to each $dirphrase in which you have encoded files.</p>";
    }
}

function ioncube_24_is_available()
{
	$loaderinfo = get_loaderinfo();
	$php_ver = php_version();
   
	return ($loaderinfo['oscode'] == 'lin' && (($php_ver['major'] == 5 && $php_ver['minor'] >= 3) || $php_ver['major'] > 5) );
}

function ioncube_24_is_enabled()
{
	$ic24_enabled = ini_get(IC24_ENABLED_INI_PROPERTY);
	return $ic24_enabled;
}

function ioncube_24_information()
{
    if (ioncube_24_is_available() && !ioncube_24_is_enabled()) {
        $self = get_self();
        echo '<div class="ic24">';
        echo '<div class="ic24graphic">';
        echo '<a target="_blank" href="' . IONCUBE24_URL . '"><img id="ic24logo" src="' . $self . '?page=ic24logo" alt="ionCube24 logo"></a>';
        echo '</div>';
        echo '<div id="ic24info">';
        echo '<p><strong>Bonus Features!</strong> The ionCube Loader can also give ';
        echo '<strong>real-time intrusion protection</strong> to protect against malware and <strong>PHP error reporting</strong> ';
        echo 'to alert when things go wrong on your website.</p>';
        echo '<p>These features are disabled by default but easily activated. ';
        echo '<strong><a target="_blank" href="' . IONCUBE24_URL . '">visit ioncube24.com</a></strong> to find out more.</p>';
        echo '</div>';
        echo '</div>';
    }
}

function cli_install_instructions()
{

	if (is_php_version_or_greater(5,3)) {
		$cli_loader_installed = shell_exec('php -r "echo extension_loaded(\"' . LOADER_EXTENSION_NAME . '\");"');
		
		if (!$cli_loader_installed) {
			$cli_php_ini_output = shell_exec("php --ini");
			
			$ini_loader_loc = scan_inis_for_loader();
		
			if (!is_null($cli_php_ini_output)) {
				echo '<div class="panel">';
				echo '<h4>Loader Installation for Command-Line (CLI) PHP</h4>';
				echo "<p>At present it does not look like the ionCube Loader is installed for command-line (CLI) PHP.</p>";
				echo "<p>Please note that if you need to run the CLI PHP, such as for <strong>cron jobs</strong>, then please ensure the zend_extension line for the ionCube Loader is included in your CLI PHP configuration.</p>";
				
				if (!empty($ini_loader_loc['location'])) {
					echo "<p>The zend_extension line that needs to be copied is:</p>";
					echo "<p><kbd>zend_extension = " . $ini_loader_loc['location'] . "</kbd></p>";
				}
				
				echo "<p>Your CLI PHP Configuration is:</p>";
				echo '<div class="terminal">';
				echo "<pre>";
				echo $cli_php_ini_output;
				echo "</pre>";
				echo '</div>';
				echo '</div>';
			}
		}
	}
}

function successful_install_end_instructions($rtl_path = null)
{
    if (empty($rtl_path)) {
        may_need_to_copy_ini();
    } elseif (is_string($rtl_path)) {
        echo "<p>The runtime loading method of installation was used with path <code>$rtl_path</code></p>";
    }
    contact_script_provider_instructions();
    if (is_legacy_platform()) {
        legacy_platform_instructions();
    }
	
	if (!is_ms_windows() && is_php_version_or_greater(5,3)) {
		cli_install_instructions();
	}
	
    uninstall_wizard_instructions();
	
	ioncube_24_information();
}

function loader_major_version_instructions($mv)
{
    if ($mv < LATEST_LOADER_MAJOR_VERSION) {
        echo "<p><strong>The installed version of the Loader cannot run files produced by the most recent ionCube Encoder.</strong>";
        echo " You will need a version " . LATEST_LOADER_MAJOR_VERSION . " ionCube Loader to run such files.</p>";
    }
    return ($mv < LATEST_LOADER_MAJOR_VERSION);
}

function loader_already_installed($rtl = null)
{
    list($lv,$mv,$newer_version) = ioncube_loader_version_information();
    $phpv = php_version_maj_min();
    $php_str = ' for PHP ' . $phpv;
    echo '<div class="success">';
    echo '<h4>Loader Installed</h4>';
    if ($newer_version) {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is <strong>already installed</strong> but it is an old version.';
        echo ' It is recommended that the Loader be upgraded to the latest version if possible.</p>';
        $know_latest_version = is_string($newer_version);
        $is_legacy_loader = loader_major_version_instructions($mv);
        echo '</div>';
        loader_upgrade_instructions($lv,$newer_version);
    } else {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is already installed and encoded files should run without problems.</p>'; 
        echo '</div>';
        $is_legacy_loader = loader_major_version_instructions($mv,true);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,true);
        }
    }

    successful_install_end_instructions($rtl);
}

function loader_upgrade_instructions($installed_version,$newer_version)
{
    if ($newer_version) {
        echo '<div class="panel">';
        echo '<h4>Loader Upgrade Instructions</h4>';
        $restart_needed = true;
        $server_type = find_server_type();
        if ($server_type == SERVER_SHARED || $server_type == SERVER_UNKNOWN) {
            $loader_path = find_loader(true);
            if (!is_string($loader_path) || false === user_ini_space_path($loader_path)) {
                $verb_case = ($server_type == SERVER_UNKNOWN)?"may":"will";
                echo "<p>Please note that you $verb_case need your system administrator to do the following to upgrade. The web server will need to be restarted after the loader file is changed.</p>";
            }
            $restart_needed = false;
        }
        if (is_string($newer_version)) {
            $version_str = "version $newer_version";
        } else {
            $version_str = "a newer version";
        }
        $loader_name =  get_loader_name();
        echo "<p>To upgrade from version $installed_version to $version_str of the ionCube Loader, please replace your existing loader file, $loader_name, with
            the file of the same name from one of the following packages:</p>";
        if (is_ms_windows()) {
            $basename = windows_package_name();
        } else {
            list($basename,$multiple_os_versions) = unix_package_name();
        }
        echo make_archive_list($basename,array('zip','tar.gz'));
        if ($restart_needed) {
            echo "<p>Once you have replaced the loader file please restart your web server.</p>";
        }
        echo '</div>';
    }
}

function legacy_platform_warning()
{
    $leg_warn = '<p><strong>You are on a platform on which ionCube Loaders are no longer being developed. ';
    $leg_warn .= 'Loaders on your platform may not be able to run files produced by the latest ionCube Encoder. ';
    $leg_warn .= 'Please switch, if possible, to a platform on which loaders are currently supported. ';
    $leg_warn .= 'A list of currently supported platforms is shown on our <a href="' . LOADERS_PAGE . '" target="loaders">loaders page</a>.</strong></p>';

    return $leg_warn;
}

function legacy_platform_instructions()
{
    echo legacy_platform_warning();
}

function loader_not_installed()
{
    $loader = get_loaderinfo();
    $sysinfo = get_sysinfo();

    $stype = get_request_parameter('stype');
    $manual_select = get_request_parameter('manual');
    $host_type = find_server_type($stype,$manual_select,true);

    if ($host_type != SERVER_UNKNOWN && is_array($loader) && !$sysinfo['DEBUG_BUILD']) {
        $warnings = server_restriction_warnings();
        if (is_legacy_platform()) {
            $warnings[] = legacy_platform_warning();
        }
        if (empty($_SESSION['use_ini_method']) && $host_type == SERVER_SHARED && runtime_loading_is_possible()) {
            $errors = runtime_loading_errors();
        } else {
            $errors = ini_loader_errors();
            $warnings = array_merge($warnings,ini_loader_warnings());
        }
        if (!empty($errors)) {
            if (count($errors) > 1) {
                $problem_str = "Please note that the following problems currently exist";
            } else {
                $problem_str = "Please note that the following problem currently exists";
            }
            echo '<div class="alert">' .$problem_str . ' with the ionCube Loader installation:';
            echo make_list($errors,"ul"); 
            echo '</div>';
        }
        if (!empty($warnings)) {
            $addword = empty($errors)?'':'also';
            $plural = (count($warnings)>1)?'s':'';
            echo '<div class="warning">';
            echo "Please note $addword the following issue$plural:";
            echo make_list($warnings,"ul"); 
            echo '</div>';
        }
    }
    if (!isset($stype)) {
        echo '<p>To use files that have been protected by the <a href="' . ENCODER_URL . '" target=encoder>ionCube PHP Encoder</a>, a component called the ionCube Loader must be installed.</p>';
    }

    if (!is_supported_php_version()) {
        echo '<p>Your server is running PHP version ' . PHP_VERSION . ' and is
                unsupported by ionCube Loaders.  Recommended PHP 4 versions are PHP 4.2 or higher, 
                PHP 5.1 or higher for PHP 5, PHP 7.1 or higher for PHP 7 and PHP 8.1 or higher for PHP 8. Please note that there is not an ionCube Loader for PHP 8.0.</p>';
	} elseif ($latest_supported_php_version = is_after_max_php_version_supported()) {
		echo '<strong>Your server is running PHP version ' . PHP_VERSION . ' and is
                currently unsupported by any ionCube Loaders. <br/>This may change in the future if a Loader is produced for your PHP platform.<br/>In the meantime please downgrade PHP to version ' . $latest_supported_php_version . '.</strong>';
    } elseif ($sysinfo['DEBUG_BUILD']) {
         echo '<p>Your server is currently running a debug build of PHP. The Loader cannot be installed with a debug build of PHP. Please ensure that PHP is reconfigured with debug disabled. Note that debug builds of PHP cannot help in debugging PHP scripts.</p>'; 
    } elseif (!is_array($loader)) {
        if ($loader == ERROR_WINDOWS_64_BIT) {
            echo '<p>Loaders for 64-bit PHP on Windows are not currently available. However, if you <b>install and run 32-bit PHP</b> the corresponding 32-bit loader for Windows should work.</p>';
            if ($sysinfo['THREAD_SAFE']) {
                echo '<li>Download one of the following archives of 32-bit Windows x86 loaders:';
            } else {
                echo '<li>Download one of the following archives of 32-bit Windows non-TS x86 loaders:';
            }
            echo make_archive_list(windows_package_name());
        } else {
            echo '<p>There may not be an ionCube Loader available for your type of system at the moment. However, if you create a <a href="'  . SUPPORT_SITE . '">support ticket</a> more advice and information may be available to assist. Please include the URL for this Wizard in your ticket.</p>';
        }
    } elseif (!$sysinfo['SUPPORTED_COMPILER']) {
        $supported_compilers = supported_win_compilers();
        $supported_compiler_string = join('/',$supported_compilers);
        echo '<p>At the current time the ionCube Loader requires PHP to be built with ' . $supported_compiler_string . '. Your PHP software has been built using ' . $sysinfo['PHP_COMPILER'] . '. Supported builds of PHP are available from <a href="https://windows.php.net/download/">PHP.net</a>.';
    } else {
        switch ($host_type) {
            case SERVER_SHARED:
                shared_server();
                break;
            case SERVER_DEDICATED:
                dedicated_server();
                break;
            case SERVER_LOCAL:
                local_install();
                break;
            default:
                echo server_selection_form();
                break;
        }
    }
}

function server_selection_form()
{
    $self = get_self();
    $timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?1:0;
    $hostprovider = (!empty($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $hostprovider = htmlspecialchars($hostprovider, ENT_QUOTES, 'UTF-8');
    $hosturl = (!empty($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $hosturl =  htmlspecialchars($hosturl, ENT_QUOTES, 'UTF-8');
    $form = <<<EOT
    <p>This Wizard will give you information on how to install the ionCube Loader.</p>
    <p>Please select the type of web server that you have and then click Next.</p>
    <script type=text/javascript>
        function trim(s) {
            return s.replace(/^\s+|\s+$/g,"");
        }
        function input_ok() {
            var l = document.getElementById('local');
            if (l.checked) {
                return true;
            } 

            var s = document.getElementById('shared');
            var d = document.getElementById('dedi');

            if (!s.checked && !d.checked) {
                alert("Please select one of the server types.");
                return false;
            } else {
                var hn = document.getElementById('hostprovider');
                var hu = document.getElementById('hosturl');
                var hostprovider = trim(hn.value);
                var hosturl = trim(hu.value);

                if (!hostprovider || !hosturl) {
                    alert("Please enter both a hosting provider name and their URL.");
                    return false;
                }
                if (hostprovider.length < 1) {
                    alert("The hosting provider name should be at least 1 character in length.");
                    return false;
                }
                if (!hosturl.match(/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+/)) {
                    alert("The hosting provider URL is invalid.");
                    return false;
                }
                if (hosturl.length < 4) {
                    alert("The hosting provider URL should be at least 4 characters in length.");
                    return false;
                }
            }
            return true;
        }
    </script>
    <form method=GET action=$self>
        <input type="hidden" name="page" value="default">
        <input type="hidden" name="timeout" value="$timeout">
        <input type=radio id=shared name=stype value=s onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=shared>Shared <small>(for example, server with FTP access only and no access to php.ini)</small></label><br>
        <input type=radio id=dedi name=stype value=d onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=dedi>Dedicated or VPS <small>(server with full root ssh access)</small></label><br>
        <div id="hostinginfo" style="display: none">If you are on a shared or dedicated server, please give your hosting provider and their URL:
            <table>
                <tr><td><label for=hostprovider>Name of your hosting provider</label></td><td><input type=text id="hostprovider" name=hostprovider value="$hostprovider"></td></tr>
                <tr><td><label for=hosturl>URL of your hosting provider</label></td><td><input type=text id="hosturl" name=hosturl value="$hosturl"></td></tr>
            </table>
        </div>
        <input type=radio id=local name=stype value=l onclick="document.getElementById('hostinginfo').style.display = 'none';"><label for=local>Local install</label>
        <p><input type=submit value=Next onclick="return (input_ok(this) && showOverlay());"></p>
    </form>
EOT;
    return $form;
}

function phpinfo_page()
{
    info_disabled_check();
    if (function_is_disabled('phpinfo')) {
        echo "phpinfo is disabled on this server";
    } else {
        @phpinfo();
    }
}

function loader_check_page($ext_name = LOADER_EXTENSION_NAME)
{
    heading();

    $rtl_path = try_runtime_loading_if_applicable();
	
    if (extension_loaded($ext_name)) {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        $php_str = ' for PHP ' . $phpv;
        echo '<div class="success">';
        echo '<h4>Loader Installed Successfully</h4>';
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' <strong>is installed</strong> and encoded files should run successfully.';
        if ($newer_version) {
            echo ' Please note though that you have an old version of the ionCube Loader.</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            loader_upgrade_instructions($lv,$newer_version);
        } else {
            echo '</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            if ($is_legacy_loader) {
                loader_upgrade_instructions($lv,true);
            }
        }
        successful_install_end_instructions($rtl_path);
    } else {
        echo '<div class="failure">';
        echo '<h4>Loader Not Installed</h4>';
        echo '<p>The ionCube Loader is <b>not</b> currently installed successfully.</p>';
	
        if (!is_null($rtl_path)) {
            echo '<p>Runtime loading was attempted but has failed.</p>';
            echo '</div>';
            $rt_errors = runtime_loading_errors();
            if (!empty($rt_errors)) {
                list_loader_errors($rt_errors);
            } 
            link_to_php_ini_instructions();
        } else {
            echo '</div>';
            list_loader_errors();
        }
    }
	
    send_stats('check');
    footer(true);
}

function ini_loader_errors()
{
    $errors = array();
    if (SERVER_SHARED == find_server_type() && !own_php_ini_possible(true)) {
        $errors[ERROR_INI_USER_CANNOT_CREATE] = "It appears that you are not be able to create your own ini files on your shared server. <br><strong>You will need to ask your server administrator to install the ionCube Loader for you.</strong>";
    }
    $loader_loc = find_loader(false);
    if (is_string($loader_loc)) {
        if (!shared_and_runtime_loading()) {
            $sys = get_sysinfo();
            if (empty($sys['PHP_INI'])) {
                $errors[ERROR_INI_NO_PATH] = 'No file path found for the PHP configuration file (php.ini).';
            } elseif (!@file_exists($sys['PHP_INI'])) {
                $errors[ERROR_INI_NOT_FOUND] = 'The PHP configuration file (' . $sys['PHP_INI'] .') cannot be found.';
            }
        }
        $errors = $errors + loader_compatibility_test($loader_loc);
    } else {
        $errors = $errors + $loader_loc;
        $fs_location = find_loader_filesystem();
        if (!empty($fs_location)) {
            $fs_loader_errors = loader_compatibility_test($fs_location);
            if (!empty($fs_loader_errors)) {
                $errors[ERROR_LOADER_WRONG_GENERAL] = "The loader file found at $fs_location is not the correct one for your system.";
            }
            $errors = $errors + $fs_loader_errors;
        }
    } 
    return $errors;
}

function unix_path_dir($dir = '')
{
    if (empty($dir)) {
        $dir = dirname(__FILE__);
    }
    if (is_ms_windows()) {
        $dir = str_replace('\\','/',substr($dir,2));
    }
    return $dir;
}

function unrecognised_inis_webspace($startdir)
{
    $ini_list = array();

    $ini_name = ini_file_name();
    $sys = get_sysinfo();
    $depth = substr_count($startdir,'/');

    $rel_path = '';
    $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
    for ($seps = 0; $seps < $depth; $seps++) {
        $full_ini_loc = @realpath($startdir . '/' . $rel_path) . DIRECTORY_SEPARATOR . $ini_name;
        if (@file_exists($full_ini_loc) && $sys['PHP_INI'] != $full_ini_loc) {
            $ini_list[] = @realpath($full_ini_loc);
        }

        if (dirname($full_ini_loc) == $rootpath) {
            break;
        }
        $rel_path .= '../';
    }
    return $ini_list;
}

function correct_loader_wrong_location()
{
    $loader_location_pair = array();
    $loader_location = find_loader_filesystem();
    if (is_string($loader_location) && !empty($loader_location)) {
        $loader_errors = loader_compatibility_test($loader_location);
        if (empty($loader_errors)) {
            $ini_loader = scan_inis_for_loader();
            if (!empty($ini_loader['location'])) {
                $ini_loader_errors = loader_compatibility_test($ini_loader['location']);
                if (!empty($ini_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = dirname($ini_loader['location']);
                }
            } else {
                $std_dir = loader_install_dir(find_server_type());
                $std_ld_path = $std_dir . DIRECTORY_SEPARATOR . get_loader_name();
                if (@file_exists($std_ld_path)) {
                    $stdloc_loader_errors = loader_compatibility_test($std_ld_path);
                } else {
                    $stdloc_loader_errors = array("Loader file does not exist.");
                }
                if (!empty($stdloc_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = $std_dir;
                }
            }
        }
    }
    return $loader_location_pair;
}

function ini_loader_warnings()
{
    $warnings = array();
    if (find_server_type() == SERVER_SHARED)
    {
        if (own_php_ini_possible()) {
            $sys = get_sysinfo();
            $ini_name = ini_file_name();
            $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
            $root_ini_file = $rootpath . DIRECTORY_SEPARATOR . $ini_name;
            $cgibinpath = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
            $cgibin_ini_file = (empty($cgibinpath))?'':$cgibinpath . DIRECTORY_SEPARATOR . $ini_name;
            $here = unix_path_dir();
            $ini_files = unrecognised_inis_webspace($here);
            $shared_ini_loc = shared_ini_location();
            $shared_ini_file = $shared_ini_loc . DIRECTORY_SEPARATOR . $ini_name;
            $ini_dir = dirname($sys['PHP_INI']);
            $all_ini_locations_used = !empty($ini_files);
            foreach ($ini_files as $full_ini_loc) {
                $advice = "The file $full_ini_loc is not being recognised by PHP.";
                $advice .= " Please check that the name and location of the file are correct.";
                if (!ini_same_dir_as_wizard()) {
                    $ini_loc_dir = dirname($full_ini_loc);
                    if (!@file_exists($shared_ini_file) && !empty($shared_ini_loc) && $ini_loc_dir != $shared_ini_loc && $ini_dir != $shared_ini_loc) {
                        $all_ini_locations_used = false;
                        $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $shared_ini_loc . "</code>.";
                    } else {
                        if (!@file_exists($root_ini_file) && $rootpath != $shared_ini_loc && $full_ini_loc != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $rootpath . "</code>.";
                        } 
                        if (!empty($cgibin_ini_file) && !@file_exists($cgibin_ini_file) && $cgibinpath != $shared_ini_loc && $full_ini_loc != $cgibinpath && $cgibinpath != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= "  Please try copying the <code>$full_ini_loc</code> file to <code>" . $cgibinpath . "</code>.";
                        }
                        $herepath = realpath($here);
                        $here_ini_file = $herepath . DIRECTORY_SEPARATOR . $ini_name;
                        if (!@file_exists($here_ini_file) && $herepath != $rootpath && $herepath != $cgibinpath) {
                            $all_ini_locations_used = false;
                            $advice .= " It may be necessary to copy the <code>$full_ini_loc</code> file to <code>$herepath</code> and to all " . (is_ms_windows()?'folders':'directories') . ' in which you have encoded files';
                        }
                    }
                } else {
                    $all_ini_locations_used = false;
                }
                $warnings[] = $advice;
            }
            if ($all_ini_locations_used) {
                $warnings[] = "<strong>It looks as if ini files are not being recognised in any of the standard locations in your webspace. Please contact your hosting provider to check whether you can create your own PHP ini file and where it should go.</strong>";
            }
        } else {
            if (own_php_ini_possible(true)) {
                $warnings[] = "You may not be able to create your own ini files on your shared server. <br><strong>You might need to ask your server administrator to install the ionCube Loader for you.</strong>";
            }
        }
    } else {
        $loader_dir_pair = correct_loader_wrong_location();
        if (!empty($loader_dir_pair)) {
            $advice = "The correct loader for your system has been found at <code>${loader_dir_pair['loader']}</code>."; 
            if ($loader_dir_pair['loader'] != $loader_dir_pair['newloc']) {
                $advice .= " Please copy the loader from <code>${loader_dir_pair['loader']}</code> to <code>${loader_dir_pair['newloc']}</code>.";
            }
            $warnings[] = $advice;
        }
    }
    return $warnings;
}

function list_loader_errors($errors = array(),$warnings = array(),$suggest_restart = true)
{
    $default = get_default_address();
    $retry_message = '';

    
    if (empty($errors)) {
        $errors = ini_loader_errors();
        if (empty($warnings)) {
            $warnings = ini_loader_warnings();
        }
    }
	
    if (!empty($errors)) {
        $try_again = '<a href="#" onClick="window.location.href=window.location.href">try again</a>';
	
        echo '<div class="alert">';
        if (count($errors) > 1) {
            echo 'The following problems have been found with the ionCube Loader installation:';
            $retry_message = "Please correct those errors and $try_again.";
        } else {
            echo 'The following problem has been found with the ionCube Loader installation:';
            $retry_message = "Please correct that error and $try_again.";
        }
        if (array_key_exists(ERROR_INI_USER_CANNOT_CREATE,$errors)) {
            $retry_message = '';
        }
        echo make_list($errors,"ul");
        echo '</div>';
        if (!empty($warnings)) {
            echo '<div class="warning">';
            echo 'Please also note the following:';
            echo make_list($warnings,"ul");
            echo '</div>';
        }
    } elseif (!empty($warnings)) {
        echo '<div class="warning">';
        echo 'There are the following potential problems:';
        echo make_list($warnings,"ul");
        echo '</div>';
    } elseif ($suggest_restart) {
        if (SERVER_SHARED == find_server_type()) {
            echo "<p>Please contact your server administrator about installing the ionCube Loader.</p>";
        } else {
            if (selinux_is_enabled()) {
                echo "<p>It appears that SELinux is enabled on your server. This might be solved by running the command <code>restorecon [full path to loader file]</code> as root.</p>";
            } elseif (grsecurity_is_enabled()) {
                echo "<p>It appears that grsecurity is enabled on your server. Please run the command, <code>execstack -c [full path to loader file]</code> and then restart your web server.</p>";
            } else {
                $sysinfo = get_sysinfo();
                $ss = $sysinfo['SS'];
				if ($ss == 'PHP-FPM') {
					echo "<p>Please check that PHP-FPM has been restarted.</p>";
                } elseif (!$sysinfo['CGI_CLI'] || is_ms_windows()) {
                    echo "<p>Please check that the $ss web server software has been restarted.</p>";
                } 
            }
        }
    }
    echo '<div>';
    echo $retry_message;
    echo " You may wish to view the following for further help:";
    echo make_list(help_resources($errors),"ul");
    echo '<a href="' . $default . '">Click here to go back to the start of the Loader Wizard</a>.</div>';
}

function phpconfig_page()
{
    info_disabled_check();
    $sys = get_sysinfo();
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        } else {
			if (!preg_match('`^.*\.ini$`',$ini_file_name) || preg_match('`/`',$ini_file_name) || preg_match('`\\\`',$ini_file_name)) {
				die("Illegal file name $ini_file_name");
			}
		}
        header('Content-Type: text/plain');
        header('Content-Disposition: attachment; filename=' . $ini_file_name);
    } else {
        header('Content-Type: text/plain');
    }
    $exclude_original = get_request_parameter('newlinesonly');
    $prepend = get_request_parameter('prepend');
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    if (!empty($exclude_original) || !empty($prepend)) {
        $loader_dir = loader_install_dir($server_type);
        $zend_lines = zend_extension_lines($loader_dir);
        echo join(PHP_EOL,$zend_lines);
        echo PHP_EOL;
    }
    if (empty($ini_file_name) || empty($sys['PHP_INI_DIR']) || ($sys['PHP_INI_BASENAME'] == $ini_file_name)) {
        $original_ini_file = isset($sys['PHP_INI'])?$sys['PHP_INI']:'';
    } else {
        $original_ini_file = $sys['PHP_INI_DIR'] . DIRECTORY_SEPARATOR . $ini_file_name;
    }
    if (empty($exclude_original) && !empty($original_ini_file) && @file_exists($original_ini_file)) {
        if (!empty($download)) {
            @readfile($original_ini_file);
        } else {
            echo all_ini_contents();
        } 
    }
}

function extra_page($check_access_to_info = true)
{
    if ($check_access_to_info) {
		info_disabled_check();
	}
    heading();
    $sys = get_sysinfo();
    $ini_loader = scan_inis_for_loader();
    $ini_loader_path = $ini_loader['location'];
    $loader_path = find_loader(true);
    $ldinf = get_loaderinfo();
    $self = get_self();
    echo "<h4>Additional Information</h4>";
    echo "<table>";
    $lines = array();
    if (is_string($loader_path)) {
        $lines['Loader is at'] = $loader_path;
        $loader_system = loader_system($loader_path);
        if (!empty($loader_system)) {
            $lines['Loader OS code'] = $loader_system['oscode'];
            $lines['Loader architecture'] = $loader_system['arch'];
            $lines['Loader word size'] = $loader_system['wordsize'];
            $lines['Loader PHP version'] = $loader_system['php_version'];
            $lines['Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Loader compiler'] = $loader_system['compiler'];
            $lines['Loader version'] = $loader_system['loader_version'];
            $lines['File size is'] = filesize($loader_path) . " bytes.";
            $lines['MD5 sum is'] = md5_file($loader_path);
        }
        $lines['Loader file'] = "<a href=\"$self?page=loaderbin\">Download loader file</a>";
    } else {
        $lines['Loader file'] = "Loader cannot be found.";
    }
    $lines['Loader found in ini file'] = empty($ini_loader_path)?"No":"Yes";
    if (!empty($ini_loader_path) && (!is_string($loader_path) || $ini_loader_path != $loader_path)) {
        $lines['Loader location found in ini file'] =  $ini_loader_path;
        $loader_system = loader_system($ini_loader_path);
        if (!empty($loader_system)) {
            $lines['Ini Loader OS code'] = $loader_system['oscode'];
            $lines['Ini Loader architecture'] = $loader_system['arch'];
            $lines['Ini Loader word size'] = $loader_system['wordsize'];
            $lines['Ini Loader PHP version'] = $loader_system['php_version'];
            $lines['Ini Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Ini Loader compiler'] = $loader_system['compiler'];
            $lines['Ini Loader version'] = $loader_system['loader_version'];
        }
    }
    $lines["OS extra security"] = (selinux_is_enabled() || possibly_selinux())?"SELinux":(grsecurity_is_enabled()?"Grsecurity":"None");
    $lines['PHPRC is'] = $sys['PHPRC'];
    $lines['INI DIR is'] = $sys['PHP_INI_DIR'];
    $lines['Additional INI files'] = $sys['PHP_INI_ADDITIONAL'];
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    $lines['Server type is'] = server_type_string();
    $lines["PHP uname"] = $ldinf['uname'];
    $lines['Server word size is'] = $ldinf['wordsize'];
    $lines['Disabled functions'] = ini_get('disable_functions');
    $writeable_dirs = writeable_directories();
    $lines['Writeable loader locations'] = (empty($writeable_dirs))?"<em>None</em>":join(", ",$writeable_dirs);
    if (!empty($_SESSION['hostprovider'])) {
        $lines['Hosting provider'] = $_SESSION['hostprovider'];
        $lines['Provider URL'] = $_SESSION['hosturl'];
    }
    foreach ($lines as $h => $i) {
        $v = (empty($i))?'<em>EMPTY</em>':$i;
        echo '<tr><th>'. $h . ':</th>' . '<td>' . $v . '</td></tr>';
    }
    echo "</table>";
    footer(true);
}

function loaderbin_page()
{
    info_disabled_check();
    $loader_path = find_loader(true);
    if (is_string($loader_path)) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. basename($loader_path));
        @readfile($loader_path);
    }
}



function GoDaddy_root($html_root = '')
{
    if (empty($_SESSION['not_go_daddy']) && empty($_SESSION['godaddy_root'])) {
        $godaddy_pattern = "[\\/]home[\\/]content[\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z]+[\\/]html";

        if (empty($html_root)) {
            $html_root =  $_SERVER['DOCUMENT_ROOT'];
        }
        if (preg_match("@$godaddy_pattern@i",$html_root,$matches)) {
            $_SESSION['godaddy_root'] = $matches[0];
        } else {
            $_SESSION['not_go_daddy'] = 1;
            $_SESSION['godaddy_root'] = '';
        } 
    } elseif (!empty($_SESSION['not_go_daddy'])) {
        $_SESSION['godaddy_root'] = '';
    }
    if (!empty($_SESSION['godaddy_root'])) {
        $_SESSION['hostprovider'] = 'GoDaddy';
        $_SESSION['hosturl'] = 'www.godaddy.com';
    }
    return $_SESSION['godaddy_root'];
}

function GoDaddy_windows_instructions()
{
    $instr = "It appears that you are hosted on a Windows server at GoDaddy.<br/>";
    $instr .= "Please change to a Linux hosting plan at GoDaddy.<br />";
    $instr .=  "If you <a href=\"https://help.godaddy.com/\">contact their support team</a> they should be able to switch you to a Linux server.";

    echo $instr;
}

function GoDaddy_linux_instructions($html_dir)
{
    $base = get_base_address();
    $loader_name = get_loader_name();
    $zend_extension_line="<code>zend_extension = $html_dir/ioncube/$loader_name</code>";
    $php_ini_name = is_php_version_or_greater(5,0)?'php5.ini':'php.ini';
    $ini_path = $html_dir . '/' . $php_ini_name;

    $instr = array();
    $instr[] = 'In your html directory, ' . $html_dir . ', create a sub-directory called <b>ioncube</b>.';
    if (@file_exists($ini_path)) {
       $instr[] = "Edit the $php_ini_name in your  $html_dir and add the following line to the <b>top</b> of the file:<br>" . $zend_extension_line ;
    } else {
        $instr[] = "<a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=s&amp;download=1&amp;prepend=1\">Save this $php_ini_name file</a> and upload it to your html directory, $html_dir";
    }
    $instr[] = 'Download the <a target="_blank" href="' . IONCUBE_DOWNLOADS_SERVER . '"/ioncube_loaders_lin_x86.zip">Linux ionCube Loaders</a>.';
    $instr[] = 'Unzip the loaders and upload them into the ioncube directory you created previously.';
    $instr[] = 'The encoded files should now be working.';

    echo '<div class=panel>';
    echo (make_list($instr));
    echo '</div>';
}

function GoDaddy_page()
{
    $base = get_base_address();

    heading();

        $inst_str = '<h4>GoDaddy Installation Instructions</h4>';
        $inst_str .= '<p>It appears that you are hosted with GoDaddy (<a target="_blank" href="https://www.godaddy.com/">www.godaddy.com</a>). ';
        $inst_str .= "If that is <b>not</b> the case then please <a href=\"$base&amp;page=default&amp;host=ngd\">click here to go to the main page of this installation wizard</a>.</p>";
        $inst_str .= "<p>If you have already installed the loader then please <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the loader</a>.</p>";

        echo $inst_str;

        if (is_ms_windows()) {
            GoDaddy_windows_instructions();
        } else {
            GoDaddy_linux_instructions($_SESSION['godaddy_root']);
        }

    send_stats('gd_default');

    footer(true);
}



function get_request_parameter($param_name)
{
    static $request_array;

    if (!isset($request_array)) {
        if (isset($_GET)) {
            $request_array = $_GET;
        } elseif (isset($HTTP_GET_VARS)) {
            $request_array = $HTTP_GET_VARS;
        }
    }

    if (isset($request_array[$param_name])) {
        $return_value = strip_tags($request_array[$param_name]);
    } else {
        $return_value = null;
    }
    return $return_value;
}

function make_list($list_items,$list_type='ol')
{
    $html = '';
    if (!empty($list_items)) {
        $html .= "<$list_type>";
        $html .= '<li>';
        $html .= join('</li><li>',$list_items);
        $html .= '</li>';
        $html .= "</$list_type>";
    }
    return $html;
} 

function make_archive_list($basename,$archives_list = array(),$download_server = IONCUBE_DOWNLOADS_SERVER)
{
    if (empty($archives_list)) {
        $archives_list = array('tar.gz','zip');
    }

    foreach ($archives_list as $a) {
        $link_text = $a;
        $ext_sep = '.';
        $archive_list[] = "<a href=\"$download_server/$basename$ext_sep$a\">$link_text</a>";
    }

    return make_list($archive_list,"ul");
}

function error($m)
{
    die("<b>ERROR:</b> <span class=\"error\">$m</span><p>Please help us improve this script by <a href=\"". SUPPORT_SITE . "\">reporting this error</a> and including the URL to the script so that we can test it.");
}


function filter_server_input($server_var)
{
	$res = htmlspecialchars($_SERVER[$server_var], ENT_QUOTES, "UTF-8");
	return $res;
}

function failsafe_get_self()
{
    $result = '';
    $sfn = filter_server_input('SCRIPT_FILENAME');
    $dr = $_SERVER['DOCUMENT_ROOT'];
    if (!empty($sfn) && !empty($dr)) {
        if ($dr == '/' || $dr == '\\') {
            $result = $sfn;
        } else {
            $drpos = strpos($sfn,$dr);
            if ($drpos === 0) {
                $drlen = strlen($dr);
                $result = substr($sfn,$drlen);
            }
        }
        $result = str_replace('\\','/',$result);
    }
    if (empty($result)) {
        $result = DEFAULT_SELF;
    }
    return $result;
}

function get_self()
{ 
	$page = '';
    if (empty($_SERVER['PHP_SELF'])) {
        if (empty($_SERVER['SCRIPT_NAME'])) {
            if (empty($_SERVER['REQUEST_URI'])) {
                $page = failsafe_get_self();
            } else {
                $page = filter_server_input('REQUEST_URI');
            }
        } else {
            $page = filter_server_input('SCRIPT_NAME');
        }
    } else {
        $page = filter_server_input('PHP_SELF');
    }
	return $page;
}

function get_default_page()
{
    $godaddy_root = GoDaddy_root();
    if (empty($godaddy_root)) {
         $page = 'default';
    } else {
         $page = 'GoDaddy';
    }
    return $page;
}

function get_base_address()
{
    $self = get_self();
    $remote_timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?'timeout=1':'timeout=0';
    $using_ini = (isset($_SESSION['use_ini_method']) && $_SESSION['use_ini_method'])?'ini=1':'ini=0';
    return $self . '?' . $remote_timeout . '&' . $using_ini;
}

function get_default_address($include_timeout = true)
{
    if ($include_timeout) {
        $base =  get_base_address();
        $base .= "&amp;";
    } else {
        $base = get_self();
        $base .= "?";
    }
    $page = get_default_page();

    return $base . 'page=' . $page;
}

function heading()
{
    $self = get_self();

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <meta name="robots" content="noindex, nofollow">
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <script type="text/javascript">
            function showOverlay()
            {
                document.getElementById('overlay').style.display = 'block';
                return true;
            }

            function hideOverlay()
            {
                document.getElementById('overlay').style.display = 'none';
                return true;
            }
        </script>
    </head>
    <body onload="hideOverlay()">
    <div id="overlay">
        <div id="inner_overlay">Checking server configuration<br>Please wait</div>
    </div>
    <div id="header">
        <img src="?page=logo" alt="ionCube logo">
    </div>
	<div id="important">
	<h3 class="important">IMPORTANT: Ensure that This Script Is Removed When No Longer Required</h3>
	</div>
    <div id="main">
    <h2>ionCube Loader Wizard</h2>
EOT;
}

function footer($update_info = null)
{
    $self = get_self();
    $base = get_base_address();
    $default = get_default_address(false);
    $year = gmdate("Y");

    echo "</div>";
    echo "<div id=\"footer\">" .
    "Copyright ionCube Ltd. 2002-$year | " .
    "Loader Wizard version " . script_version() . " ";

    if ($update_info === true) {
        $update_info = check_for_wizard_update(false);  
    }
    $loader_wizard_loc = LOADER_WIZARD_URL;
    $wizard_version_string =<<<EOT
    <script type="text/javascript">
    var xmlhttp;
    function version_check()
    { 
        var body = document.getElementsByTagName('body')[0];
        var ldel = document.getElementById('loading');
        if (!ldel) {
            body.innerHTML += '<div id="loading"></div>';
            ldel = document.getElementById('loading');
        }
        ldel.innerHTML = '<p>Retrieving Wizard version information<br>Please wait</p>';
        ldel.style.display = 'block';
        ldel.style.height = '300px';
        ldel.style.left = '200px';
        ldel.style.border = '4px #660000 solid';
        if (window.XMLHttpRequest) {
            xmlhttp=new XMLHttpRequest();
        } else {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            var loadedOkay = 0;
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                var wizardversion = xmlhttp.responseText;
                var msg;
                clearTimeout(xmlHttpTimeout);
                buttons = '';
                if (wizardversion == '1') {
                    msg = 'You have the current version of the<br>ionCube Loader Wizard'; 
                } else if (wizardversion != '0') {
                    msg = 'A new version, ' + wizardversion + ', of the loader wizard is available';
                    buttons = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; window.open(\'$loader_wizard_loc\'); return false">Get new version</button> &nbsp;'; 
                } else {
                    msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
                }
                buttons += '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>'; 
                ldel.innerHTML = '<p>' + msg +  '<br>' + buttons + '</p>';
            }
        }
        xmlhttp.open("GET",'$self?page=wizardversion&wizard_only=1&clear_info=1',true);
        xmlhttp.send();
        var xmlHttpTimeout=setTimeout(ajaxTimeout,7000);
    }
    function ajaxTimeout(){
       xmlhttp.abort();
       msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
       button = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>';
       var ldel = document.getElementById('loading');
       ldel.innerHTML = '<p>' + msg +  '<br>' + button + '</p>';
    }
    </script>
EOT;

    $wizard_version_string .= '('; 
    if ($update_info === null) {
        $wizard_version_string .= '<a target="_blank" href="' . $loader_wizard_loc . '" onclick="version_check();return false;">check for new version</a>';
    } else if ($update_info !== false) {
        $wizard_version_string .= '<a href="' . LOADERS_PAGE .'" target="_blank">download version ' . $update_info . '</a>';
    } else {
        $wizard_version_string .=  "current";
    }
    $wizard_version_string .= ')'; 
    echo $wizard_version_string;

    $server_type_code = server_type_code();
	
	if (!info_should_be_disabled(true)) {
		echo " | <a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo</a>";
		echo " | <a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a>";
		echo " | <a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional</a>";
	}

    echo " | <a href=\"$default\" onclick=\"showOverlay();\">wizard start</a>";
    echo " | <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">loader test</a>";
    echo ' | <a href="' . LOADERS_PAGE . '" target="loaders">loaders</a>';

    echo "</div>\n";
    echo "\n</body></html>\n";
}

function css_page()
{
    header('Content-Type: text/css');
    echo <<<EOT
    body {
        font-family: verdana, helvetica, arial, sans-serif;
        font-size: 10pt;
        line-height: 150%;
        margin: 0px;
        min-height: 400px;
        position: relative;
    }

    code {
        color: #c00080;
    }

    li {
        margin-top: 10px;
    }
    #overlay {
        display: block;
        z-index: 100;
        position: absolute;
        top: 0;
        left: 0;
        padding: 0;
        margin: 0;
        width: 100%;
        height: 100%;
        background-color: white;
    }
    #inner_overlay {
        display: block;
        z-index: 100;
        position: absolute;
        font-size: 200%;
        color: #660000;
        top: 50%;
        left: 25%;
        width: 460px;
        height: 460px;
        line-height: 200%;
        text-align: center;
        vertical-align: middle;
    }

    #loading {
        display: block;
        position: absolute;
        top: 33%;
        left: 25%;
        margin: auto;
        height: 320px;
        width: 460px;
        padding: 4px;
        color: #660000;
        background-color: white;
        z-index: 100;
    }

    #loading p {
        position: absolute;
        margin-top: 10px;
        text-align: center;
        vertical-align: middle;
        padding-left: 40px;
        padding-right: 30px;
        font-size: 200%;
        line-height: 200%;
    }

    #loading p span#status{
        font-size: 60%;
        line-height: 120%;
    }
    #loading p#noscript {
        font-size: 120%;
        line-height: 120%;
        position: absolute;
        text-align: left;
        padding-top: 10px;
        bottom: 0;
    }
    #loading p#noscript a {
        text-align: center;
    }

    #loading button {
        margin-top: 20px;
        line-height: 100%;
        padding-top: 4px;
        padding-bottom: 4px;
    }


    h4 {
        margin-bottom: 0;
        padding-bottom: 4px;
    }

    p,#main div {
        max-width: 1000px;
        width: 75%;
    }

    #hostinginfo {
        margin-top: 10px;
        margin-left: 20px;
    }
    #hostinginfo table {
        font-size: 1.00em;
    }
    #hostinginfo table td {
        padding-right: 4px;
    }
    #hostinginfo input {
        margin-top: 6px;
    }

    #hostinginfo label {
        margin-left: 6px;
    }

    th {
        text-align: left;
    }
	
	#important {
		margin-top: 12px;
	} 
	h3.important {
		margin: 0;
		border: 0;
        border-top: 1px solid #660000;
		border-bottom: 1px solid #660000;
        padding: 1ex 0 1ex 0;
        background-color: #CB2430;
		text-align: center;
        color: #ffffff; 
        width: 100%;
	}

    .alert {
        margin: 2ex 0;
        border: 1px solid #660000;
        padding: 1ex 1em;
        background-color: #ffeeee;
        color: #660000; 
        width: 75%;
    }

    .warning {
        margin: 2ex 0;
        border: 1px solid #FFBF00;
        padding: 1ex 1em;
        background-color: #FDF5E6;
        color: #000000; 
        width: 75%;
    }

    .success {
        margin: 2ex 0;
        border: 1px solid #006600;
        padding: 1ex 1em;
        background-color: #EEFFEE;
        color: #000000; 
        width: 75%;
    }

    .error {
        color: #FF0000;
    }

    .panel {
        border: 1px solid #c0c0c0;
        background-color: #f0f0f0;
        width: 75%;
        padding: 1ex 1em;
    }
	
	.terminal {
		border: none;
		background-color: #000000;
		color: #ffffff;
		width: 50%;
		padding: 1ex 1em;
	}

    #header {
        background: #fff;
    }

    #footer {
        border-top: 1px solid #404040;
        margin-top: 20px;
        padding-top: 10px;
        padding-left: 20px;
        font-size: 75%;
        text-align: left;
    }

    #main {
        margin: 20px;
    }
	
	
	#main .ic24 {
		position: relative;
		width: 75%;
		height: auto;
		border-width: 1px 1px 1px 1px;
		border-style: solid;
		border-color: #4B8DF8;   
		background-color: #EFEFFF;
		padding: 12px;
		padding-top: 16px;
		padding-bottom: 8px;
		margin-top: 20px;
		overflow: hidden;
	}
	
	#main .ic24 p {
		width: 100%;
	}
	
	
	#main .ic24graphic {
		position: relative;
		width: auto;
		height: auto;
		border: none;
		padding: 0px;
		padding-right: 16px;
		margin: 0px;
		float: left;
		
	}
	
	#main #ic24info {
		position: relative;
		width: auto;
		height: auto;
		float: left;
	}
	
	#main #ic24info a {
		color: #0B4DB8;
		text-decoration: none;
	}
	
	#main #ic24logo {
		max-width: 132px;
		max-height: 132px;
	}
	
EOT;
}

function logo_page()
{
$img_encoded = 'iVBORw0KGgoAAAANSUhEUgAAAakAAACABAMAAABD1osiAAAAKlBMVEUAAAAAAADnHCwAAAAAAAAAAAAAAAAAAABMCQ4AAADnHCznHCznHCwAAAAjcBE1AAAADHRSTlMAeDRHwSqg4BJl/PLTJLuIAAAF1UlEQVR42u2by4vTQBzHp3TTzR6EBtfXYS/+BZW6Pg6FFavgoRDBBx4KFd+HQgWFvQQqiuJhoeL7sP+LR0EPlj6yPfz+F5NMZ77TmmJjM3ZT5nNpOzvNzGcev5lMusxgMBgMBoPBYDAYDAaDwWDQwel5YRnC/jkvbZYdjFV2MFbZwVhlB2OVIVZyb2HIED/n5AfLEj/nhWUJY5UdjFV2MFbZwVgdMqzNZydXz2qrf59Kq2a1NmTsRnfVrLZOfj3VrrkrZuVb/dpBvZEJqzOOc5TNQ75rjXKDtV+ZsNoi6rJ52OhZwxONwiGwsi46zqnt1Kx8r7N8q/wmRfhP3BSsrK7VW/u13krDysGwT8o5kvilxa2YZ/U2eulEC0KhCTlLCo0UrPYff7Tfe+2lWt0glTT6qjB02e0eW6ZVjiZYaF4hq+eXlmll1yik75TL5eMeDVOxsj89hNQyrN5QyDFRm9GCVmCZVrYXBr4OE9w8ZFbBCNr+x646ycAhs/o3moFUj62Y1UY4/txVs9oLrAZs1azCAVhaNSsLgXNpVt/+dlNXZAplx4mLiXecU5hHhcBqN6lV/p3znk1xEYUltfr+t0J/4dN1jwKGWIg+VKuBdL5JAQ9EYj34ILOAjWq12lG+eE2xsk9EF/7CFN7WKOCpq9kK2/CTyp93mFUbpyKRZmwNi2oX4Y0dfgULd8QL4vRdvVavJ+6XYLVPIQjmHq9xAqvbJBTa8paTBCOtVpZHY1DrSmCF7flABotBIiuLJM+RQdJJO1qoVnUKqfLh1pBWrX10YVu0ciuRVXjlfpUiXGSmp85xdFaaT7thZUV95I5DRldaDYJPT8oXmyQqnYP0nFZetL23tgjtsT/e8uc9mKa3XsFqL3Rpy3YsCSufhwmrJgbeGmo/jxUCjd2UzWWFg1EuEzv6rJoY4ftyQapghBRElda5cxKrEfaPvGPWw+Esyx1ps8pHhaP0LqxK8p7KZwFHklt1kEqNcbsNcFfT12a1zgtEv7WFVZehB93xUGVJrPg7MXgPxotDUWlCV5dVhYtgjhV5KuLd+jixktjqYHoHmVcLw9fSt2ry8lDBlrAqKomN5FZI5aX0+Rztqmk7uqywtGKhRQ+KmbeT3AoDDN89gsJQBQ1WWFrFpmgkIruq2kpuhWCASFNBYXxN1GGFKk1XqqLWiXjeOvpv3n2gpBDm4dtL1aqnyaqAcA2bGCu0d3Ir5GkSPasKsFlO3WpNGf68P3wdVhs84tRIRZ/VEUwWfIyxwo4puRUiDh0+q2jntnJWOf6aplVv+VZ5VGMBq3tlhQuarNYnw3V9Zgzkr8PFYiByAi0xcM7ILva+7kJWNeyktVoV5l2FeSI1kluh8UKrlnar6dv2qNhejBVG6yDeaifOajg5X9tR4sH/sLIIBeFTjJV4JMImmd5KNmGFvHxfyV9Guq2mDvnQc9NWyIuOBWrD2BSzZ4fsHi6rzUq26cRdY2e2VSU+ChJ6IDdh1Zi+wylAVa9VfWqu+2y2VYFiO6uGzHsTVj01WOxgsOq3KqB0nMbMsLK96fNxKVASgrDCSogcHjpbq5WNg1WcVsRY4Zi3i1Xblqm7OLFXrHbRWn2GxUG/FduX0yIHwRlWFomD3ojrT+Vxje+KE3tYiQ6ym3JJKKidnW9rscJkuSwOiUdsphXO5P2724y9PPOI+njMMSyxOzWiTViF7/0v4kS6gzEcZA0545X0WbFmVClnk1B4vJXsDYArcPzXitUxCnhW5f070SyXHGfTw1jUYVUgMGKzrTBKQQk/LonYzSlWxToyFuOapaXRim2hqd2/WbFbJEBlLTx8k1a1QNmaai0eUMBAp5XVFFIdNtMqVqs/nhmvpGQuSJRWUmHoMsl5klzRacWsE4Sn3TOswMtH9Mfvbj+L36JNWrFzUgqcE6ofdf8X9PXN6qWjbF5eOverV51ye/ICd+NCWv549er0ha3o69vMYDAYDAaDwWAwGAwGg8FgSJffF2mwYDNbStYAAAAASUVORK5CYII=';

    header('Content-Type: image/png');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}

function ic24logo_page()
{
	$img_encoded = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6b3NiPSJodHRwOi8vd3d3Lm9wZW5zd2F0Y2hib29rLm9yZy91cmkvMjAwOS9vc2IiCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB2ZXJzaW9uPSIxLjAiCiAgIHdpZHRoPSI2OTAiCiAgIGhlaWdodD0iNjkxLjI1IgogICB2aWV3Qm94PSIwIDAgNTUyIDU1MyIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgaWQ9InN2ZzMwMzUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImlvbkN1YmUyNF9jdWJlLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwODMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzQ5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTM1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzMzkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzMxIgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTMzMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzMjUiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzI3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NSIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4ODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NzMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODc1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDEiCiAgICAgICB4MT0iNDQzNS40NDI0IgogICAgICAgeTE9IjI5NDkuMDQyIgogICAgICAgeDI9IjQ4MzQuMzkyMSIKICAgICAgIHkyPSIyOTQ5LjA0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTgiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjAiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxOCIKICAgICBpZD0ibmFtZWR2aWV3MzA4MSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC45NjUzODc0IgogICAgIGlua3NjYXBlOmN4PSI3MjQuNTI3MjIiCiAgICAgaW5rc2NhcGU6Y3k9IjMzMy4xMTQ1MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMzAzNSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMCIKICAgICBmaXQtbWFyZ2luLWxlZnQ9IjAiCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIKICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDM3Ij4KQ3JlYXRlZCBieSBwb3RyYWNlIDEuMTEsIHdyaXR0ZW4gYnkgUGV0ZXIgU2VsaW5nZXIgMjAwMS0yMDEzCjxyZGY6UkRGPgogIDxjYzpXb3JrCiAgICAgcmRmOmFib3V0PSIiPgogICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICA8ZGM6dHlwZQogICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICA8L2NjOldvcms+CjwvcmRmOlJERj4KPC9tZXRhZGF0YT4KICA8ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMSwwLDAsLTAuMSwtNCw1NTcpIgogICAgIGlkPSJnMzAzOSIKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO3N0cm9rZTpub25lIj4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIC0yLDg2OCAtMyw4NjcgLTg2NywzIC04NjgsMiAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA0MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDMiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDM4MjcsNTU2MyBjIC00LC0zIC03LC0zOTUgLTcsLTg3MCBsIDAsLTg2MyA4NzAsMCA4NzAsMCAwLDg3MCAwLDg3MCAtODYzLDAgYyAtNDc1LDAgLTg2NywtMyAtODcwLC03IHoiCiAgICAgICBpZD0icGF0aDMwNDUiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDI4MDAgMCwtODcwIDg2OCwyIDg2NywzIDMsODY4IDIsODY3IC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDciCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDE5MzAsMjgwMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiBtIDEwMzUsNjMwIGMgODAsLTMxIDE1NCwtMTAyIDE5MSwtMTgzIDI1LC01NCAyOCwtNzQgMjksLTE1NyAwLC0xOTAgLTc0LC0zMTggLTM0NCwtNTkyIGwgLTE3NCwtMTc4IDI3NiwwIDI3NywwIDAsLTgwIDAsLTgwIC00MDcsMiAtNDA4LDMgLTMsNTYgLTMsNTUgMTgxLDE3NCBjIDM1NSwzMzkgNDUyLDQ5MyA0MjMsNjY3IC0xOSwxMDYgLTcxLDE2MiAtMTcyLDE4NCAtOTIsMjAgLTIwMiwtNiAtMjkzLC02OSBsIC00NiwtMzEgLTI2LDU4IGMgLTE0LDMyIC0yNiw2MiAtMjYsNjYgMCwyMiAxNDcsOTkgMjI4LDEyMCA4MiwyMSAyMjEsMTQgMjk3LC0xNSB6IgogICAgICAgaWQ9InBhdGgzMDQ5IgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAzODIyLDI4MDMgMywtODY4IDg2OCwtMyA4NjcsLTIgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAyLC04NjcgeiBtIDExNzgsMjQyIDAsLTM5NSA5MCwwIDkwLDAgMCwtNzAgMCwtNzAgLTkwLDAgLTkwLDAgMCwtMTcwIDAsLTE3MCAtODUsMCAtODUsMCAwLDE3MCAwLDE3MCAtMjkwLDAgLTI5MCwwIDAsNjMgMCw2NCAyODEsNDAxIDI4MSw0MDIgOTQsMCA5NCwwIDAsLTM5NSB6IgogICAgICAgaWQ9InBhdGgzMDUxIgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA0NzkwLDMxNzMgYyAtMjQsLTQzIC0xMTEsLTE3MiAtMTk1LC0yODggLTgzLC0xMTUgLTE1NSwtMjE2IC0xNTksLTIyMiAtNiwtMTAgMzUsLTEzIDE5MywtMTMgbCAxOTksMCA0LDI5OCBjIDIsMTYzIDMsMjk4IDIsMzAwIC0xLDIgLTIxLC0zMiAtNDQsLTc1IHoiCiAgICAgICBpZD0icGF0aDMwNTMiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NTM0MSk7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTg1MTYsMTc0MyBjIC0zLC04MzUgLTksLTE1NTMgLTEyLC0xNTk1IGwgLTYsLTc4IDE3MCwwIDE3MCwwIDcsODggYyAzLDQ4IDksMTI3IDEzLDE3NiBsIDcsODkgNDAsLTU5IGMgNTMsLTc3IDE2MCwtMTgxIDIyOSwtMjIzIDEyOCwtNzcgMjQ4LC0xMTEgNDIxLC0xMTggMjEwLC05IDM4NywzOCA1NTIsMTQ3IDI3NiwxODEgNDM4LDQ4MiA0NzQsODc5IDM5LDQzMyAtMTA1LDgzOSAtMzc1LDEwNTYgLTE1NSwxMjUgLTMzMCwxODUgLTU0MSwxODUgLTE5OSwwIC0zNTcsLTQwIC00OTMsLTEyNiAtNzEsLTQ1IC0xODMsLTE1MyAtMjI1LC0yMTkgbCAtMzIsLTUwIC0zLDY4MyAtMiw2ODIgLTE5NCwwIC0xOTQsMCAtNiwtMTUxNyB6IG0gMTE1NSwyMjMgYyAxNDksLTMyIDMwNSwtMTQ4IDM4OCwtMjg5IDc5LC0xMzUgMTIxLC0zMTMgMTIxLC01MTIgMCwtMTk2IC0zNSwtMzU2IC0xMDgsLTUwMCAtNDMsLTg0IC0xNzEsLTIxNyAtMjQ5LC0yNTggLTc3LC00MSAtMTkyLC02NyAtMjk0LC02NyAtMTE2LDAgLTE3NywxMyAtMjc4LDYyIC0xNDYsNjkgLTI1OCwyMDMgLTMxNywzNzggLTE3LDQ5IC0xOSw4OCAtMTksMzYwIDAsMzA1IDAsMzA1IDI3LDM4NSAzNywxMDkgOTEsMTk2IDE2OSwyNzUgNzQsNzQgMTkwLDE0MSAyODYsMTY0IDc2LDE5IDE5MSwxOSAyNzQsMiB6IgogICAgICAgaWQ9InBhdGgzMDU1IgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE3NCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTQ2MTAsMzEzOSBjIC01MTgsLTY1IC05NDQsLTM1NyAtMTE2NCwtNzk3IC0xNDEsLTI4MCAtMjAxLC02MzYgLTE2NiwtOTgzIDcyLC03MTEgNDgwLC0xMTc3IDExNDcsLTEzMTAgMjExLC00MiA1NTcsLTM2IDgxMywxMiAxMTksMjMgMzIwLDg2IDMyNiwxMDMgNiwxNyAtNzIsMzExIC04MiwzMDkgLTUsLTEgLTQ5LC0xNiAtOTcsLTMzIC0xNDcsLTUyIC0yNjIsLTcxIC00NzAsLTc3IC0yMTAsLTYgLTMyMCw0IC00NTcsNDQgLTQzNywxMjYgLTcwNSw0NzIgLTc2MSw5NzkgLTE1LDE0MCAtNSwzODggMjAsNTE0IDYwLDI5OSAxOTgsNTM2IDQwMyw2OTAgMjIzLDE2OSA0NzIsMjM4IDgwOCwyMjcgMTg0LC02IDMwNywtMjggNDQyLC03OCA0NiwtMTYgODksLTMxIDk2LC0zMiA5LC0xIDMwLDQ5IDYyLDE1MyAyNyw4NSA0OCwxNTUgNDcsMTU2IC01Miw0MCAtMjc2LDEwMSAtNDU3LDEyMyAtOTcsMTMgLTQxNCwxMiAtNTEwLDAgeiIKICAgICAgIGlkPSJwYXRoMzA1NyIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNzApIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczNzAsMjg1NSAwLC0xOTUgMjEwLDAgMjEwLDAgMCwxOTUgMCwxOTUgLTIxMCwwIC0yMTAsMCAwLC0xOTUgeiIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNjYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIzODg2LDMwMjQgYyAtOTksLTE4IC0yNjQsLTczIC0zNDgsLTExNSAtNzEsLTM1IC0yMTgsLTEzMCAtMjM3LC0xNTMgLTEwLC0xMiAwLC00MCA1MCwtMTUwIDM0LC03NSA2MywtMTM2IDY1LC0xMzYgMSwwIDM2LDI0IDc3LDUzIDE2NiwxMTkgMzI0LDE3NiA1MTMsMTg0IDMwOCwxNCA1MDMsLTEwOCA1ODAsLTM2MiAxNCwtNDYgMTksLTkzIDE5LC0yMDAgLTEsLTE3MSAtMTksLTI0NyAtMTAwLC00MTAgLTEzMCwtMjYxIC0zODAsLTU0MyAtMTA0NCwtMTE4MCBsIC0yNTAsLTI0MCAtMSwtMTIyIDAsLTEyMyA5MzUsMCA5MzUsMCAwLDE2NSAwLDE2NSAtNjU3LDAgLTY1NywwIDEwOSwxMDEgYyA2MSw1NiAyMTgsMjEwIDM1MCwzNDMgMzQyLDM0NSA1MTgsNTYzIDYzNCw3ODYgMTc5LDM0NSAxOTgsNjc4IDU3LDk2NSAtODEsMTYzIC0xODgsMjcwIC0zNTEsMzUxIC0xNDEsNzAgLTIxOSw4NiAtNDI1LDkwIC0xMjUsMiAtMTk4LC0xIC0yNTQsLTEyIHoiCiAgICAgICBpZD0icGF0aDMwNjEiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE2MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMjY2ODEsMjk3NyBjIC02LC04IC0yOTksLTQyNSAtNjUxLC05MjggbCAtNjQwLC05MTQgMCwtMTMyIDAsLTEzMyA2ODAsMCA2ODAsMCAwLC00MDAgMCwtNDAwIDE4NSwwIDE4NSwwIDAsNDAwIDAsNDAwIDIwNSwwIDIwNSwwIDAsMTU1IDAsMTU1IC0yMDUsMCAtMjA1LDAgMCw5MDUgMCw5MDUgLTIxNCwwIGMgLTE2NiwwIC0yMTYsLTMgLTIyNSwtMTMgeiBtIDcxLC0xMDg0IC0zLC03MTMgLTQ4MCwwIGMgLTM4MiwwIC00NzksMyAtNDczLDEzIDUsNiAxNjYsMjMwIDM1OCw0OTcgMzQ3LDQ4MSAzOTksNTYwIDUzMCw3OTggMzgsNjggNjksMTIyIDcwLDEyMCAwLC0yIDAsLTMyNCAtMiwtNzE1IHoiCiAgICAgICBpZD0icGF0aDMwNjMiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE1OCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTE5MjcsMjI4OCBjIC0xMDgsLTEwIC0yNDgsLTU1IC0zNDEsLTExMCAtODIsLTQ4IC0yMDMsLTE2MCAtMjQ3LC0yMjkgLTE3LC0yNyAtMzQsLTQ3IC0zOCwtNDQgLTMsNCAtMTAsODIgLTE2LDE3MyBsIC0xMCwxNjcgLTE3OSwzIC0xNzgsMiA2LC00NyBjIDQsLTI3IDksLTUxNyAxMiwtMTA5MCBsIDYsLTEwNDMgMTk5LDAgMTk4LDAgMyw3MjcgMyw3MjggMzEsNzIgYyAxMTMsMjYwIDM0MSwzOTggNTk4LDM2MiAxNjQsLTIyIDI3NiwtMTAzIDM0NiwtMjUxIDczLC0xNTQgNzIsLTE0OCA3NywtOTM1IGwgNSwtNzAzIDE5NCwwIDE5NCwwIDAsNzIzIGMgMCw3OTYgLTIsODI0IC02Miw5OTcgLTEyMSwzNDcgLTQyMCw1MzMgLTgwMSw0OTggeiIKICAgICAgIGlkPSJwYXRoMzA2NSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNTQpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczOTAsMTE4MCAwLC0xMTEwIDE5MCwwIDE5MCwwIDAsMTExMCAwLDExMTAgLTE5MCwwIC0xOTAsMCAwLC0xMTEwIHoiCiAgICAgICBpZD0icGF0aDMwNjciCiAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMTUwKSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA5MTk5LDIyODAgYyAtMjIwLC0zNyAtNDE4LC0xMzggLTU3MCwtMjg5IC0xNTAsLTE1MSAtMjQyLC0zMjkgLTI5NSwtNTcxIC0yNiwtMTE5IC0yNywtNDI5IC0xLC01NDcgNTIsLTI0NCAxNDksLTQyNiAzMDUsLTU3NSAxODcsLTE3OCAzOTYsLTI2NCA2NjgsLTI3NSA1MDAsLTIxIDkxMiwyNTEgMTA2NSw3MDQgNTQsMTYxIDY0LDIzMCA2Myw0NDggMCwxNjcgLTMsMjE1IC0yMSwyOTEgLTEwMyw0NDEgLTM5MCw3MzAgLTgwMyw4MDggLTg3LDE3IC0zMjYsMjAgLTQxMSw2IHogbSAzMzQsLTMwNSBjIDI1NSwtNjYgNDM4LC0zMDggNDg3LC02NDQgMTcsLTExNiA4LC0zNDMgLTE4LC00NDIgLTY0LC0yNDMgLTE5NywtNDIzIC0zNzQsLTUwOCAtMTA1LC01MCAtMTg0LC02NiAtMjk2LC01OCAtMjIxLDE1IC0zOTMsMTM2IC01MDgsMzU5IC02NiwxMjkgLTk1LDI1MCAtMTAxLDQyNSAtMTEsMzA4IDY3LDU0NSAyMzYsNzE0IDgxLDgxIDE1OCwxMjYgMjYxLDE1MyA3MywxOSAyNDEsMjAgMzEzLDEgeiIKICAgICAgIGlkPSJwYXRoMzA2OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNDYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIxNzUwLDIyNzUgYyAtMzUyLC03MCAtNjExLC0zMDUgLTczOSwtNjY4IC01OCwtMTY1IC03NSwtMjcxIC03NSwtNDc3IC0xLC0yMDQgMTAsLTI3OSA2NiwtNDQ3IDExOSwtMzYwIDQyMCwtNTk4IDgyNiwtNjUzIDEyNywtMTggMzkyLC04IDU0MiwyMCAxMjIsMjIgMzYwLDk2IDM2MCwxMTEgMCwxOCAtNjMsMjY0IC02OSwyNzEgLTMsNCAtNTEsLTggLTEwNiwtMjcgLTE1NCwtNTEgLTI3MiwtNjggLTQ3NSwtNjggLTIwMywwIC0yNzgsMTUgLTQwOSw4MyAtMjE0LDExMSAtMzI4LDMwMiAtMzU2LDU5OCBsIC03LDcyIDc2NSwwIGMgNjg4LDAgNzY1LDIgNzcxLDE2IDEyLDMyIDYsMzAzIC05LDM5MCAtNDMsMjQ0IC0xMzQsNDMzIC0yNzcsNTcwIC0xMTUsMTEyIC0yMzUsMTc0IC00MDAsMjA4IC05NCwxOSAtMzE0LDIwIC00MDgsMSB6IG0gMzUzLC0yOTUgYyAyMDcsLTY0IDMzOCwtMjU3IDM2MywtNTM1IGwgNywtNzUgLTU3NywwIC01NzYsMCAwLDIzIGMgMCw1MiA0MiwxODcgODYsMjc1IDgyLDE2OCAyMjcsMjkyIDM3NCwzMjEgMzAsNiA2NCwxMyA3NSwxNSA0MSwxMCAxODUsLTUgMjQ4LC0yNCB6IgogICAgICAgaWQ9InBhdGgzMDcxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE0MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gNDAsOTEwIDAsLTg3MCA4NjgsMiA4NjcsMyAzLDg2OCAyLDg2NyAtODcwLDAgLTg3MCwwIDAsLTg3MCB6IgogICAgICAgaWQ9InBhdGgzMDc1IgogICAgICAgc3R5bGU9ImZpbGw6I2MwMWQyZTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDkxMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA3NyIKICAgICAgIHN0eWxlPSJmaWxsOiNjMDFkMmU7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMzgyMCw5MTAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNzkiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICA8L2c+Cjwvc3ZnPgo=';
	header('Content-Type: image/svg+xml');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}
alt-php73-ioncube-loader/README.txt000064400000007751150464070010012656 0ustar00                            The ionCube Loader 
                            ------------------

This package contains:

* ionCube Loaders

* a Loader Wizard script to assist with Loader installation (loader-wizard.php)

* the License document for use of the Loader and encoded files (LICENSE.txt)

* User Guide describing options that can be configured through a php.ini file.  
  There are options that may improve performance, particularly with files on
  a network drive. Options for the ionCube24 intrusion protection and PHP error
  reporting service (ioncube24.com) are also described.


INSTALLATION
============

Quick Guide for experienced system admins
-----------------------------------------

The Loader is a PHP engine extension, so should be referenced with 
a zend_extension line in a php.ini file. It must be the first engine
extension to be installed. 

The Loader must be for the correct operating system, match the 
PHP version, and for whether PHP is built as thread-safe (TS) or not. 
All information required for installing is available on a phpinfo page. 

For example, if your web server is 64 bit Linux, thread safety is disabled,
PHP is version 8.1.8, the main php.ini file is /etc/php.ini and you
have unpacked Loaders to /usr/local/ioncube, you would:

1) edit /etc/php.ini
2) at the top of the php.ini file add

zend_extension = /usr/local/ioncube/ioncube_loader_lin_8.1.so

3) restart the PHP environment (i.e. Apache, php-fpm, etc.)

4) Check a phpinfo page and the Loader should show up in the Zend Engine box.


Assisted Installation with the Loader Wizard
--------------------------------------------

1. Upload the contents of this package to a directory/folder called ioncube
   within the top level of your web scripts area. This is sometimes called the
   "web root" or "document root". Common names for this location are "www",
   "public_html", and "htdocs", but it may be different on your server.

2. Launch the Loader Wizard script in your browser. For example:
     https://yourdomain/ioncube/loader-wizard.php

   If the wizard is not found, check carefully the location on your server
   where you uploaded the Loaders and the wizard script. 

3. Follow the steps given by the Loader Wizard. If you have full access to the 
   server then installation should be easy. If your hosting plan is more limited, 
   you may need to ask your hosting provider for assistance. 

4. The Loader Wizard can automatically create a ticket in our support system
   if installation is unsuccessful, and we are happy to assist in that case.

   YouTube with a search for "ioncube loader wizard" also gives some helpful 
   examples of installation.


WHERE TO INSTALL THE LOADERS
============================

The Loader Wizard should be used to guide the installation process but the
following are the standard locations for the Loader files. Loader file
packages can be obtained from https://www.ioncube.com/loaders.php

Please check that you have the correct package of Loaders for your system.

Installing to a remote SHARED server
------------------------------------

* Upload the Loader files to a directory/folder called ioncube within your
  main web scripts area.  (This will probably be where you placed the
  loader-wizard.php script.)


Installing to a remote UNIX/LINUX DEDICATED or VPS server
---------------------------------------------------------

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, /usr/local/ioncube


** Installing to a remote WINDOWS DEDICATED or VPS server

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, C:\windows\system32


64-BIT LOADERS FOR WINDOWS
--------------------------

64-bit Loaders for Windows are available for PHP 5.5 upwards.
The Loader Wizard will not give directions for installing 64-bit Loaders for
any earlier version of PHP 5.

Copyright (c) 2002-2025 ionCube Ltd.           Last revised January 2025
alt-php71-suhosin/CREDITS000064400000000045150475525240010777 0ustar00suhosin7
Stefan Esser
Ben Fuhrmannek
alt-php71-ioncube-loader/USER-GUIDE.txt000064400000026060150475525310013334 0ustar00ionCube Loader 14.4 User Guide
=====================================

This document describes the available php.ini configuration options of the
ionCube Loader that relate to processing of PHP encoded files, and also the
ionCube24 service. It also describes which encoded files can be run by each
ionCube Loader.

PERFORMANCE OF ENCODED FILES
----------------------------

We recommend that the encoded paths feature (see below) is used 
with encoded files in order to maximise performance.

ENCODED FILES  
-------------

INI entry: ioncube.loader.encoded_paths

Purpose:   Specify the locations of encoded files

  The ionCube Loader will normally examine a PHP file before processing
  to test whether it is encoded, and will run the file itself if necessary.
  Although this checking is very efficient, restricting which files the
  Loader tests for being encoded may give extra performance. If set to 
  a series of paths or files, only files in those locations are tested.

  Entries should be separated by a : on Unix and ; on Windows. 
  A path may be prefixed with + or - to add or remove that path from
  the possible locations. + is assumed if no character is given.


Examples: (... means ioncube.loader.encoded_paths)

  * Site with a single encoded module in /var/www/html/modules/RSS

... = "/var/www/html/modules/RSS"


  * As above, with a site configuration file encoded too.

... = "/var/www/html/modules/RSS:/var/www/html/config/config.php"


  * Encoded files may be anywhere except for /var/www/html/framework

... = "/:-/var/www/html/framework"


  * Site with most modules encoded except for one

... = "/var/www/html/modules:-/var/www/html/modules/plain"


  * As above, with an encoded config file in the plain directory

... = "/site/modules:-/site/modules/plain:/site/modules/plain/config.php"


Locations:

  The ioncube.loader.encoded_paths property can be set in a php.ini
  file, in a .htaccess file (when using Apache), in a .user.ini file
  (when using CGI PHP 5.3+) or using ini_set within a PHP script. In ini
  files only the last value will be used for the encoded_paths property. If
  you wish to build up the value in several lines then, for PHP 5.1+, you
  can use the following syntax:

ioncube.loader.encoded_paths = "/path1"  
ioncube.loader.encoded_paths = ${ioncube.loader.encoded_paths}":/path2"  
; etc...

LIMITATIONS OF LOADERS AND ENCODED FILES
----------------------------------------

Encoded files can, in general, run on versions of PHP equal to
or greater than the source language of the Encoder used to
produce them. So a file produced by the Encoder for PHP 7.2
can be run by the Loaders for PHP 7.2, 7.3 and 7.4, but 7.1. This 
means that the Loaders offer good backwards compatibility, 
however there are the following limitations:

  * The Loader for PHP 8.3 can run files produced by the PHP 8.2 and
    8.3 Encoders.

  * The Loader for PHP 8.2 can only run files produced for
    PHP 8.2. Updates for files produced for PHP 8.1 should
    be obtained to use them with PHP 8.2.

  * The Loader for PHP 8.1 can only run files produced for
    PHP 8.1.

  * The Loaders for PHP 7.1 through 7.4 can only run files 
    produced by the Encoders for PHP 7. 

  * The Loader for PHP 7.0 can only run files produced by the
    Encoder for PHP 5.6.

  * The Loaders for PHP 5.5 and PHP 5.6 cannot run files 
    produced by the PHP 4 Encoder.


IONCUBE24 : real-time intrusion protection and PHP error reporting
---------
### (Available for Linux 32 and 64 bit x86 servers using PHP 7)

ionCube24 (https://ioncube24.com) is an ionCube service that uses the
ionCube Loader to provide both real-time protection against the exploit of
website vulnerabilities and alerting of website errors.

Vulnerabilities in PHP applications are common, particularly in sites using 
Wordpress and other plugin based systems. Exploits result in website
defacement or customer data being compromised, and ionCube24 provides a 
uniquely powerful defense. 

PHP errors can cause intermittent or even persistent blank pages or errors for
visitors until discovered, and without active monitoring this could go
undetected indefinitely. ionCube24 active monitoring ensures you are always
aware of problems in your website code.

ionCube24 is free to try, with the server side support built into the Linux
Loaders as standard. With the Loader installed, ionCube24 can be activated
at any time to give active intrusion protection and error reporting.

## php.ini settings

ionCube24 has a powerful real-time web interface to configure, monitor and
manage things, and there are also settings that can be used in a php.ini
file as summarised below.

The setup process at https://ioncube24.com automatically gives the settings
that you need to get started, but you may wish to make changes yourself
once setup. The default values are given with each example.

### Global settings

INI entry: ic24.enable ; default 0

Purpose: Enable or disable all ionCube24 features. 

This defaults to 0 (off), and in this case no ionCube24 behaviour is
activated.

Example:

  ic24.enable = 1

----------

INI entry: ic24.api_access_key ; provided during setup

Purpose: An authentication key for adminstration requests. 

  This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.api_check_ip ; default 1

Purpose: Specify whether the IP for admin requests should be validated

  If set, ionCube24 refuses access to API functions unless the calling IP
  is a known ionCube IP address. This option should be left with the
  default setting unless web requests pass through a proxy and your site
  appears to be accessed from the IP of the proxy instead of ionCube. Note
  that access to API functions will still be authenticated by access key.

----------

INI entry: ic24.api_max_timeout ; default 7

Purpose: Maximum timeout period when sending notifications to ionCube24.

  The actual period is adaptive so that a brief increase in typical latency
  will favour a timeout followed by a retry rather than a longer than usual
  timeout.

----------

INI entry: ic24.home_dir ; no default

Purpose: The home directory for ionCube24 related system files. 

  A location outside of the web root is recommended.  It should be writable
  by the web server during startup.

Example:

ic24.home_dir = /var/www/ic24_home

----------

INI entry: ic24.update_domains_retry_interval ; default 30

Purpose: The number of seconds to wait before retrying a fetch of the set
of domains being managed.


### Security related settings

INI entry: ic24.sec.enable ; default "auto"

Purpose: Enable the intrusion protection feature of ionCube24.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

INI entry: ic24.sec.initial_state ; default 1

Purpose: The default for whether security should be enabled or
disabled. The default is to enable protection. Any files on a protected
domain will become blocked if they are changed, so setting this to 0 will
avoid accidental blocking when using ionCube24 for the first time.
Protection may be enabled and disabled using the ionCube24 control panel and
also via the User API.

Accepted values:

   * 1 : protection will be active when ionCube24 initialises.
   * 0 : protection will be disabled.

----------

INI entry: ic24.sec.initial_action ; default "block"

Purpose: The initial setting for how new and modified files should be
treated when about to execute. The default is to block. The action is taken
only if protection is enabled, and the setting may be changed via the
ionCube24 control panel.

Accepted values:

   * "block" : prevent execution of new or modified files
   * "allow" : allow execution of new or modified files

Note that depending on the notification settings, a notification may still
be generated when a new or modified file is about to execute even if it is
not blocked.

----------

INI entry: ic24.sec.initial_notify ; default "always"

Purpose: The initial setting for whether a notification is generated the 
first time an unacknowledged new or modified file is attempted to be
executed. This setting can be changed via the ionCube24 control panel.

Accepted values:

   * "always" : always notify of a new modification 
   * "once"   : only the first detected modification is reported
   * "never"  : never notify of new and modified files

----------

INI entry: ic24.sec.exclusion_key ; provided during setup

Purpose: A key that if present at the start of a file, will identify the
file as trusted. This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.sec.trusted_include_paths ; no default

Purpose: List paths from where files can be included and automatically
trusted.

Example:

ic24.sec.trusted_include_paths = "/var/cache:/var/cache2"

Directories can be excluded from the list by prefixing with a minus
character -. e.g.

"/var/cache:-/var/cache/subdir"

This is useful if your site creates and/or modifies files by itself from
time to time, e.g. in a cache directory. Requests that *directly* access
files on a trusted include path will be blocked but the file itself will
not be blocked, so requests that use the file as intended will still work.
See ioncube24.com for more details once signed up.  As an alternative, if
possible we recommend producing files that include the exclusion key.

----------

INI entry: ic24.sec.block_uploaded_files ; default 1

Purpose: If set, block any uploaded files in ionCube24 that are processed
using the standard PHP mechanism for uploaded files. This applies even if
the file is subsequently included and where included files being
automatically approved with the previous setting.

----------

INI entry: ic24.sec.block_stdin ; default 1

Purpose: Refuse code that PHP sees via stdin.  If disabled, code via
stdin will run without security checking as there is no filepath. This
setting should be left on as PHP would normally never receive a script via
stdin.

### PHP Error reporting settings

INI entry: ic24.phperr.enable ; default "auto"

Purpose: Enable reporting of PHP errors to ionCube24.  When enabled, any
non-ignored errors are reported to ionCube24 in realtime, triggering
alerting so errors can be investigated as necessary.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

### Deprecated settings

Deprecated settings are subject to removal in a future
release.

INI entry: ic24.phperr.ignore ; default 0

Purpose: Specify default error levels to always ignore for all domains.

Note that default and per-domain errors to ignore can also be set via the
web interface, and are combined with this setting. Leaving this unset and
using the web interface is recommended for maximum flexibility.

Example: 

ic24.phperr.ignore = E_NOTICE | E_DEPRECATED

(c) ionCube Ltd. 2025
alt-php71-ioncube-loader/USER-GUIDE.pdf000064400000115466150475525360013304 0ustar00%PDF-1.4
1 0 obj
<<
/Title (��Markdown To PDF)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20250130155421Z)
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 33  
813.500000  0]
endobj
9 0 obj
[0 /XYZ 33  
749.750000  0]
endobj
10 0 obj
[0 /XYZ 33  
700.250000  0]
endobj
11 0 obj
[0 /XYZ 33  
131.750000  0]
endobj
12 0 obj
[0 /XYZ 33  
296  0]
endobj
13 0 obj
[0 /XYZ 33  
97.2500000  0]
endobj
14 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [71.2500000  66.5000000  144.750000  75.5000000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 15 0 R
/Resources 17 0 R
/Annots 18 0 R
/MediaBox [0 0 595 842]
>>
endobj
17 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
18 0 obj
[ 14 0 R ]
endobj
15 0 obj
<<
/Length 16 0 R
/Filter /FlateDecode
>>
stream
x��][��8v~�_��FI���@w� �0l A�l���8;��Ϗ.TU�򱪾�(���H�\lR���_�ۗo��#y����|�r�RSd�I���ej�'�P�{��Ï�����s�����~�n�|���{ޡ������/�ɿ��{�_�]��.���#L�,/������Sd�Nu%���=������O�o�>���2)�T������魞�eZ	�s�e�]y��J7ߕ�5X��}�I.����/�ߟ���ㄪ�>Oʰ�WVEXx
=��12����E��?�fy���C���}�5eH��5�^���k���N��%y����׿tjJ!����َ�"�t��ӈ�Gre�s�n�L��)�s��ӈ�GL��=�FL7���,�#��u5yNկ�������|�[�k��ҎTi�=�]<>g<�
G>�#&UE���w ���D�o*D����
aϧ�����Ont)�}���o��ɻ�����/_���ɇ��Ǘ���xy��y�������sf}��6��&-��.#�wV�-�Ϡ��7��t�w�i5����Av
u٣�N5����}�i9>wQ�9�z�v-�-�Ң{��y�TM�K�պ9j
�M�0D0�p?O�|Lg��Y�����a`�9�
�����SL�I7�H˞]��
B�a�X���x�ρ��s,�WSJ�*xs�`����q���-��}���;�ۈqS7���i/ƪ@���~��S1���[^o&�'�^�/8ާ�s�B�+y�����q��6s�1��1w&8�co�����&��:���b�"��eBѷ��R�)g#�fW���x�c׌��H��s0�������ɮ�EVv�:�a�Y
�|��>2��ءӜ�ַ֊��El��|�_w�{�N��A<����v�V)a��-�ë��lr
�E
��Z��-e�`�->S��Y��xݵT�^k�;�
�1M�{�v��w��:I#�(@�(Yw\-t�9]�����4b�Tr:��9cG�<:�&� ^�CQ�j�t�U��	S|�3A�8g��M�^���c�@8Vðf���c��5;�s��@�9�>!�ٽ�5{�����%)�&ěpW7aMW�g7c�R��<����&M��o�ףO��{�Y��Ms���|�tFs�Z-��`�b|����~��z�?��^���{��G~�����o���bN�ҝ[�V���5t��8�q�f5*؈p�:H��a��K�u���–n_��99��F���] p�9��\rSݟ�LfG��Օ�6��` 1|���=ę0 <dz���#��ص�.�#��1J���*K�|�ɔU��T}���=��(��DT��?6��3��)Z���1��xG69Qp$�#�p���T�<��gbo/Į�j��2��|�#��?����������8*I�d�.6��u4r��Y&iRqC�
c���
��PF\Ƥń�<N"H�����,�U�щ�d�>L��N���L����4�шy��w�!�5a<t��k���2���g?�W�g��e�-镫��� @'-��~�7�?�$�h0W�.��-��m@$
�XL�^�3�
��ǁ��L�T(A����e�n����v�W��7����U��\KL�q,����j�^Y!��D���a�M����`p	n��$N&$0�J5��?",�~}�����3��d츮�M���rb�#�($fR��>m��~��E�ofw(n�K�ox,��ŰƄ�H�Z�)&�X�c�n�
3L]0�|�5���x� �b�X�Zڈ��׏��r�_��TK�WL$�W��p���,�9�&F�Q6ܾ����*u��կ9���?���{Z�ߙ���5� �u�_�9��L�O�!h��IH�˴{UN=K�$���ue��B&Bm?ץ��9���b$k�<Я��l���t�!:98"�D�Ah��� ���i㣗4J�r
�v�<b�x�U���9ۊ����E*��__�_ߚ�Y�a�T��[�b{h�l	������"���/MV
��L�/Y����1��1�s~�1�
��Ռ"�׿�Pu�ٰQΫ�p5ח/0oe2J�.�)�^��i�9�TM�&��cE�JkY�?��~��2/Êaeq��r4n).c<C��fD�P�L���ע��φʋc<8�½0�p��Y�k���7�х�k �Ţ7s֍�ni��;�%�҉���vF�c���ե����t��Y��oZ�Se�f��L'r18�X�.��s��K�)Y
8�\�`��v+�i+�$�RɯݗZ���BW��[^��(i���RiY�ʺ��T�V�W�a�2��Z����gԿ��$c���OA����cp�TG�_ ����7N�k����I�a��ğ�-�v)� P�H��\�0;�d��"h�2�W�� �x1��Ȓl�fpıF�âO�s�
(T;�⁀��#�L�I^�l��֯�hT�߮K��J(;�@A9ҒHKV�%Gߪ�T��<���y*��)��<��j0I�ku:OY��<eծUu��w3�d�ZK�<U�k�<��|�5�ɡ{�˯�JiCX�b��dži����~�,�җ��6<rf� �"Kr�7R#��,�(�F�7����aq4�R�.�7p��*�j��vPL��jx�ձ�M�:y9�:��Q��������T�V�:y1�:m|d�1P���`��k-�:���L���
2�g�C�w��߮T�6��5��cr3����-gtR4�7�r�J�4�9ጲZ8Y�!��(,�3Z�m���&E�KV&�n�������)�;����L�2o�2�iP�Vm~��
Jg��z������T�V�A�L�hP�M�o?T��L2v��5�ZH��i��¶8�8
��n�q)p����e!R�<i�B��*�iE�����Y���U��
;�p���� ��U~�m#���ԺS4�(b��]
&�v�Ni)�"�_۵�Q�`��L2v���#O#�MT�ՇQ6���r��֧r@��0p`/~Sj���B(��pձ��0�}�����9b��`�8/�M(��j�S�?Մ��xpx�6���|�v�E3R���.��,�Bԇ4y_�ƶ�03��؝yqY��f�Njj��豤��XǒZ^RK6U�Ϯ�ߖ�a�m�Y	�ӓ`f�ud��s�k߳�hޚ*�
�k�qo�����z�5$�����W��3�k���L*m��|�75/:QT��QS�i����T��bANx��(,~��VLW	'�;�l%�Z8��fn1WGe*^�v�3�s��ֶ�l�Uc�1�cKR��vC�u9��ܤ�;��~��M
[&��g��%_Y8P������IM5V�;��Sk�pT�3]��ϱxw6�j�SL��F��
|� S=`�=��k��T*GsT��b��i�V2T7��j&��G�	#�ln2�R�s�@�i<z����ʉ~����d�0�bB�O��m��"pC0�bN���K=���$���"m���F�{�|��C�P�	�8*��W6
����u��C�����W�2��gn����׳B�
��2_��a�*B\칺 k�@Fv�2FpL���g̼��L�C�1ta��3�Y�H���-�Ӊ��"!�*O>�9�.�[�J��c�p@���K��:u�%�ʑ]�E.j�4�WaY�W�R(�j����׃O�q)��1WF:����i*��=�ƛ��X�-��g1f޽����ύ��J
'V�%����ȓ��UO)���"�0R�s$<�O!ެx���fI3����A0	�?��^뵽�f��i��'�}���a�&lM�42,��
]ji��2�>t���ˠ��`�j�S�c)����;���&U�ݑ�2U���c�慜T���B����֡��ӉM��Y��ϱ���Y�XA�st�bނ6����s ��s?b]Gc�^?����)zLF���S��v<�|�����ݦ0��2�qc�w��왎(û/��-y�>y��~�����#y�!��!y��r0in-���D
)H� ��?�\_�سtY�b����1@ԭ_��)����($����Y3�`���D29K^˕1p�5�b����Mo����7��I~����`�ôue
�1��op��0�`�!�n3QA�V
���P!%��fxp(:�6-Æ��+E{��~���{~�W�v4 d�'pSI�o3ɳ��"�)�1I0�"pN�ΰ*�WRw!�}4�
!����9wV�4�a+d�6�u���S�x�w�1�1;���(��F�}3�s��Q&#�)�@�)LUbc���e�oQ��D���y����lQ�7"�
fQw0<�B3�yaX3�>C6�Ҭ��[fF%`�lw0D�z�fb܁��o]�G
�c� 
�a�"_��gS���`��d^����7#m^z��f��X|1}�sa�HP���,㛹W�욹W��i�^�YӀ��4soW�I�]�m�^=�̽��]��4so7�IƮ�p3��T�`��l;��~s��������n:�0��6m����f�.�,��h�>��J1�vw�x$���G�7+���G���j�ρ�ԍ��<խ��H�7���p��멡�ԍ��<ӯ���T?�/�((�'���ի}GQ�D�H��q^fv�f��
c>9����� ҃M�G0�-��gxැ�ߐ9�>�9�e�o��c�YX���*|��T��;�7�
��M�F?c*Py��ן#SA3��T��5�l�T�2�^66t>��y�_oqS��+'FSA�� �
�j�h��.��E�l�Ekѱ�sĢ�5����,�.��.�w�0c݌��<ӯ�8��}٭Ȣ7n��pBżm�!��84F����z\UjD�F��g��݅`D��Mp-u/��fNp-�N�,˱�ڌ��<խg�2�\Kk�*��ڌ��<ӯ���Z)
��z9�,��D1��Ĭ��-Eq(�8�@T�h��^.�y��$�������$D�
6��PPjG�`�������A��Ϯ'F�R;b�L��҂�&
Joc�欞�i�a"J��#8{��)�pb��:=��Q<ݴx�6:�/ة�|���jѲ��~[�&26N���ĝ>�#CnԒ�#�<;�F��&�rA1���d}5����w0���~$���
�t5�ڟ�$����r�PI��(�2U5�f��9�V7
{̰�c���q�1�v ����r�M�j��p��	�~�t�X:)�v��f1�:��=�#�3ŧp�!R�`�h��x|K�ix��"9����o�R���_ds��E6�\ds��m��{N��0
�Fy,�!{J�O��������I���ޜr�gK�Z�p���jڎ��~s�;g�;UZ���0XLM-Y�g�s�i5D��s�9ֽQ���s��Kp&����gT��nE�k�f���=���33#�7�g�����z�x�w���J�����	JR����zB�v�)�ka���
Ʒⵃ0�����X��Y����Ǟ�NL�G���9ܩ�O��e!�E�Fd�aD��X��\0�$�����S�kk�qo�"��Ҋ��q��|�5�������Yϭ��T59(j�p仼��W���=��A;�Nw<.=�A5�]�<���kF<�j��+��y�*�GT�'e���w�����7bo[&�L�.*���SN[����k#/���53c����.l9H:T96�a�=����#Bm�"T&L�`ج��T��M�p�f����)�
�L�VA���h��@����[Y�9֬SLu
�VC4ᢚVy��{��$�5.U��!�������Sl�)����ɫ��t��k��$��RzQ����x��{ʤ���3΂��������'��H�@����EaJ�%0F6c�JnJ�H�]~=���z$�K��o�=	�R�4�yp`<�k��i�R�@�u�[�ނ�@���< ��p�g��XL���Nل��ݴ>���׮�pc���_j�1�g|`LQ�L�)�Ѷ�>rS0��e�E)��*F�,�^���Y�ê����2X��j��wai�EU]�!�1~T�4^�E"�n���4��ӳ���W�1��r"�Fg&��2��oh�>#.<kU˗��ŀwP�ptk��]�s0l�Zk�����	�F��+����S�>��K~8�|z;�*�~N>�I�˙
endstream
endobj
16 0 obj
6379
endobj
20 0 obj
[1 /XYZ 33  
760.250000  0]
endobj
21 0 obj
[1 /XYZ 33  
672.500000  0]
endobj
22 0 obj
[1 /XYZ 33  
158.750000  0]
endobj
23 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [102  696.500000  175.500000  705.500000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
19 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 24 0 R
/Resources 26 0 R
/Annots 27 0 R
/MediaBox [0 0 595 842]
>>
endobj
26 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
27 0 obj
[ 23 0 R ]
endobj
24 0 obj
<<
/Length 25 0 R
/Filter /FlateDecode
>>
stream
x��][k�H~�_��Ȫ*�.`�maaL���C�dv���d��+�JmK꯺��QIrk㶫���:��\��o>F��#����-zr?o>l�8�I�_T�{������P�}���l�G�7����7���x���h��4�p���"�����_��~�����e��<�_�l��痿�$��TeQ�=�Z���?��V�H�"I�6ڨf,��߽x��=��K�gi�آ��mZ&����&o~���JuE5�迟6�V�?w]�X]���\�؎��:)�Ĕ��]�&�vm�w]X=Q�:Iҩ�V:��k3ݬm�w�~� ���c[׏���,R:z�5j���X��2���KtYq�۫��M�L[�C]�ݶ�b�iV�5:�LRl[t\6��hɷ-YlR�k�ٶ�q���Ӣ�ۊ�ߦ�{F5C;f�ʺgt�t����Ūf�[�kɒ�tG-ۏE�xf�w�j[��768S��c�<CЁʶ-*iሱ�Pccf�W��^�d��;�z�L=���h�N��z�n�gf��ZU“Ep�RU�7�����#P7��6�{C��Y˟k�6�	c���Sg��ʡVKM���ⳍ�vݞ���·u
�֔�􆟁3U�n��h(�.�����u+�d����pl�,`���L��Cڡ�CU�Wam���@��Ң��ū����[��k�G��YQ<6QY�5֞�:�������aLT��W�je�~Ō��%xl��q�4sd���{��p>�}��ӆ��q^�9 >-�B«������lY%�IBʾ��S/��2r�s�	�Jiӌ�Ϝ9��߆׍�q?�؄W�uX�1���0(>?��Q{��P�@s<���
�,���9Ƣ �A�=���fzռ��!Y����2��68��#��`��,����5�ش,�ʌs�72#���-<Z�!��y�(���&��H��1)�3�5�H�㑍p�L��i�׎
�(���(�Ö#�_�������LM߶�I�&��X��Ԝ�Y棢t��=,�O]�`��Lg�c��~��||�Dc<c��]����+F�y����L���M���*y,+S��<�V'T���і��1��P���o������"�yZK𹓃r���;u�Z+ĩS�wwF����윪�o��g܊�=�C�������i^w�3-������-o���
��ma�s�=-�|��[k7��V]|���kty]�����Ϗ���]^EWW��Me��Ԭ[:�-�����@z�x
Yj��$�S����x%�Q��Pnj,T��	.U��9%A�itzSQ6�`֩���qf9J�ך�����!v�Ѐ���=Ϻ1#M=�*�h�ŒӠ�]K��J�^��b''�U���@/Lo�N��:�dD00�h`��]�i�c��P�t!*��IE��|1�I���a*Ɣ���Hr	v�^�ƊNmՎ�9i��lL(�:D�d0�a�ztZ�дCr��H��uW}N�_]��.f�"�=���i�zi]iӥv,�-�#'���̽��AP%n�Ex=�;=���dG���lt��ӬC���Ɣ�8�'Iq
O%,&�
%#�F(�u���u�Y���%Ťp�"_�!r�* �	k	�L��̙�i�H*�S�h�u��u�OMYf�2�5��L��Z0e����u
_�ܨ�I �F�Dcӈ��Ri���U����х���"!���S�J�T#F�I��c��>ƶ��ƒ�k���-�u��Ze7}խ���q�Ͳ
eh��E�'��QO?E{
�	����`7�8z����6`�;���f\?.�w����:�昬7��M m�z���k�۽�た��'Z��^:~z�5����6*���06{�-0��S6/+ΚD�[�vL�'SJZM��RԢ3ؒ÷�?c`�{�Ƕ+Yp�v���
?��CN�=��X���~q��cv��Q�������>;�={C{����-����kf�:�EA�2\�c�(�py� �\}E^G���̉�t\&f'��e| ��Ӣ�ZZhDiaܢ�( %Q�2XQ�h�Y_��2��s�*︨_&N���.����?ӗ
UR+�n���Ƕ͜��"�! �TD*+�H%��0&UcLy�bLnj��1ݞ���0�|��б�ɔtn�H�zI�a@?��>�w��ZO?p���P��p���h��u�?�
����׀���3�����mx>pv�){J�vDxfzD�;��8"J7Ӂ�\8��Ԧ�eo{f��ɫ�2!�TBR�[̙��P�P5��LgL;�[ô���
=�`� �G��n�w�L<
�N�g�O�^��ee�,f��w�2�eW��:���F>���QO�u<gY.N+��
N��Q��xu���g�����5�s�5�iM�2E�y�!���!ѬvFV�t��)X���9'���5�i����j%VPa����%�.����z•���4��D&
��у��PQ��WӔ�K�	D��S�%�S��7f�Dtc(z���c(8���R��#�C�YSl"��S���)�CY��n"���N�}��1o����A�pd���%IJp���T���N�(:ĈR�2��Rr���o���[Ӭ_q��8N�_!��zb��I��b.\�\W5gj��AK�� 2��P9���R�����:5]~��2֣	�)U{}r4P��9㫢!�]�	N���Q:a��H2��ZF�Jx`8c��R�B�<�������L֑��ߕ3k���
ߜߐ��D�R"��rԱ��|��	��Ռ�]�����хSC$�褲�I�59f��]�*�jq�1/�|�cN��#�xl8����*4D�,\�œ�B����6�R���I�3��'զiQI||�OQD��a8���"56,v���f`{�1f�"��)Мq��
 ������E��dZ&\;��:)�:��.�-����I�zc�#X(7��&�J�Ya�sm������5)���r���6�U
�	˘v0T��|�:Õ�3�p4AUA�QSz��l����}���PWN0�o�f&
=P��$p-ҁ$�N-꘠�F��YWa�zeyqJ(�䭭5S@`r�D$�w�eʛ ��ں��k�K��]�ʚH��s-?��eO�C|����`�ū�]��NZ|�^�%�|�f�e{���oCA�L�;%���b\p�q�@�D��Y__q>.+Y�6��dwA��REsj�p�-�Fvi�+���75���g2���t"C��@������iA/L]&&�;ZTa4/J'c¢�u(Cp��"�ra�!,Z��|*Hyx���g�|�!�K��Ҥ���Ɋe^��9��[8P0*e0�D� :ZF�O�+Yu{�4�	�Ǻ7��8,��k�

��֙���%!�F�u�"�{8�؈;N4����\���p��sL�'%�]�G��f��n`竩�ʗ$
��W3���CwӟƼ1�NDY�
<j�?ؕKd=c!�Y��8C�s% vM3��%#v�L�j�|4n��
�3̮���!Z&����C���'�u�>��a`��_E�d��dM�*Ü���C��'�)ܽHת��J�b�	#8��%g��3�e���C�ݭ��$���t��s�;���?����i��fH�MUv�4�2N�~�Y�bE[dg���y�[��u�dE
�pL\���x��5p��_����G�gZ��%-��'�~�q?��i:p>�G{�;<86Ϩ�Z�)E{�Z����Ňo�F�����~������Utu]�����I�Ļ���{��MO(l���>H"=�������.��gڿ�tJ�/~�ǯ�߆Qc�~b&�^`�`�36<S쩹{f1#��<k�;�1��(���*�mN�]*�?�5���P	@�_\!�dR�2LX��%g�$H�&�@#|��
L�B�DR�T-���e��1��r�<Ӄ�#mu}q��O*��d͇2��ZD��S�|ژʒ.mj�c:ϙ�}���Oi��T�ޗ����T����}�m����-q�vY�b0�e�e3!��*u�2bh,�m}ߎ��s�ަ,�)���Z ���w���]�g�z�
S��p"e�0.L��>w$!�S�
�T�����Ϟ�ߊ��s�y����'�Mټ����uK�y.o�7��Ow	0��7�v0����bJcȂ��0��<��Q�;���Ս�Ӎ�@7�N7����tc�W7�N7���:��vtcD7�vd�u�<�=+r��E߽;2��d�=l��S
endstream
endobj
25 0 obj
4362
endobj
29 0 obj
[2 /XYZ 33  
122.750000  0]
endobj
28 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 30 0 R
/Resources 32 0 R
/Annots 33 0 R
/MediaBox [0 0 595 842]
>>
endobj
32 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
33 0 obj
[ ]
endobj
30 0 obj
<<
/Length 31 0 R
/Filter /FlateDecode
>>
stream
x��]߯۶~�_��QDR% ����A�a�C��+��h�
۟?ɢl�G��=�$�-��k]Q$ux~~����}��?��O�>��O7E�l��u��:�B׹�������/����͇͇�߯�a��?>��y�?k�����f:�s��/����������S.�V�����_UQVyը�n�/����߾�~k�Q�uQhm�Q�\F���EcrS��u�'}�޼����)U����\U��sS4ua�F�8�:Ӯ6Y]����������L�6j�U�v��z�-˹]٣G��4�i
�w�6���L���OY?�W��Oݤ_�J�٧�7�����/�k�cd�ʷ�+-+��ck�+��^�y��rp�m�T�)���T����NSTz|��J�'s�G�y���Q��NF�g���}{�iZb)lKC�g�m���>��c��P�mYE�������.�~��J��P����Ŗ芮�G���g�G�s��	���<�|�4��wľ���{�[PO�
�Q|O��RK�����liBQ`�0��R\n{�xf�',3b5����h�>;��\#>.��3��S�˕=�G�p�X�a�7P���]1�z�w�dn{�Tǣ����;�
�
�SL!�9��8^)�~�J��M���k5�S]���&NcO	��J1+
�5���g��A9�U̩'T�نs���;�g;0L���̿o�����$��E!�-�`�_��{��4|����w��s�Ѱ·�~�	֍?����ϡ�)>��,œj��h�,���Jg|^i�]T1l�5o�9�mc
���ŋ�|���kF�3r�
����R/~�hS{?��x^������#�1��+�s���O�!��7�K5Bã�xLU�v��5���`���ю
�C�d���L��L;w�s�<�Hfn�aC�Q
"�,��)d���u�=��D�ak��Q���X�c�/���r����X�a_�����a�8�!4�
a<�8��d�\���!�nʒH�����̬3ұJ��1��v���q4·&�!�:����坨�)�	{K�g�mh|�HD,����vCx�(l�|a�/~��i�*/Ϟ�h�S	O��P��/�DL�c��o���:M&1.Ӯ��T�(m����ДݷMfl���Ƙ�nli
��1��L?^�w�'�q6���l�w�'�W��>7�����7�v�%�R
�b��� v)��:î�����e�?�	̸(0�"f��eR�9�Ue����b�sZs���DZ=�AkΉA[�b��y$�+ft����b��Ġ-�xű쮸�}nor1��ދ4"��`�F�7o^˫��&%��f=G�i��.'~u��{J��$��D�hxw�Y��-����=
����'�m?����+)=Vڙ�R��q��@=Djh����F�ר�D
��$��0f��
f,8
*�<��v�̕#��=&U�EgM�W��:�D���R�wJ���hIK��H�C�T�X�w�J�dV�@� ]SPeF�L!�i�zj_JU���g�0)��l�X�{�q�2%c�)܏�M؟�%���?NȾ1=$��Uy�X���X��-���9F�m���}��G�5�<�k���G(��7��
�M�k��-9��5�I��6L���a��t%�2�0%u���l@1Ʀ	��X5!��	�V�l�F��HuW��>ӏ煐n�	!�gu?��Pwō�s�x��vJ=�:I�'|Xc	��W�J(I��'P�a�[N[���d.��=1Hٸ06>q&��u���O�sc�W���C��J1�2����Ʀ%ƣ�H(��*S�����4Ʉ`��.�:x � 6+�l��`� R"r��k�uJdu�%ci��Ho�Ա�t�3$қ���\۵%�PJ�? �u%��Y��jb�8%]�Y�D���Dz�B�x8Z��͛bo�ԁ��JJ��;��)���Q;����N�Kn�i��o�$x�#��G�:�DG�K��D��z�R�R�BZ���C(=�x�B�����l`bс�K����K��f'�����ޛ]��\OJqN)�aJL)α��M3�CJq��g��o��~:���v����9�.믘�}�o�]�~:���֏w����F��a����ڧUvd��F+�S�İ伳X{�d'6U�F6�l���%;Vdx1�����4�k�mz�|���bF��~<���5����cF�7�;��
�M��w��,��C	��"ӞR���͠d��u��o[p���Od\�L�FYe<I�E����7�(p�xJ|�t�;3�\?��[oF�쯘�}��K�s��o�x'f��f��Q1�	e�0�����dV�;�&J�ξ��Ғ~?�c�#�����0:���=r��VE��\]��~�6�p4�4d�0�"�R|�h�3fp������q�9!��;
��"��Ce��<�յ����N�s�s��J�d��ld����P���'[l��+D�8Z-aѽ��=ӆ�rO-8�("�q��XE�0�%��i��$Yr�E{����ej����A0ώ׊��'۴���2��ފ���_��������HA�̖�hG�
5�&7t1��wZ�zO@��.1��c\�9�33P��)*%�V�ܶx=Li"\	;Zq�!Y�:Q$kՅ��z��x��n�Kkԕ*�p�
"�qkPvk0�d�2���N���iķ���)����1���$�� *���s�E��f�p��:�W�4�Z�p�^��>q��f�w�/!x�a�jD����ڬ�V�\W�Q�Np�&zΚ)6��	�������%�X���v'�a��.��4G�]^۫�Ԉ�d�����i���D���ɋ�i���d!���(`E
�S05��d���0�	�<Z�;���l>�%�Clk�T63�j��U�˥�C�-M��z�D8�8Z�=�B1uK/e�i�*�A�_�C��d��=/i�B{��B؏�W�=<�9�<"Sۮ��
���a�����|�sD�����@t����x���M�E���h��D��<�=8��R�i���X
Y�e=3�G������b5�����Z��8�mw�u�xkd=I҄��0>t&Qg��%hG[��{�|�J��?M�-�N���rs�Ө�M��ȾZ2�_D�Mh�VM1�'&1X����{�e뙊�~Y4���p�q1���l���7�
Y�-07l�0�3eO��=?z`�����pNe+�&~jsK��e�zu��H���$|?�Q7�\S�e�R6��e�D�[`w?X@b0~��9.W7�`٬M٦DK)>s�M4�� ���yͮ���,���5b�p¨�!:FP�.ք������I�{Sp��)pS{��u��|kY�1�@ٜs�$u�U��������&�Z@c�h�jA�{�h��0o�;)�e���'�-b�2�#��E#���/���~I*:gAP�T�]��t�mA�==P9��K��Pxw�zp)�K]z�f��uD{2��T�}�+�	C��~.�P�M������R�C�q�{b�K�L�����`���h�
�>A��ݡ�'�*2�*���K6�R��H&�(T9VP�1�e_� !LX_�l.C�'��OW?�2hiLЖI|`����Zp�<�!��U�uHgL!�DJ��FHe�Dʞ{��%�����e�#tsʏ 
Hf\�E�W�[p˄%�y����C6%���~��@���jx�=p�O`�5�ҿ��0>O�r����lS�/
ܣj��d�s�=�Ze�rmp�=%�G���K��LJ"��Aհ����y��~�`рl����d�쌚|�nRluE�23N�Y����sƸ�rB��+3ZٜY��jFs���Q5�9�'K6�K������qn�\��ŝr�RUc.��JL�A&�ɸ�M�q�1u2���x=Tg5�
��y�@L���ك�Tp��)��0�?��*�P+
50�UYY�)Q�n(��2��F
��s��3����>T�X��H�e�
�@D%*�π�ek��j�8��L�,�Ra,�{�Ehk���u+�Eh[����"t�G+;c�iBUu�]�qY�y��������*+(�w��dmelj�륱RyY�x�?I�Y�fl��r��'�ɟ��<�]d�?�W����y��@��m7���@���u��'�M�gpZy�	�
�?�P�8�X��>&������͛�����������y��}����S#��t�Q����/OGKX-yu'qzO��9q�uQfz]j�W�'��q��PR��8.��g�Qp�
�5~���q�#�F0��v���BLj���ui���#��u� �<Ǫ<L�Lj�x���B��$eG�}S~R��1~s�Q`����]��g�F��A\����2�|&�Ō�JL`��tL�
�c�f��I���!�Ʌ���*��h�B6�?�5�r������9S�N1�_89�-�G;2Z���ឪ���LQ��\�S{b�Q�]�u���T�T�I5,�T�J����N�z(��_�����2�'Y-�WF����6�kO��C����T�}�T���V���M�}�3c���7��ucKS�o��g��k?u���订��k�w������~޼�f�l���U�m-w�c�UG+0�,?�
�i*v�2{@(��y���.���DTIej��Տ�"����s�T��T1,���i{̘ژv���D:����y��נ�;���C�a��l��
endstream
endobj
31 0 obj
4897
endobj
35 0 obj
[3 /XYZ 33  
765.500000  0]
endobj
36 0 obj
<<
/__WKANCHOR_2 8 0 R
/__WKANCHOR_4 9 0 R
/__WKANCHOR_6 10 0 R
/__WKANCHOR_a 11 0 R
/__WKANCHOR_8 12 0 R
/__WKANCHOR_c 13 0 R
/__WKANCHOR_e 20 0 R
/__WKANCHOR_g 21 0 R
/__WKANCHOR_i 22 0 R
/__WKANCHOR_k 29 0 R
/__WKANCHOR_m 35 0 R
>>
endobj
39 0 obj
<</Title (��PERFORMANCE OF ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_4
  /Count 0
  /Next 40 0 R
>>
endobj
40 0 obj
<</Title (��ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_6
  /Count 0
  /Next 41 0 R
  /Prev 39 0 R
>>
endobj
41 0 obj
<</Title (��LIMITATIONS OF LOADERS AND ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_8
  /Count 0
  /Next 42 0 R
  /Prev 40 0 R
>>
endobj
44 0 obj
<</Title (��\(Available for Linux 32 and 64 bit x86 servers using PHP 7\))
  /Parent 42 0 R
  /Dest /__WKANCHOR_c
  /Count 0
>>
endobj
42 0 obj
<</Title (��IONCUBE24 : real-time intrusion protection and PHP error reporting)
  /Parent 38 0 R
  /Dest /__WKANCHOR_a
  /Count 0
  /Next 43 0 R
  /Prev 41 0 R
  /First 44 0 R
  /Last 44 0 R
>>
endobj
45 0 obj
<</Title (��Global settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_g
  /Count 0
  /Next 46 0 R
>>
endobj
46 0 obj
<</Title (��Security related settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_i
  /Count 0
  /Next 47 0 R
  /Prev 45 0 R
>>
endobj
47 0 obj
<</Title (��PHP Error reporting settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_k
  /Count 0
  /Next 48 0 R
  /Prev 46 0 R
>>
endobj
48 0 obj
<</Title (��Deprecated settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_m
  /Count 0
  /Prev 47 0 R
>>
endobj
43 0 obj
<</Title (��php.ini settings)
  /Parent 38 0 R
  /Dest /__WKANCHOR_e
  /Count 0
  /Prev 42 0 R
  /First 45 0 R
  /Last 48 0 R
>>
endobj
38 0 obj
<</Title (��ionCube Loader 14.4 User Guide)
  /Parent 37 0 R
  /Dest /__WKANCHOR_2
  /Count 0
  /First 39 0 R
  /Last 43 0 R
>>
endobj
37 0 obj
<</Type /Outlines /First 38 0 R
/Last 38 0 R>>
endobj
49 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/Outlines 37 0 R
/PageMode /UseOutlines
/Dests 36 0 R
>>
endobj
34 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 50 0 R
/Resources 52 0 R
/Annots 53 0 R
/MediaBox [0 0 595 842]
>>
endobj
52 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
53 0 obj
[ ]
endobj
50 0 obj
<<
/Length 51 0 R
/Filter /FlateDecode
>>
stream
x��[mk�8��_��u�jIP
M��AI�>��d�X�e�����?9gc'��L��^wj'�F�g4�������MLf�/bI�ټ��w��'�g�_�Pҽ�нX��ⱸ-n��Ǣm���|(&M_E��|�{��Gh�k��I��W��%�����+_�M+�>~�����*�����~�c����e�Rk��jl�|>3��Rz]=���-C���hU}�.�W֧�(c�&j�ixO�0��F|}W��=v�a��a�:7:�Lsg��xW	S57��ߦ?��.��H��I���3M{�s��l]-I���NOI�;z�m�c1}�c���:]��J(-�E�γ沸/lHތ����<���B,>U�5u��O5����2Va;k�Q�DV�#�:�qʭ��QkZ�$��}ܚ6+�++�Bg<J�N�0�=�s6$�$��=�A�d�Z���>�X0m[���ܬ$׋Y�	��*6�
h�k/Tj��虦=
�v��uԞ�J-�=߶w�Pq����H��'���i±TU���N�X<�����i�j86���e����
+��=J۟guI�m�h����Zs$1Dt��Op�.����}�~h�w-�
�M]�E��w
�-c�"–�t��6C�@V�'~2�r� ����r���ϋw�~���BL�f�o���	�����f�s�i�9�E�/��3�h�69l�B�-%9~Hk�$��A�Ϸ�%���I�x<ж��8�C�Hە�9�'|Ɯ�<��H1尚���o����:��	ýÊ���4u,P��:r��������kF�Lɣ�2o�9�5JX8��o<ی�o��0w�5;j��V��-7q}�a�q�����U�'7�+�wr��^�t}ﵳ1A��o�qi{����"�� �LSZ�����T� ق��dž[-��
J<l-@�5�(�����l5��V(���H�Q���&��Xpu.��AI����X.�D+[K�h{A�y�4��T���8�7=����T���l�p5R�XX�Dl5&[��a	
��g�8&[X��=�$�A�2�A9[Ƒ�>/�U�F�=�l}8��l�q���kΜ���x��yo��Z�)�`Te���/m�(�%N���b(c�S|=Y
[�WN!��a�a�i�:��x‘|�����̄���.Y��3?��>r��b$�f�8�9ebNfb�-�Xqkx�F-��r=^�Y3�U74�}��GʚG{����ɚo��9��L��É�qW
�	���Ki�������i�G?X��8��3��N������돶*��)#�<��������aX�*N�{<��-2��sh�Q�aU?�T/�T2���F��a���F����g�.����13�ގS������ [�'�Y�����B֬�^:�� ��F�_�U�o��u��|˾V���-W��h�#�D���D��~3���
[�Gj�8�18��<���Lk�o�6��L?��K��]bT[^����'_0��ls��K��[��Y{XE�얞�]�^u�����H��Ȍ��d��}����jz�
endstream
endobj
51 0 obj
1581
endobj
54 0 obj
<< /Type /FontDescriptor
/FontName /QCCAAA+Roboto-Regular
/Flags 4 
/FontBBox [-736.816406 -270.996093 1148.43750 1056.15234 ]
/ItalicAngle 0 
/Ascent 927.734375 
/Descent -244.140625 
/CapHeight 927.734375 
/StemV 48.8281250 
/FontFile2 55 0 R
>>
endobj
55 0 obj
<<
/Length1 6976 
/Length 58 0 R
/Filter /FlateDecode
>>
stream
x�}X	\G����{�F�1+Ȍ�`�P`&�7�)ry" �9ܠ� ry+(*�&��&Fr�I0�$���[s=�xd�M6	0��g0׾���ꪯ���5B�
�L8B����j�=���bI��_�y=�����Н����q!l!���';Ư������삲*���`�B`l�1-���#d~&��UE$�,�v#�U����7�	Bh;��`:Rp����$��V,�-BGb�j���!K�������eD$$S�A�e�x?�4�C��Hm�9"'���B�j��S{5�A�M3ϥ����a����F9QG�5��S��rs���R�*Z9�%M1�_��$���Wq
{��Q�87���K��0Q.�LպA��t�'�蝝���>��y?p��rqQ�r����j���G�J�����J��˴HF���t4x�o��v�\�j��b��͍s�Kv�����}{\,�'�4��Sm��MAA;��Vo���m�����3�((D���'�.�J��^�Q�Y�˱
���˰�3Q�޸* ���5k�z�f����6�~�R��]�}��ȲF�uS��F7�� U
R�)u��Ͽ�c�}��q�C�O}��2��_b��LY9ik�=��W���h:�ցCq�[�x::��ip���V=��m���@��Z��)&���p�
�>�r���ө�͐��O��A����.I�C��dg����i�D���Q�Т�5(	�c^UR�w�h�m*�����x~I™��aT�s��=52b~������Y�%���,\'	���y2�� C.���
(����*����z�����<����zy�Yï\ޒ�]�$~X��Sl�&ž]�O=�ych0���b���4�>m���Ҹ=�GG2u�_8������
��g��_<r�9%���7ȝ+�Dv��4ȡ���	�P���*�����R�t�)lk�9��
[6}s�Ͽ(- z��7-��7/GpZ��->	����W��HNJH�O]pLTĬ�����8~�r�������Ӌq�9��~�-���e�B��ՙ�%�J�ʊ/Mݶ�K/TT� *��'6�(�ˁ�Z�=Hʚu�,7eew�wsr�^@�q��!�-@�,����<��t�[�w�3�Of�05�a���Y�L�{A画�-t�3���kȽ��"C�#e��	����B�5�shk�y�;�����[�}7�K�1�v���*�-�ta@#Q�$u�����;�	�i����s����E�1g�
@5E��c7��
N���7��7�aD�w�M[n�ݱ^Z��c�@85<��k���͟s���:���e�:���d���(%���z�r栱
�o�me�Ĝɀ�Q0��l���N�b�se%��f���[�fN(-?_��a�5�!A%ً�KČi.SfL���ٺz���}zf��5ST3f��Oܓ�`��ؔ$�Gf�`��C	���e�����S��7����h�Qy��j�Fx}CϳM�Qh&����fU�A���P\t!�R��C�.����:���g�C�����R��=0i�/�f�7��96Ԓ��|�8���g
�:Gc0���:���l�ε�!��j�C����_�!Ӻ���@lx�e�@L秅���榦ܬ�C�,���*���М��Q�us�L�O��{�ȎTo��q2_�}��3��-�Ȫpu��Ip)�y�f4��xk-i�O�x�8�e	��&7��Ouv@И��g0�T���� 6�gҁR�y��^��@��7�lc;r�&
��Y7s��R p���Wh�:l�<y��ox`����Bqp�9u��zl�Ĉ�fzt'HrS��{�,6\�75X���/���Ū��C�,k2�&� Β�Y^�I9DL���-9Ē�-�	�Aa�O��⋗�L]�E���	ډ�ا�c�-Y����!�`�^q�?����C�򲑃��܀́�Z���8�\��ҁ��O&%u/\0��{%��m�ɝƧ��ص�z����N@����{�y
�i��J����t��K�4L�Yf�)�e/_2�vU�\+/*�K�8�a�PV�|DĶ����Eb�5��h��um�z��\n܋Ѹ9i�:��s�w�^*e�>�M��8Z���U�8`XG
9}�M���-v���q��q;����|I8�ֿ���28����6:���;��>$i�y��:��yj_��"=nNN�w��,~��#b���bRӱ�r���<�ďCk[��;�b㫑[F'�#��caP�5��%�����f�6GF��n���}q=�h+���X�r��:7��{�{�
������*��l��H��F8-ԞY(3R{{��I�o!m�����.q��o�~��r3p����¹vH�R�V�W��`@;�?|I�ʸ�	�Z��i���an搋�=7��ws�,�g[�C�E����
w��Do�q{��e:�x�S��zE�Ͽ�3��Xc��Ajd�a��^�/�g?6ԇE�B�s!hw$�Ò�v�Ce~V8UT�NSz���m,�&<�f[h��4W��/q�H�`��i��\ø�ܔ��lQo�0I��ѰȲ����AK����	�	����[{N�7�F��5ԟ�i�z���?���A^��73��]�u���ĸ��Wr�?�,!>���w(������w삦ъ�d��9���
{�'��pn��_�&�S��{T��j��j��C��Q��Ć(8K�e�?������2w6]��NP�~s|�3T��x����]��[fa ��_h.^��\��u��,�o��!����Z��r"�s
ӡ��.8�Ҟ�K�钘��_�>p�fK�©���C�'�w���x&�47�$����1)� �.A�X�eV5<@�Q$!��H��$ǣ�?��o�,_��b|����1q�Lv��gs��ں���kSo�]I��s�<U\�矑��.*�-0��7_��7?6��tn�?����>2j���ܹR̟����2�����Ar@�\��;M�_�i.�]����P*��{�c}�F�I��a�S�r_��F��GLs@��t�,�L��Y	��e��Ξr-�
��VUmqۓ�l������%�^}��+d}�#~� ֈ_v���@<��
HqҨm�1����-M������_��N{09���Y�1����y~4��W�:V\��Oࡺz���K�û�z�
R���nc�C��

���?�;������@�|��@��k�M�/�Q
U2m@�Z����������{<�?����v�ֱ��1F���L]���2�)
�~*��w?�׉�22�\	��\s3�ف���ѠF�1�p���a4�bW�IH~%�~c~vVn�k���6|��
v=va!�[�Ö�ԯ��w�K@��O>�Ry�/�,X�b���+���4\��k~A�b��G�$���߁|T>SG���z��@CKmd�Ⱥ�Pl��[����V-^�i�[W6m鍈ظ����{[8/(�EO��^LY�r����1k�g�� $�nS`���d�͟��z+jU�h'����b.��r�zDox�XD�Gr8�'8�;0���koG��y5A��G`�_-�A�5�^�K�������~I��\���a`���Po�,���}F�nS�����1Q
O,[q�aIuٿoK�����mz1�v@n�,
-�킁D\����x���˽/��&`�6���G]��W
��5 �Y�ꖳ�{�5�ؑ�A�kX���.޴��k7â�%k
�Be��}�����O'�au��a ~S�8�ޅ�s���+^,*����k��$&���k����H���P\�
*-


(*	F���yi�C�<�,'&Noga[±Z]��1����3��19��;.������-{�t�)�'Xt�p��qw�s�����]�0/�\��uN���c�s��J���l����G���d���ؗ\~	q4��~�*`��w-eI��Ҙ��a�.�>"l��U[�]�t۶�G����u����/!��ի�ڒV�&�FF�F)�;�S�NB��Q_d���;W���4�.�q�����*��o�����K"A�L샩5Q�!;�/����ˌ��1u՚M��b�]� $h=Ƞc����G}��R:��eŌ��'�Wԥ�}�0R��Y���4��F�_�f��ZO1��]3�m���z0Ƃ�	T��x	9q{���0��0�=�*��7��� F�
��qęat;�T��b�?�����s�ϛ���<Y?��s2�7&^���4�8�yp����P��m��'?<�G�����1CvO�<S�����E����8�PvO���+�k%�����"��\�*�I%��r�!��<�C(�h�ů$|I��a�FҍEO'�]��U$Y(%�Kē�ƶY-�H=Bl�[D��3z�52�)�X�%�!]��8#�$�N��82�{�8��=r���1�I�lߏ'6^X��.��#d}�l������$
�x��Fҁe
�D��Ä��d:�Kƾ(,EXJ���C���+I&J�Dw�F�z��Ë$���,��x�O�D:�.��t#�;�rq\%w�����Z^�g�����`/L��B���p_��"d�&�Q��Z./���$����M�M��36l�ٺ��l�m���4f՘�1c��<6�IKd�#i�/;r�A��b�3�wZ���s�:��oX�<�oY�����u����d�
g�^@�HX?��)�z�Z�Ek��5k] n䶵.#N���Ǔx��IYGJH�"٤��P��o	��F��'�
#�$����"���w�Y�R+�H���8��֕�de���<<=U!FcV~�*�0m�jQ~�*�}*U�f�f�Td��X\o-�2,$ָ�X��H.��㒩H��fd�秖����Cg��V)�k�M�-��
��?�0���c��k�����x6�����x�p��EJ�-b����8�K~��'f��|d'
{
%��bO$�8�!‰ç�Ħ-++�3���rvjQjZv�lcI֜�����Ҍ�9�aA�qA�^�q��G+�
endstream
endobj
58 0 obj
5244
endobj
56 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Roboto-Regular
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 54 0 R
/CIDToGIDMap /Identity
/W [0 [440 241 566 547 646 547 557 526 246 534 540 559 336 557 557 261 643 512 676 592 546 519 869 324 481 241 557 344 557 626 707 195 557 270 745 469 564 611 548 682 866 647 707 651 589 880 339 345 492 240 503 557 557 562 448 210 564 557 557 557 557 618 274 409 631 317 237 ]
]
>>
endobj
57 0 obj
<< /Length 826 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0042> [<0069> <006F> <006E> <0043> <0075> <0062> <0065> <0020> <004C> <0061> <0064> <0072> <0031> <0034> <002E> <0055> <0073> <0047> <0054> <0068> <0063> <006D> <0074> <0076> <006C> <0070> <0066> <0067> <0050> <0048> <002C> <0032> <0049> <0077> <0079> <0045> <0052> <0046> <004F> <004D> <0041> <004E> <0044> <0053> <0057> <0028> <0029> <0078> <003A> <006B> <0035> <0033> <002B> <005F> <003B> <0071> <0037> <0038> <0030> <0036> <0042> <002D> <002F> <0056> <0022> <006A> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
6 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Roboto-Regular
/Encoding /Identity-H
/DescendantFonts [56 0 R]
/ToUnicode 57 0 R>>
endobj
59 0 obj
<< /Type /FontDescriptor
/FontName /QHCAAA+Consolas
/Flags 4 
/FontBBox [-432.128906 -302.246093 677.246093 1011.23046 ]
/ItalicAngle 0 
/Ascent 742.675781 
/Descent -257.324218 
/CapHeight 742.675781 
/StemV 70.3125000 
/FontFile2 60 0 R
>>
endobj
60 0 obj
<<
/Length1 11900 
/Length 63 0 R
/Filter /FlateDecode
>>
stream
x��yytǙgW7�� �H$��M���/�%ID @�hZ�%��x��-;vd[����$���x2Il����;M6;���y��y����Yٱw=~�l�W�
�e�X�+tuu�W���jR����8�P�������`����%Vf�Ux�o������c�hde��e��X�<�L�=<�����}���u<�<�6�����ߚ(ʌ�/.��[�ڨ'(ʢ�g6^��ێ��\MQ�a�͢�(1E��(
�;�kj��

i����E-�J�7��՛@��c�R]TwS���'hZ:E�)�o���bލ2S"j��D��̀�
8EJ�7;��J��:\��`��_G0P���K���f�$��Pe�_���!frMD��*U��@p@���h����.�;�c{��~Ra�K
d�R���D)SH*�*d����5��n��g���x�mv����5FCqQ�`�r����`tnZZ�T�*�R��^�����A6{��*'CN�r��`�>��{�#�3j7��2�L&/S�f���T��j��L=���S�ĔL�R���Xƿ,3�-f�N���(�c��"�Q6����*�uא����w���4j~<��+���wN�[L�M���X���}�d:1>��b���TZgecS��PsyE�R�r9C�};�B�e��[
��8]�a��
<��90��r"�����L
���Zde���[�o��k���}��:u4�&��Rt��k�e�R��ܳR����rW�<32|y�'X+˖;]����
�r��P���ڽ���!T(��ܭk�x��n~¼���sb�
`}h�?�(��üпep���@�}�����������7���V�3�N������4*�щ��	��W:�Ln�hW��~�ď�M!�,e1���NY(��pI6,R��I�y󌤦ʍ�yvx�|��Zv����ݡ�J�ԾW���x��Z���~|�������LTӆo`i]���.~!U�9s�,�o�޽���s�`���XOW�W�}�c���^�pT�ܾ@������Se������� n�x�;�j�[�*�]�������g6�r�F���3hd
�V�x�
b�΂f>O��:���
~B���yv�I�(�IN�cD����oyk�g\Nvpr���[������D|d�)d1��⨫�i�Ֆ;�Z��5ώ�AbF")�>��:��g��Ӄ[����clr����]��ju.w�	�3����_�V��h*l5�kg�:MqQQ�Fge��U�+*F��H��ZQkQ�����q��Vi���7�xt��壍�G�P�:���1?'�F�<�`����(�
�+ǝ��q����o�t+����;���yi|dϤB����~���@����;=�Z�����P���j�vn�xh���.g0������PR�˟S(d�B�!�����1��])*�����`Vi
T�؅�I���9�n�(U>恟���p�Q=�*�#�b�Q��9�/�ռxF24:>3������!�3�u�r��;w���b��^g9�H���G~z�>PQ�ӵ��/�xr_k��*�0[�
d?)hؐ�2�+RG�-(v�y�����3#���*�pEy������\�Ku~������(6Z<�mkG�.�͊f��p
��,���x�}k�7�܀=�T0/�hw(y@�k���PwV�������.?+���X��5L|5���Ţ"nJ����y����~:���k�6X��6�W)��\i���z}�~�}d��~���֦{����%�4>�Z�8R�p?{��$�L��bdU6���|fh�7/{�G�=�.W��eI���$�'��OdZ��3��$7w��Cj)������5�Ȇ��6���F���]��Lks�ɿ����ll��W[W��=911��BPf xO_s�ۣ׫U���ᕖ��;�5�xkL�B.���{&;�+���˂��\�+)�R"��Qc�F�F��hL*��Q�u{�몽����Y��P&/Ui�&�V�Ҫ4P�X�+�5���������OT<�"�V�Y�.V(����ʚ,j�m�B���ػ�c���Xs��-���%��������Kp��r��q��Ľ��V:tZTTR�**)���A��6�����֎�S˨�.r����t���
:�����j�]Q��ZSӾg�Ζ�r�x�"j�j��hJ���W@i�q�/p��k/����p���i�$wg��w�4�ɡ3�v�Gw�T榛�~��ysm�E����]���ij@5S�O�����ןC���;�7�����o���\'�큹e�8�~�5�G��[�,��u��h����Ք�d���х�7��O�(�=��"���)��]�ʆM�_���Fy�-�^j*�L�K
eE��R�J�5؞��EQiY��t�����Qo4����G�Ӛ
v��u��>���N	
����Z;B���aW�H�4��lY;�\�Y��e�C�@
�T��e1�Kp�9�/�&8/9�z�ZL0�r�|N��rhR�ĥ���/tZ��dc]�/��{����2UyECco��t�D]����Xg��Y�Q��~֊�Ck��McuMg���`��g���}�aZ2l�v�Y͞*����5��1xȫV�E�N�$T�	�6�h�p�
�!����`&X�=�����:�\NU)Bf���������3[����2}�	(��.��|��OZ�u���v��jF3�1C��"\��^��(�x2\���jƶd�������:�ƈDi���hktVZ�0�hc��M�`����\e	�\��ru�3���'8���4�%#��
�k�`�g�҉��v��)J3A7:
΂$d���^'2}-r��p�?�^G�}k��wf��K��B�S�cHI���M��Խ�zh3P�]�U'�t�[Q���v��5(WF��)�Ѩ$<�ug�}LƤ,1[�C㝡&���@Ն
��;jk�d��uLM�l<Ԥ7�45`T��
��u���D�I,�`���
G�%֘��'w��)�����q7���H$���bv���X+U�-.wm��6Y�J�i���qgW��Vo,.R��Zi0"SZf����}�m5�F�Z��c�`S(�(S�4z��+�^�5�f����Z0n�W��6{I�Q����Huj�F��i���
6-V��R�����b���#��k	�x�G?"u

 ��\�e�|��ܴq�=���3�\�LJ����v�{���xg�������B�A�W/}㟿8�}#uS�\�M5C����`d6e9��ʅ�NU�q6 ��ñ�R5�8�SƆ`CMS������'�`��r������G�5vn�:����YWoc���ͪ�6�"��@@�PG{Q���t5���DZ({�H.s�F+[�in�ꮩ1�D}$Q�J.�JD�
���q55�h�h���6�S
_��-�'Z^5���&*,f�s�4v��1'�ߥ� =�^G��;��z@�@TK�ԣ�Co�?���5Y�k���Alt�
���P��߼��͢�����:��l�{X!7�+��G�z�>���W?�W�f����6�5��9R�rt�X�w獡S�sTB��ǵ��:0
�������
F�NKꚚ�C�Cm�͵6�w�M���zg��\T��B�7:+��>X�hߧV�ڵk��'�M>���BB^懰+�4��x�v���o�ݻ�
�\VTl4y�[G{��n�9x|bp~�U���!}�ڵ��
�
�j8��U�ʖ��ZBc]����m]�ݽ}#��J��Q�QF�.ɈAP����}y�a��ƻ\�kFo";�.�?̈́W��_Y�~?q�CQ1He�s�P�wɝ�9!A�u�pb�G��M�b��깕/��ї�#���:���XG��B��v�N[n�V5�6�\.�f�d�]����U�@_�	�ҏ<u���^=B��=#Ǐ]~��N�]�=ǎ���ag�X�[
ٹ�n��9p\�ZY3z:�q�Ve)��w���vl��Zf�%U�D
!�ڲp�Cͽ}û"F�ƀ1�頻he��_s���
��_�D:�-Vi�1�Ev[}� .�Μ��{n�aO9�/��0����>�>��Nr��&�6�:Ɲ@��O�Пq�v	���W�ז8�~���7��&+Z��!��y,�8�
�ܕW��o+�{�vÁ��3��T��x�j�@��ׇ�;۷�����P(��궎�'��R��%]W���-��.g��嬘�5l0��[#�z��ҨG��o�j�����\")+-��ڂ�*����Q�,���=�q���\^P {<mm��ݶ��@�wV���K��S�E�o�Kk���_Ҷ��tPlz�;���I��p��
%�"H�T���=��x
z�"S�$kܴش����K��k��%1�y{uwˑ��t�[�ET��<[������juW
���=�������J�\����Ѷ�J�J���\Ύ��=m�J��~��N��r�ښ�G��|���nO��vt�ȑ�dNo��U��S旦ý[�pb��O�!����ƩGT��!w�yU��GE�����k��&������b�-T��P���SO��N�S7���N�\�{�C�Tn>Ư+c�����~���'�tW�؞H|���;��ػ붆�ɂ��ߌ��>X׍��m�w���~���|����g��
w�W�Y��d������������������� �z ~�q��"**������‘/s�G#���S�!���qxW���u�́���Cm�j�^lz�,������
hU���}���~��2��"mX?�0�[��]�p�e��;���ze��o���sc�ûv�j�t�8�ؤ�������]{�����F4E�H*"\<`1�h�{���+��O��yY�߁#�'���~��)ķط�ׅ%m����v��ȳ�K��F��5���D�Ǐ�YB)�/c��^��s��
wܖD�����]�F	�;���`�3p�m�p�@�愶�%h)a-�B�П��S	��C��	h^��Vh[x~��К��o�
<bd�����D����>A���oL#s��>�D�!J�>��.�'��şK�%A�i���NH�)}��t�
�>Q�O�JY�짲��Z�G~^���mE�bX1���⇊�ElQ+�n�z��۟%��멜=�B���B���ӧB_D ��S
�.�%0>%�TzW�PzP�R��q�/��'�&��W���WPy��/Bۋ� �ƒK�	�F	W���R�i�Oì
}������Q��@�)=r}	�	})u�	��C��~!���B_&�M��rj\���WP�J�ѧ�cB��J��Q߃J�j�:*�T��Pi*Ee��RY�^|��a$�$ԉ,�M%�b��06G�ûy��=��oW��c�uvG<�NeR�Y�7�^L���x*�c�	vw|n>�aw�2���X��m0	�6�d&�C�0�~�����R"�۹o����:-�ͻl7N����PJ�@YxKg@6��Ja�+h��0�,Qk�X ��1�<~3�w6�y^��fG��a�)NL��`��g�0�M����p���e��<�̥SK�x8�ZX'㱌�N��c�@�Ѵ�X�PUDh7�������/E��7���T*{7]�A>�P,���g�x���,�s��������~�҄�y�
4��^J�u��ό���%s"D�,Y���`�B��=��]�(�������2�[�'4Ä���=�%c��>9/��b��8���𔀧Cdk,JV����V|�f5�7ssz��ě�9�7)b�X��X�0�:��bLk(#�a��(C�����=*�'ފmrX�����eBiC�Q��E�+dw�;<�_\+C�()�k(����ܕ�3A,�[=}��2M�� c1�>���#���uZ�ܻ{B�;���M_H��$��9�2y�_ ��z��
҄A�	���狷-�	<�1�՘�9�x,ː��9��ab�$p��!F}I�)mX{KB8���;-ț\K�x��%�J+ٛ��y�[5�!���Uy��*�*)�Fn~�{zR���B�`��s��s4#؟�WΧp��lI�ov=��=8A�&�s���2#D���躟�OY�_�̟!=LPae]�9��3dn>�-�q{�/Ģ�l*�.ebl<�.�Ss���B<9�ƒ���Tr!��\NF�d�4��#K�l8�e�e�A6YH%S��p��Kf1��b,��C�&I=2N�#YȒ�|�p���Lx!�.ǣ�j6?cS�(�]Y�-��xf5�>�y�ga��T*
dR�H��3R�p�07���'c��t:�YL%��C;
��@0�$؉x2�Z��<F��Dx�
'�ex�ē��%���<V�.���f"��M��Tzv���˂�$I�q<F7)!��ԛZJ�ci�	V9�,C�_H�� �B?�I����i!��X2
��NPVd"�X���Xr4�����%��I,A�n���4�Ľ��B,NdZ�|>�f��l�
D�?�������$dk0Of>��cB3 ?�5����[�,6��D*�����e����6�
g�1vf�=N�`�lО	�yG[��%�<��E(�j�Z&����[����B���E���8�n�/5��.���.//�r���P���q~�6�%��C��,A�4A���9�x�lx&?��R�^��|�]ɫS��8����G��Wr���@.�1(���P,���pQRje׫�e�W��;���o ���ǕE����r<-���ȸYn���OU��M2�]�?�U�6�~mP�Ȅ|���#�T��r�f��3
���%K�˕˜>/+_�$I~�QIy=�o�i�ߍ�k{�P
�H=|*Erp�[�����_W�g16T���'8��c�l{7���]�dq�X��G�����ш�:�BL/��0!� ����ީ$�^U���������w�L'`	�M�#<P����i��V�]��|I�aWH�D*��)��9ň�2^j)���"vg�3K,n�XmU-1.��%R���/BY��0`���lx)���3���;�	
endstream
endobj
63 0 obj
7274
endobj
61 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Consolas
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 59 0 R
/CIDToGIDMap /Identity
/DW 545 >>
endobj
62 0 obj
<< /Length 742 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0036> [<0069> <006F> <006E> <0063> <0075> <0062> <0065> <002E> <006C> <0061> <0064> <0072> <005F> <0070> <0074> <0068> <0073> <003A> <003B> <002B> <002D> <002F> <0076> <0077> <006D> <0052> <0053> <0020> <003D> <0022> <0066> <0067> <006B> <0031> <0024> <007B> <007D> <0032> <0034> <0030> <0079> <0078> <0037> <0033> <0045> <004E> <004F> <0054> <0049> <0043> <007C> <0044> <0050> <0041> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Consolas
/Encoding /Identity-H
/DescendantFonts [61 0 R]
/ToUnicode 62 0 R>>
endobj
2 0 obj
<<
/Type /Pages
/Kids 
[
5 0 R
19 0 R
28 0 R
34 0 R
]
/Count 4
/ProcSet [/PDF /Text /ImageB /ImageC]
>>
endobj
xref
0 64
0000000000 65535 f 
0000000009 00000 n 
0000038255 00000 n 
0000000187 00000 n 
0000000282 00000 n 
0000000756 00000 n 
0000029337 00000 n 
0000038121 00000 n 
0000000319 00000 n 
0000000362 00000 n 
0000000405 00000 n 
0000000449 00000 n 
0000000493 00000 n 
0000000530 00000 n 
0000000574 00000 n 
0000001080 00000 n 
0000007535 00000 n 
0000000877 00000 n 
0000001053 00000 n 
0000007863 00000 n 
0000007556 00000 n 
0000007600 00000 n 
0000007644 00000 n 
0000007688 00000 n 
0000008188 00000 n 
0000012626 00000 n 
0000007985 00000 n 
0000008161 00000 n 
0000012691 00000 n 
0000012647 00000 n 
0000013009 00000 n 
0000017982 00000 n 
0000012813 00000 n 
0000012989 00000 n 
0000020361 00000 n 
0000018003 00000 n 
0000018047 00000 n 
0000020194 00000 n 
0000020020 00000 n 
0000018298 00000 n 
0000018452 00000 n 
0000018591 00000 n 
0000018987 00000 n 
0000019859 00000 n 
0000018784 00000 n 
0000019263 00000 n 
0000019391 00000 n 
0000019554 00000 n 
0000019723 00000 n 
0000020257 00000 n 
0000020679 00000 n 
0000022336 00000 n 
0000020483 00000 n 
0000020659 00000 n 
0000022357 00000 n 
0000022621 00000 n 
0000027977 00000 n 
0000028459 00000 n 
0000027956 00000 n 
0000029477 00000 n 
0000029735 00000 n 
0000037122 00000 n 
0000037327 00000 n 
0000037101 00000 n 
trailer
<<
/Size 64
/Info 1 0 R
/Root 49 0 R
>>
startxref
38374
%%EOF
alt-php71-ioncube-loader/LICENSE.txt000064400000025020150475525430013003 0ustar00LICENCE AGREEMENT FOR THE IONCUBE PHP LOADER, PROVIDED TO ENABLE THE USE
OF IONCUBE ENCODED FILES AND AS PART OF THE IONCUBE24 SERVICE (ioncube24.com)

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING THE
LOADER SOFTWARE. THE INSTALLATION AND/OR USE OR COPYING OF THE IONCUBE PHP
LOADER SOFTWARE INDICATES YOUR ACCEPTANCE OF THIS LICENCE AGREEMENT.  IF YOU
DO NOT ACCEPT THE TERMS OF THIS LICENCE AGREEMENT, DO NOT INSTALL, COPY
AND/OR USE THE LOADER SOFTWARE.

DEFINITIONS

The following definitions shall apply in this document:

LOADER shall mean the ionCube PHP Loader software package or collection 
of Loaders, including any modifications or upgrades to the software, used for
executing PHP scripts previously encoded with the ionCube PHP Encoder
software to render them non-humanly readable, and any associated
documentation or electronic or online materials relating to the software.

ENCODER shall mean any ionCube PHP Encoder software or service used for the
purpose of producing non-humanly readable encoded files from PHP scripts.

ENCODED FILE shall mean a non-humanly readable file produced by the 
Encoder and being derived from humanly readable PHP script source.

PROVIDER shall mean ionCube Ltd.

USER/YOU shall mean any entity who has downloaded or obtained through any
other means a version of the Loader software.


1 LICENSE ENTITLEMENT 

1.1 The Loader is provided without charge.  Title to the Loader does not pass
to the user in any circumstances.  The Loader is supplied as object code.

1.2 The provider grants a personal, non-transferable, non-exclusive licence to
use the Loader in accordance with the terms and conditions of this Licence
Agreement.

1.3 The installation or downloading and use of the Loader entitles the user
to install and use the Loader for its own internal lawful purposes.


2 DISTRIBUTION 

2.1 The Loader may be freely distributed to third parties alone or as 
part of a distribution containing other items provided that this license
is also included. 

2.2 The Loader may under no circumstances be branded as another product, 
whether distributed or not. 

2.3 Distribution as part of a commercial product is permitted provided such
distribution is in accordance with clauses 2.1 and 2.2 with respect to the 
Loader.


3 ANALYSIS / REVERSE ENGINEERING / MODIFICATION 

Except insofar as the user is permitted to do so in accordance with applicable
law:

3.1 Any analysis of the Loader and embedded data by any means and by
any entity whether human or otherwise and including but without limitation to
discover details of internal operation, to reverse engineer, to de-compile
object code, or to modify for the purposes of modifying behaviour is
forbidden.

3.2 Any analysis of encoded files by any means and by any entity whether human
or otherwise and including but without limitation to discover details of file
format or for the purposes of modifying behaviour or scope of their usage is
forbidden.


4 WARRANTY

THE LOADER SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
WARRANTIES INCLUDING BUT WITHOUT LIMITATION THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE ARE
DISCLAIMED. THE PROVIDER DOES NOT WARRANT THAT THE LOADER IS UNINTERRUPTED
OR ERROR FREE, NOR THAT THE OPERATION OF THE LOADER WILL FUNCTION IN
CONJUNCTION WITH ANY OTHER PRODUCT.  


5 LIMITATION OF LIABILITY 

5.1 IN NO EVENT WILL THE PROVIDER OF THE LOADER BE LIABLE TO THE USER OR ANY
PARTY FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR OTHER
CONSEQUENTIAL DAMAGES ARISING DIRECTLY OR INDIRECTLY FROM THIS LICENCE
AGREEMENT OR ANY USE OF THE LOADER OR ENCODED FILES, EVEN IF THE PROVIDER IS
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

5.2 THE LOADER IS PROVIDED ON AN "AS IS" BASIS.  THE PROVIDER EXCLUDES ALL
WARRANTIES, CONDITIONS, TERMS, UNDERTAKINGS AND REPRESENTATIONS (EXCLUDING
FRAUDULENT MISREPRESENTATION) OF ANY KIND, EXPRESS OR IMPLIED, STATUTORY OR
OTHERWISE IN CONNECTION WITH THE LOADER TO THE FULLEST EXTENT PERMITTED BY
LAW.

5.3 DOWNLOADING THE LOADER IS AT YOUR OWN RISK AND THE PROVIDER DOES NOT
ACCEPT LIABILITY FOR ANY DIRECT OR INDIRECT LOSS OR DAMAGE HOWSOEVER CAUSED AS
A RESULT OF ANY COMPUTER VIRUSES, BUGS, TROJAN HORSES, WORMS, SOFTWARE BOMBS
OR OTHER SIMILAR PROGRAMS ARISING FROM YOUR USE OF THE LOADER.  WHILST THE
PROVIDER WILL DO ITS BEST TO ENSURE THAT THE LOADER IS FREE FROM SUCH
DESTRUCTIVE PROGRAMS, IT IS YOUR RESPONSIBILITY TO TAKE REASONABLE PRECAUTIONS
TO SCAN FOR SUCH DESTRUCTIVE PROGRAMS DOWNLOADED FROM THE INTERNET.

5.4 THE PROVIDER'S MAXIMUM LIABILITY FOR ANY LOSS OR DAMAGE ARISING FROM THIS
LICENCE AGREEMENT SHALL IN ANY EVENT BE LIMITED IN THE SOLE DISCRETION OF THE
PROVIDER TO THE REPLACEMENT OF THE LOADER PRODUCT.

5.5 DUE TO THE NATURE OF THE INTERNET, THE PROVIDER CANNOT GUARANTEE THAT ANY
E-MAILS OR OTHER ELECTRONIC TRANSMISSIONS WILL BE SENT TO YOU OR RECEIVED BY
THE PROVIDER OR THAT THE CONTENT OF SUCH TRANSMISSIONS WILL BE SECURE DURING
TRANSMISSION.


6 BUG FIXING AND PRODUCT SUPPORT 

6.1 The provider will use reasonable endeavours to provide support to users.
The provider will at their discretion only provide support for the latest
release.

6.2 Support comprises of fault reporting via tickets and fault diagnosis,
recommendations on workarounds, and where reasonably possible a timely
resolution.

6.3 The user accepts that on occasion the ability of the provider to meet
anticipated or published support schedules may be impaired due to, but without
limitation, Internet service provider failures or software failures that
affect the ability to communicate for an indeterminate period.

6.4 The provider reserves the right to refuse to provide support at any time.

6.5 The provider wishes to maintain and offer a product of the highest
possible quality, and accordingly may from time to time and at its discretion
make product changes for the purpose of correcting behaviour in variance to
the published specification or the user's reasonable expectations. 

6.6 The provider reserves the right to charge for support where the user does
not have a valid support plan in place, or where the support offered exceeds
the scope of the active support plan.


7 PRODUCT UPGRADES

7.1 The provider may from time to time release product upgrades. These will
be provided free of charge and attempts made to provide a timely notification
to customers of the existence of any new release.


8 ERRORS AND OMISSIONS

Whilst reasonable endeavours are made to ensure the accuracy of documentation
concerning the details of the Loader, the user accepts the possibility of
inaccuracies in information presented in any format, including email
communications and online services. The provider shall under no circumstances
be liable for any events that arise as a result of unintentional inaccuracies
or omissions.


9 USER INDEMNITY

You agree to fully indemnify, defend and hold the provider harmless
immediately upon demand from and against all actions, liability, claims,
losses, damages, costs and expenses (including legal/attorney fees) incurred
by the provider arising directly or indirectly as a result of your breach of
this Licence Agreement.


10 INTELLECTUAL PROPERTY RIGHTS

10.1 The user acknowledges that the Loader and associated documentation and
materials contain proprietary information of the provider and are and shall
remain the exclusive property of the provider and/or its licensors and all
title, copyright, trade marks, trade names, patents and other intellectual
property rights therein of whatever nature shall remain the sole property of
the provider and/or its licensors.

10.2 No title to or rights of ownership, copyright or other intellectual
property in the Loader is transferred to the user (other than the licence
rights expressly granted in this Licence Agreement).


11 TERMINATION

11.1 The provider reserves the right to terminate this Licence Agreement
immediately by notice in writing against the user if the user is in breach of
any terms and conditions of this Licence Agreement.

11.2 Termination of this Licence Agreement for any reason shall be without
prejudice to any other rights or remedies of the provider which may have
arisen on or before the date of termination under this Licence Agreement or in
law.

11.3 The provisions of the following clauses shall survive any termination of
this agreement; clause 3, 5, 10 and 13.


12 GENERAL

12.1 The provider reserves the right to transfer or assign all or any of its
rights and duties and responsibilities set out in this Licence Agreement to
another party.

12.2 Headings have been included for convenience only and will not be used in
construing any provision of this Licence Agreement.

12.3 No delay or failure by the provider to exercise any powers, rights or
remedies under this Licence Agreement will operate as a waiver of them nor
will any single or partial exercise of any such powers, rights or remedies
include any other or further exercise of them.

12.4 If any part of this Licence Agreement is found by a court of competent
jurisdiction or other competent authority to be invalid, unlawful or
unenforceable then such part shall be severed from the remainder of this
Licence Agreement which will continue to be valid and enforceable to the
fullest extent permitted by applicable law.

12.5 This Licence Agreement including the documents or other sources referred
to herein supersede all prior representations, understandings and agreements
between the user and the provider relating to the Loader and sets forth the
entire agreement and understanding between the user and the provider relating
to the Loader.

12.6 Nothing in this Licence Agreement shall be deemed to constitute a
partnership between you and the provider nor constitute either party being an
agent of the other party.

12.7 This Agreement does not create any rights or benefits enforceable by any
person not a party to it (within the meaning of the U.K.Contracts (Rights of
Third Parties) Act 1999) except that a person who under clause 12.1 is a
permitted successor or assignee of the rights or benefits of the provider may
enforce such rights or benefits.


13 GOVERNING LAW AND JURISDICTION

This License Agreement and any issues relating thereto shall be construed and
interpreted in accordance with the laws of England and subject to the
exclusive jurisdiction of the English courts.

Copyright (c) 2002-2024 ionCube Ltd.          Last revised 23-April-2015
alt-php71-ioncube-loader/loader-wizard.php000064400000541746150475525500014455 0ustar00<?php // -*- c++ -*-

/** 
 * ionCube Loader install Wizard
 *
 * ionCube is a registered trademark of ionCube Ltd. 
 *
 * Copyright (c) ionCube Ltd. 2002-2022
 */


 

define ('ERROR_UNKNOWN_OS',1);
define ('ERROR_UNSUPPORTED_OS',2);
define ('ERROR_UNKNOWN_ARCH',3);
define ('ERROR_UNSUPPORTED_ARCH',4);
define ('ERROR_UNSUPPORTED_ARCH_OS',5);
define ('ERROR_WINDOWS_64_BIT',6);
define ('ERROR_PHP_UNSUPPORTED',7);
define ('ERROR_PHP_DEBUG_BUILD',8);
define ('ERROR_RUNTIME_EXT_DIR_NOT_FOUND',101);
define ('ERROR_RUNTIME_LOADER_FILE_NOT_FOUND',102);
define ('ERROR_INI_NOT_FIRST_ZE',201);
define ('ERROR_INI_WRONG_ZE_START',202);
define ('ERROR_INI_ZE_LINE_NOT_FOUND',203);
define ('ERROR_INI_LOADER_FILE_NOT_FOUND',204);
define ('ERROR_INI_NOT_FULL_PATH',205);
define ('ERROR_INI_NO_PATH',206);
define ('ERROR_INI_NOT_FOUND',207);
define ('ERROR_INI_NOT_READABLE',208);
define ('ERROR_INI_MULTIPLE_IC_LOADER_LINES',209);
define ('ERROR_INI_USER_INI_NOT_FOUND',210);
define ('ERROR_INI_USER_CANNOT_CREATE',211);
define ('ERROR_LOADER_UNEXPECTED_NAME',301);
define ('ERROR_LOADER_NOT_READABLE',302);
define ('ERROR_LOADER_PHP_MISMATCH',303);
define ('ERROR_LOADER_NONTS_PHP_TS',304);
define ('ERROR_LOADER_TS_PHP_NONTS',305);
define ('ERROR_LOADER_WRONG_OS',306);
define ('ERROR_LOADER_WRONG_ARCH',307);
define ('ERROR_LOADER_WRONG_GENERAL',308);
define ('ERROR_LOADER_WIN_SERVER_NONWIN',321);
define ('ERROR_LOADER_WIN_NONTS_PHP_TS',322);
define ('ERROR_LOADER_WIN_TS_PHP_NONTS',323);
define ('ERROR_LOADER_WIN_PHP_MISMATCH',324);
define ('ERROR_LOADER_WIN_COMPILER_MISMATCH',325);
define ('ERROR_LOADER_NOT_FOUND',380);
define ('ERROR_LOADER_PHP_VERSION_UNKNOWN',390);


define ('SERVER_UNKNOWN',0);
define ('HAS_PHP_INI',1);
define ('SERVER_SHARED',2); 
define ('SERVER_VPS',5); 
define ('SERVER_DEDICATED',7); 
define ('SERVER_LOCAL',9);

define ('IONCUBE_IP_ADDRESS',
			'94.101.154.134');
define  ('IONCUBE_ACCESS_ADDRESS',
			'lwaccess.ioncube.com');
define ('LOADERS_PAGE',
            'https://loaders.ioncube.com/'); 
define ('SUPPORT_SITE',
            'https://support.ioncube.com/');                                 
define ('WIZARD_SUPPORT_TICKET_DEPARTMENT',
			'3');
define ('LOADER_FORUM_URL',
            'https://forum.ioncube.com/viewforum.php?f=4');                  
define ('LOADERS_FAQ_URL',
            'https://www.ioncube.com/faqs/loaders.php');                     
define ('UNIX_ERRORS_URL',
            'https://www.ioncube.com/loaders/unix_startup_errors.php');      
define ('LOADER_WIZARD_URL',
            LOADERS_PAGE);                                                  
define ('ENCODER_URL',
            'https://www.ioncube.com/sa_encoder.php');                       
define ('LOADER_VERSION_URL',
            'https://www.ioncube.com/feeds/product_info/versions.php');    
define ('WIZARD_LATEST_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-wizard'); 
define ('PHP_COMPILERS_URL',
            LOADER_VERSION_URL . '?item=php-compilers');
define ('LOADER_PLATFORM_URL',
            LOADER_VERSION_URL . '?item=loader-platforms-all');   
define ('LOADER_LATEST_VERSIONS_URL',
            LOADER_VERSION_URL . '?item=loader-versions'); 
define ('LOADER_PHP_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-php-support'); 
define ('WIZARD_STATS_URL',
            'https://www.ioncube.com/feeds/stats/wizard.php');    
define ('IONCUBE_DOWNLOADS_SERVER',
            'https://downloads.ioncube.com/loader_downloads');          
define ('IONCUBE24_URL',
			'https://ioncube24.com');
define ('IONCUBE_CONNECT_TIMEOUT',4);

define ('DEFAULT_SELF','/ioncube/loader-wizard.php');
define ('LOADER_NAME_CHECK',true);
define ('LOADER_EXTENSION_NAME','ionCube Loader');
define ('LOADER_SUBDIR','ioncube');
define ('WINDOWS_IIS_LOADER_DIR', 'system32');
define ('ADDITIONAL_INI_FILE_NAME','00-ioncube.ini');
define ('UNIX_SYSTEM_LOADER_DIR','/usr/local/ioncube');
define ('RECENT_LOADER_VERSION','4.0.7');
define ('LATEST_LOADER_MAJOR_VERSION',12);
define ('LOADERS_PACKAGE_PREFIX','ioncube_loaders_');
define ('SESSION_LIFETIME_MINUTES',360);
define ('WIZARD_EXPIRY_MINUTES',2880);
define ('IONCUBE_WIZARD_EXPIRY_MINUTES',10080);
define ('MIN_INITIALISE_TIME',4);
define ('IC24_ENABLED_INI_PROPERTY',"ic24.enable");

    run();


function php4_http_build_query($formdata, $numeric_prefix = null, $key = null ) {
    $res = array();
    foreach ((array)$formdata as $k=>$v) {
        $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
        if ($key) $tmp_key = $key.'['.$tmp_key.']';
        if ( is_array($v) || is_object($v) ) {
            $res[] = php4_http_build_query($v, null , $tmp_key);
        } else {
            $res[] = $tmp_key."=".urlencode($v);
        }
   }
   $separator = ini_get('arg_separator.output');
   return implode($separator, $res);
}


function script_version()
{
    return "2.73";
}

function retrieve_latest_wizard_version()
{
    $v = false;

    $s = trim(remote_file_contents(WIZARD_LATEST_VERSION_URL));
    if (preg_match('/^\d+([.]\d+)*$/', $s)) {
        $v = $s;
    }

    return $v;
}

function latest_wizard_version()
{
    if (!isset($_SESSION['latest_wizard_version'])) {
        $_SESSION['latest_wizard_version'] = retrieve_latest_wizard_version();
    } 
    return $_SESSION['latest_wizard_version'];
}

function update_is_available($lv)
{
    if (is_numeric($lv)) {
        $lv_parts = explode('.',$lv);
        $script_parts = explode('.',script_version());
        return ($lv_parts[0] > $script_parts[0] || ($lv_parts[0] == $script_parts[0] && $lv_parts[1] > $script_parts[1]));
    } else {
        return null;
    }
}

function check_for_wizard_update($echo_message = false)
{
    $latest_version = latest_wizard_version();
    $update_available = update_is_available($latest_version);

    if ($update_available) {
        if ($echo_message) {
            echo '<p class="alert">An updated version of this Wizard script is available <a href="' . LOADER_WIZARD_URL . '">here</a>.</p>';
        }
        return $latest_version;
    } else {
        return $update_available;
    }
}


function remote_file_contents($url)
{
    $remote_file_opening = ini_get('allow_url_fopen');
    $contents = false;
    if (isset($_SESSION['timing_out']) && $_SESSION['timing_out']) {
        return false;
    }
    @session_write_close();
    $timing_out = 0;
    if ($remote_file_opening) {
        $fh = @fopen($url,'rb');
        if ($fh) {
            stream_set_blocking($fh,0);
            stream_set_timeout($fh,IONCUBE_CONNECT_TIMEOUT);
            while (!feof($fh)) {
                $result = fread($fh, 8192);
                $info = stream_get_meta_data($fh);
                $timing_out = $info['timed_out']?1:0;
                if ($timing_out) {
                    break;
                }
                if ($result !== false) {
                    $contents .= $result;
                } else {
                    break;
                }
            }
            fclose($fh);
        } else {
            $timing_out = 1;
        }
    } elseif (extension_loaded('curl')) {
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,IONCUBE_CONNECT_TIMEOUT);
            $output = curl_exec($ch);
            $info = curl_getinfo($ch);
            $timing_out = ($info['http_code'] >= 400)?1:0;
            curl_close($ch);

            if (is_string($output)) {
                $contents = $output;
            }
    } else {
        $timing_out = 1;
    }
    @session_start();
    $_SESSION['timing_out'] = $timing_out;
    return $contents;
}

function php_version()
{
    $v = explode('.',PHP_VERSION);

    return array(
           'major'      =>  $v[0],
           'minor'      =>  $v[1],
           'release'    =>  $v[2]);
}

function php_version_maj_min()
{
    $vprts = php_version();
    return ($vprts['major'] . '.' . $vprts['minor']);
}

function is_supported_php_version()
{
    $v = php_version(); 

    return ((($v['major'] == 4) && ($v['minor'] >= 1)) ||
      (($v['major'] == 5) && (($v['minor'] >= 1) || ($v['release'] >= 3))) ||
	  $v['major'] == 7 || ($v['major'] == 8 && $v['minor'] >= 1));
}

function is_php_version_or_greater($major,$minor,$release = 0)
{
    $version = php_version();
    return ($version['major'] > $major || 
            ($version['major'] == $major && $version['minor'] > $minor) ||
            ($version['major'] == $major && $version['minor'] == $minor && $version['release'] >= $release));
}

function ini_file_name()
{
    $sysinfo = get_sysinfo();
    return (!empty($sysinfo['PHP_INI'])?$sysinfo['PHP_INI_BASENAME']:'php.ini');
}

function get_remote_session_value($session_var,$remote_url,$default_function)
{
    if (!isset($_SESSION[$session_var])) {
        $serialised_res = remote_file_contents($remote_url);
        $unserialised_res = @unserialize($serialised_res);
        if (empty($unserialised_res)) {
            $unserialised_res = call_user_func($default_function);
        } else {
			$_SESSION['remote_access_successful'] = 1;
		}
        if (false === $unserialised_res) {
            $unserialised_res = '';
        }
        $_SESSION[$session_var] = $unserialised_res;
    }
    return $_SESSION[$session_var];
}

function get_file_contents($file)
{
    if (function_exists('file_get_contents')) {
        $strs = @file_get_contents($file);
    } else {
        $lines = @file($file);
        $strs = join(' ',$lines);
    }
    return $strs;
}

function default_platform_list()
{
    $platforms = array();


    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6', 'is_legacy' => 1,       'os_mod' => '_vc6',     'arch'=>'x86',  'dirname'=>'win32', 'us1-dir'=>'windows_vc6/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6 (Non-TS)',   'is_legacy' => 1,  'os_mod' => '_nonts_vc6',   'arch'=>'x86',  'dirname'=>'win32-nonts', 'us1-dir'=>'windows_vc6/x86-nonts' );

    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9',        'os_mod' => '_vc9',     'arch'=>'x86',  'dirname'=>'win32_vc9', 'us1-dir'=>'windows_vc9/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9 (Non-TS)',   'os_mod' => '_nonts_vc9',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc9', 'us1-dir'=>'windows_vc9/x86-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86',  'dirname'=>'win32_vc11', 'us1-dir'=>'windows_vc11/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc11', 'us1-dir'=>'windows_vc11/x86-nonts' );
	
	$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86-64',  'dirname'=>'win64_vc11', 'us1-dir'=>'windows_vc11/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc11', 'us1-dir'=>'windows_vc11/amd64-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86',  'dirname'=>'win32_vc14', 'us1-dir'=>'windows_vc14/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc14', 'us1-dir'=>'windows_vc14/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86-64',  'dirname'=>'win64_vc14', 'us1-dir'=>'windows_vc14/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc14', 'us1-dir'=>'windows_vc14/amd64-nonts' );
	
		 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86',  'dirname'=>'win32_vc15', 'us1-dir'=>'windows_vc15/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc15', 'us1-dir'=>'windows_vc15/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86-64',  'dirname'=>'win64_vc15', 'us1-dir'=>'windows_vc15/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc15', 'us1-dir'=>'windows_vc15/amd64-nonts' );

    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86',      'dirname'=>'linux_i686-glibc2.3.4', 'us1-dir'=>'linux/x86');
    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86-64',   'dirname'=>'linux_x86_64-glibc2.3.4', 'us1-dir'=>'linux/x86_64');
$platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc',      'dirname'=>'linux_ppc-glibc2.3.4','us1-dir'=>'linux/ppc');
            $platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc64',    'dirname'=>'linux_ppc64-glibc2.5','us1-dir'=>'linux/ppc64');
    

$platforms[] = array('os'=>'dra', 'os_human'=>'DragonFly', 'arch'=>'x86',      'dirname'=>'dragonfly_i386-1.7', 'us1-dir'=>'Dragonfly/x86');

$platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 4', 'os_mod'=>'_4',  'arch'=>'x86',      'dirname'=>'freebsd_i386-4.8', 'us1-dir'=>'FreeBSD/v4');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86',      'dirname'=>'freebsd_i386-6.2', 'us1-dir'=>'FreeBSD/v6/x86');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-6.2', 'us1-dir'=>'FreeBSD/v6/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86',      'dirname'=>'freebsd_i386-7.3', 'us1-dir'=>'FreeBSD/v7/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-7.3', 'us1-dir'=>'FreeBSD/v7/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86',      'dirname'=>'freebsd_i386-8.0', 'us1-dir'=>'FreeBSD/v8/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-8.0', 'us1-dir'=>'FreeBSD/v8/AMD64');
    
    $platforms[] = array('os'=>'bsd', 'os_human'=>'BSDi',     'is_legacy' => 1,           'arch'=>'x86',      'dirname'=>'bsdi_i386-4.3.1');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86',      'dirname'=>'netbsd_i386-2.1','us1-dir'=>'NetBSD/x86');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86-64',   'dirname'=>'netbsd_amd64-2.0','us1-dir'=>'NetBSD/x86_64');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.2', 'os_mod'=>'_4.2',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.2', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.5', 'os_mod'=>'_4.5',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.5', 'us1-dir'=>'OpenBSD/x86');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.6', 'os_mod'=>'_4.6',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.6', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.7', 'os_mod'=>'_4.7',  'arch'=>'x86-64', 'dirname'=>'openbsd_amd64-4.7', 'us1-dir' => 'OpenBSD/x86_64');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',    'is_legacy' => 1, 'arch'=>'ppc',      'dirname'=>'osx_powerpc-8.5','us1-dir'=>'OSX/ppc');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86',      'dirname'=>'osx_i386-8.11','us1-dir'=>'OSX/x86');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86-64',       'dirname'=>'osx_x86-64-10.2','us1-dir'=>'OSX/x86_64');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',  'is_legacy' => 1,          'arch'=>'sparc',    'dirname'=>'solaris_sparc-5.9', 'us1-dir'=>'Solaris/sparc');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',            'arch'=>'x86',      'dirname'=>'solaris_i386-5.10','us1-dir'=>'Solaris/x86');

    return $platforms;
}

function get_loader_platforms()
{
    return get_remote_session_value('loader_platform_info',LOADER_PLATFORM_URL,'default_platform_list');
}

function get_platforminfo()
{
    static $platforminfo;

    if (empty($platforminfo)) {
        $platforminfo = get_loader_platforms();
    }
    return $platforminfo;
}

function default_php_versions()
{
	return array();
}

function get_php_versions()
{
	return get_remote_session_value('php_version_info',LOADER_PHP_VERSION_URL,'default_php_versions');
}


function get_max_php_version_supported()
{
	static $max_php_version;
	
	if (empty($max_php_version)) {
		$php_versions = get_php_versions();
		
		$dirname = calc_dirname();
		
		if (array_key_exists($dirname,$php_versions)) {
			$max_php_version = $php_versions[$dirname];
		} else {
			$max_php_version = NULL;
		}
	}
	
	return $max_php_version;
}

function is_after_max_php_version_supported()
{
	$is_too_recent_php = false;
	
	$supported_php_version = get_max_php_version_supported();
	
	if (!is_null($supported_php_version)) {
		$pversion = php_version();
		
		$supported_parts = explode('.',$supported_php_version);
		$is_too_recent_php = ($supported_parts[0] < $pversion['major'] || ($supported_parts[0] == $pversion['major'] && $supported_parts[1] < $pversion['minor']));
	}
	
	if ($is_too_recent_php) {
		return $supported_php_version;
	} else {
		return false;
	}
}

function supported_os_variants($os_code,$arch_code)
{
    if (empty($os_code)) {
        return ERROR_UNKNOWN_OS;
    }
    if (empty($arch_code)) {
        return ERROR_UNKNOWN_ARCH;
    }

    $os_found = false;
    $arch_found = false;
    $os_arch_matches = array();
    $pinfo = get_platforminfo();

    foreach ($pinfo as $p) {
        if ($p['os'] == $os_code && $p['arch'] == $arch_code) {
            $os_arch_matches[$p['os_human']] = (isset($p['os_mod']))?(0 + (int) str_replace('_','',$p['os_mod'])):'';
        } 
        if ($p['os'] == $os_code) {
            $os_found = true;
        } elseif ($p['arch'] == $arch_code) {
            $arch_found = true;
        }
    }
    if (!empty($os_arch_matches)) {
        asort($os_arch_matches);
        return $os_arch_matches;
    } elseif (!$os_found) {
        return ERROR_UNSUPPORTED_OS;
    } elseif (!$arch_found) {
        return ERROR_UNSUPPORTED_ARCH;
    } else {
        return ERROR_UNSUPPORTED_ARCH_OS;
    }
}

function default_win_compilers()
{
    return array('VC6','VC9','VC11','VC14','VC15', 'VC16');
}

function supported_win_compilers()
{
    static $win_compilers;

    if (empty($win_compilers)) {
        $win_compilers = find_win_compilers();
    }
    return $win_compilers;
}

function find_win_compilers()
{
    return get_remote_session_value('php_compilers_info',PHP_COMPILERS_URL,'default_win_compilers');
}

function server_software_info()
{
    $ss = array('full' => '','short' => '');
    $ss['full'] = $_SERVER['SERVER_SOFTWARE'];

    if (preg_match('/apache/i', $ss['full'])) {
        $ss['short'] = 'Apache';
    } else if (preg_match('/IIS/',$ss['full'])) {
        $ss['short'] = 'IIS';
    } else {
        $ss['short'] = '';
    }
    return $ss;
}

function match_arch_pattern($str)
{
    $arch = null;
    $arch_patterns = array(
             'i.?86'        => 'x86',
             'x86[-_]64'    => 'x86',
             'x86'          => 'x86',
             'amd64'        => 'x86',
             'SMP Tue Jan 01 00:00:00 CEST 2000 all GNU\/Linux' => 'x86',
             'ppc64'        => 'ppc',
             'ppc'          => 'ppc',
             'powerpc'      => 'ppc',
             'sparc'        => 'sparc',
             'sun'          => 'sparc',
			 'armv7l'       => 'armv7l',
             'aarch64'      => 'aarch64'
         );

    foreach ($arch_patterns as $token => $a) {
        if (preg_match("/$token/i", $str)) {
          $arch = $a;
          break;
        }
    }
    return $arch;
}

function required_loader_arch($mach_info,$os_code,$wordsize)
{
    if ($os_code == 'win') {
        $arch = ($wordsize == 32)?'x86':'x86-64';
    } elseif (!empty($os_code)) {
        $arch = match_arch_pattern($mach_info);
        if ($wordsize == 64) {
            if ($arch == 'x86') {
                $arch = 'x86-64';
            } elseif ($arch == 'ppc') {
                $arch = 'ppc64';
            }
        }
    } else {
        $arch = ERROR_UNKNOWN_ARCH;
    }
    return $arch;
}

function uname($part = 'a')
{
    $result = '';
    if (!function_is_disabled('php_uname')) {
        $result = @php_uname($part);
    } elseif (function_exists('posix_uname') && !function_is_disabled('posix_uname')) {
        $posix_equivs = array(
                     'm' => 'machine',
                     'n' => 'nodename',
                     'r' => 'release',
                     's' => 'sysname'
                 );
        $puname = @posix_uname();
        if ($part == 'a' || !array_key_exists($part,$posix_equivs)) {
           $result = join(' ',$puname);
        } else {
           $result = $puname[$posix_equivs[$part]];
        }
    } else {
        if (!function_is_disabled('phpinfo')) {
            ob_start();
            phpinfo(INFO_GENERAL);
            $pinfo = ob_get_contents();
            ob_end_clean();
            if (preg_match('~System.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$match)) {
                $uname = $match[2];
                if ($part == 'r') {
                    if (!empty($uname) && preg_match('/\S+\s+\S+\s+([0-9.]+)/',$uname,$matchver)) {
                        $result = $matchver[1];
                    } else {
                        $result = '';
                    }
                } else {
                    $result = $uname;
                }
            }
        } else {
            $result = '';
        }
    }
    return $result;
}

function calc_word_size($os_code)
{
    $wordsize = null;
    if ('win' === $os_code) {
        ob_start();
        phpinfo(INFO_GENERAL);
        $pinfo = ob_get_contents();
        ob_end_clean();
        if (preg_match('~Compiler.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$compmatch)) {
            if (preg_match("/(VC[0-9]+)/i",$compmatch[2],$vcmatch)) {
                $compiler = strtoupper($vcmatch[1]);
            } elseif (stripos(trim($compmatch[2]),"Visual C++ 2019") === 0) {
                $compiler = 'VC16';
            } else {
                $compiler = 'VC6';
            }
        } else {
            $compiler = 'VC6';
        }
        if ($compiler === 'VC9' || $compiler === 'VC11' || $compiler === 'VC14' 
                || $compiler === 'VC15' || $compiler === 'VC16') {
			if (preg_match('~Architecture.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$archmatch)) {
				if (preg_match("/x64/i",$archmatch[2])) {
					$wordsize = 64;
				} else {
					$wordsize = 32;
				}
            } elseif (isset($_ENV['PROCESSOR_ARCHITECTURE']) && preg_match('~(amd64|x86-64|x86_64)~i',$_ENV['PROCESSOR_ARCHITECTURE'])) {
                if (preg_match('~Configure Command.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$confmatch)) {
                    if (preg_match('~(x64|lib64|system64)~i',$confmatch[2])) {
                        $wordsize = 64;
                    }
                }
            } else {
				$wordsize = 32;
			}
        }
    }
    if (empty($wordsize)) {
        $wordsize = ((-1^0xffffffff)?64:32);
    }
    return $wordsize;
}

function required_loader($unamestr = '')
{
    $un = empty($unamestr)?uname():$unamestr;

    $php_major_version = substr(PHP_VERSION,0,3);

    $os_name = substr($un,0,strpos($un,' '));
    $os_code = empty($os_name)?'':strtolower(substr($os_name,0,3));

    $wordsize = calc_word_size($os_code);

	if ($os_code == 'win' && $wordsize == 64 && $php_major_version < '5.5') {
        $arch = ERROR_WINDOWS_64_BIT;
	} else {
		$arch = required_loader_arch($un,$os_code,$wordsize);
	}
    if (!is_string($arch)) {
        return $arch;
    }
    $os_variants = supported_os_variants($os_code,$arch);
    if (!is_array($os_variants)) {
        return $os_variants;
    }

    $os_ver = '';
    if (preg_match('/([0-9.]+)/',uname('r'),$match)) {
        $os_ver = $match[1];
    }
    $os_ver_parts = preg_split('@\.@',$os_ver);

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $loader_sfix = (($os_code == 'win') ? 'dll' : 'so');
    $file = "ioncube_loader_{$os_code_h}_{$php_major_version}.{$loader_sfix}";

    if ($os_code == 'win') {
        $os_name = 'Windows';
        $file_ts = $file;
        $os_name_qual = 'Windows';
    } else {
        $os_names = array_keys($os_variants);
        if (count($os_variants) > 1) {
            $parts = explode(" ",$os_names[0]); 
            $os_name = $parts[0];
            $os_name_qual = $os_name . ' ' . $os_ver_parts[0] . '.' . $os_ver_parts[1];
        } else {
            $os_name = $os_names[0];
            $os_name_qual = $os_name;
        }
        $file_ts = "ioncube_loader_{$os_code_h}_{$php_major_version}_ts.{$loader_sfix}";
    }

    return array(
           'uname'      =>  $un,
           'arch'       =>  $arch,
           'oscode'     =>  $os_code,
           'oscode_h'   =>  $os_code_h,
           'osname'     =>  $os_name,
           'osnamequal' =>  $os_name_qual,
           'osvariants' =>  $os_variants,
           'osver'      =>  $os_ver,
           'osver2'     =>  $os_ver_parts,
           'file'       =>  $file,
           'file_ts'    =>  $file_ts,
           'wordsize'   =>  $wordsize
       );
}

function ic_system_info()
{
    $thread_safe = null;
    $debug_build = null;
    $cgi_cli = false;
	$is_fpm = false;
    $is_cgi = false;
    $is_cli = false;
    $php_ini_path = '';
    $php_ini_dir = '';
    $php_ini_add = '';
    $is_supported_compiler = true;
    $php_compiler = is_ms_windows()?'VC6':'';

    ob_start();
    phpinfo(INFO_GENERAL);
    $php_info = ob_get_contents();
    ob_end_clean();

    $breaker = (php_sapi_name() == 'cli')?"\n":'</tr>';
    $lines = explode($breaker,$php_info);
    foreach ($lines as $line) {
        if (preg_match('/command/i',$line)) {
          continue;
        }

        if (preg_match('/thread safety/i', $line)) {
          $thread_safe = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('/debug build/i', $line)) {
          $debug_build = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('~configuration file.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
          $php_ini_path = $match[2];

          if (!@file_exists($php_ini_path)) {
                $php_ini_path = '';
          }
        }
        if (preg_match('~dir for additional \.ini files.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_dir = $match[2];
            if (!@file_exists($php_ini_dir)) {
                $php_ini_dir = '';
            }
        }
        if (preg_match('~additional \.ini files parsed.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_add = $match[2];
        }
        if (preg_match('/compiler/i',$line)) {
            $supported_match = join('|',supported_win_compilers());
            $is_supported_compiler = preg_match("/($supported_match)/i",$line);
            if (preg_match("/(VC[0-9]+)/i",$line,$match)) {
                $php_compiler = strtoupper($match[1]);
            } elseif (preg_match("/Visual C\+\+ 2017/i",$line)) {
				$php_compiler = "VC15";
				$is_supported_compiler = true;
            } elseif (preg_match("/Visual C\+\+ 2019/i",$line)) {
				$php_compiler = "VC16";
				$is_supported_compiler = true;
			} else {
                $php_compiler = '';
            }
        }
    }
    $is_cgi = strpos(php_sapi_name(),'cgi') !== false;
    $is_cli = strpos(php_sapi_name(),'cli') !== false;
	$is_fpm = strpos(php_sapi_name(),'fpm-fcgi') !== false;
    $cgi_cli = $is_cgi || $is_cli;

    $ss = server_software_info();
	
	if ($is_fpm) {
		$ss['short'] = 'PHP-FPM';
		$ss['full'] = 'PHP-FPM ' . $ss['full'];
	}

    if (!$php_ini_path && function_exists('php_ini_loaded_file')) {
        $php_ini_path = php_ini_loaded_file();
        if ($php_ini_path === false) {
            $php_ini_path = '';
        }
    }
    if (!empty($php_ini_path)) {
        $real_path = @realpath($php_ini_path);
        if (false !== $real_path) {
            $php_ini_path = $real_path;
        }
    }

    $php_ini_basename = basename($php_ini_path);

    return array(
           'THREAD_SAFE'        => $thread_safe,
           'DEBUG_BUILD'        => $debug_build,
           'PHP_INI'            => $php_ini_path,
           'PHP_INI_BASENAME'   => $php_ini_basename,
           'PHP_INI_DIR'        => $php_ini_dir,
           'PHP_INI_ADDITIONAL' => $php_ini_add,
           'PHPRC'              => getenv('PHPRC'),
           'CGI_CLI'            => $cgi_cli,
           'IS_CGI'             => $is_cgi,
           'IS_CLI'             => $is_cli,
		   'IS_FPM'				=> $is_fpm,
           'PHP_COMPILER'       => $php_compiler,
           'SUPPORTED_COMPILER' => $is_supported_compiler,
           'FULL_SS'            => $ss['full'],
           'SS'                 => $ss['short']);
}

function is_possibly_dedicated_or_local()
{
    $sys = get_sysinfo();

    return (empty($sys['PHP_INI']) || !@file_exists($sys['PHP_INI']) || (is_readable($sys['PHP_INI']) && (0 !== strpos($sys['PHP_INI'],$_SERVER['DOCUMENT_ROOT']))));
}

function is_local()
{
    $ret = false;
    if ($_SERVER["SERVER_NAME"] == 'localhost') {
        $ret = true;
    } else {
        $ip_address = strtolower($_SERVER["REMOTE_ADDR"]);
        if (strpos(':',$ip_address) === false) {
            $ip_parts = explode('.',$ip_address);
            $ret = (($ip_parts[0] == 10) || 
                    ($ip_parts[0] == 172 && $ip_parts[1] >= 16 &&  $ip_parts[1] <= 31) ||
                    ($ip_parts[0] == 192 && $ip_parts[1] == 168));
        } else {
            $ret = ($ip_address == '::1') || (($ip_address[0] == 'f') && ($ip_address[1] >= 'c' && $ip_address[1] <= 'f'));
        }
    }
    return $ret;
}

function is_shared()
{
    return !is_local() && !is_possibly_dedicated_or_local();
}

function find_server_type($chosen_type = '',$type_must_be_chosen = false,$set_session = false)
{
    $server_type = SERVER_UNKNOWN;
    if (empty($chosen_type)) {
        if ($type_must_be_chosen) {
            $server_type = SERVER_UNKNOWN;
        } else {
            if (isset($_SESSION['server_type']) && $_SESSION['server_type'] != SERVER_UNKNOWN) {
                $server_type = $_SESSION['server_type'];
            } elseif (is_local()) {
                $server_type = SERVER_LOCAL;
            } elseif (!is_possibly_dedicated_or_local()) {
                $server_type = SERVER_SHARED;
            } else {
                $server_type = SERVER_UNKNOWN;
            } 
        }
    } else {
        switch ($chosen_type)  {
            case 's':
                $server_type = SERVER_SHARED;
                break;
            case 'd':
                $server_type = SERVER_DEDICATED;
                break;
            case 'l':
                $server_type = SERVER_LOCAL;
                break;
            default:
                $server_type = SERVER_UNKNOWN;
                break;
        }
    }
    if ($set_session) {
        $_SESSION['server_type'] = $server_type;
    }
    return $server_type;
}

function server_type_string()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_string = 'SHARED';
            break;
        case SERVER_LOCAL:
            $server_string = 'LOCAL';
            break;
        case SERVER_DEDICATED:
            $server_string = 'DEDICATED';
            break;
        default:
            $server_string = 'UNKNOWN';
            break;
    }
    return $server_string;
}

function server_type_code()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_char = 's';
            break;
        case SERVER_LOCAL:
            $server_char = 'l';
            break;
        case SERVER_DEDICATED:
            $server_char = 'd';
            break;
        default:
            $server_char = '';
            break;
    }
    return $server_char;
}

function get_sysinfo()
{
    static $sysinfo;

    if (empty($sysinfo)) {
        $sysinfo = ic_system_info();
    }
    return $sysinfo;
}

function get_loaderinfo()
{
    static $loader;

    if (empty($loader)) {
        $loader = required_loader();
    }
    return $loader;
}

function is_ms_windows()
{
    $loader_info = get_loaderinfo();
    return ($loader_info['oscode'] == 'win');
}

function function_is_disabled($fn_name)
{
    $disabled_functions=explode(',',ini_get('disable_functions'));
    return in_array($fn_name, $disabled_functions);
}

function selinux_is_enabled()
{
    $se_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('sestatus');
        $se_enabled = preg_match('/enabled/i',$cmd);
    }

    return $se_enabled;
}

function grsecurity_is_enabled()
{
    $gr_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('gradm -S');
        $gr_enabled = preg_match('/enabled/i',$cmd);
    }

    return $gr_enabled;
}

function threaded_and_not_cgi()
{
    $sys = get_sysinfo();
    return($sys['THREAD_SAFE'] && !$sys['IS_CGI']);
}

function is_restricted_server($only_safe_mode = false)
{
    $disable_functions = ini_get('disable_functions');
    $open_basedir = ini_get('open_basedir');
    $php_restrictions = !empty($disable_functions) || !empty($open_basedir);
    $system_restrictions = selinux_is_enabled() || grsecurity_is_enabled();
    $non_safe_mode_restrictions = $php_restrictions || $system_restrictions;
    return (ini_get('safe_mode') || (!$only_safe_mode && $non_safe_mode_restrictions));
}

function server_restriction_warnings()
{
    $warnings = array();

    if (find_server_type() == SERVER_SHARED) {
        if (is_restricted_server()) {
            $warnings[] = "Server restrictions are in place which might affect the operation of this Loader Wizard or prevent the installation of the Loader.";
        }
    } else {
        $warning_suffix = "This may affect the operation of this Loader Wizard.";
        if (ini_get('safe_mode')) {
            $warnings[] = "Safe mode is in effect on the server. " . $warning_suffix;
        } 
        $disabled_functions = ini_get('disable_functions');
        if (!empty($disabled_functions)) {
            $warnings[] = "Some functions are disabled through disable_functions. " . $warning_suffix;
        }
        $open_basedir = ini_get('open_basedir');
        if (!empty($open_basedir)) {
            $warnings[] = "Open basedir restrictions are in effect. " . $warning_suffix;
        }
    }
    return $warnings;
}

function own_php_ini_possible($only_safe_mode = false)
{
    $sysinfo = get_sysinfo();
    return ($sysinfo['CGI_CLI'] && !is_ms_windows() && !is_restricted_server($only_safe_mode));
}

function extension_dir()
{
    $extdir = ini_get('extension_dir');
    if ($extdir == './' || ($extdir == '.\\' && is_ms_windows())) {
        $extdir = '.';
    }
    return $extdir;
}

function possibly_selinux()
{
    $loaderinfo = get_loaderinfo();
    $se_env = (getenv("SELINUX_INIT"));
    return (strtolower($loaderinfo['osname']) == 'linux' && $se_env && ($se_env == 'Yes' || $se_env == '1'));
}

function ini_same_dir_as_wizard()
{
    $sys = get_sysinfo();
    return dirname($sys['PHP_INI']) == dirname(__FILE__); 
}

function extension_dir_path()
{
    $ext_dir = extension_dir();
    if ($ext_dir == '.' || (dirname($ext_dir) == '.')) {
        $ext_dir_path = @realpath($ext_dir);
    } else {
        $ext_dir_path = $ext_dir;
    }
    return $ext_dir_path;
}

function get_loader_name()
{
    $u = uname();
    $sys = get_sysinfo();
    $os = substr($u,0,strpos($u,' '));
    $os_code = strtolower(substr($u,0,3));

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $php_version = phpversion();
    $php_family = substr($php_version,0,3);

    $loader_sfix = (($os_code == 'win') ? '.dll' : (($sys['THREAD_SAFE'])?'_ts.so':'.so'));
    $loader_name="ioncube_loader_{$os_code_h}_{$php_family}{$loader_sfix}";

    return $loader_name;
}

function get_reqd_version($variants)
{
    $exact_match = false;
    $nearest_version = 0;
    $loader_info = get_loaderinfo();
    $os_version = $loader_info['osver2'][0] . '.' . $loader_info['osver2'][1];
    $os_version_major = $loader_info['osver2'][0];
    foreach ($variants as $v) {
        if ($v == $os_version || (is_int($v) && $v == $os_version_major)) {
            $exact_match = true;
            $nearest_version = $v;
            break;
        } elseif ($v > $os_version) {
            break;
        } else {
            $nearest_version = $v;
        }
    }
    return (array($nearest_version,$exact_match));
}

function get_default_loader_dir_webspace()
{
    return ($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . LOADER_SUBDIR);
}

function get_loader_location($loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = get_default_loader_dir_webspace();
    }
    $loader_name = get_loader_name(); 
    return ($loader_dir . DIRECTORY_SEPARATOR . $loader_name);
}

function get_loader_location_from_ini($php_ini = '')
{
    $errors = array();
    if (empty($php_ini)) {
        $sysinfo = get_sysinfo();
        $php_ini = $sysinfo['PHP_INI'];
    }
    if (!@file_exists($php_ini)) {
        if (empty($php_ini)) {
            $errors[ERROR_INI_NOT_FOUND] = "The configuration file could not be found.";
        } else {
            $errors[ERROR_INI_NOT_FOUND] = "The $php_ini file could not be found.";
        }
    } elseif (!is_readable($php_ini)) {
        $errors[ERROR_INI_NOT_READABLE] = "The $php_ini file could not be read.";
    }
    if (!empty($errors)) {
        return array('location' => '', 'errors' => $errors);
    } 
    $lines = file($php_ini);
    $ext_start = zend_extension_line_start();
    $wrong_ext_start = ($ext_start == 'zend_extension')?'zend_extension_ts':'zend_extension';
    $loader_path = '';
    $loader_name_match = "ioncube_loader";
    foreach ($lines as $l) {
        if (preg_match("/^\s*$ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$corr_matches)) {
            if (preg_match("/$loader_name_match/i",$corr_matches[1])) {
                if (!empty($loader_path)) {
                    $errors[ERROR_INI_MULTIPLE_IC_LOADER_LINES] = "It appears that multiple $ext_start lines for the ionCube Loader have been included in the configuration file, $php_ini.";
                }
                $loader_path = $corr_matches[1];
            } else {
                if (empty($loader_path)) {
                    $errors[ERROR_INI_NOT_FIRST_ZE] = "The ionCube Loader must be the first Zend extension listed in the configuration file, $php_ini.";
                }
            }
        }
        if (empty($loader_path)) {
            if (preg_match("/^\s*$wrong_ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$bad_start_matches)) {
                if (preg_match("/$loader_name_match/i",$bad_start_matches[1])) {
                    $bad_zend_ext_msg = "The line for the ionCube Loader in the configuration file, $php_ini, should start with $ext_start and <b>not</b> $wrong_ext_start.";
                    $errors[ERROR_INI_WRONG_ZE_START] = $bad_zend_ext_msg;
                    $loader_path = $bad_start_matches[1];
                }
            }
        }
    }
    $loader_path = trim($loader_path);
    if ($loader_path === '') {
        $errors[ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration file, $php_ini.";
    } elseif (!@file_exists($loader_path)) {
        $errors[ERROR_INI_LOADER_FILE_NOT_FOUND] = "The loader file  $loader_path, listed in the configuration file, $php_ini, does not exist or is not accessible.";
    } elseif (basename($loader_path) == $loader_path) {
        $errors[ERROR_INI_NOT_FULL_PATH] = "A full path must be specified for the loader file in the configuration file, $php_ini.";
    }
    return array('location' => $loader_path, 'errors' => $errors);
}

function zend_extension_line_missing($ini_path)
{
    $loader_loc = get_loader_location_from_ini($ini_path);
    return (!empty($loader_loc['errors']) && array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$loader_loc['errors']));
}

function find_additional_ioncube_ini()
{
    $sys = get_sysinfo();
    $ioncube_ini = '';

    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
        foreach ($ini_files as $f) {
            $fn = trim($f);
            $bfn = basename($fn);
            if (preg_match('/ioncube/i',$bfn)) {
                $ioncube_ini = $fn;
                break;
            }
        }
    }
    return $ioncube_ini;
}

function get_additional_ini_files()
{
    $sys = get_sysinfo();
    $ini_files = array();
    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
    }
    return (array_map('trim',$ini_files));
}

function all_ini_contents()
{
    $sys = get_sysinfo();
    $output = '';

    $output .= ";;; *MAIN INI FILE AT ${sys['PHP_INI']}* ;;;" . PHP_EOL;
    $output .= get_file_contents($sys['PHP_INI']);
    $other_inis = get_additional_ini_files();
    foreach ($other_inis as $inif) {
        $output .= ";;; *Additional ini file at $inif* ;;;" . PHP_EOL;
        $output .= get_file_contents($inif);
    }
    $here = unix_path_dir();
    $unrec_ini_files = unrecognised_inis_webspace($here);
    foreach ($unrec_ini_files as $urinif) {
        $output .= ";;; *UNRECOGNISED INI FILE at $urinif* ;;;" . PHP_EOL;
        $output .= get_file_contents($urinif);
    }
    return $output;
}

function scan_inis_for_loader()
{
    $ldloc = array('location' => '', 'errors' => array());
    $sysinfo = get_sysinfo();
    if (empty($sysinfo['PHP_INI'])) {
        $ini_files_not_found = array("Main ini file");
        $ini_file_list = get_additional_ini_files();
    } else {
        $ini_files_not_found = array();
        $ini_file_list = array_merge(array($sysinfo['PHP_INI']),get_additional_ini_files());
    }
    $server_type = find_server_type();
    $shared_server = SERVER_SHARED == $server_type;
    foreach ($ini_file_list as $f) {
        $ldloc = get_loader_location_from_ini($f);
        if (array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$ldloc['errors'])) {
            unset($ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND]);
        } 
        if ($shared_server && array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            if (false == user_ini_space_path($f)) {
                $ldloc['errors'][ERROR_INI_NOT_FOUND] = "A system ini file cannot be found or read by the Wizard - you cannot do anything about this on your shared server.";
            } else {
                $ldloc['errors'][ERROR_INI_USER_INI_NOT_FOUND] = $ldloc['errors'][ERROR_INI_NOT_FOUND];
            }
        } elseif (array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            $ini_files_not_found[] = $f;
        }
        if (!empty($ldloc['location'])) {
            break;
        }
    }
    if (!empty($ini_files_not_found)) {
        $plural = (count($ini_files_not_found) > 1)?"s":"";
        $ldloc['errors'][ERROR_INI_NOT_FOUND] = "The following ini file$plural could not be found by the Wizard: " . join(',',$ini_files_not_found);
        if (is_restricted_server()) {
            $ldloc['errors'][ERROR_INI_NOT_FOUND] .= "<br> This may be due to server restrictions in place.";
        }
    }
    if (empty($ldloc['location'])) {
        $ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration.";
    }
    return $ldloc;
}

function find_loader_filesystem()
{
    $ld_inst_dir = loader_install_dir(find_server_type());
    $loader_name = get_loader_name();
    $suggested_loader_path = $ld_inst_dir . DIRECTORY_SEPARATOR . $loader_name;
    if (@file_exists($suggested_loader_path)) {
        $location = $suggested_loader_path;
    } elseif (@file_exists($loader_name)) {
        $location = @realpath($loader_name);
    } else {
        $ld_loc = get_loader_location();
        if (@file_exists($ld_loc)) {
            $location = $ld_loc;
        } else {
            $location = '';
        }
    }
    return $location;
}

function find_loader($search_directories_if_not_ini = false)
{
    $sysinfo = get_sysinfo();
    $php_ini = $sysinfo['PHP_INI'];
    $rtl_path = get_runtime_loading_path_if_applicable();
    $location = '';
    $errors = array();

    if (!empty($rtl_path)) {
        $location = $rtl_path;
    } else {
        $loader_ini = scan_inis_for_loader();
        $location = $loader_ini['location'];
        $errors = $loader_ini['errors'];
    }
    if (empty($location) && (empty($errors) || $search_directories_if_not_ini)) {
        $errors = array(); 
        $location = find_loader_filesystem();
        if (empty($location)) {
            $errors[ERROR_LOADER_NOT_FOUND] = 'The loader file could not be found in standard locations.';
        }
    }
    if (!empty($errors)) {
        return $errors;
    } else {
        return $location;
    }
}

function zend_extension_line_start()
{
    $sysinfo = get_sysinfo();
    $is_53_or_later = is_php_version_or_greater(5,3);
    return (is_bool($sysinfo['THREAD_SAFE']) && $sysinfo['THREAD_SAFE'] && !$is_53_or_later ? 'zend_extension_ts' : 'zend_extension');
}

function ioncube_loader_version_information()
{
    $old_version = true;
    $liv = "";
    $lv = "";
    $mv = 0;
    if (function_exists('ioncube_loader_iversion')) {
        $liv = ioncube_loader_iversion();
        $lv = sprintf("%d.%d.%d", $liv / 10000, ($liv / 100) % 100, $liv % 100);

        $latest_version =  get_latestversion();

        $lat_parts = explode('.',$latest_version);
        $cur_parts = explode('.',$lv);

        if (($cur_parts[0] > $lat_parts[0]) || 
            ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] > $lat_parts[1]) ||
             ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] == $lat_parts[1] && $cur_parts[2] >= $lat_parts[2])) {
            $old_version = false;
        } else {
            $old_version = $latest_version;
        }
        $mv = $cur_parts[0];
    }
    return array($lv,$mv,$old_version);
}

function default_loader_version_info()
{
    return array();
}

function get_loader_version_info()
{
    return get_remote_session_value('loader_version_info',LOADER_LATEST_VERSIONS_URL,'default_loader_version_info');
}

function calc_platform()
{
    $platform = array();
    $platform_info = get_platforminfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($osvar,$exact_match) = get_reqd_version($loader['osvariants']);
    } else {
        $osvar = null;
        if (is_ms_windows()) {
            $sys = get_sysinfo();
            $phpc = (empty($sys['PHP_COMPILER']))?'vc6':strtolower($sys['PHP_COMPILER']); 
            $osvar = ($sys['THREAD_SAFE']?'':'nonts_') . $phpc;
        }
    }
    foreach ($platform_info as $p) {
        if ($p['os'] == $loader['oscode'] && $p['arch'] == $loader['arch'] && (empty($osvar) || $p['os_mod'] == "_" . $osvar)) {
            $platform = $p;
            break;
        }
    }
    return $platform;
}

function get_platform()
{
    static $this_platform;

    if (!isset($this_platform)) {
        $this_platform = calc_platform();
    }

    return $this_platform;
}

function is_legacy_platform()
{
    $platform = get_platform();
    return array_key_exists('is_legacy',$platform);
}

function calc_dirname()
{
    $dirname = '';
    $platform = get_platform();
    if (!empty($platform)) {
        $dirname = $platform['dirname'];
    }
    return $dirname;
}

function calc_loader_latest_version()
{
    $lv_info = get_loader_version_info();
    $latest_version = RECENT_LOADER_VERSION;
    if (!empty($lv_info)) {
        $dirname = calc_dirname();
      
        if (!empty($dirname)) {
            $compiler_specific_version = false;
            if (is_ms_windows()) {
                $sys = get_sysinfo();
                $phpc = strtolower($sys['PHP_COMPILER']);
                if (!empty($phpc)) {
                    $dirname_comp = $dirname . "_" . $phpc;
                    if (array_key_exists($dirname_comp,$lv_info)) {
                        $latest_version = $lv_info[$dirname_comp];
                        $compiler_specific_version = true;
                    }
                }
            }
            if (!$compiler_specific_version && array_key_exists($dirname,$lv_info)) {
                $latest_version = $lv_info[$dirname];
            }
        } 
    }
    return $latest_version;
}

function get_latestversion()
{
    static $latest_version;

    if (empty($latest_version)) {
        $latest_version = calc_loader_latest_version();
    }
    return $latest_version;
}


function runtime_loader_location()
{
    $loader_path = false;
    $ext_path = extension_dir_path();
    if ($ext_path !== false) {
        $id = $ext_path;
        $here = dirname(__FILE__);
        if (isset($id[1]) && $id[1] == ':') {
            $id = str_replace('\\','/',substr($id,2));
            $here = str_replace('\\','/',substr($here,2));
        }
        $rd=str_repeat('/..',substr_count($id,'/')).$here.'/';
        $i=strlen($rd);

        $loader_loc = DIRECTORY_SEPARATOR . basename($here) . DIRECTORY_SEPARATOR . get_loader_name();
        while($i--) {
            if($rd[$i]=='/') {
                $loader_path = runtime_location_exists($ext_path,$rd,$i,$loader_loc);
                if ($loader_path !== false) {
                    break;
                }
            }
        }

        if (!$loader_path && !empty($loader_loc) && @file_exists($loader_loc)) {
            $loader_path = basename($loader_loc);
        }
    }
    return $loader_path;
}

function runtime_location_exists($ext_dir,$path_str,$sep_pos,$loc_name)
{
    $sub_path = substr($path_str,0,$sep_pos);
    $lp = $sub_path . $loc_name;
    $fqlp = $ext_dir.$lp;

    if(@file_exists($fqlp)) {
        return $lp;
    } else {
        return false;
    }
}

function runtime_loading_is_possible() {
    return !((is_php_version_or_greater(5,2,5)) || is_restricted_server() || !ini_get('enable_dl') || !function_exists('dl') || function_is_disabled('dl') || threaded_and_not_cgi());
}

function shared_and_runtime_loading()
{
    return (find_server_type() == SERVER_SHARED && empty($_SESSION['use_ini_method']) && runtime_loading_is_possible());
}

function get_valid_runtime_loading_path($ignore_loading_check = false)
{
    if ($ignore_loading_check || runtime_loading_is_possible()) {
        return runtime_loader_location();
    } else {
        return false;
    }
}

function runtime_loading($rtl_path = null)
{
    if (empty($rtl_path)) {
        $rtl_path = get_valid_runtime_loading_path();
    }
    if (!empty($rtl_path) && @dl($rtl_path)) {
        return $rtl_path;
    } else {
        return false;
    }
}

function get_runtime_loading_path_if_applicable()
{
    $rtl = null;
    if (shared_and_runtime_loading()) {
        $rtl = get_valid_runtime_loading_path();
    }
    return $rtl;
}

function try_runtime_loading_if_applicable()
{
    $rtl_path = get_runtime_loading_path_if_applicable();
    if (!empty($rtl_path)) {
        return runtime_loading($rtl_path);
    } else {
        return $rtl_path;
    }
}

function runtime_loading_instructions()
{
    $default = get_default_address();
    echo '<h4>Runtime Loading Instructions</h4>';
    echo '<div class=panel>';
    echo '<p>On your shared server the Loader can be installed using the runtime loading method.';
    echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";

    if ('.' == extension_dir()) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        echo "Please note that on your system the Loader <em>must</em> be present in the same " . $dirphrase . " as the first encoded file accessed.";
    }
    echo '<ol>';
    loader_download_instructions(); 
    $loader_dir = loader_install_instructions(SERVER_SHARED,dirname(__FILE__));
    shared_test_instructions();
    echo '</ol>';
    echo '</div>';
}

function runtime_loading_errors()
{
    $errors = array();
    $ext_path = extension_dir_path();
    if (false === $ext_path) {
        $errors[ERROR_RUNTIME_EXT_DIR_NOT_FOUND] = "Extensions directory cannot be found.";
    } else {
        $expected_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . get_loader_name();
        if (!@file_exists($expected_file)) {
            $errors[ERROR_RUNTIME_LOADER_FILE_NOT_FOUND] = "The Loader file was expected to be at $expected_file but could not be found.";
        } else {
            $errors = loader_compatibility_test($expected_file);
        }
    }
    return $errors;
}


function windows_package_name()
{
    $sys = get_sysinfo();
	$loader = get_loaderinfo();
    return (LOADERS_PACKAGE_PREFIX . 'win' . '_' . ($sys['THREAD_SAFE']?'':'nonts_') . strtolower($sys['PHP_COMPILER']) .  '_' . $loader['arch']);
}

function unix_package_name()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($reqd_version,$exact_match) = get_reqd_version($loader['osvariants']);
        if ($reqd_version) {
            $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $reqd_version . '_' . $loader['arch'];
        } else {
            $basename = "";
        }
    } else {
        $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $loader['arch'];
    }
    return array($basename,$multiple_os_versions);
}

function loader_download_instructions()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;

    if (is_ms_windows()) {
        if (is_bool($sysinfo['THREAD_SAFE'])) {
            $download_str = '<li>Download the following archive of Windows ' . $sysinfo['PHP_COMPILER'];
            if (!$sysinfo['THREAD_SAFE']) {
                $download_str .= ' non-TS';
            }
            $download_str .= ' ' . $loader['arch'] . ' Loaders:';
            echo $download_str;
            $basename = windows_package_name();
            echo make_archive_list($basename,array('zip'));
            echo 'A Loaders archive can also be downloaded from <a href="' . LOADERS_PAGE . '" target="loaders">' . LOADERS_PAGE . '</a>.';
        } else {
            echo '<li>Download a Windows Loaders archive from <a href="' . LOADERS_PAGE  . '" target=loaders>here</a>. If PHP is built with thread safety disabled, use the Windows non-TS Loaders.';
        }
    } else {
        list($basename,$multiple_os_versions) = unix_package_name(); 
        if ($basename == "") {
            echo '<li>Download a ' . $loader['osname'] . ' ' . $loader['arch'] . ' Loaders archive from <a href="' . LOADERS_PAGE . '" target="loaders">here</a>.';
            echo "<br>Your system appears to be ${loader['osnamequal']} for ${loader['wordsize']} bit. If Loaders are not available for that exact release of ${loader['osname']}, Loaders built for an earlier release should work. Note that you may need to install back compatibility libraries for the operating system.";
            echo '<br>If you cannot find a suitable loader then please raise a ticket at <a href="'. SUPPORT_SITE . '">our support helpdesk</a>.';
        } else {
            echo '<li>Download one of the following archives of Loaders for ' . $loader['osnamequal'] . ' ' . $loader['arch'] . ':'; 
            if (SERVER_SHARED == find_server_type()) {
                $archives = array('zip','tar.gz');
            } else {
                $archives = array('tar.gz','zip');
            }
            echo make_archive_list($basename,$archives);
            echo "</p>";
            if ($multiple_os_versions && !$exact_match) {
                echo "<p>Note that you may need to install back compatibility libraries for  ${loader['osname']}.</p>";
            }
        }
    }

    echo '</li>';
}

function ini_dir()
{
    $sysinfo = get_sysinfo();
    $parent_dir = '';
    if (!empty($sysinfo['PHP_INI'])) {
        $parent_dir = dirname($sysinfo['PHP_INI']);
    } else {
        $parent_dir = $_SERVER["PHPRC"];
        if (@is_file($parent_dir)) {
            $parent_dir = dirname($parent_dir);
        }
    }
    return $parent_dir;
}

function unix_install_dir()
{
    $ext_dir = extension_dir_path();
    $cur_dir = @realpath('.');
    if (empty($ext_dir) || $ext_dir == $cur_dir) {
        $loader_dir = UNIX_SYSTEM_LOADER_DIR;
    } else {
        $loader_dir = $ext_dir;
    }
    return $loader_dir;
}

function windows_install_dir()
{
    $sysinfo = get_sysinfo();
    if ($sysinfo['SS'] == 'IIS') {
        if (false === ($ext_dir = extension_dir_path())) {
            $parent_dir = ini_dir();
            $ext_dir = $parent_dir . '\\ext';
            if (!empty($parent_dir) && @file_exists($ext_dir)) {
                $loader_dir = $ext_dir;
            } else {
                $loader_dir = $_SERVER['windir'] . '\\' . WINDOWS_IIS_LOADER_DIR;
            }
        } else {
            $loader_dir = $ext_dir;
        }
    } else {
        if (false === ($ext_dir = extension_dir_path())) {
			$parent_dir = ini_dir();
			$loader_dir = $parent_dir . '\\' . 'ioncube';
		} else {
			$loader_dir = $ext_dir;
		}
    }
    return $loader_dir;
}

function loader_install_dir($server_type)
{
    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $loader_dir = get_default_loader_dir_webspace();
    } elseif (is_ms_windows()) {
        $loader_dir = windows_install_dir();
    } else {
        $loader_dir = unix_install_dir();
    }
    return $loader_dir;
}

function writeable_directories()
{
    $root_path = @realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    $root_path_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
    $above_root_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/../cgi-bin");

    $paths = array();
    foreach (array($root_path,$above_root_path,$root_path_cgi_bin,$above_root_cgi_bin) as $p) {
        if (@is_writeable($p)) {
            $paths[] = $p;
        }
    }
    return $paths;
}

function loader_install_instructions($server_type,$loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = loader_install_dir($server_type);
    }
    if (SERVER_LOCAL == $server_type) {
        echo "<li>Put the Loader files in <code>$loader_dir</code></li>";
    } else {
        echo "<li>Transfer the Loaders to your web server and install in <code>$loader_dir</code></li>";
    }
    return $loader_dir;
}

function zend_extension_lines($loader_dir)
{
    $zend_extension_lines = array();
    $sysinfo = get_sysinfo();
    $qt = (is_ms_windows()?'"':'');
    $loader = get_loaderinfo();

    if (!is_bool($sysinfo['THREAD_SAFE']) || !$sysinfo['THREAD_SAFE']) {
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file'] . $qt;
        $zend_extension_lines[] = "zend_extension = " . $path;
    }
    if ((!is_bool($sysinfo['THREAD_SAFE']) && !is_php_version_or_greater(5,3)) || $sysinfo['THREAD_SAFE']) {
        $line_start = is_php_version_or_greater(5,3)?'zend_extension':'zend_extension_ts';
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file_ts'] . $qt;
        $zend_extension_lines[] = $line_start . " = " . $path;
    }
    return $zend_extension_lines;
}

function user_ini_base()
{
    $doc_root_path = realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    if (!empty($above_root_path) && @is_writeable($above_root_path)) {
        $start_path = $above_root_path;
    } else {
        $start_path = $doc_root_path;
    }
    return $start_path;
}

function user_ini_space_path($file)
{
    $user_base = user_ini_base();
    $fpath = @realpath($file);
    if (!empty($fpath) && (0 === strpos($fpath,$user_base))) {
        return $fpath;
    } else {
        return false;
    }
}

function default_ini_path()
{
    return (realpath($_SERVER['DOCUMENT_ROOT']));
}

function shared_ini_location()
{
    $phprc = getenv('PHPRC');
    if (!empty($phprc)) {
        $phprc_path = user_ini_space_path($phprc);
        if (false !== $phprc_path) {
            return $phprc_path;
        } else {
            return default_ini_path();
        }
    } else {
        return default_ini_path();
    }
}


function zend_extension_instructions($server_type,$loader_dir)
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();
    $editing_ini = true;

    $php_ini_name = ini_file_name();

    if (isset($sysinfo['PHP_INI']) && @file_exists($sysinfo['PHP_INI'])) {
        $php_ini_path = $sysinfo['PHP_INI'];
    } else {
        $php_ini_path = '';
    }

    if (is_bool($sysinfo['THREAD_SAFE'])) {
        $kwd = zend_extension_line_start();
    } else {
        $kwd = 'zend_extension/zend_extension_ts';
    }

    $server_type_code = server_type_code();

    $zend_extension_lines = zend_extension_lines($loader_dir);

    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $ini_dir = shared_ini_location();
        $php_ini_path = $ini_dir . DIRECTORY_SEPARATOR . $php_ini_name;
        if (@file_exists($php_ini_path)) {
            $edit_line = "<li>Edit the <code>$php_ini_name</code> in the <code>$ini_dir</code> directory";
            if (zend_extension_line_missing($php_ini_path) && @is_writeable($php_ini_path) && @is_writeable($ini_dir)) {
                if (function_exists('file_get_contents')) {
                    $ini_strs = @file_get_contents($php_ini_path);
                } else {
                    $lines = @file($php_ini_path);
                    $ini_strs = join(' ',$lines);
                }
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                        fwrite($fh,$zl . PHP_EOL);
                    }
                    fwrite($fh,$ini_strs);
                    fclose($fh);
                    $editing_ini = false;
                    echo "<li>Your php.ini file at $php_ini_path has been modified to include the necessary line for the ionCube Loader.";
                } else {
                    echo $edit_line;
                }
            } else {
               echo $edit_line;
            }
        } else {
            $download_ini_file = "<li><a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">Save this  <code>$php_ini_name</code> file</a> and upload it to <code>$ini_dir</code> (full path on your server).";
            if (@is_writeable($ini_dir)) {
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                       fwrite($fh,$zl . PHP_EOL);
                    }
                    if (!empty($sysinfo['PHP_INI']) && is_readable($sysinfo['PHP_INI'])) {
                        if (function_exists('file_get_contents')) {
                           $ini_strs = @file_get_contents($sysinfo['PHP_INI']);
                        } else {
                           $lines = @file($sysinfo['PHP_INI']);
                           $ini_strs = join(' ',$lines);
                        }
                        fwrite($fh,$ini_strs);
                    }
                    fclose($fh); 
                    echo "<li>A <code>$php_ini_name</code> file has been created for you in <code>$ini_dir</code>.";
                } else {
                    echo $download_ini_file;
                }
            } else {
                echo $download_ini_file;
            }
            $editing_ini = false;
        }
    } elseif (!empty($sysinfo['PHP_INI'])) {
        if (empty($sysinfo['PHP_INI_DIR'])) {
            echo "<li>Edit the file <code>${sysinfo['PHP_INI']}</code>";
        } else {
            $php_ini_path = find_additional_ioncube_ini();
            if (empty($php_ini_path)) {
                $php_ini_name = ADDITIONAL_INI_FILE_NAME;
                echo "<li><a href=\"$base&amp;page=phpconfig&amp;download=1&amp;newlinesonly=1&amp;ininame=$php_ini_name&amp;stype=$server_type_code\">Save this $php_ini_name file</a> and put it in your ini files directory, <code>${sysinfo['PHP_INI_DIR']}</code>";
                $editing_ini = false;
            } else {
                $php_ini_name = basename($php_ini_path);
                echo "<li>Edit the file <code>$php_ini_path</code>";
            }
        }
    } else {
        echo "<li>Edit the system <code>$php_ini_name</code> file";
    }
    if ($editing_ini) {
        echo " and <b>before</b> any other $kwd lines ensure that the following is included:<br>";
        foreach ($zend_extension_lines as $zl) {
            echo "<code>$zl</code><br>";
        }
        if (!empty($php_ini_path)) {
            if (zend_extension_line_missing($php_ini_path)) {
                echo "<a>Alternatively, replace your current <code>$php_ini_path</code> file with <a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">this new $php_ini_name file</a>."; 
            }
        }
    }
    echo '</li>';
}

function server_restart_instructions()
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();

    if ($sysinfo['SS']) {
		if ($sysinfo['SS'] == 'PHP-FPM') {
			echo "<li>Restart PHP-FPM.</li>";
		} else {
			echo "<li>Restart the ${sysinfo['SS']} server software.</li>";
		}
    } else {
        echo "<li>Restart the server software.</li>";
    }

    echo "<li>When the server software has restarted, <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the Loader</a>.</li>";

	if ($sysinfo['SS'] && $sysinfo['SS'] == 'PHP-FPM') {
		echo '<li>If the Loader installation failed, check the PHP-FPM error log file for errors.</li>';
    } elseif ($sysinfo['SS'] == 'Apache' && !is_ms_windows()) {
        echo '<li>If the Loader installation failed, check the Apache error log file for errors and see our guide to <a target="unix_errors" href="'. UNIX_ERRORS_URL . '">Unix related errors</a>.</li>';
    }
}

function shared_test_instructions()
{
    $base = get_base_address();
    echo "<li><a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">Click here to test the Loader</a>.</li>";
}

function link_to_php_ini_instructions()
{
    $default = get_default_address();
    echo "<p><a href=\"{$default}&amp;stype=s&amp;ini=1\">Please click here for instructions on using the php.ini method instead</a>.</p>";
}

function php_ini_instruction_list($server_type)
{
    echo '<h4>Installation Instructions</h4>';
    echo '<div class=panel>';
    echo '<ol>';

    loader_download_instructions(); 
    $loader_dir = loader_install_instructions($server_type);
    zend_extension_instructions($server_type,$loader_dir);
    if ($server_type != SERVER_SHARED || !own_php_ini_possible()) {
        server_restart_instructions();
    } else {
        shared_test_instructions();
    } 
    echo '</ol>';
    echo '</div>';
}

function php_ini_install_shared($give_preamble = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();
    if ($give_preamble) {
        echo "<p>On your <strong>shared</strong> server, the Loader should be installed using a <code>$php_ini_name</code> configuration file.";
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";
    }

    if (own_php_ini_possible()) {
        echo '<p>With your hosting account, you may be able to use your own PHP configuration file.</p>';
    } else {
        echo "<p>It appears that you cannot install the ionCube Loader using the <code>$php_ini_name</code> file. Your server provider or system administrator should be able to perform the installation for you. Please refer them to the following instructions.</p>";
    }

    php_ini_instruction_list(SERVER_SHARED);
}

function php_ini_install($server_type_desc = null, $server_type = SERVER_DEDICATED, $required = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();

    echo '<p>';
    if ($server_type_desc) {
        echo "For a <strong>$server_type_desc</strong> server ";
    } else {
        echo "For this server ";
    }

    if ($required) {
        echo "you should install the ionCube Loader using the <code>$php_ini_name</code> configuration file.";
    } else {
        echo "installing the ionCube Loader using the <code>$php_ini_name</code> file is recommended.";
    }
    if ($server_type_desc) {
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a $server_type_desc server</a>.)";
    }
    echo '</p>';
      
    php_ini_instruction_list($server_type);
}



function help_resources($error_list = array())
{
	$self = get_self();
    $base = get_base_address();
    $server_type_code = server_type_code();
    $server_type = find_server_type();
    $sysinfo = get_sysinfo();
    $resources = array(
            '<a target="_blank" href="' . LOADERS_FAQ_URL . '">ionCube Loaders FAQ</a>',
            '<a target="_blank" href="' . LOADER_FORUM_URL . '">ionCube Loader Forum</a>'
        );
    if (SERVER_SHARED != $server_type || own_php_ini_possible(true)) {
		$support_info = array ( 
			'department' 		=> WIZARD_SUPPORT_TICKET_DEPARTMENT,
			'subject' 			=> "ionCube Loader installation problem",
			'message' 			=> support_ticket_information()
		   );
		if (SERVER_LOCAL == $server_type && !info_should_be_disabled()) {
			$temp_files = system_info_temporary_files();
		} else {
			$temp_files = NULL;
		}
		if (!empty($temp_files)) {
			$support_info['ini'] = base64_encode(file_get_contents($temp_files['ini']));
			$support_info['phpinfo'] = base64_encode(file_get_contents($temp_files['phpinfo']));
			$support_info['additional'] = base64_encode(file_get_contents($temp_files['additional']));
			
			$loader_path = find_loader(true);
			if (is_string($loader_path)) {		
				$support_info['loader'] = base64_encode(file_get_contents($loader_path));
				$support_info['loader_name'] = basename($loader_path);
			} else {
				$support_info['loader'] = '';
				$support_info['loader_name'] = '';
			}
		} else {
			$support_info['ini'] = '';
			$support_info['phpinfo'] = '';
			$support_info['additional'] = '';
			$support_info['loader'] = '';
			$support_info['loader_name'] = '';
		}
		 
        $resources[2] = '<form action="' . SUPPORT_SITE . 'lw_index.php' .'" method="POST" id="support-ticket"><a href="" onclick="document.getElementById(\'support-ticket\').submit(); return false;">Raise a support ticket through our helpdesk</a>';
		$resources[2] .= '<input type="hidden" name="department" value="' . $support_info['department'] . '"/>';
		$resources[2] .= '<input type="hidden" name="subject" value="' . $support_info['subject'] . '"/>';
		$resources[2] .= '<input type="hidden" name="message" value="' . $support_info['message'] . '"/>';
		if (!empty($temp_files)) {
			$resources[2] .= '<input type="hidden" name="phpinfo" value="' . $support_info['phpinfo'] . '"/>';
			$resources[2] .= '<input type="hidden" name="ini" value="' . $support_info['ini'] . '"/>';
			$resources[2] .= '<input type="hidden" name="additional" value="' . $support_info['additional'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader" value="' . $support_info['loader'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader_name" value="' . $support_info['loader_name'] . '"/>';
		}
		$resources[2] .= '</form>';
    } 
	
    if (SERVER_SHARED == $server_type && own_php_ini_possible(true) && !user_ini_space_path($sysinfo['PHP_INI'])) {
        $resources[3] = '<strong>Please check with your host that you can create php.ini files that will override the system one.</strong>';
    }
    return $resources;
}

function system_info_temporary_files()
{
    $tmpfname_ini = get_tempnam("/tmp", "INI");
    $tmpfname_ini .= ".ini";
    $fh_ini = @fopen($tmpfname_ini,'wb');
    if ($fh_ini) {
        $config = all_ini_contents();
        fwrite($fh_ini,$config);
        fclose($fh_ini);
    } else {
        $tmpfname_ini = '';
    }

    $tmpfname_pinf = get_tempnam("/tmp", "PIN");
    $tmpfname_pinf .= ".html";
    $fh_pinfo = @fopen($tmpfname_pinf,'wb');
    if ($fh_pinfo) {
        ob_start();
        @phpinfo();
        $pinfo = ob_get_contents();
        ob_end_clean();
        fwrite($fh_pinfo,$pinfo);
        fclose($fh_pinfo);
    } else {
        $tmpfname_pinf = '';
    }

    $tmpfname_add = get_tempnam("/tmp", "ADD");
    $tmpfname_add .= ".html";
    $fh_add = @fopen($tmpfname_add,'wb');
    if ($fh_add) {
        ob_start();
        extra_page(false);
        $extra = ob_get_contents();
        ob_end_clean();
        fwrite($fh_add,$extra);
        fclose($fh_add);
    } else {
        $tmpfname_add = '';
    }

    if (empty($tmpfname_ini) || empty($tmpfname_pinf) || empty($tmpfname_add)) {
        return (array());
    } else {
        return (array('ini'           =>   $tmpfname_ini,
                      'phpinfo'       =>   $tmpfname_pinf,
                      'additional'    =>   $tmpfname_add));
    }
}

function get_tempnam($default_tmp_dir = '', $prefix = '')
{
	if (function_exists('sys_get_temp_dir')) {
		return tempnam(sys_get_temp_dir(),$prefix);
	} else {
		return @tempnam($default_tmp_dir, $prefix);
	}
}
function system_info_archive_page()
{
    info_disabled_check();
	$server_type = find_server_type();
	if (SERVER_LOCAL != $server_type) {
		exit;
	}
    $loader = find_loader(true);
    if (is_string($loader)) {
        $loader_file = $loader;
    } else {
        $loader_file = '';
    }
    $all_files = system_info_temporary_files();
    if (!empty($all_files)) {
        if (!empty($loader_file)) {
            $all_files['loader'] = $loader_file;
        }
        $archive_name =  get_tempnam('/tmp',"ARC");
        if (extension_loaded('zip')) {
            $archive_name .= '.zip';
            $zip = @new ZipArchive();
            $mode = @constant("ZIPARCHIVE::OVERWRITE");
            if (!$zip || $zip->open($archive_name, $mode)!==TRUE) {
                $archive_name = '';
            } else {
                foreach($all_files as $f) {
                    $zip->addFile($f,basename($f));
                }
                $zip->close();
            }
        } elseif (extension_loaded('zlib') && !is_ms_windows()) {
            $tar_name = $archive_name . ".tar";
            $all_files_str = join(' ',$all_files);
            $script = "tar -chf $tar_name $all_files_str";
            $result = @system($script,$retval);
            if ($result !== false) {
                $archive_name = $tar_name . '.gz';
                $zp = gzopen($archive_name,"w9");
                $tar_contents = get_file_contents($tar_name);
                gzwrite($zp,$tar_contents);
                gzclose($zp);
            } else {
                $archive_name = '';
            }
        } else {
            $archive_name = '';
        }
    } else {
        $archive_name = '';
    }
    if ($archive_name) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. $archive_name);
        @readfile($archive_name);
    } else {
        $self = get_self();
        $base = get_base_address();
        $server_type_code = server_type_code();
        heading();
        echo "<p>A downloadable archive of system information could not be created.<br> 
            <strong>Please save each of the following and then attach those files to the support ticket:</strong></p>"; 
        echo "<ul>";
        echo "<li><a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo()</a></li>";
        echo "<li><a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a></li>";
        echo "<li><a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional information</a></li>";
        echo "<li><a href=\"$self?page=loaderbin\">loader file</a></li>";
        echo "</ul>";
        footer(true);
    }
}

function support_ticket_information($error_list = array())
{
    $sys = get_sysinfo();
    $ld = get_loaderinfo();

    $ticket_strs = array();
    $ticket_strs[] = "PLEASE DO NOT REMOVE THE FOLLOWING INFORMATION\r\n";
    $ticket_strs[] = "==============\r\n";
    if (!empty($error_list)) {
        $ticket_strs[] = "[hr]";
        $ticket_strs[] = "ERRORS";
        $ticket_strs[] = "[table]";
        $ticket_strs[] = '[tr][td]' . join('[/td][/tr][tr][td]',$error_list) . '[/td][/tr]';
        $ticket_strs[] = "[/table]";
    }
    $ticket_strs[] = "[hr]";
    $ticket_strs[] = "SYSTEM INFORMATION";
    $info_lines = array();
    $info_lines["Wizard version"] = script_version();
    $info_lines["PHP uname"] = $ld['uname'];
    $info_lines["Machine architecture"] = $ld['arch'];
    $info_lines["Word size"] = $ld['wordsize'];
    $info_lines["Operating system"] = $ld['osname'] . ' ' . $ld['osver'];
    if (selinux_is_enabled() || possibly_selinux()) {
        $info_lines["Security enhancements"] = "SELinux";
    } elseif (grsecurity_is_enabled()) {
        $info_lines["Security enhancements"] = "Grsecurity";
    } else {
        $info_lines["Security enhancements"] = "None";
    }
    $info_lines["PHP version"] = PHP_VERSION; 
    if ($sys['DEBUG_BUILD']) {
        $info_lines["DEBUG BUILD"] = "DEBUG BUILD OF PHP";
    }
    if (!$sys['SUPPORTED_COMPILER']) {
        $info_lines["SUPPORTED PHP COMPILER"] = "FALSE";
        $info_lines["PHP COMPILER"] = $sys['PHP_COMPILER'];
    }
    $info_lines["Is CLI?"] = ($sys['IS_CLI']?"Yes":"No");
    $info_lines["Is CGI?"] = ($sys['IS_CGI']?"Yes":"No");
    $info_lines["Is thread-safe?"] = ($sys['THREAD_SAFE']?"Yes":"No");
    $info_lines["Web server"] = $sys['FULL_SS'];
    $info_lines["Server type"] = server_type_string();
    $info_lines["PHP ini file"] = $sys['PHP_INI'];
    if (!@file_exists($sys['PHP_INI'])) {
        $info_lines["Ini file found"] = "INI FILE NOT FOUND";
    } else {
        if (is_readable($sys['PHP_INI'])) {
            $info_lines["Ini file found"] = "INI FILE READABLE";
        } else {
            $fh = @fopen($sys['PHP_INI'],"rb");
            if ($fh === false) {
                $info_lines["Ini file found"] = "INI FILE FOUND BUT POSSIBLY NOT READABLE";
            } else {
                $info_lines["Ini file found"] = "INI FILE READABLE";
            }
        }
    }
    $info_lines["PHPRC"] = $sys['PHPRC'];
    $loader_path = find_loader();
    if (is_string($loader_path)) {
        $info_lines["Loader path"] =  $loader_path;
        $info_lines["Loader file size"] = filesize($loader_path) . " bytes.";
        $info_lines["Loader MD5 sum"] =  md5_file($loader_path);
    } else {
        $info_lines["Loader path"] =  "LOADER PATH NOT FOUND";
    }
    $server_type_code = server_type_code();
    if (!empty($_SESSION['hostprovider'])) {
      $info_lines['Hosting provider'] = $_SESSION['hostprovider'];
      $info_lines['Provider URL'] = $_SESSION['hosturl'];
    }
    $info_lines["Wizard script path"] = '[url]http://' . $_SERVER["HTTP_HOST"] . get_self() . '?stype='. $server_type_code . '[/url]';
    $ticket_strs[] = "[table]";
    foreach ($info_lines as $h => $i) {
        $value = (empty($i))?'EMPTY':$i;
        $ticket_strs[] = '[tr][td]' . $h . '[/td]' . '[td]' . $value . '[/td][/tr]';
    }
    $ticket_strs[] = '[/table]';
    $ticket_strs[] = '[hr]';
    $ticket_strs[] = "\r\n==============\r\n";
    $ticket_strs[] = "PLEASE ENTER ANY ADDITIONAL INFORMATION BELOW\r\n";

    $support_ticket_str = join('',$ticket_strs);
    return urlencode($support_ticket_str);
}

function wizard_stats_data($page_id)
{
    $data = array();

    try_runtime_loading_if_applicable();
    $sysinfo = get_sysinfo();
    $ldinfo = get_loaderinfo();

    $data['sessionid'] = session_id();
    $data['wizard_version'] = script_version();
    $data['server_type'] = server_type_code();
    $data['hostprovider'] = (isset($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $data['hosturl'] = (isset($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $data['page_id'] = $page_id;
    $data['loader_state'] = (extension_loaded(LOADER_EXTENSION_NAME))?'installed':'failure';
    $data['ini_location'] = $sysinfo['PHP_INI'];
    $data['is_cgi'] = ($sysinfo['IS_CGI'])?"yes":"no";
    $data['is_ts'] = ($sysinfo['THREAD_SAFE'])?"yes":"no";
    $data['arch'] = $ldinfo['arch'];
    $data['php_version'] = PHP_VERSION;
    $data['os'] = $ldinfo['osname'];
    $data['word_size'] = $ldinfo['wordsize'];
    $data['referrer'] =  $_SERVER["HTTP_HOST"] . get_self();

    return $data;
}

function send_stats($page_id = 'default')
{
    $server_type = find_server_type();
    $res = false;

    if (SERVER_LOCAL != $server_type) {
        $stats_data = wizard_stats_data($page_id);

        if (!isset($_SESSION['stats_sent'][$page_id][$stats_data['loader_state']])) {
            $url = WIZARD_STATS_URL;

            if (!empty($stats_data)) {
                if(function_exists('http_build_query')) {
                    $qparams = http_build_query($stats_data);
                } else {
                    $qparams = php4_http_build_query($stats_data);
                }
                $url .= '?' . $qparams;
                $res = remote_file_contents($url);
            }
            $_SESSION['stats_sent'][$page_id][$stats_data['loader_state']] = 1;
        } else {
            $res = true;
        }
    } else {
        $res = 'LOCAL';
    }
    return $res;
}

function os_arch_string_check($loader_str)
{
    $errors = array();
    if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_str,$os_matches)) {
        $loader_info = get_loaderinfo();
        $dirname = calc_dirname();
        $packed_osname = preg_replace('/\s/','',strtolower($loader_info['osname']));
        if (strtolower($dirname) != $os_matches[1] && $packed_osname != $os_matches[2]) {
            $errors[ERROR_LOADER_WRONG_OS] = "You have the wrong loader for your operating system, ". $loader_info['osname'] . ".";
        } else {
            $loader_wordsize = (strpos($os_matches[3],'64') === false)?32:64;
            if ($loader_info['arch'] != ($ap = required_loader_arch($os_matches[3],$loader_info['oscode'],$loader_wordsize))) {
                $err_str = "You have the wrong loader for your machine architecture.";
                $err_str .= " Your system is " . $loader_info['arch'];
                $err_str .= " but the loader you are using is for " . $ap . ".";
                $errors[ERROR_LOADER_WRONG_ARCH] = $err_str;
            }
        }
    }
    return $errors;
}

function get_loader_strings($loader_location)
{
    if (function_exists('file_get_contents')) {
        $loader_strs = @file_get_contents($loader_location);
    } else {
        $lines = @file($loader_location);
        $loader_strs = join(' ',$lines);
    }
    return $loader_strs;
}

function loader_system($loader_location)
{
    $loader_system = array();
    $loader_strs = get_loader_strings($loader_location);

    if (!empty($loader_strs)) {

        if (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
            $loader_system['oscode'] = 'win';
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '_nonts')?0:1;
			if (preg_match("/_localtime([0-9][0-9])/i",$loader_strs,$size_matches)) {
				$loader_system['wordsize'] = ($size_matches[1] == '64')?64:32;
			} else {
				$loader_system['wordsize'] = 32;
			}
            $loader_system['arch'] = ($loader_system['wordsize'] == 64)?'x86-64':'x86';
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
			if ($loader_system['php_version_major'] == 8 && $loader_system['php_version_minor'] >= 1) {
				$loader_system['compiler'] = 'VC16';
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] >= 2) {
				$loader_system['compiler'] = 'VC15'; 
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] < 2) {
				$loader_system['compiler'] = 'VC14'; 
			} elseif ($loader_system['php_version_major'] == 5 && $loader_system['php_version_minor'] >= 5) {
				$loader_system['compiler'] = 'VC11'; 
			} elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_system['compiler'] = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_system['compiler'] = 'VC6';
            }
        } elseif (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '-ts')?1:0;
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
            if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_strs,$os_matches)) {
                $loader_system['oscode'] = strtolower(substr($os_matches[2],0,3));
                $loader_system['wordsize'] = (strpos($os_matches[3],'64') === false)?32:64;
                $loader_system['arch'] = required_loader_arch($os_matches[3],$loader_system['oscode'],$loader_system['wordsize']);
                $loader_system['compiler'] = $os_matches[4];
            }
        }
        if (preg_match("/ionCube Loader Version\s+(\S+)/",$loader_strs,$loader_version)) {
            $loader_system['loader_version'] = $loader_version[1];
		} elseif (preg_match("/ioncube_loader_(\d{1,2}\.\d\.\d{1,2})\./",$loader_strs,$loader_version)){
			$loader_system['loader_version'] = $loader_version[1];
        } else {
            $loader_system['loader_version'] = 'UNKNOWN';
        }
        if (isset($loader_system['php_version_major'])) {
            $loader_system['php_version'] = $loader_system['php_version_major'] . '.' . $loader_system['php_version_minor'];
        }
    }
    return $loader_system;
}

function loader_compatibility_test($loader_location)
{
    $errors = array();

    $sysinfo = get_sysinfo();
    if (LOADER_NAME_CHECK) {
        $installed_loader_name = basename($loader_location);
        $expected_loader_name = get_loader_name();
        if ($installed_loader_name != $expected_loader_name) {
            $errors[ERROR_LOADER_UNEXPECTED_NAME] = "The installed loader (<code>$installed_loader_name</code>) does not have the name expected (<code>$expected_loader_name</code>) for your system. Please check that you have the correct loader for your system.";
        }
    }
    if (empty($errors) && !is_readable($loader_location)) {
        $execute_error = "The loader at $loader_location does not appear to be readable.";
        $execute_error .= "<br>Please check that it exists and is readable.";
        $execute_error .= "<br>Please also check the permissions of the containing ";
        $execute_error .= (is_ms_windows()?'folder':'directory') . '.';
		if ($sysinfo['SS'] == 'PHP-FPM') {
			$execute_error .= "<br>Please also check that PHP-FPM has been restarted.";
        } elseif (($sysinfo['SS'] == 'IIS') || !($sysinfo['IS_CGI'] || $sysinfo['IS_CLI'])) {
            $execute_error .= "<br>Please also check that the web server has been restarted.";
        }
        $execute_error .= ".";
        $errors[ERROR_LOADER_NOT_READABLE] = $execute_error;
    }
    $loader_strs = get_loader_strings($loader_location);
    $phpv = php_version(); 
    if (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
        if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
            $loader_php = $version_matches[1] . "." . $version_matches[2];
            $server_php =  $phpv['major'] . "." .  $phpv['minor'];
            $errors[ERROR_LOADER_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
        }
        if (is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'] && !is_ms_windows() && !(isset($version_matches[4]) && $version_matches[4] == '-ts')) {
            $errors[ERROR_LOADER_NONTS_PHP_TS] = "Your server is running a thread-safe version of PHP but the loader is not a thread-safe version.";
        } elseif (isset($version_matches[4]) && $version_matches[4] == '-ts' && !(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'])) {
            $errors[ERROR_LOADER_TS_PHP_NONTS] = "Your server is running a non-thread-safe version of PHP but the loader is a thread-safe version.";
        }
    } elseif (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
        if (!is_ms_windows()) {
            $errors[ERROR_LOADER_WIN_SERVER_NONWIN] = "You have a Windows loader but your server does not appear to be running Windows.";
        } else {
            if (isset($version_matches[4]) && $version_matches[4] == '_nonts' && is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) {
                $errors[ERROR_LOADER_WIN_NONTS_PHP_TS] = "You have the non-thread-safe version of the Windows loader but you need the thread-safe one.";
            } elseif (!(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) && !(isset($version_matches[4]) && $version_matches[4] == '_nonts')) {
                $errors[ERROR_LOADER_WIN_TS_PHP_NONTS] = "You have the thread-safe version of the Windows loader but you need the non-thread-safe one."; 
            }
            if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
                $loader_php = $version_matches[1] . "." . $version_matches[2];
                $server_php =  $phpv['major'] . "." .  $phpv['minor'];
                $errors[ERROR_LOADER_WIN_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
            }
                        
            if ($version_matches[1] == 8 && $version_matches[2] >= 1) {
                $loader_compiler = 'VC16';
            } elseif ($version_matches[1] == 7 && $version_matches[2] >= 2) {
                $loader_compiler = 'VC15'; 
            } elseif ($version_matches[1] == 7) {
                $loader_compiler = 'VC14'; 
            } elseif ($version_matches[1] == 5 && $version_matches[2] >= 5) {
                $loader_compiler = 'VC11'; 
            } elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_compiler = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_compiler = 'VC6';
            }
            if ($loader_compiler != $sysinfo['PHP_COMPILER']) {
                $errors[ERROR_LOADER_WIN_COMPILER_MISMATCH] = "Your loader was built using $loader_compiler but you need the loader built using ${sysinfo['PHP_COMPILER']}.";
            }
        }
    } else {
            $errors[ERROR_LOADER_PHP_VERSION_UNKNOWN] = "The PHP version for the loader cannot be determined - please check that you have a valid ionCube Loader.";
    } 
    $errors += os_arch_string_check($loader_strs);

    return $errors;
}


function shared_server()
{
    if (!$rtl_path = runtime_loading()) {
        if (empty($_SESSION['use_ini_method']) && runtime_loading_is_possible()) {
            runtime_loading_instructions();
        } else {
            php_ini_install_shared();
        }
    } else {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        echo "<p>The ionCube Loader $lv for PHP $phpv has been successfully installed.</p>";
        $is_legacy_loader = loader_major_version_instructions($mv);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,$newer_version);
        }
        successful_install_end_instructions($rtl_path);
    }
}

function dedicated_server()
{
    php_ini_install('dedicated or VPS', SERVER_DEDICATED, true);
}

function local_install()
{
    php_ini_install('local',SERVER_LOCAL, true);
}


function unregister_globals()
{
    if (!ini_get('register_globals')) {
        return;
    }

    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

function clear_session($persist = array())
{
    $persist['not_go_daddy'] = empty($_SESSION['not_go_daddy'])?0:1;
    $persist['use_ini_method'] = empty($_SESSION['use_ini_method'])?0:1;
    $persist['server_type'] = empty($_SESSION['server_type'])?SERVER_UNKNOWN:$_SESSION['server_type'];
    @session_destroy();
    $_SESSION = array();
    $_SESSION['CREATED'] = time();
    $_SESSION = $persist;
}

function can_archive()
{
	return (extension_loaded('zip') || (extension_loaded('zlib') && !is_ms_windows()));
}

function is_ioncube()
{
        return (($_SERVER["REMOTE_ADDR"] == IONCUBE_IP_ADDRESS) || ($_SERVER["REMOTE_ADDR"] == gethostbyname(IONCUBE_ACCESS_ADDRESS)));
}

function can_reach_ioncube()
{
	return (isset($_SESSION['remote_access_successful']));
}

function info_should_be_disabled($only_allow_ioncube = false)
{
    $elapsed = time() - max(filemtime(__FILE__),filectime(__FILE__));
	
	if (is_ioncube()) {
		$cutoff_time = IONCUBE_WIZARD_EXPIRY_MINUTES * 60;
	} else {
		if (!$only_allow_ioncube && !extension_loaded(LOADER_EXTENSION_NAME)) {
			$cutoff_time = WIZARD_EXPIRY_MINUTES * 60;
		} else {
			return true;
		}
	}
	
    return ($elapsed > $cutoff_time);
}

function info_disabled_text()
{
    return "The information you have tried to access has been disabled for security reasons. Please re-install this Loader Wizard script and try again.";
}

function info_disabled_check()
{
    if (info_should_be_disabled()) {
        heading();
        echo info_disabled_text();
        footer(true);
        exit;
    }
}

function run()
{

	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (preg_match('/googlebot/i',$user_agent)) {
		exit;
	}
    unregister_globals();
    if (is_php_version_or_greater(4,3,0)) {
        ini_set('session.use_only_cookies',1);
    }
    $session_ok = @session_start();

    if (!defined('PHP_EOL')) {
        if (is_ms_windows()) {
            define('PHP_EOL',"\r\n");
        } else {
            define('PHP_EOL',"\n");
        }
    }

    if (!isset($_SESSION['CREATED'])) {
        $_SESSION['CREATED'] = time();
    } elseif (time() - $_SESSION['CREATED'] > SESSION_LIFETIME_MINUTES * 60 ) {
        clear_session(); 
    }
    if (!isset($_SERVER)) $_SERVER =& $HTTP_SERVER_VARS;

    (php_sapi_name() == 'cli') && die("This script should only be run by a web server.\n");

    $page = get_request_parameter('page');
    $host = get_request_parameter('host');
    $clear = get_request_parameter('clear');
    $ini = get_request_parameter('ini');
    $timeout = get_request_parameter('timeout');

    if ($timeout) {
        $_SESSION['timing_out'] = 1;
        $_SESSION['initial_run'] = 0;
    }

    if (!empty($host)) {
        if ($host == 'ngd') {
            $_SESSION['not_go_daddy'] = 1;
        }
    }
    if (!empty($ini)) {
        $_SESSION['use_ini_method'] = 1;
    }

    if (!empty($clear)) {
        clear_session();
        unset($_SESSION['not_go_daddy']);
        unset($_SESSION['use_ini_method']);
        unset($_SESSION['server_type']);
    } else {
        $stype = get_request_parameter('stype');
        $hostprovider = get_request_parameter('hostprovider');
        $hosturl = get_request_parameter('hosturl');
        if (!empty($hostprovider)) {
            $_SESSION['hostprovider'] = $hostprovider;
            $_SESSION['hosturl'] = $hosturl;
        }
        $server_type = find_server_type($stype,false,true);
    }
    if ($session_ok && !$timeout && !isset($_SESSION['initial_run']) && empty($page)) {
        $_SESSION['initial_run'] = 1;
        initial_page();
        @session_write_close();
        exit;
    } else {
        $_SESSION['initial_run'] = 0;
    }

    if (empty($_SESSION['server_type'])) {
        $_SESSION['server_type'] = SERVER_UNKNOWN;
    }

    if (empty($page) || !function_exists($page . "_page")) {
        $page = get_default_page();
    } 

    $fn = "{$page}_page";
    $fn();

    @session_write_close();
    exit(0);
}

function wizardversion_page()
{
    $start_time = time();
    $wizard_version_only = get_request_parameter('wizard_only');
    $clear_session_info = get_request_parameter('clear_info');
    if ($clear_session_info) {
        unset($_SESSION['timing_out']);
        unset($_SESSION['latest_wizard_version']);
    }
    $wizard_version = latest_wizard_version();
    $message = '';
    if (false === $wizard_version) {
        $message = "0";
    } elseif (update_is_available($wizard_version)) {
        $message = "$wizard_version";
    } else {
        $message = "1";
    }
    echo $message;
    @session_write_close();
    exit(0);
}

function platforminfo_page()
{
    $message = '';
    $platforms = get_loader_platforms();
    $message = empty($platforms)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function loaderversion_page()
{
    $message = '';
    $loader_versions = get_loader_version_info();
    $message = empty($loader_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function compilerversion_page()
{
    $message = '';
    $compiler_versions = find_win_compilers();
    $message = empty($compiler_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function initial_page()
{
    $self = get_self();
    $start_page = get_default_address(false);
    $stage_timeout = 7000;
    $step_lag = 500;

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <style type="text/css">
        body {
            height: 100%;
            width: 100%;
        }
        </style>
        <script type="text/javascript">
        var timingOut = 0;
        var xmlHttpTimeout;
        var ajax;
        var statusPar;
        var stage_timeout = $stage_timeout;
        var step_lag = $step_lag;

        function checkNextStep(ajax,expected,continuation) {
            if (ajax.readyState==4 && ajax.status==200)
            {
                clearTimeout(xmlHttpTimeout);
                if (ajax.responseText == expected) {
                   setTimeout('',step_lag);
                   continuation();
                } else {
                   statusPar.innerHTML = 'Unable to check for update<br>script continuing';
                   setTimeout("window.location.href = '$start_page&timeout=1'",1000);
                }
            }
        }

        function getXmlHttp() {
            if (window.XMLHttpRequest) {
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xmlhttp;
        }
        var startMainLoaderWizard = function() {
            window.location.href = '$start_page';
        }
        var loaderVersionCheck = function() {
            statusPar.innerHTML = 'Stage 4/4: Getting latest loader versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",startMainLoaderWizard);
            }
            xmlHttp.open("GET","$self?page=loaderversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var platformCheck = function() {
            statusPar.innerHTML = 'Stage 3/4: Getting platform information';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",loaderVersionCheck);
            }
            xmlHttp.open("GET","$self?page=platforminfo",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var compilerVersionCheck = function() {
            statusPar.innerHTML = 'Stage 2/4: Getting compiler versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",platformCheck);
            }
            xmlHttp.open("GET","$self?page=compilerversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var startChecks = function() {
            statusPar = document.getElementById('status');
            statusPar.innerHTML = 'Stage 1/4: Getting Loader Wizard version';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",compilerVersionCheck);
            }
            xmlHttp.open("GET","$self?page=wizardversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        function ajaxTimeout(){
           ajax.abort();
           statusPar.innerHTML = 'Cannot reach server<br>script continuing';
           setTimeout("window.location.href = '$start_page&timeout=1'",1000);
        }
        </script>
    </head>
    <body>

    <div id="loading"><script type="text/javascript">document.write('<p>Initialising<br>ionCube Loader Wizard<br><span id="status"></span></p>');</script><p id="noscript">Your browser does not support JavaScript so the ionCube Loader Wizard initialisation cannot be made now. This script can get the latest loader version information from the ionCube server when you go to the next page.<br>Please choose one of the following. <br>If the script appears to hang please restart the script and choose the "NO" option.<br><br><br><a href="$start_page">YES - my server DOES have internet access</a><br><br><a href="$start_page&timeout=1">NO - my server does NOT have internet access</a></p></div>
    <script type="text/javascript">
        document.getElementById('noscript').style.display = 'none';
        window.onload = startChecks;
    </script>
    </body>
    </html>
EOT;
}

function default_page($loader_extension = LOADER_EXTENSION_NAME)
{
    $self = get_self();
    foreach (array('self') as $vn) {
        if (empty($$vn)) {
			$server_data = print_r($_SERVER,true);
            error("Unable to initialise ($vn)". ' $_SERVER is: ' . $server_data);
        }
    }

    heading();

    $wizard_update = check_for_wizard_update(true);

    $rtl = try_runtime_loading_if_applicable();

    $server_type = find_server_type();

    if (extension_loaded($loader_extension) && $server_type != SERVER_UNKNOWN) {
        loader_already_installed($rtl);
    } else {
        loader_not_installed();
    }
    send_stats('default');

    footer($wizard_update);
}

function uninstall_wizard_instructions()
{
    echo '<p><strong>For security reasons we advise that you remove this Wizard script from your server now that the ionCube Loader is installed.</strong></p>';
}

function contact_script_provider_instructions()
{
    echo '<p>Please contact the script provider if you do experience any problems running encoded files.</p>';
}

function may_need_to_copy_ini()
{
    $sys = get_sysinfo();
    if (ini_same_dir_as_wizard() && $sys['IS_CGI']) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        $ini = ini_file_name();
        echo "<p>Please note that if encoded files in a different $dirphrase from the Wizard fail then you should attempt to copy the $ini file to each $dirphrase in which you have encoded files.</p>";
    }
}

function ioncube_24_is_available()
{
	$loaderinfo = get_loaderinfo();
	$php_ver = php_version();
   
	return ($loaderinfo['oscode'] == 'lin' && (($php_ver['major'] == 5 && $php_ver['minor'] >= 3) || $php_ver['major'] > 5) );
}

function ioncube_24_is_enabled()
{
	$ic24_enabled = ini_get(IC24_ENABLED_INI_PROPERTY);
	return $ic24_enabled;
}

function ioncube_24_information()
{
    if (ioncube_24_is_available() && !ioncube_24_is_enabled()) {
        $self = get_self();
        echo '<div class="ic24">';
        echo '<div class="ic24graphic">';
        echo '<a target="_blank" href="' . IONCUBE24_URL . '"><img id="ic24logo" src="' . $self . '?page=ic24logo" alt="ionCube24 logo"></a>';
        echo '</div>';
        echo '<div id="ic24info">';
        echo '<p><strong>Bonus Features!</strong> The ionCube Loader can also give ';
        echo '<strong>real-time intrusion protection</strong> to protect against malware and <strong>PHP error reporting</strong> ';
        echo 'to alert when things go wrong on your website.</p>';
        echo '<p>These features are disabled by default but easily activated. ';
        echo '<strong><a target="_blank" href="' . IONCUBE24_URL . '">visit ioncube24.com</a></strong> to find out more.</p>';
        echo '</div>';
        echo '</div>';
    }
}

function cli_install_instructions()
{

	if (is_php_version_or_greater(5,3)) {
		$cli_loader_installed = shell_exec('php -r "echo extension_loaded(\"' . LOADER_EXTENSION_NAME . '\");"');
		
		if (!$cli_loader_installed) {
			$cli_php_ini_output = shell_exec("php --ini");
			
			$ini_loader_loc = scan_inis_for_loader();
		
			if (!is_null($cli_php_ini_output)) {
				echo '<div class="panel">';
				echo '<h4>Loader Installation for Command-Line (CLI) PHP</h4>';
				echo "<p>At present it does not look like the ionCube Loader is installed for command-line (CLI) PHP.</p>";
				echo "<p>Please note that if you need to run the CLI PHP, such as for <strong>cron jobs</strong>, then please ensure the zend_extension line for the ionCube Loader is included in your CLI PHP configuration.</p>";
				
				if (!empty($ini_loader_loc['location'])) {
					echo "<p>The zend_extension line that needs to be copied is:</p>";
					echo "<p><kbd>zend_extension = " . $ini_loader_loc['location'] . "</kbd></p>";
				}
				
				echo "<p>Your CLI PHP Configuration is:</p>";
				echo '<div class="terminal">';
				echo "<pre>";
				echo $cli_php_ini_output;
				echo "</pre>";
				echo '</div>';
				echo '</div>';
			}
		}
	}
}

function successful_install_end_instructions($rtl_path = null)
{
    if (empty($rtl_path)) {
        may_need_to_copy_ini();
    } elseif (is_string($rtl_path)) {
        echo "<p>The runtime loading method of installation was used with path <code>$rtl_path</code></p>";
    }
    contact_script_provider_instructions();
    if (is_legacy_platform()) {
        legacy_platform_instructions();
    }
	
	if (!is_ms_windows() && is_php_version_or_greater(5,3)) {
		cli_install_instructions();
	}
	
    uninstall_wizard_instructions();
	
	ioncube_24_information();
}

function loader_major_version_instructions($mv)
{
    if ($mv < LATEST_LOADER_MAJOR_VERSION) {
        echo "<p><strong>The installed version of the Loader cannot run files produced by the most recent ionCube Encoder.</strong>";
        echo " You will need a version " . LATEST_LOADER_MAJOR_VERSION . " ionCube Loader to run such files.</p>";
    }
    return ($mv < LATEST_LOADER_MAJOR_VERSION);
}

function loader_already_installed($rtl = null)
{
    list($lv,$mv,$newer_version) = ioncube_loader_version_information();
    $phpv = php_version_maj_min();
    $php_str = ' for PHP ' . $phpv;
    echo '<div class="success">';
    echo '<h4>Loader Installed</h4>';
    if ($newer_version) {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is <strong>already installed</strong> but it is an old version.';
        echo ' It is recommended that the Loader be upgraded to the latest version if possible.</p>';
        $know_latest_version = is_string($newer_version);
        $is_legacy_loader = loader_major_version_instructions($mv);
        echo '</div>';
        loader_upgrade_instructions($lv,$newer_version);
    } else {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is already installed and encoded files should run without problems.</p>'; 
        echo '</div>';
        $is_legacy_loader = loader_major_version_instructions($mv,true);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,true);
        }
    }

    successful_install_end_instructions($rtl);
}

function loader_upgrade_instructions($installed_version,$newer_version)
{
    if ($newer_version) {
        echo '<div class="panel">';
        echo '<h4>Loader Upgrade Instructions</h4>';
        $restart_needed = true;
        $server_type = find_server_type();
        if ($server_type == SERVER_SHARED || $server_type == SERVER_UNKNOWN) {
            $loader_path = find_loader(true);
            if (!is_string($loader_path) || false === user_ini_space_path($loader_path)) {
                $verb_case = ($server_type == SERVER_UNKNOWN)?"may":"will";
                echo "<p>Please note that you $verb_case need your system administrator to do the following to upgrade. The web server will need to be restarted after the loader file is changed.</p>";
            }
            $restart_needed = false;
        }
        if (is_string($newer_version)) {
            $version_str = "version $newer_version";
        } else {
            $version_str = "a newer version";
        }
        $loader_name =  get_loader_name();
        echo "<p>To upgrade from version $installed_version to $version_str of the ionCube Loader, please replace your existing loader file, $loader_name, with
            the file of the same name from one of the following packages:</p>";
        if (is_ms_windows()) {
            $basename = windows_package_name();
        } else {
            list($basename,$multiple_os_versions) = unix_package_name();
        }
        echo make_archive_list($basename,array('zip','tar.gz'));
        if ($restart_needed) {
            echo "<p>Once you have replaced the loader file please restart your web server.</p>";
        }
        echo '</div>';
    }
}

function legacy_platform_warning()
{
    $leg_warn = '<p><strong>You are on a platform on which ionCube Loaders are no longer being developed. ';
    $leg_warn .= 'Loaders on your platform may not be able to run files produced by the latest ionCube Encoder. ';
    $leg_warn .= 'Please switch, if possible, to a platform on which loaders are currently supported. ';
    $leg_warn .= 'A list of currently supported platforms is shown on our <a href="' . LOADERS_PAGE . '" target="loaders">loaders page</a>.</strong></p>';

    return $leg_warn;
}

function legacy_platform_instructions()
{
    echo legacy_platform_warning();
}

function loader_not_installed()
{
    $loader = get_loaderinfo();
    $sysinfo = get_sysinfo();

    $stype = get_request_parameter('stype');
    $manual_select = get_request_parameter('manual');
    $host_type = find_server_type($stype,$manual_select,true);

    if ($host_type != SERVER_UNKNOWN && is_array($loader) && !$sysinfo['DEBUG_BUILD']) {
        $warnings = server_restriction_warnings();
        if (is_legacy_platform()) {
            $warnings[] = legacy_platform_warning();
        }
        if (empty($_SESSION['use_ini_method']) && $host_type == SERVER_SHARED && runtime_loading_is_possible()) {
            $errors = runtime_loading_errors();
        } else {
            $errors = ini_loader_errors();
            $warnings = array_merge($warnings,ini_loader_warnings());
        }
        if (!empty($errors)) {
            if (count($errors) > 1) {
                $problem_str = "Please note that the following problems currently exist";
            } else {
                $problem_str = "Please note that the following problem currently exists";
            }
            echo '<div class="alert">' .$problem_str . ' with the ionCube Loader installation:';
            echo make_list($errors,"ul"); 
            echo '</div>';
        }
        if (!empty($warnings)) {
            $addword = empty($errors)?'':'also';
            $plural = (count($warnings)>1)?'s':'';
            echo '<div class="warning">';
            echo "Please note $addword the following issue$plural:";
            echo make_list($warnings,"ul"); 
            echo '</div>';
        }
    }
    if (!isset($stype)) {
        echo '<p>To use files that have been protected by the <a href="' . ENCODER_URL . '" target=encoder>ionCube PHP Encoder</a>, a component called the ionCube Loader must be installed.</p>';
    }

    if (!is_supported_php_version()) {
        echo '<p>Your server is running PHP version ' . PHP_VERSION . ' and is
                unsupported by ionCube Loaders.  Recommended PHP 4 versions are PHP 4.2 or higher, 
                PHP 5.1 or higher for PHP 5, PHP 7.1 or higher for PHP 7 and PHP 8.1 or higher for PHP 8. Please note that there is not an ionCube Loader for PHP 8.0.</p>';
	} elseif ($latest_supported_php_version = is_after_max_php_version_supported()) {
		echo '<strong>Your server is running PHP version ' . PHP_VERSION . ' and is
                currently unsupported by any ionCube Loaders. <br/>This may change in the future if a Loader is produced for your PHP platform.<br/>In the meantime please downgrade PHP to version ' . $latest_supported_php_version . '.</strong>';
    } elseif ($sysinfo['DEBUG_BUILD']) {
         echo '<p>Your server is currently running a debug build of PHP. The Loader cannot be installed with a debug build of PHP. Please ensure that PHP is reconfigured with debug disabled. Note that debug builds of PHP cannot help in debugging PHP scripts.</p>'; 
    } elseif (!is_array($loader)) {
        if ($loader == ERROR_WINDOWS_64_BIT) {
            echo '<p>Loaders for 64-bit PHP on Windows are not currently available. However, if you <b>install and run 32-bit PHP</b> the corresponding 32-bit loader for Windows should work.</p>';
            if ($sysinfo['THREAD_SAFE']) {
                echo '<li>Download one of the following archives of 32-bit Windows x86 loaders:';
            } else {
                echo '<li>Download one of the following archives of 32-bit Windows non-TS x86 loaders:';
            }
            echo make_archive_list(windows_package_name());
        } else {
            echo '<p>There may not be an ionCube Loader available for your type of system at the moment. However, if you create a <a href="'  . SUPPORT_SITE . '">support ticket</a> more advice and information may be available to assist. Please include the URL for this Wizard in your ticket.</p>';
        }
    } elseif (!$sysinfo['SUPPORTED_COMPILER']) {
        $supported_compilers = supported_win_compilers();
        $supported_compiler_string = join('/',$supported_compilers);
        echo '<p>At the current time the ionCube Loader requires PHP to be built with ' . $supported_compiler_string . '. Your PHP software has been built using ' . $sysinfo['PHP_COMPILER'] . '. Supported builds of PHP are available from <a href="https://windows.php.net/download/">PHP.net</a>.';
    } else {
        switch ($host_type) {
            case SERVER_SHARED:
                shared_server();
                break;
            case SERVER_DEDICATED:
                dedicated_server();
                break;
            case SERVER_LOCAL:
                local_install();
                break;
            default:
                echo server_selection_form();
                break;
        }
    }
}

function server_selection_form()
{
    $self = get_self();
    $timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?1:0;
    $hostprovider = (!empty($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $hostprovider = htmlspecialchars($hostprovider, ENT_QUOTES, 'UTF-8');
    $hosturl = (!empty($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $hosturl =  htmlspecialchars($hosturl, ENT_QUOTES, 'UTF-8');
    $form = <<<EOT
    <p>This Wizard will give you information on how to install the ionCube Loader.</p>
    <p>Please select the type of web server that you have and then click Next.</p>
    <script type=text/javascript>
        function trim(s) {
            return s.replace(/^\s+|\s+$/g,"");
        }
        function input_ok() {
            var l = document.getElementById('local');
            if (l.checked) {
                return true;
            } 

            var s = document.getElementById('shared');
            var d = document.getElementById('dedi');

            if (!s.checked && !d.checked) {
                alert("Please select one of the server types.");
                return false;
            } else {
                var hn = document.getElementById('hostprovider');
                var hu = document.getElementById('hosturl');
                var hostprovider = trim(hn.value);
                var hosturl = trim(hu.value);

                if (!hostprovider || !hosturl) {
                    alert("Please enter both a hosting provider name and their URL.");
                    return false;
                }
                if (hostprovider.length < 1) {
                    alert("The hosting provider name should be at least 1 character in length.");
                    return false;
                }
                if (!hosturl.match(/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+/)) {
                    alert("The hosting provider URL is invalid.");
                    return false;
                }
                if (hosturl.length < 4) {
                    alert("The hosting provider URL should be at least 4 characters in length.");
                    return false;
                }
            }
            return true;
        }
    </script>
    <form method=GET action=$self>
        <input type="hidden" name="page" value="default">
        <input type="hidden" name="timeout" value="$timeout">
        <input type=radio id=shared name=stype value=s onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=shared>Shared <small>(for example, server with FTP access only and no access to php.ini)</small></label><br>
        <input type=radio id=dedi name=stype value=d onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=dedi>Dedicated or VPS <small>(server with full root ssh access)</small></label><br>
        <div id="hostinginfo" style="display: none">If you are on a shared or dedicated server, please give your hosting provider and their URL:
            <table>
                <tr><td><label for=hostprovider>Name of your hosting provider</label></td><td><input type=text id="hostprovider" name=hostprovider value="$hostprovider"></td></tr>
                <tr><td><label for=hosturl>URL of your hosting provider</label></td><td><input type=text id="hosturl" name=hosturl value="$hosturl"></td></tr>
            </table>
        </div>
        <input type=radio id=local name=stype value=l onclick="document.getElementById('hostinginfo').style.display = 'none';"><label for=local>Local install</label>
        <p><input type=submit value=Next onclick="return (input_ok(this) && showOverlay());"></p>
    </form>
EOT;
    return $form;
}

function phpinfo_page()
{
    info_disabled_check();
    if (function_is_disabled('phpinfo')) {
        echo "phpinfo is disabled on this server";
    } else {
        @phpinfo();
    }
}

function loader_check_page($ext_name = LOADER_EXTENSION_NAME)
{
    heading();

    $rtl_path = try_runtime_loading_if_applicable();
	
    if (extension_loaded($ext_name)) {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        $php_str = ' for PHP ' . $phpv;
        echo '<div class="success">';
        echo '<h4>Loader Installed Successfully</h4>';
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' <strong>is installed</strong> and encoded files should run successfully.';
        if ($newer_version) {
            echo ' Please note though that you have an old version of the ionCube Loader.</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            loader_upgrade_instructions($lv,$newer_version);
        } else {
            echo '</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            if ($is_legacy_loader) {
                loader_upgrade_instructions($lv,true);
            }
        }
        successful_install_end_instructions($rtl_path);
    } else {
        echo '<div class="failure">';
        echo '<h4>Loader Not Installed</h4>';
        echo '<p>The ionCube Loader is <b>not</b> currently installed successfully.</p>';
	
        if (!is_null($rtl_path)) {
            echo '<p>Runtime loading was attempted but has failed.</p>';
            echo '</div>';
            $rt_errors = runtime_loading_errors();
            if (!empty($rt_errors)) {
                list_loader_errors($rt_errors);
            } 
            link_to_php_ini_instructions();
        } else {
            echo '</div>';
            list_loader_errors();
        }
    }
	
    send_stats('check');
    footer(true);
}

function ini_loader_errors()
{
    $errors = array();
    if (SERVER_SHARED == find_server_type() && !own_php_ini_possible(true)) {
        $errors[ERROR_INI_USER_CANNOT_CREATE] = "It appears that you are not be able to create your own ini files on your shared server. <br><strong>You will need to ask your server administrator to install the ionCube Loader for you.</strong>";
    }
    $loader_loc = find_loader(false);
    if (is_string($loader_loc)) {
        if (!shared_and_runtime_loading()) {
            $sys = get_sysinfo();
            if (empty($sys['PHP_INI'])) {
                $errors[ERROR_INI_NO_PATH] = 'No file path found for the PHP configuration file (php.ini).';
            } elseif (!@file_exists($sys['PHP_INI'])) {
                $errors[ERROR_INI_NOT_FOUND] = 'The PHP configuration file (' . $sys['PHP_INI'] .') cannot be found.';
            }
        }
        $errors = $errors + loader_compatibility_test($loader_loc);
    } else {
        $errors = $errors + $loader_loc;
        $fs_location = find_loader_filesystem();
        if (!empty($fs_location)) {
            $fs_loader_errors = loader_compatibility_test($fs_location);
            if (!empty($fs_loader_errors)) {
                $errors[ERROR_LOADER_WRONG_GENERAL] = "The loader file found at $fs_location is not the correct one for your system.";
            }
            $errors = $errors + $fs_loader_errors;
        }
    } 
    return $errors;
}

function unix_path_dir($dir = '')
{
    if (empty($dir)) {
        $dir = dirname(__FILE__);
    }
    if (is_ms_windows()) {
        $dir = str_replace('\\','/',substr($dir,2));
    }
    return $dir;
}

function unrecognised_inis_webspace($startdir)
{
    $ini_list = array();

    $ini_name = ini_file_name();
    $sys = get_sysinfo();
    $depth = substr_count($startdir,'/');

    $rel_path = '';
    $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
    for ($seps = 0; $seps < $depth; $seps++) {
        $full_ini_loc = @realpath($startdir . '/' . $rel_path) . DIRECTORY_SEPARATOR . $ini_name;
        if (@file_exists($full_ini_loc) && $sys['PHP_INI'] != $full_ini_loc) {
            $ini_list[] = @realpath($full_ini_loc);
        }

        if (dirname($full_ini_loc) == $rootpath) {
            break;
        }
        $rel_path .= '../';
    }
    return $ini_list;
}

function correct_loader_wrong_location()
{
    $loader_location_pair = array();
    $loader_location = find_loader_filesystem();
    if (is_string($loader_location) && !empty($loader_location)) {
        $loader_errors = loader_compatibility_test($loader_location);
        if (empty($loader_errors)) {
            $ini_loader = scan_inis_for_loader();
            if (!empty($ini_loader['location'])) {
                $ini_loader_errors = loader_compatibility_test($ini_loader['location']);
                if (!empty($ini_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = dirname($ini_loader['location']);
                }
            } else {
                $std_dir = loader_install_dir(find_server_type());
                $std_ld_path = $std_dir . DIRECTORY_SEPARATOR . get_loader_name();
                if (@file_exists($std_ld_path)) {
                    $stdloc_loader_errors = loader_compatibility_test($std_ld_path);
                } else {
                    $stdloc_loader_errors = array("Loader file does not exist.");
                }
                if (!empty($stdloc_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = $std_dir;
                }
            }
        }
    }
    return $loader_location_pair;
}

function ini_loader_warnings()
{
    $warnings = array();
    if (find_server_type() == SERVER_SHARED)
    {
        if (own_php_ini_possible()) {
            $sys = get_sysinfo();
            $ini_name = ini_file_name();
            $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
            $root_ini_file = $rootpath . DIRECTORY_SEPARATOR . $ini_name;
            $cgibinpath = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
            $cgibin_ini_file = (empty($cgibinpath))?'':$cgibinpath . DIRECTORY_SEPARATOR . $ini_name;
            $here = unix_path_dir();
            $ini_files = unrecognised_inis_webspace($here);
            $shared_ini_loc = shared_ini_location();
            $shared_ini_file = $shared_ini_loc . DIRECTORY_SEPARATOR . $ini_name;
            $ini_dir = dirname($sys['PHP_INI']);
            $all_ini_locations_used = !empty($ini_files);
            foreach ($ini_files as $full_ini_loc) {
                $advice = "The file $full_ini_loc is not being recognised by PHP.";
                $advice .= " Please check that the name and location of the file are correct.";
                if (!ini_same_dir_as_wizard()) {
                    $ini_loc_dir = dirname($full_ini_loc);
                    if (!@file_exists($shared_ini_file) && !empty($shared_ini_loc) && $ini_loc_dir != $shared_ini_loc && $ini_dir != $shared_ini_loc) {
                        $all_ini_locations_used = false;
                        $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $shared_ini_loc . "</code>.";
                    } else {
                        if (!@file_exists($root_ini_file) && $rootpath != $shared_ini_loc && $full_ini_loc != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $rootpath . "</code>.";
                        } 
                        if (!empty($cgibin_ini_file) && !@file_exists($cgibin_ini_file) && $cgibinpath != $shared_ini_loc && $full_ini_loc != $cgibinpath && $cgibinpath != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= "  Please try copying the <code>$full_ini_loc</code> file to <code>" . $cgibinpath . "</code>.";
                        }
                        $herepath = realpath($here);
                        $here_ini_file = $herepath . DIRECTORY_SEPARATOR . $ini_name;
                        if (!@file_exists($here_ini_file) && $herepath != $rootpath && $herepath != $cgibinpath) {
                            $all_ini_locations_used = false;
                            $advice .= " It may be necessary to copy the <code>$full_ini_loc</code> file to <code>$herepath</code> and to all " . (is_ms_windows()?'folders':'directories') . ' in which you have encoded files';
                        }
                    }
                } else {
                    $all_ini_locations_used = false;
                }
                $warnings[] = $advice;
            }
            if ($all_ini_locations_used) {
                $warnings[] = "<strong>It looks as if ini files are not being recognised in any of the standard locations in your webspace. Please contact your hosting provider to check whether you can create your own PHP ini file and where it should go.</strong>";
            }
        } else {
            if (own_php_ini_possible(true)) {
                $warnings[] = "You may not be able to create your own ini files on your shared server. <br><strong>You might need to ask your server administrator to install the ionCube Loader for you.</strong>";
            }
        }
    } else {
        $loader_dir_pair = correct_loader_wrong_location();
        if (!empty($loader_dir_pair)) {
            $advice = "The correct loader for your system has been found at <code>${loader_dir_pair['loader']}</code>."; 
            if ($loader_dir_pair['loader'] != $loader_dir_pair['newloc']) {
                $advice .= " Please copy the loader from <code>${loader_dir_pair['loader']}</code> to <code>${loader_dir_pair['newloc']}</code>.";
            }
            $warnings[] = $advice;
        }
    }
    return $warnings;
}

function list_loader_errors($errors = array(),$warnings = array(),$suggest_restart = true)
{
    $default = get_default_address();
    $retry_message = '';

    
    if (empty($errors)) {
        $errors = ini_loader_errors();
        if (empty($warnings)) {
            $warnings = ini_loader_warnings();
        }
    }
	
    if (!empty($errors)) {
        $try_again = '<a href="#" onClick="window.location.href=window.location.href">try again</a>';
	
        echo '<div class="alert">';
        if (count($errors) > 1) {
            echo 'The following problems have been found with the ionCube Loader installation:';
            $retry_message = "Please correct those errors and $try_again.";
        } else {
            echo 'The following problem has been found with the ionCube Loader installation:';
            $retry_message = "Please correct that error and $try_again.";
        }
        if (array_key_exists(ERROR_INI_USER_CANNOT_CREATE,$errors)) {
            $retry_message = '';
        }
        echo make_list($errors,"ul");
        echo '</div>';
        if (!empty($warnings)) {
            echo '<div class="warning">';
            echo 'Please also note the following:';
            echo make_list($warnings,"ul");
            echo '</div>';
        }
    } elseif (!empty($warnings)) {
        echo '<div class="warning">';
        echo 'There are the following potential problems:';
        echo make_list($warnings,"ul");
        echo '</div>';
    } elseif ($suggest_restart) {
        if (SERVER_SHARED == find_server_type()) {
            echo "<p>Please contact your server administrator about installing the ionCube Loader.</p>";
        } else {
            if (selinux_is_enabled()) {
                echo "<p>It appears that SELinux is enabled on your server. This might be solved by running the command <code>restorecon [full path to loader file]</code> as root.</p>";
            } elseif (grsecurity_is_enabled()) {
                echo "<p>It appears that grsecurity is enabled on your server. Please run the command, <code>execstack -c [full path to loader file]</code> and then restart your web server.</p>";
            } else {
                $sysinfo = get_sysinfo();
                $ss = $sysinfo['SS'];
				if ($ss == 'PHP-FPM') {
					echo "<p>Please check that PHP-FPM has been restarted.</p>";
                } elseif (!$sysinfo['CGI_CLI'] || is_ms_windows()) {
                    echo "<p>Please check that the $ss web server software has been restarted.</p>";
                } 
            }
        }
    }
    echo '<div>';
    echo $retry_message;
    echo " You may wish to view the following for further help:";
    echo make_list(help_resources($errors),"ul");
    echo '<a href="' . $default . '">Click here to go back to the start of the Loader Wizard</a>.</div>';
}

function phpconfig_page()
{
    info_disabled_check();
    $sys = get_sysinfo();
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        } else {
			if (!preg_match('`^.*\.ini$`',$ini_file_name) || preg_match('`/`',$ini_file_name) || preg_match('`\\\`',$ini_file_name)) {
				die("Illegal file name $ini_file_name");
			}
		}
        header('Content-Type: text/plain');
        header('Content-Disposition: attachment; filename=' . $ini_file_name);
    } else {
        header('Content-Type: text/plain');
    }
    $exclude_original = get_request_parameter('newlinesonly');
    $prepend = get_request_parameter('prepend');
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    if (!empty($exclude_original) || !empty($prepend)) {
        $loader_dir = loader_install_dir($server_type);
        $zend_lines = zend_extension_lines($loader_dir);
        echo join(PHP_EOL,$zend_lines);
        echo PHP_EOL;
    }
    if (empty($ini_file_name) || empty($sys['PHP_INI_DIR']) || ($sys['PHP_INI_BASENAME'] == $ini_file_name)) {
        $original_ini_file = isset($sys['PHP_INI'])?$sys['PHP_INI']:'';
    } else {
        $original_ini_file = $sys['PHP_INI_DIR'] . DIRECTORY_SEPARATOR . $ini_file_name;
    }
    if (empty($exclude_original) && !empty($original_ini_file) && @file_exists($original_ini_file)) {
        if (!empty($download)) {
            @readfile($original_ini_file);
        } else {
            echo all_ini_contents();
        } 
    }
}

function extra_page($check_access_to_info = true)
{
    if ($check_access_to_info) {
		info_disabled_check();
	}
    heading();
    $sys = get_sysinfo();
    $ini_loader = scan_inis_for_loader();
    $ini_loader_path = $ini_loader['location'];
    $loader_path = find_loader(true);
    $ldinf = get_loaderinfo();
    $self = get_self();
    echo "<h4>Additional Information</h4>";
    echo "<table>";
    $lines = array();
    if (is_string($loader_path)) {
        $lines['Loader is at'] = $loader_path;
        $loader_system = loader_system($loader_path);
        if (!empty($loader_system)) {
            $lines['Loader OS code'] = $loader_system['oscode'];
            $lines['Loader architecture'] = $loader_system['arch'];
            $lines['Loader word size'] = $loader_system['wordsize'];
            $lines['Loader PHP version'] = $loader_system['php_version'];
            $lines['Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Loader compiler'] = $loader_system['compiler'];
            $lines['Loader version'] = $loader_system['loader_version'];
            $lines['File size is'] = filesize($loader_path) . " bytes.";
            $lines['MD5 sum is'] = md5_file($loader_path);
        }
        $lines['Loader file'] = "<a href=\"$self?page=loaderbin\">Download loader file</a>";
    } else {
        $lines['Loader file'] = "Loader cannot be found.";
    }
    $lines['Loader found in ini file'] = empty($ini_loader_path)?"No":"Yes";
    if (!empty($ini_loader_path) && (!is_string($loader_path) || $ini_loader_path != $loader_path)) {
        $lines['Loader location found in ini file'] =  $ini_loader_path;
        $loader_system = loader_system($ini_loader_path);
        if (!empty($loader_system)) {
            $lines['Ini Loader OS code'] = $loader_system['oscode'];
            $lines['Ini Loader architecture'] = $loader_system['arch'];
            $lines['Ini Loader word size'] = $loader_system['wordsize'];
            $lines['Ini Loader PHP version'] = $loader_system['php_version'];
            $lines['Ini Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Ini Loader compiler'] = $loader_system['compiler'];
            $lines['Ini Loader version'] = $loader_system['loader_version'];
        }
    }
    $lines["OS extra security"] = (selinux_is_enabled() || possibly_selinux())?"SELinux":(grsecurity_is_enabled()?"Grsecurity":"None");
    $lines['PHPRC is'] = $sys['PHPRC'];
    $lines['INI DIR is'] = $sys['PHP_INI_DIR'];
    $lines['Additional INI files'] = $sys['PHP_INI_ADDITIONAL'];
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    $lines['Server type is'] = server_type_string();
    $lines["PHP uname"] = $ldinf['uname'];
    $lines['Server word size is'] = $ldinf['wordsize'];
    $lines['Disabled functions'] = ini_get('disable_functions');
    $writeable_dirs = writeable_directories();
    $lines['Writeable loader locations'] = (empty($writeable_dirs))?"<em>None</em>":join(", ",$writeable_dirs);
    if (!empty($_SESSION['hostprovider'])) {
        $lines['Hosting provider'] = $_SESSION['hostprovider'];
        $lines['Provider URL'] = $_SESSION['hosturl'];
    }
    foreach ($lines as $h => $i) {
        $v = (empty($i))?'<em>EMPTY</em>':$i;
        echo '<tr><th>'. $h . ':</th>' . '<td>' . $v . '</td></tr>';
    }
    echo "</table>";
    footer(true);
}

function loaderbin_page()
{
    info_disabled_check();
    $loader_path = find_loader(true);
    if (is_string($loader_path)) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. basename($loader_path));
        @readfile($loader_path);
    }
}



function GoDaddy_root($html_root = '')
{
    if (empty($_SESSION['not_go_daddy']) && empty($_SESSION['godaddy_root'])) {
        $godaddy_pattern = "[\\/]home[\\/]content[\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z]+[\\/]html";

        if (empty($html_root)) {
            $html_root =  $_SERVER['DOCUMENT_ROOT'];
        }
        if (preg_match("@$godaddy_pattern@i",$html_root,$matches)) {
            $_SESSION['godaddy_root'] = $matches[0];
        } else {
            $_SESSION['not_go_daddy'] = 1;
            $_SESSION['godaddy_root'] = '';
        } 
    } elseif (!empty($_SESSION['not_go_daddy'])) {
        $_SESSION['godaddy_root'] = '';
    }
    if (!empty($_SESSION['godaddy_root'])) {
        $_SESSION['hostprovider'] = 'GoDaddy';
        $_SESSION['hosturl'] = 'www.godaddy.com';
    }
    return $_SESSION['godaddy_root'];
}

function GoDaddy_windows_instructions()
{
    $instr = "It appears that you are hosted on a Windows server at GoDaddy.<br/>";
    $instr .= "Please change to a Linux hosting plan at GoDaddy.<br />";
    $instr .=  "If you <a href=\"https://help.godaddy.com/\">contact their support team</a> they should be able to switch you to a Linux server.";

    echo $instr;
}

function GoDaddy_linux_instructions($html_dir)
{
    $base = get_base_address();
    $loader_name = get_loader_name();
    $zend_extension_line="<code>zend_extension = $html_dir/ioncube/$loader_name</code>";
    $php_ini_name = is_php_version_or_greater(5,0)?'php5.ini':'php.ini';
    $ini_path = $html_dir . '/' . $php_ini_name;

    $instr = array();
    $instr[] = 'In your html directory, ' . $html_dir . ', create a sub-directory called <b>ioncube</b>.';
    if (@file_exists($ini_path)) {
       $instr[] = "Edit the $php_ini_name in your  $html_dir and add the following line to the <b>top</b> of the file:<br>" . $zend_extension_line ;
    } else {
        $instr[] = "<a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=s&amp;download=1&amp;prepend=1\">Save this $php_ini_name file</a> and upload it to your html directory, $html_dir";
    }
    $instr[] = 'Download the <a target="_blank" href="' . IONCUBE_DOWNLOADS_SERVER . '"/ioncube_loaders_lin_x86.zip">Linux ionCube Loaders</a>.';
    $instr[] = 'Unzip the loaders and upload them into the ioncube directory you created previously.';
    $instr[] = 'The encoded files should now be working.';

    echo '<div class=panel>';
    echo (make_list($instr));
    echo '</div>';
}

function GoDaddy_page()
{
    $base = get_base_address();

    heading();

        $inst_str = '<h4>GoDaddy Installation Instructions</h4>';
        $inst_str .= '<p>It appears that you are hosted with GoDaddy (<a target="_blank" href="https://www.godaddy.com/">www.godaddy.com</a>). ';
        $inst_str .= "If that is <b>not</b> the case then please <a href=\"$base&amp;page=default&amp;host=ngd\">click here to go to the main page of this installation wizard</a>.</p>";
        $inst_str .= "<p>If you have already installed the loader then please <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the loader</a>.</p>";

        echo $inst_str;

        if (is_ms_windows()) {
            GoDaddy_windows_instructions();
        } else {
            GoDaddy_linux_instructions($_SESSION['godaddy_root']);
        }

    send_stats('gd_default');

    footer(true);
}



function get_request_parameter($param_name)
{
    static $request_array;

    if (!isset($request_array)) {
        if (isset($_GET)) {
            $request_array = $_GET;
        } elseif (isset($HTTP_GET_VARS)) {
            $request_array = $HTTP_GET_VARS;
        }
    }

    if (isset($request_array[$param_name])) {
        $return_value = strip_tags($request_array[$param_name]);
    } else {
        $return_value = null;
    }
    return $return_value;
}

function make_list($list_items,$list_type='ol')
{
    $html = '';
    if (!empty($list_items)) {
        $html .= "<$list_type>";
        $html .= '<li>';
        $html .= join('</li><li>',$list_items);
        $html .= '</li>';
        $html .= "</$list_type>";
    }
    return $html;
} 

function make_archive_list($basename,$archives_list = array(),$download_server = IONCUBE_DOWNLOADS_SERVER)
{
    if (empty($archives_list)) {
        $archives_list = array('tar.gz','zip');
    }

    foreach ($archives_list as $a) {
        $link_text = $a;
        $ext_sep = '.';
        $archive_list[] = "<a href=\"$download_server/$basename$ext_sep$a\">$link_text</a>";
    }

    return make_list($archive_list,"ul");
}

function error($m)
{
    die("<b>ERROR:</b> <span class=\"error\">$m</span><p>Please help us improve this script by <a href=\"". SUPPORT_SITE . "\">reporting this error</a> and including the URL to the script so that we can test it.");
}


function filter_server_input($server_var)
{
	$res = htmlspecialchars($_SERVER[$server_var], ENT_QUOTES, "UTF-8");
	return $res;
}

function failsafe_get_self()
{
    $result = '';
    $sfn = filter_server_input('SCRIPT_FILENAME');
    $dr = $_SERVER['DOCUMENT_ROOT'];
    if (!empty($sfn) && !empty($dr)) {
        if ($dr == '/' || $dr == '\\') {
            $result = $sfn;
        } else {
            $drpos = strpos($sfn,$dr);
            if ($drpos === 0) {
                $drlen = strlen($dr);
                $result = substr($sfn,$drlen);
            }
        }
        $result = str_replace('\\','/',$result);
    }
    if (empty($result)) {
        $result = DEFAULT_SELF;
    }
    return $result;
}

function get_self()
{ 
	$page = '';
    if (empty($_SERVER['PHP_SELF'])) {
        if (empty($_SERVER['SCRIPT_NAME'])) {
            if (empty($_SERVER['REQUEST_URI'])) {
                $page = failsafe_get_self();
            } else {
                $page = filter_server_input('REQUEST_URI');
            }
        } else {
            $page = filter_server_input('SCRIPT_NAME');
        }
    } else {
        $page = filter_server_input('PHP_SELF');
    }
	return $page;
}

function get_default_page()
{
    $godaddy_root = GoDaddy_root();
    if (empty($godaddy_root)) {
         $page = 'default';
    } else {
         $page = 'GoDaddy';
    }
    return $page;
}

function get_base_address()
{
    $self = get_self();
    $remote_timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?'timeout=1':'timeout=0';
    $using_ini = (isset($_SESSION['use_ini_method']) && $_SESSION['use_ini_method'])?'ini=1':'ini=0';
    return $self . '?' . $remote_timeout . '&' . $using_ini;
}

function get_default_address($include_timeout = true)
{
    if ($include_timeout) {
        $base =  get_base_address();
        $base .= "&amp;";
    } else {
        $base = get_self();
        $base .= "?";
    }
    $page = get_default_page();

    return $base . 'page=' . $page;
}

function heading()
{
    $self = get_self();

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <meta name="robots" content="noindex, nofollow">
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <script type="text/javascript">
            function showOverlay()
            {
                document.getElementById('overlay').style.display = 'block';
                return true;
            }

            function hideOverlay()
            {
                document.getElementById('overlay').style.display = 'none';
                return true;
            }
        </script>
    </head>
    <body onload="hideOverlay()">
    <div id="overlay">
        <div id="inner_overlay">Checking server configuration<br>Please wait</div>
    </div>
    <div id="header">
        <img src="?page=logo" alt="ionCube logo">
    </div>
	<div id="important">
	<h3 class="important">IMPORTANT: Ensure that This Script Is Removed When No Longer Required</h3>
	</div>
    <div id="main">
    <h2>ionCube Loader Wizard</h2>
EOT;
}

function footer($update_info = null)
{
    $self = get_self();
    $base = get_base_address();
    $default = get_default_address(false);
    $year = gmdate("Y");

    echo "</div>";
    echo "<div id=\"footer\">" .
    "Copyright ionCube Ltd. 2002-$year | " .
    "Loader Wizard version " . script_version() . " ";

    if ($update_info === true) {
        $update_info = check_for_wizard_update(false);  
    }
    $loader_wizard_loc = LOADER_WIZARD_URL;
    $wizard_version_string =<<<EOT
    <script type="text/javascript">
    var xmlhttp;
    function version_check()
    { 
        var body = document.getElementsByTagName('body')[0];
        var ldel = document.getElementById('loading');
        if (!ldel) {
            body.innerHTML += '<div id="loading"></div>';
            ldel = document.getElementById('loading');
        }
        ldel.innerHTML = '<p>Retrieving Wizard version information<br>Please wait</p>';
        ldel.style.display = 'block';
        ldel.style.height = '300px';
        ldel.style.left = '200px';
        ldel.style.border = '4px #660000 solid';
        if (window.XMLHttpRequest) {
            xmlhttp=new XMLHttpRequest();
        } else {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            var loadedOkay = 0;
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                var wizardversion = xmlhttp.responseText;
                var msg;
                clearTimeout(xmlHttpTimeout);
                buttons = '';
                if (wizardversion == '1') {
                    msg = 'You have the current version of the<br>ionCube Loader Wizard'; 
                } else if (wizardversion != '0') {
                    msg = 'A new version, ' + wizardversion + ', of the loader wizard is available';
                    buttons = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; window.open(\'$loader_wizard_loc\'); return false">Get new version</button> &nbsp;'; 
                } else {
                    msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
                }
                buttons += '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>'; 
                ldel.innerHTML = '<p>' + msg +  '<br>' + buttons + '</p>';
            }
        }
        xmlhttp.open("GET",'$self?page=wizardversion&wizard_only=1&clear_info=1',true);
        xmlhttp.send();
        var xmlHttpTimeout=setTimeout(ajaxTimeout,7000);
    }
    function ajaxTimeout(){
       xmlhttp.abort();
       msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
       button = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>';
       var ldel = document.getElementById('loading');
       ldel.innerHTML = '<p>' + msg +  '<br>' + button + '</p>';
    }
    </script>
EOT;

    $wizard_version_string .= '('; 
    if ($update_info === null) {
        $wizard_version_string .= '<a target="_blank" href="' . $loader_wizard_loc . '" onclick="version_check();return false;">check for new version</a>';
    } else if ($update_info !== false) {
        $wizard_version_string .= '<a href="' . LOADERS_PAGE .'" target="_blank">download version ' . $update_info . '</a>';
    } else {
        $wizard_version_string .=  "current";
    }
    $wizard_version_string .= ')'; 
    echo $wizard_version_string;

    $server_type_code = server_type_code();
	
	if (!info_should_be_disabled(true)) {
		echo " | <a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo</a>";
		echo " | <a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a>";
		echo " | <a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional</a>";
	}

    echo " | <a href=\"$default\" onclick=\"showOverlay();\">wizard start</a>";
    echo " | <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">loader test</a>";
    echo ' | <a href="' . LOADERS_PAGE . '" target="loaders">loaders</a>';

    echo "</div>\n";
    echo "\n</body></html>\n";
}

function css_page()
{
    header('Content-Type: text/css');
    echo <<<EOT
    body {
        font-family: verdana, helvetica, arial, sans-serif;
        font-size: 10pt;
        line-height: 150%;
        margin: 0px;
        min-height: 400px;
        position: relative;
    }

    code {
        color: #c00080;
    }

    li {
        margin-top: 10px;
    }
    #overlay {
        display: block;
        z-index: 100;
        position: absolute;
        top: 0;
        left: 0;
        padding: 0;
        margin: 0;
        width: 100%;
        height: 100%;
        background-color: white;
    }
    #inner_overlay {
        display: block;
        z-index: 100;
        position: absolute;
        font-size: 200%;
        color: #660000;
        top: 50%;
        left: 25%;
        width: 460px;
        height: 460px;
        line-height: 200%;
        text-align: center;
        vertical-align: middle;
    }

    #loading {
        display: block;
        position: absolute;
        top: 33%;
        left: 25%;
        margin: auto;
        height: 320px;
        width: 460px;
        padding: 4px;
        color: #660000;
        background-color: white;
        z-index: 100;
    }

    #loading p {
        position: absolute;
        margin-top: 10px;
        text-align: center;
        vertical-align: middle;
        padding-left: 40px;
        padding-right: 30px;
        font-size: 200%;
        line-height: 200%;
    }

    #loading p span#status{
        font-size: 60%;
        line-height: 120%;
    }
    #loading p#noscript {
        font-size: 120%;
        line-height: 120%;
        position: absolute;
        text-align: left;
        padding-top: 10px;
        bottom: 0;
    }
    #loading p#noscript a {
        text-align: center;
    }

    #loading button {
        margin-top: 20px;
        line-height: 100%;
        padding-top: 4px;
        padding-bottom: 4px;
    }


    h4 {
        margin-bottom: 0;
        padding-bottom: 4px;
    }

    p,#main div {
        max-width: 1000px;
        width: 75%;
    }

    #hostinginfo {
        margin-top: 10px;
        margin-left: 20px;
    }
    #hostinginfo table {
        font-size: 1.00em;
    }
    #hostinginfo table td {
        padding-right: 4px;
    }
    #hostinginfo input {
        margin-top: 6px;
    }

    #hostinginfo label {
        margin-left: 6px;
    }

    th {
        text-align: left;
    }
	
	#important {
		margin-top: 12px;
	} 
	h3.important {
		margin: 0;
		border: 0;
        border-top: 1px solid #660000;
		border-bottom: 1px solid #660000;
        padding: 1ex 0 1ex 0;
        background-color: #CB2430;
		text-align: center;
        color: #ffffff; 
        width: 100%;
	}

    .alert {
        margin: 2ex 0;
        border: 1px solid #660000;
        padding: 1ex 1em;
        background-color: #ffeeee;
        color: #660000; 
        width: 75%;
    }

    .warning {
        margin: 2ex 0;
        border: 1px solid #FFBF00;
        padding: 1ex 1em;
        background-color: #FDF5E6;
        color: #000000; 
        width: 75%;
    }

    .success {
        margin: 2ex 0;
        border: 1px solid #006600;
        padding: 1ex 1em;
        background-color: #EEFFEE;
        color: #000000; 
        width: 75%;
    }

    .error {
        color: #FF0000;
    }

    .panel {
        border: 1px solid #c0c0c0;
        background-color: #f0f0f0;
        width: 75%;
        padding: 1ex 1em;
    }
	
	.terminal {
		border: none;
		background-color: #000000;
		color: #ffffff;
		width: 50%;
		padding: 1ex 1em;
	}

    #header {
        background: #fff;
    }

    #footer {
        border-top: 1px solid #404040;
        margin-top: 20px;
        padding-top: 10px;
        padding-left: 20px;
        font-size: 75%;
        text-align: left;
    }

    #main {
        margin: 20px;
    }
	
	
	#main .ic24 {
		position: relative;
		width: 75%;
		height: auto;
		border-width: 1px 1px 1px 1px;
		border-style: solid;
		border-color: #4B8DF8;   
		background-color: #EFEFFF;
		padding: 12px;
		padding-top: 16px;
		padding-bottom: 8px;
		margin-top: 20px;
		overflow: hidden;
	}
	
	#main .ic24 p {
		width: 100%;
	}
	
	
	#main .ic24graphic {
		position: relative;
		width: auto;
		height: auto;
		border: none;
		padding: 0px;
		padding-right: 16px;
		margin: 0px;
		float: left;
		
	}
	
	#main #ic24info {
		position: relative;
		width: auto;
		height: auto;
		float: left;
	}
	
	#main #ic24info a {
		color: #0B4DB8;
		text-decoration: none;
	}
	
	#main #ic24logo {
		max-width: 132px;
		max-height: 132px;
	}
	
EOT;
}

function logo_page()
{
$img_encoded = 'iVBORw0KGgoAAAANSUhEUgAAAakAAACABAMAAABD1osiAAAAKlBMVEUAAAAAAADnHCwAAAAAAAAAAAAAAAAAAABMCQ4AAADnHCznHCznHCwAAAAjcBE1AAAADHRSTlMAeDRHwSqg4BJl/PLTJLuIAAAF1UlEQVR42u2by4vTQBzHp3TTzR6EBtfXYS/+BZW6Pg6FFavgoRDBBx4KFd+HQgWFvQQqiuJhoeL7sP+LR0EPlj6yPfz+F5NMZ77TmmJjM3ZT5nNpOzvNzGcev5lMusxgMBgMBoPBYDAYDAaDwWDQwel5YRnC/jkvbZYdjFV2MFbZwVhlB2OVIVZyb2HIED/n5AfLEj/nhWUJY5UdjFV2MFbZwVgdMqzNZydXz2qrf59Kq2a1NmTsRnfVrLZOfj3VrrkrZuVb/dpBvZEJqzOOc5TNQ75rjXKDtV+ZsNoi6rJ52OhZwxONwiGwsi46zqnt1Kx8r7N8q/wmRfhP3BSsrK7VW/u13krDysGwT8o5kvilxa2YZ/U2eulEC0KhCTlLCo0UrPYff7Tfe+2lWt0glTT6qjB02e0eW6ZVjiZYaF4hq+eXlmll1yik75TL5eMeDVOxsj89hNQyrN5QyDFRm9GCVmCZVrYXBr4OE9w8ZFbBCNr+x646ycAhs/o3moFUj62Y1UY4/txVs9oLrAZs1azCAVhaNSsLgXNpVt/+dlNXZAplx4mLiXecU5hHhcBqN6lV/p3znk1xEYUltfr+t0J/4dN1jwKGWIg+VKuBdL5JAQ9EYj34ILOAjWq12lG+eE2xsk9EF/7CFN7WKOCpq9kK2/CTyp93mFUbpyKRZmwNi2oX4Y0dfgULd8QL4vRdvVavJ+6XYLVPIQjmHq9xAqvbJBTa8paTBCOtVpZHY1DrSmCF7flABotBIiuLJM+RQdJJO1qoVnUKqfLh1pBWrX10YVu0ciuRVXjlfpUiXGSmp85xdFaaT7thZUV95I5DRldaDYJPT8oXmyQqnYP0nFZetL23tgjtsT/e8uc9mKa3XsFqL3Rpy3YsCSufhwmrJgbeGmo/jxUCjd2UzWWFg1EuEzv6rJoY4ftyQapghBRElda5cxKrEfaPvGPWw+Esyx1ps8pHhaP0LqxK8p7KZwFHklt1kEqNcbsNcFfT12a1zgtEv7WFVZehB93xUGVJrPg7MXgPxotDUWlCV5dVhYtgjhV5KuLd+jixktjqYHoHmVcLw9fSt2ry8lDBlrAqKomN5FZI5aX0+Rztqmk7uqywtGKhRQ+KmbeT3AoDDN89gsJQBQ1WWFrFpmgkIruq2kpuhWCASFNBYXxN1GGFKk1XqqLWiXjeOvpv3n2gpBDm4dtL1aqnyaqAcA2bGCu0d3Ir5GkSPasKsFlO3WpNGf68P3wdVhs84tRIRZ/VEUwWfIyxwo4puRUiDh0+q2jntnJWOf6aplVv+VZ5VGMBq3tlhQuarNYnw3V9Zgzkr8PFYiByAi0xcM7ILva+7kJWNeyktVoV5l2FeSI1kluh8UKrlnar6dv2qNhejBVG6yDeaifOajg5X9tR4sH/sLIIBeFTjJV4JMImmd5KNmGFvHxfyV9Guq2mDvnQc9NWyIuOBWrD2BSzZ4fsHi6rzUq26cRdY2e2VSU+ChJ6IDdh1Zi+wylAVa9VfWqu+2y2VYFiO6uGzHsTVj01WOxgsOq3KqB0nMbMsLK96fNxKVASgrDCSogcHjpbq5WNg1WcVsRY4Zi3i1Xblqm7OLFXrHbRWn2GxUG/FduX0yIHwRlWFomD3ojrT+Vxje+KE3tYiQ6ym3JJKKidnW9rscJkuSwOiUdsphXO5P2724y9PPOI+njMMSyxOzWiTViF7/0v4kS6gzEcZA0545X0WbFmVClnk1B4vJXsDYArcPzXitUxCnhW5f070SyXHGfTw1jUYVUgMGKzrTBKQQk/LonYzSlWxToyFuOapaXRim2hqd2/WbFbJEBlLTx8k1a1QNmaai0eUMBAp5XVFFIdNtMqVqs/nhmvpGQuSJRWUmHoMsl5klzRacWsE4Sn3TOswMtH9Mfvbj+L36JNWrFzUgqcE6ofdf8X9PXN6qWjbF5eOverV51ye/ICd+NCWv549er0ha3o69vMYDAYDAaDwWAwGAwGg8FgSJffF2mwYDNbStYAAAAASUVORK5CYII=';

    header('Content-Type: image/png');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}

function ic24logo_page()
{
	$img_encoded = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6b3NiPSJodHRwOi8vd3d3Lm9wZW5zd2F0Y2hib29rLm9yZy91cmkvMjAwOS9vc2IiCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB2ZXJzaW9uPSIxLjAiCiAgIHdpZHRoPSI2OTAiCiAgIGhlaWdodD0iNjkxLjI1IgogICB2aWV3Qm94PSIwIDAgNTUyIDU1MyIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgaWQ9InN2ZzMwMzUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImlvbkN1YmUyNF9jdWJlLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwODMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzQ5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTM1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzMzkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzMxIgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTMzMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzMjUiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzI3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NSIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4ODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NzMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODc1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDEiCiAgICAgICB4MT0iNDQzNS40NDI0IgogICAgICAgeTE9IjI5NDkuMDQyIgogICAgICAgeDI9IjQ4MzQuMzkyMSIKICAgICAgIHkyPSIyOTQ5LjA0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTgiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjAiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxOCIKICAgICBpZD0ibmFtZWR2aWV3MzA4MSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC45NjUzODc0IgogICAgIGlua3NjYXBlOmN4PSI3MjQuNTI3MjIiCiAgICAgaW5rc2NhcGU6Y3k9IjMzMy4xMTQ1MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMzAzNSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMCIKICAgICBmaXQtbWFyZ2luLWxlZnQ9IjAiCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIKICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDM3Ij4KQ3JlYXRlZCBieSBwb3RyYWNlIDEuMTEsIHdyaXR0ZW4gYnkgUGV0ZXIgU2VsaW5nZXIgMjAwMS0yMDEzCjxyZGY6UkRGPgogIDxjYzpXb3JrCiAgICAgcmRmOmFib3V0PSIiPgogICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICA8ZGM6dHlwZQogICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICA8L2NjOldvcms+CjwvcmRmOlJERj4KPC9tZXRhZGF0YT4KICA8ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMSwwLDAsLTAuMSwtNCw1NTcpIgogICAgIGlkPSJnMzAzOSIKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO3N0cm9rZTpub25lIj4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIC0yLDg2OCAtMyw4NjcgLTg2NywzIC04NjgsMiAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA0MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDMiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDM4MjcsNTU2MyBjIC00LC0zIC03LC0zOTUgLTcsLTg3MCBsIDAsLTg2MyA4NzAsMCA4NzAsMCAwLDg3MCAwLDg3MCAtODYzLDAgYyAtNDc1LDAgLTg2NywtMyAtODcwLC03IHoiCiAgICAgICBpZD0icGF0aDMwNDUiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDI4MDAgMCwtODcwIDg2OCwyIDg2NywzIDMsODY4IDIsODY3IC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDciCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDE5MzAsMjgwMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiBtIDEwMzUsNjMwIGMgODAsLTMxIDE1NCwtMTAyIDE5MSwtMTgzIDI1LC01NCAyOCwtNzQgMjksLTE1NyAwLC0xOTAgLTc0LC0zMTggLTM0NCwtNTkyIGwgLTE3NCwtMTc4IDI3NiwwIDI3NywwIDAsLTgwIDAsLTgwIC00MDcsMiAtNDA4LDMgLTMsNTYgLTMsNTUgMTgxLDE3NCBjIDM1NSwzMzkgNDUyLDQ5MyA0MjMsNjY3IC0xOSwxMDYgLTcxLDE2MiAtMTcyLDE4NCAtOTIsMjAgLTIwMiwtNiAtMjkzLC02OSBsIC00NiwtMzEgLTI2LDU4IGMgLTE0LDMyIC0yNiw2MiAtMjYsNjYgMCwyMiAxNDcsOTkgMjI4LDEyMCA4MiwyMSAyMjEsMTQgMjk3LC0xNSB6IgogICAgICAgaWQ9InBhdGgzMDQ5IgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAzODIyLDI4MDMgMywtODY4IDg2OCwtMyA4NjcsLTIgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAyLC04NjcgeiBtIDExNzgsMjQyIDAsLTM5NSA5MCwwIDkwLDAgMCwtNzAgMCwtNzAgLTkwLDAgLTkwLDAgMCwtMTcwIDAsLTE3MCAtODUsMCAtODUsMCAwLDE3MCAwLDE3MCAtMjkwLDAgLTI5MCwwIDAsNjMgMCw2NCAyODEsNDAxIDI4MSw0MDIgOTQsMCA5NCwwIDAsLTM5NSB6IgogICAgICAgaWQ9InBhdGgzMDUxIgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA0NzkwLDMxNzMgYyAtMjQsLTQzIC0xMTEsLTE3MiAtMTk1LC0yODggLTgzLC0xMTUgLTE1NSwtMjE2IC0xNTksLTIyMiAtNiwtMTAgMzUsLTEzIDE5MywtMTMgbCAxOTksMCA0LDI5OCBjIDIsMTYzIDMsMjk4IDIsMzAwIC0xLDIgLTIxLC0zMiAtNDQsLTc1IHoiCiAgICAgICBpZD0icGF0aDMwNTMiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NTM0MSk7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTg1MTYsMTc0MyBjIC0zLC04MzUgLTksLTE1NTMgLTEyLC0xNTk1IGwgLTYsLTc4IDE3MCwwIDE3MCwwIDcsODggYyAzLDQ4IDksMTI3IDEzLDE3NiBsIDcsODkgNDAsLTU5IGMgNTMsLTc3IDE2MCwtMTgxIDIyOSwtMjIzIDEyOCwtNzcgMjQ4LC0xMTEgNDIxLC0xMTggMjEwLC05IDM4NywzOCA1NTIsMTQ3IDI3NiwxODEgNDM4LDQ4MiA0NzQsODc5IDM5LDQzMyAtMTA1LDgzOSAtMzc1LDEwNTYgLTE1NSwxMjUgLTMzMCwxODUgLTU0MSwxODUgLTE5OSwwIC0zNTcsLTQwIC00OTMsLTEyNiAtNzEsLTQ1IC0xODMsLTE1MyAtMjI1LC0yMTkgbCAtMzIsLTUwIC0zLDY4MyAtMiw2ODIgLTE5NCwwIC0xOTQsMCAtNiwtMTUxNyB6IG0gMTE1NSwyMjMgYyAxNDksLTMyIDMwNSwtMTQ4IDM4OCwtMjg5IDc5LC0xMzUgMTIxLC0zMTMgMTIxLC01MTIgMCwtMTk2IC0zNSwtMzU2IC0xMDgsLTUwMCAtNDMsLTg0IC0xNzEsLTIxNyAtMjQ5LC0yNTggLTc3LC00MSAtMTkyLC02NyAtMjk0LC02NyAtMTE2LDAgLTE3NywxMyAtMjc4LDYyIC0xNDYsNjkgLTI1OCwyMDMgLTMxNywzNzggLTE3LDQ5IC0xOSw4OCAtMTksMzYwIDAsMzA1IDAsMzA1IDI3LDM4NSAzNywxMDkgOTEsMTk2IDE2OSwyNzUgNzQsNzQgMTkwLDE0MSAyODYsMTY0IDc2LDE5IDE5MSwxOSAyNzQsMiB6IgogICAgICAgaWQ9InBhdGgzMDU1IgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE3NCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTQ2MTAsMzEzOSBjIC01MTgsLTY1IC05NDQsLTM1NyAtMTE2NCwtNzk3IC0xNDEsLTI4MCAtMjAxLC02MzYgLTE2NiwtOTgzIDcyLC03MTEgNDgwLC0xMTc3IDExNDcsLTEzMTAgMjExLC00MiA1NTcsLTM2IDgxMywxMiAxMTksMjMgMzIwLDg2IDMyNiwxMDMgNiwxNyAtNzIsMzExIC04MiwzMDkgLTUsLTEgLTQ5LC0xNiAtOTcsLTMzIC0xNDcsLTUyIC0yNjIsLTcxIC00NzAsLTc3IC0yMTAsLTYgLTMyMCw0IC00NTcsNDQgLTQzNywxMjYgLTcwNSw0NzIgLTc2MSw5NzkgLTE1LDE0MCAtNSwzODggMjAsNTE0IDYwLDI5OSAxOTgsNTM2IDQwMyw2OTAgMjIzLDE2OSA0NzIsMjM4IDgwOCwyMjcgMTg0LC02IDMwNywtMjggNDQyLC03OCA0NiwtMTYgODksLTMxIDk2LC0zMiA5LC0xIDMwLDQ5IDYyLDE1MyAyNyw4NSA0OCwxNTUgNDcsMTU2IC01Miw0MCAtMjc2LDEwMSAtNDU3LDEyMyAtOTcsMTMgLTQxNCwxMiAtNTEwLDAgeiIKICAgICAgIGlkPSJwYXRoMzA1NyIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNzApIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczNzAsMjg1NSAwLC0xOTUgMjEwLDAgMjEwLDAgMCwxOTUgMCwxOTUgLTIxMCwwIC0yMTAsMCAwLC0xOTUgeiIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNjYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIzODg2LDMwMjQgYyAtOTksLTE4IC0yNjQsLTczIC0zNDgsLTExNSAtNzEsLTM1IC0yMTgsLTEzMCAtMjM3LC0xNTMgLTEwLC0xMiAwLC00MCA1MCwtMTUwIDM0LC03NSA2MywtMTM2IDY1LC0xMzYgMSwwIDM2LDI0IDc3LDUzIDE2NiwxMTkgMzI0LDE3NiA1MTMsMTg0IDMwOCwxNCA1MDMsLTEwOCA1ODAsLTM2MiAxNCwtNDYgMTksLTkzIDE5LC0yMDAgLTEsLTE3MSAtMTksLTI0NyAtMTAwLC00MTAgLTEzMCwtMjYxIC0zODAsLTU0MyAtMTA0NCwtMTE4MCBsIC0yNTAsLTI0MCAtMSwtMTIyIDAsLTEyMyA5MzUsMCA5MzUsMCAwLDE2NSAwLDE2NSAtNjU3LDAgLTY1NywwIDEwOSwxMDEgYyA2MSw1NiAyMTgsMjEwIDM1MCwzNDMgMzQyLDM0NSA1MTgsNTYzIDYzNCw3ODYgMTc5LDM0NSAxOTgsNjc4IDU3LDk2NSAtODEsMTYzIC0xODgsMjcwIC0zNTEsMzUxIC0xNDEsNzAgLTIxOSw4NiAtNDI1LDkwIC0xMjUsMiAtMTk4LC0xIC0yNTQsLTEyIHoiCiAgICAgICBpZD0icGF0aDMwNjEiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE2MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMjY2ODEsMjk3NyBjIC02LC04IC0yOTksLTQyNSAtNjUxLC05MjggbCAtNjQwLC05MTQgMCwtMTMyIDAsLTEzMyA2ODAsMCA2ODAsMCAwLC00MDAgMCwtNDAwIDE4NSwwIDE4NSwwIDAsNDAwIDAsNDAwIDIwNSwwIDIwNSwwIDAsMTU1IDAsMTU1IC0yMDUsMCAtMjA1LDAgMCw5MDUgMCw5MDUgLTIxNCwwIGMgLTE2NiwwIC0yMTYsLTMgLTIyNSwtMTMgeiBtIDcxLC0xMDg0IC0zLC03MTMgLTQ4MCwwIGMgLTM4MiwwIC00NzksMyAtNDczLDEzIDUsNiAxNjYsMjMwIDM1OCw0OTcgMzQ3LDQ4MSAzOTksNTYwIDUzMCw3OTggMzgsNjggNjksMTIyIDcwLDEyMCAwLC0yIDAsLTMyNCAtMiwtNzE1IHoiCiAgICAgICBpZD0icGF0aDMwNjMiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE1OCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTE5MjcsMjI4OCBjIC0xMDgsLTEwIC0yNDgsLTU1IC0zNDEsLTExMCAtODIsLTQ4IC0yMDMsLTE2MCAtMjQ3LC0yMjkgLTE3LC0yNyAtMzQsLTQ3IC0zOCwtNDQgLTMsNCAtMTAsODIgLTE2LDE3MyBsIC0xMCwxNjcgLTE3OSwzIC0xNzgsMiA2LC00NyBjIDQsLTI3IDksLTUxNyAxMiwtMTA5MCBsIDYsLTEwNDMgMTk5LDAgMTk4LDAgMyw3MjcgMyw3MjggMzEsNzIgYyAxMTMsMjYwIDM0MSwzOTggNTk4LDM2MiAxNjQsLTIyIDI3NiwtMTAzIDM0NiwtMjUxIDczLC0xNTQgNzIsLTE0OCA3NywtOTM1IGwgNSwtNzAzIDE5NCwwIDE5NCwwIDAsNzIzIGMgMCw3OTYgLTIsODI0IC02Miw5OTcgLTEyMSwzNDcgLTQyMCw1MzMgLTgwMSw0OTggeiIKICAgICAgIGlkPSJwYXRoMzA2NSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNTQpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczOTAsMTE4MCAwLC0xMTEwIDE5MCwwIDE5MCwwIDAsMTExMCAwLDExMTAgLTE5MCwwIC0xOTAsMCAwLC0xMTEwIHoiCiAgICAgICBpZD0icGF0aDMwNjciCiAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMTUwKSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA5MTk5LDIyODAgYyAtMjIwLC0zNyAtNDE4LC0xMzggLTU3MCwtMjg5IC0xNTAsLTE1MSAtMjQyLC0zMjkgLTI5NSwtNTcxIC0yNiwtMTE5IC0yNywtNDI5IC0xLC01NDcgNTIsLTI0NCAxNDksLTQyNiAzMDUsLTU3NSAxODcsLTE3OCAzOTYsLTI2NCA2NjgsLTI3NSA1MDAsLTIxIDkxMiwyNTEgMTA2NSw3MDQgNTQsMTYxIDY0LDIzMCA2Myw0NDggMCwxNjcgLTMsMjE1IC0yMSwyOTEgLTEwMyw0NDEgLTM5MCw3MzAgLTgwMyw4MDggLTg3LDE3IC0zMjYsMjAgLTQxMSw2IHogbSAzMzQsLTMwNSBjIDI1NSwtNjYgNDM4LC0zMDggNDg3LC02NDQgMTcsLTExNiA4LC0zNDMgLTE4LC00NDIgLTY0LC0yNDMgLTE5NywtNDIzIC0zNzQsLTUwOCAtMTA1LC01MCAtMTg0LC02NiAtMjk2LC01OCAtMjIxLDE1IC0zOTMsMTM2IC01MDgsMzU5IC02NiwxMjkgLTk1LDI1MCAtMTAxLDQyNSAtMTEsMzA4IDY3LDU0NSAyMzYsNzE0IDgxLDgxIDE1OCwxMjYgMjYxLDE1MyA3MywxOSAyNDEsMjAgMzEzLDEgeiIKICAgICAgIGlkPSJwYXRoMzA2OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNDYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIxNzUwLDIyNzUgYyAtMzUyLC03MCAtNjExLC0zMDUgLTczOSwtNjY4IC01OCwtMTY1IC03NSwtMjcxIC03NSwtNDc3IC0xLC0yMDQgMTAsLTI3OSA2NiwtNDQ3IDExOSwtMzYwIDQyMCwtNTk4IDgyNiwtNjUzIDEyNywtMTggMzkyLC04IDU0MiwyMCAxMjIsMjIgMzYwLDk2IDM2MCwxMTEgMCwxOCAtNjMsMjY0IC02OSwyNzEgLTMsNCAtNTEsLTggLTEwNiwtMjcgLTE1NCwtNTEgLTI3MiwtNjggLTQ3NSwtNjggLTIwMywwIC0yNzgsMTUgLTQwOSw4MyAtMjE0LDExMSAtMzI4LDMwMiAtMzU2LDU5OCBsIC03LDcyIDc2NSwwIGMgNjg4LDAgNzY1LDIgNzcxLDE2IDEyLDMyIDYsMzAzIC05LDM5MCAtNDMsMjQ0IC0xMzQsNDMzIC0yNzcsNTcwIC0xMTUsMTEyIC0yMzUsMTc0IC00MDAsMjA4IC05NCwxOSAtMzE0LDIwIC00MDgsMSB6IG0gMzUzLC0yOTUgYyAyMDcsLTY0IDMzOCwtMjU3IDM2MywtNTM1IGwgNywtNzUgLTU3NywwIC01NzYsMCAwLDIzIGMgMCw1MiA0MiwxODcgODYsMjc1IDgyLDE2OCAyMjcsMjkyIDM3NCwzMjEgMzAsNiA2NCwxMyA3NSwxNSA0MSwxMCAxODUsLTUgMjQ4LC0yNCB6IgogICAgICAgaWQ9InBhdGgzMDcxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE0MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gNDAsOTEwIDAsLTg3MCA4NjgsMiA4NjcsMyAzLDg2OCAyLDg2NyAtODcwLDAgLTg3MCwwIDAsLTg3MCB6IgogICAgICAgaWQ9InBhdGgzMDc1IgogICAgICAgc3R5bGU9ImZpbGw6I2MwMWQyZTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDkxMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA3NyIKICAgICAgIHN0eWxlPSJmaWxsOiNjMDFkMmU7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMzgyMCw5MTAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNzkiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICA8L2c+Cjwvc3ZnPgo=';
	header('Content-Type: image/svg+xml');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}
alt-php71-ioncube-loader/README.txt000064400000007751150475525550012674 0ustar00                            The ionCube Loader 
                            ------------------

This package contains:

* ionCube Loaders

* a Loader Wizard script to assist with Loader installation (loader-wizard.php)

* the License document for use of the Loader and encoded files (LICENSE.txt)

* User Guide describing options that can be configured through a php.ini file.  
  There are options that may improve performance, particularly with files on
  a network drive. Options for the ionCube24 intrusion protection and PHP error
  reporting service (ioncube24.com) are also described.


INSTALLATION
============

Quick Guide for experienced system admins
-----------------------------------------

The Loader is a PHP engine extension, so should be referenced with 
a zend_extension line in a php.ini file. It must be the first engine
extension to be installed. 

The Loader must be for the correct operating system, match the 
PHP version, and for whether PHP is built as thread-safe (TS) or not. 
All information required for installing is available on a phpinfo page. 

For example, if your web server is 64 bit Linux, thread safety is disabled,
PHP is version 8.1.8, the main php.ini file is /etc/php.ini and you
have unpacked Loaders to /usr/local/ioncube, you would:

1) edit /etc/php.ini
2) at the top of the php.ini file add

zend_extension = /usr/local/ioncube/ioncube_loader_lin_8.1.so

3) restart the PHP environment (i.e. Apache, php-fpm, etc.)

4) Check a phpinfo page and the Loader should show up in the Zend Engine box.


Assisted Installation with the Loader Wizard
--------------------------------------------

1. Upload the contents of this package to a directory/folder called ioncube
   within the top level of your web scripts area. This is sometimes called the
   "web root" or "document root". Common names for this location are "www",
   "public_html", and "htdocs", but it may be different on your server.

2. Launch the Loader Wizard script in your browser. For example:
     https://yourdomain/ioncube/loader-wizard.php

   If the wizard is not found, check carefully the location on your server
   where you uploaded the Loaders and the wizard script. 

3. Follow the steps given by the Loader Wizard. If you have full access to the 
   server then installation should be easy. If your hosting plan is more limited, 
   you may need to ask your hosting provider for assistance. 

4. The Loader Wizard can automatically create a ticket in our support system
   if installation is unsuccessful, and we are happy to assist in that case.

   YouTube with a search for "ioncube loader wizard" also gives some helpful 
   examples of installation.


WHERE TO INSTALL THE LOADERS
============================

The Loader Wizard should be used to guide the installation process but the
following are the standard locations for the Loader files. Loader file
packages can be obtained from https://www.ioncube.com/loaders.php

Please check that you have the correct package of Loaders for your system.

Installing to a remote SHARED server
------------------------------------

* Upload the Loader files to a directory/folder called ioncube within your
  main web scripts area.  (This will probably be where you placed the
  loader-wizard.php script.)


Installing to a remote UNIX/LINUX DEDICATED or VPS server
---------------------------------------------------------

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, /usr/local/ioncube


** Installing to a remote WINDOWS DEDICATED or VPS server

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, C:\windows\system32


64-BIT LOADERS FOR WINDOWS
--------------------------

64-bit Loaders for Windows are available for PHP 5.5 upwards.
The Loader Wizard will not give directions for installing 64-bit Loaders for
any earlier version of PHP 5.

Copyright (c) 2002-2025 ionCube Ltd.           Last revised January 2025
alt-php71-snuffleupagus/README.md000064400000014667150475527550012462 0ustar00<h1 align="center">
  <br>
  <a href="https://snuffleupagus.readthedocs.io/">
    <img src="https://github.com/jvoisin/snuffleupagus/raw/master/doc/source/_static/sp.png" alt="Snuffleupagus' logo" width="200"></a>
  <br>
  Snuffleupagus
  <br>
</h1>

<h4 align="center">Security module for php7 and php8 - Killing bugclasses and virtual-patching the rest!</h4>

<p align="center">
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml/badge.svg"
         alt="Testing PHP7 on various Linux distributions" />
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml/badge.svg"
         alt="Testing PHP8 on various Linux distributions" />
  </a>
  <a href="https://scan.coverity.com/projects/jvoisin-snuffleupagus">
    <img src="https://scan.coverity.com/projects/13821/badge.svg?flat=1"
         alt="Coverity">
  </a>
  <a href="https://bestpractices.coreinfrastructure.org/projects/1267">
      <img src="https://bestpractices.coreinfrastructure.org/projects/1267/badge"
           alt="CII Best Practises">
  </a>
  <a href="http://snuffleupagus.readthedocs.io/?badge=latest">
    <img src="https://readthedocs.org/projects/snuffleupagus/badge/?version=latest"
         alt="readthedocs.org">
  </a>
  <a href="https://coveralls.io/github/jvoisin/snuffleupagus?branch=master">
    <img src="https://coveralls.io/repos/github/jvoisin/snuffleupagus/badge.svg?branch=master"
         alt="coveralls">
  </a>
  <a href="https://twitter.com/dustriorg">
    <img src="https://img.shields.io/badge/twitter-follow-blue.svg"
         alt="twitter">
  </a>
  <a href="https://repology.org/project/php:snuffleupagus/versions">
    <img src="https://repology.org/badge/tiny-repos/php:snuffleupagus.svg"
         alt="Packaging status">
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/codeql-analysis.yml/badge.svg"
         alt="CodeQL">
  </a>
</p>

<p align="center">
  <a href="#key-features">Key Features</a> •
  <a href="#download">Download</a> •
  <a href="#examples">Examples</a> •
  <a href="https://snuffleupagus.readthedocs.io/">Documentation</a> •
  <a href="https://github.com/jvoisin/snuffleupagus/blob/master/LICENSE">License</a> •
  <a href="#thanks">Thanks</a>
</p>

Snuffleupagus is a [PHP 7+ and 8+](https://secure.php.net/) module designed to
drastically raise the cost of attacks against websites, by killing entire bug
classes. It also provides a powerful virtual-patching system, allowing
administrator to fix specific vulnerabilities and audit suspicious behaviours
without having to touch the PHP code.

## Key Features

* No [noticeable performance impact](https://dustri.org/b/snuffleupagus-030-dentalium-elephantinum.html)
* Powerful yet simple to write virtual-patching rules
* Killing several classes of vulnerabilities
  * [Unserialize-based](https://www.owasp.org/images/9/9e/Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits.pdf) code execution
  * [`mail`-based]( https://blog.ripstech.com/2016/roundcube-command-execution-via-email/ ) code execution
  * Cookie-stealing [XSS]( https://en.wikipedia.org/wiki/Cross-site_scripting )
  * File-upload based code execution
  * Weak PRNG
  * [XXE]( https://en.wikipedia.org/wiki/XML_external_entity_attack )
  * Filter based remote code execution and assorted shenanigans
* Several hardening features
  * Automatic `secure` and `samesite` flag for cookies
  * Bundled set of rules to detect post-compromissions behaviours
  * Global [strict mode]( https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations) and type-juggling prevention
  * Whitelisting of [stream wrappers](https://secure.php.net/manual/en/intro.stream.php)
  * Preventing writeable files execution
  * Whitelist/blacklist for `eval`
  * Enforcing TLS certificate validation when using [curl](https://secure.php.net/manual/en/book.curl.php)
  * Request dumping capability
* A relatively sane code base:
  * A [comprehensive](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master) test suite close to 100% coverage
  * Every commit is tested on [several distributions](https://gitlab.com/jvoisin/snuffleupagus/pipelines)
  * An `clang-format`-enforced code style
  * A [comprehensive documentation](https://snuffleupagus.rtfd.io)
  * Usage of [coverity](https://scan.coverity.com/projects/jvoisin-snuffleupagus), codeql, [scan-build](https://clang-analyzer.llvm.org/scan-build.html), …

## Download

We've got a [download
page](https://snuffleupagus.readthedocs.io/download.html), where you can find
packages for your distribution, but you can of course just `git clone` this
repo, or check the releases on [github](https://github.com/jvoisin/snuffleupagus/releases).

## Examples

We're providing [various example rules](https://github.com/jvoisin/snuffleupagus/tree/master/config),
that are looking like this:

```python
# Harden the `chmod` function
sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop();

# Mitigate command injection in `system`
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n]").drop();
```

Upon violation of a rule, you should see lines like this in your logs:

```python
[snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in /var/www/index.php:2, because the return value (0) of the function 'strpos' matched a rule.
```

## Documentation

We've got a [comprehensive website](https://snuffleupagus.readthedocs.io/) with
all the documentation that you could possibly wish for. You can of course
[build it yourself](https://github.com/jvoisin/snuffleupagus/tree/master/doc).

## Thanks

Many thanks to:

- The [Suhosin project](https://suhosin.org) for being a __huge__ source of inspiration
- [NBS System](https://www.nbs-system.com) for initially sponsoring the development
- [Suhosin-ng](https://github.com/sektioneins/suhosin-ng) for their
  [experimentations](https://github.com/sektioneins/suhosin-ng/wiki/News)
  and [contributions](https://github.com/jvoisin/snuffleupagus/commits?author=bef),
  as well as [NLNet](https://nlnet.nl/project/Suhosin-NG/) for sponsoring it
- All [our contributors](https://github.com/jvoisin/snuffleupagus/graphs/contributors)

alt-php71-snuffleupagus/CONTRIBUTING.md000064400000013046150475527620013420 0ustar00## Contributing

First off, thank you for considering contributing to snuffleupagus.

### 1. Where do I go from here?

If you've noticed a bug or have a question,
look at the [faq](https://snuffleupagus.readthedocs.io/faq.html) and
[search the issue tracker](https://github.com/jvoisin/snuffleupagus/issues)
to see if someone else has already created a ticket. If not, go ahead and
[make one](https://github.com/jvoisin/snuffleupagus/issues/new)!

### 2. Fork & create a branch

If this is something you think you can fix,
then [fork snuffleupagus](https://help.github.com/articles/fork-a-repo) and
create a branch with a descriptive name.

A good branch name would be (where issue #325 is the ticket you're working on):

```sh
git checkout -b 325-kill-sql-injections
```

### 3. Get the test suite running

Just type `make coverage` or `make debug`, the testsuite should be run
automatically.

Please add tests if you're fixing a bug or adding a new feature: we do have a
[high coverage](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master)
(functions, lines and branches), and intend to keep it that way.

#### 3.3 Debugging failures in the test suite

If your changes have introduced run-time failures in the test-suite, you can
easily troubleshoot them by inspecting the files that
[php has generated](https://qa.php.net/write-test.php#analyzing-failing-tests)
for this purpose.

A nice trick is to edit the `.sh` file to prepend `gdb --args` to it before
launching it, in order to run the failing test inside GDB.


### 4. Did you find a bug?

* **Ensure the bug was not already reported** by
  [searching all issues](https://github.com/jvoisin/snuffleupagus/issues?q=).
* If you're unable to find an open issue addressing the problem,
  [open a new one](https://github.com/jvoisin/snuffleupagus/issues/new).
  Be sure to include a **title and clear description**,
  as much relevant information as possible, and a **code sample**
  or an **executable test case** demonstrating the expected behavior that is not
  occurring.


### 5. Get the style right

Your patch should follow the same conventions & pass the same code quality
checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to
ensure a consistent code-style. Please run it with `clang-format --style="{BasedOnStyle: google, SortIncludes: false}"`
before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format).

### 6. Make a Pull Request

At this point, you should switch back to your master branch and make sure it's
up to date with our upstream master branch:

```sh
git remote add upstream git@github.com:jvoisin/snuffleupagus.git
git checkout master
git pull upstream master
```

Then update your feature branch from your local copy of master, and push it!

```sh
git checkout 325-kill-sql-injections
git rebase master
git push --set-upstream origin 325-kill-sql-injections
```

Finally, go to GitHub and [make a Pull Request](https://help.github.com/articles/creating-a-pull-request) :D

Travis CI will [run our test suite](https://travis-ci.org/jvoisin/snuffleupagus)
against all supported PHP versions. We care about quality, so your PR won't be
merged until all tests pass. It's unlikely, but it's possible that your changes
pass tests in one PHP version but fail in another. In that case, you'll have to
setup your development environment to use the problematic PHP version, and
investigate what's going on!

### 7. Keeping your Pull Request updated

If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
has changed, and that you need to update your branch so it's easier to merge.

To learn more about rebasing in Git, there are a lot of [good](http://git-scm.com/book/en/Git-Branching-Rebasing)
[resources](https://help.github.com/articles/interactive-rebase) but here's the suggested workflow:

```sh
git checkout 325-kill-sql-injections
git pull --rebase upstream master
git push --force-with-lease 325-kill-sql-injections
```

### 8. Merging a PR (maintainers only)

A PR can only be merged into master by a maintainer if:

1. It is passing CI.
2. It has been approved by at least one maintainer. If it was a maintainer who
   opened the PR, only one extra approval is needed.
3. It has no requested changes.
4. It is up to date with current master.

Any maintainer is allowed to merge a PR if all of these conditions are met.

### 9. Shipping a release (maintainers only)

Maintainers need to do the following to push out a release:

1. Make sure that all pending and mergeable pull requests are in
2. Close the corresponding
	 [milestone](https://github.com/jvoisin/snuffleupagus/milestones)
2. Run `valgrind` (by adding a `-m` after the `-q` in the Makefile) and check that everything is ok.
   Don't mind the python-related issues.
2. Run `cd src; phpize; ./configure --enable-snuffleupagus --enable-debug; scan-build make`
   and fix the possible issues.
3. Update the `src/php_snuffleupagus.h` according to [semantic versioning](https://semver.org/)
4. Update the changelog page in the documentation
5. Update the Debian changelog in `./debian/changelog` with `cd debian; dch`
6. Commit the result
7. Clean up the folder `make clean; git clean -xdf`
8. Create a tag for the release:

  ```sh
  git tag -s v$MAJOR.$MINOR.$PATCH -m "v$MAJOR.$MINOR.$PATCH"
  git push --tags
	git push origin master
  ```

9. Wait for the CI on the new tag branch to finish
10. Create the [release on github](https://github.com/jvoisin/snuffleupagus/releases)
11. Add the freshly built Debian packages from the CI to the release
12. Do the *secret release dance*
alt-liblqr-1/ChangeLog000064400000006141150510151710010515 0ustar002009-05-12  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Forgot (undocumented) legacy macro

2009-05-09  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Changed lqr_carver_get_[true_]energy
	* Added lqr_carver_get_energy_image

2009-05-05  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Updated the example files with the new features

2009-05-04  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added lqr_carver_bias/rigmask_clear

2009-05-03  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Changed CATCH* macros to LQR_CATCH*
	* No alpha by default for LQR_CUSTOM_IMAGE
	* Improved set alpha/black channel
	* Bias activates energy (for using with
	  lqr_carver_get_energy)
	* Fixes in lqr_carver_bias/rigmask_add_area
	* Added lqr_carver_rigmask_add_xy
	* Don't call transpose when adding rigmasks
	* Rigmask init set to 0 instead of 1
	* Removed energy previews
	* Added lqr_carvre_get_true_energy

2009-04-28  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Heavily optimised the update_mmap code
	* Progress report spans whole sessions instead
	  of being divided into steps when enlagement
	  exceeds the enl_step

2009-04-27  Carlo Baldassi  <carlobaldassi@gmail.com>

	* New framework for energy definition, 
	  including energy previews
	* Added lqr_carver_bias_add_xy
	* Better bias managment (saves memory if
	  bias is not used, no unnecessary
	  transpositions)

2009-04-16  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added cancel methods and structures
	* Fixed recursiveness of some calls to
	  lqr_carver_list_foreach
	* Fixed return value of lqr_carver_resize

2009-04-09  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added lqr_carver_set_preserve_input_image
	* Version bump 0.4

2009-04-08  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Fixed bug with 16-bit images

2009-01-26  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added readouts for current visiblity map

2008-11-01  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Bugfix in update_mmap causing crashes with
	  delta_x > 1
	* Removed unnecessary includes of stdio.h
	* Added debug_checkrows

2008-10-22  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Moved classes definitions to private headers

2008-10-21  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Removed 2-fold scale-up limit, added
	  enl_step setting

2008-10-12  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added 32 bit and 64 bit floating point support
	* Added get_col_depth
	* Turned all internal floating point maps from
	  gdouble to gfloat
	* Collapsed all the nonstandard constructors
	  and span functions to a single version (*_ext)

2008-09-04  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added set_no_dump_vmaps

2008-09-04  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Hid private symbols

2008-07-30  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Optimized vsmap memory management
	* Bugfixes

2008-04-06  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added 16 bit support

2008-02-25  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added left-right switches

2008-02-20  Carlo Baldassi  <carlobaldassi@gmail.com>

	* Added rigidity mask

2007-12-07  Carlo Baldassi  <carlobaldassi@yahoo.it>

	* initial revision.

alt-liblqr-1/COPYING000064400000104513150510151710010000 0ustar00                    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>.
alt-liblqr-1/README000064400000010054150510151710007621 0ustar00
LiquidRescale library 0.4.0
===========================

Table of contents
-----------------
  * Introduction
    + Library features
  * Installation
    + Requirements
    + Normal setup
  * Using the library
  * References
  * Copyright


+ Introduction
--------------

The LiquidRescale (lqr) library provides a C/C++ API for
performing non-uniform resizing of images by the seam-carving
technique.

++ Library features

The library takes images in plain array format as input
and converts them to a multi-size representation.
Following is a list of features:

  * Easy to use and fully documented API
  * Currently supports 8 bit to 64 bit per channel images
  * Support for different color models: grayscale, RGB, CMY
    and their variants, and even custom ones
  * Areas in the image can be marked for preservation or
    discard, or for additional seam rigidity
  * Once the image has been fully processed, the scaling can
    be done in real-time. In fact, the information can be saved
    and read out later without any further processing
  * The resizing is done with a single function which
    automatically performs all the necessary operations; it
    can also work in successive steps without wasting
    computational time
  * Possibility to tune the carving operation by letting the
    seams be less connected, or more rigid, or both (the
    rigidity can be also be modulated through a mask, to get
    a differnet behaviour in different areas of the image)
  * Can export and import the visibility map (the seams)
  * Other images can be attached and undergo the same carving
    process as the parent image 
  * The automatic feature detection algorithm can be tuned
    by selecting among different energy gradient functions,
    and easily defining custom ones
  * Reports progress through a customisable interface
  * A signalling system permits to cleanly handle errors
  * Portable to all major OS's



+ Installation
--------------

++ Dependencies

The lqr library depends on the glib-2.0 libraries

++ Normal setup

The build package uses autotools and libtool, so the installation
commands on Unix systems are simply

./configure && make && sudo make install

The last step requires administrative privileges.
(Note: the default installation path is /usr since version 0.4)

If you want to also install the man pages for the library functions,
add the option `--enable-install-man' in the call to ./configure.

If you want to disable legacy macro names which do not begin with
LQR_ then add the option `--diable-legacy-macros'

See the INSTALL file for a full description.



+ Using the library for development
-------------------------------------

In order to use the library functions and structures from
a C or C++ program, you have to add this include line in 
your program:

#include <lqr.h>

At compile time, you can take advantage of pkg-config to set
the proper flags.

In the `examples' directory you can find a basic example program,
`liquidrescale-basic', and a full-featured demo program,
`liquidrescale', together with a simple Makefile. Both
programs are fully commented.

The "basic" version demonstrates how to use the strictly-needed 
library functions, while the full version uses almost all of the
API methods provided. The Makefile shows how to set the compilation
flags.

See the README file in that directory for more information.

The complete manual and reference for the library, together with
some additional notes, can be found in the `docs' directory in
docbook format. The reference is also provided in man page format.
The makefile in that directory (hopefully) generates the manual in
html format, using xsltproc; then you'll find the index named after
`liblqr_manual_index.html'.
See the README file in that directory for further information.



+ References
------------

The library implements the algorithm described in the paper
"Seam Carving for Content-Aware Image Resizing"
by Shai Avidan and Ariel Shamir, which can be found at
http://www.faculty.idc.ac.il/arik/imret.pdf



+ Copyright
-----------

Copyright (C) 2007-2009 Carlo Baldassi <carlobaldassi@gmail.com>

alt-php74-snuffleupagus/README.md000064400000014667150536141640012453 0ustar00<h1 align="center">
  <br>
  <a href="https://snuffleupagus.readthedocs.io/">
    <img src="https://github.com/jvoisin/snuffleupagus/raw/master/doc/source/_static/sp.png" alt="Snuffleupagus' logo" width="200"></a>
  <br>
  Snuffleupagus
  <br>
</h1>

<h4 align="center">Security module for php7 and php8 - Killing bugclasses and virtual-patching the rest!</h4>

<p align="center">
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml/badge.svg"
         alt="Testing PHP7 on various Linux distributions" />
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml/badge.svg"
         alt="Testing PHP8 on various Linux distributions" />
  </a>
  <a href="https://scan.coverity.com/projects/jvoisin-snuffleupagus">
    <img src="https://scan.coverity.com/projects/13821/badge.svg?flat=1"
         alt="Coverity">
  </a>
  <a href="https://bestpractices.coreinfrastructure.org/projects/1267">
      <img src="https://bestpractices.coreinfrastructure.org/projects/1267/badge"
           alt="CII Best Practises">
  </a>
  <a href="http://snuffleupagus.readthedocs.io/?badge=latest">
    <img src="https://readthedocs.org/projects/snuffleupagus/badge/?version=latest"
         alt="readthedocs.org">
  </a>
  <a href="https://coveralls.io/github/jvoisin/snuffleupagus?branch=master">
    <img src="https://coveralls.io/repos/github/jvoisin/snuffleupagus/badge.svg?branch=master"
         alt="coveralls">
  </a>
  <a href="https://twitter.com/dustriorg">
    <img src="https://img.shields.io/badge/twitter-follow-blue.svg"
         alt="twitter">
  </a>
  <a href="https://repology.org/project/php:snuffleupagus/versions">
    <img src="https://repology.org/badge/tiny-repos/php:snuffleupagus.svg"
         alt="Packaging status">
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/codeql-analysis.yml/badge.svg"
         alt="CodeQL">
  </a>
</p>

<p align="center">
  <a href="#key-features">Key Features</a> •
  <a href="#download">Download</a> •
  <a href="#examples">Examples</a> •
  <a href="https://snuffleupagus.readthedocs.io/">Documentation</a> •
  <a href="https://github.com/jvoisin/snuffleupagus/blob/master/LICENSE">License</a> •
  <a href="#thanks">Thanks</a>
</p>

Snuffleupagus is a [PHP 7+ and 8+](https://secure.php.net/) module designed to
drastically raise the cost of attacks against websites, by killing entire bug
classes. It also provides a powerful virtual-patching system, allowing
administrator to fix specific vulnerabilities and audit suspicious behaviours
without having to touch the PHP code.

## Key Features

* No [noticeable performance impact](https://dustri.org/b/snuffleupagus-030-dentalium-elephantinum.html)
* Powerful yet simple to write virtual-patching rules
* Killing several classes of vulnerabilities
  * [Unserialize-based](https://www.owasp.org/images/9/9e/Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits.pdf) code execution
  * [`mail`-based]( https://blog.ripstech.com/2016/roundcube-command-execution-via-email/ ) code execution
  * Cookie-stealing [XSS]( https://en.wikipedia.org/wiki/Cross-site_scripting )
  * File-upload based code execution
  * Weak PRNG
  * [XXE]( https://en.wikipedia.org/wiki/XML_external_entity_attack )
  * Filter based remote code execution and assorted shenanigans
* Several hardening features
  * Automatic `secure` and `samesite` flag for cookies
  * Bundled set of rules to detect post-compromissions behaviours
  * Global [strict mode]( https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations) and type-juggling prevention
  * Whitelisting of [stream wrappers](https://secure.php.net/manual/en/intro.stream.php)
  * Preventing writeable files execution
  * Whitelist/blacklist for `eval`
  * Enforcing TLS certificate validation when using [curl](https://secure.php.net/manual/en/book.curl.php)
  * Request dumping capability
* A relatively sane code base:
  * A [comprehensive](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master) test suite close to 100% coverage
  * Every commit is tested on [several distributions](https://gitlab.com/jvoisin/snuffleupagus/pipelines)
  * An `clang-format`-enforced code style
  * A [comprehensive documentation](https://snuffleupagus.rtfd.io)
  * Usage of [coverity](https://scan.coverity.com/projects/jvoisin-snuffleupagus), codeql, [scan-build](https://clang-analyzer.llvm.org/scan-build.html), …

## Download

We've got a [download
page](https://snuffleupagus.readthedocs.io/download.html), where you can find
packages for your distribution, but you can of course just `git clone` this
repo, or check the releases on [github](https://github.com/jvoisin/snuffleupagus/releases).

## Examples

We're providing [various example rules](https://github.com/jvoisin/snuffleupagus/tree/master/config),
that are looking like this:

```python
# Harden the `chmod` function
sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop();

# Mitigate command injection in `system`
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n]").drop();
```

Upon violation of a rule, you should see lines like this in your logs:

```python
[snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in /var/www/index.php:2, because the return value (0) of the function 'strpos' matched a rule.
```

## Documentation

We've got a [comprehensive website](https://snuffleupagus.readthedocs.io/) with
all the documentation that you could possibly wish for. You can of course
[build it yourself](https://github.com/jvoisin/snuffleupagus/tree/master/doc).

## Thanks

Many thanks to:

- The [Suhosin project](https://suhosin.org) for being a __huge__ source of inspiration
- [NBS System](https://www.nbs-system.com) for initially sponsoring the development
- [Suhosin-ng](https://github.com/sektioneins/suhosin-ng) for their
  [experimentations](https://github.com/sektioneins/suhosin-ng/wiki/News)
  and [contributions](https://github.com/jvoisin/snuffleupagus/commits?author=bef),
  as well as [NLNet](https://nlnet.nl/project/Suhosin-NG/) for sponsoring it
- All [our contributors](https://github.com/jvoisin/snuffleupagus/graphs/contributors)

alt-php74-snuffleupagus/CONTRIBUTING.md000064400000013046150536141710013411 0ustar00## Contributing

First off, thank you for considering contributing to snuffleupagus.

### 1. Where do I go from here?

If you've noticed a bug or have a question,
look at the [faq](https://snuffleupagus.readthedocs.io/faq.html) and
[search the issue tracker](https://github.com/jvoisin/snuffleupagus/issues)
to see if someone else has already created a ticket. If not, go ahead and
[make one](https://github.com/jvoisin/snuffleupagus/issues/new)!

### 2. Fork & create a branch

If this is something you think you can fix,
then [fork snuffleupagus](https://help.github.com/articles/fork-a-repo) and
create a branch with a descriptive name.

A good branch name would be (where issue #325 is the ticket you're working on):

```sh
git checkout -b 325-kill-sql-injections
```

### 3. Get the test suite running

Just type `make coverage` or `make debug`, the testsuite should be run
automatically.

Please add tests if you're fixing a bug or adding a new feature: we do have a
[high coverage](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master)
(functions, lines and branches), and intend to keep it that way.

#### 3.3 Debugging failures in the test suite

If your changes have introduced run-time failures in the test-suite, you can
easily troubleshoot them by inspecting the files that
[php has generated](https://qa.php.net/write-test.php#analyzing-failing-tests)
for this purpose.

A nice trick is to edit the `.sh` file to prepend `gdb --args` to it before
launching it, in order to run the failing test inside GDB.


### 4. Did you find a bug?

* **Ensure the bug was not already reported** by
  [searching all issues](https://github.com/jvoisin/snuffleupagus/issues?q=).
* If you're unable to find an open issue addressing the problem,
  [open a new one](https://github.com/jvoisin/snuffleupagus/issues/new).
  Be sure to include a **title and clear description**,
  as much relevant information as possible, and a **code sample**
  or an **executable test case** demonstrating the expected behavior that is not
  occurring.


### 5. Get the style right

Your patch should follow the same conventions & pass the same code quality
checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to
ensure a consistent code-style. Please run it with `clang-format --style="{BasedOnStyle: google, SortIncludes: false}"`
before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format).

### 6. Make a Pull Request

At this point, you should switch back to your master branch and make sure it's
up to date with our upstream master branch:

```sh
git remote add upstream git@github.com:jvoisin/snuffleupagus.git
git checkout master
git pull upstream master
```

Then update your feature branch from your local copy of master, and push it!

```sh
git checkout 325-kill-sql-injections
git rebase master
git push --set-upstream origin 325-kill-sql-injections
```

Finally, go to GitHub and [make a Pull Request](https://help.github.com/articles/creating-a-pull-request) :D

Travis CI will [run our test suite](https://travis-ci.org/jvoisin/snuffleupagus)
against all supported PHP versions. We care about quality, so your PR won't be
merged until all tests pass. It's unlikely, but it's possible that your changes
pass tests in one PHP version but fail in another. In that case, you'll have to
setup your development environment to use the problematic PHP version, and
investigate what's going on!

### 7. Keeping your Pull Request updated

If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
has changed, and that you need to update your branch so it's easier to merge.

To learn more about rebasing in Git, there are a lot of [good](http://git-scm.com/book/en/Git-Branching-Rebasing)
[resources](https://help.github.com/articles/interactive-rebase) but here's the suggested workflow:

```sh
git checkout 325-kill-sql-injections
git pull --rebase upstream master
git push --force-with-lease 325-kill-sql-injections
```

### 8. Merging a PR (maintainers only)

A PR can only be merged into master by a maintainer if:

1. It is passing CI.
2. It has been approved by at least one maintainer. If it was a maintainer who
   opened the PR, only one extra approval is needed.
3. It has no requested changes.
4. It is up to date with current master.

Any maintainer is allowed to merge a PR if all of these conditions are met.

### 9. Shipping a release (maintainers only)

Maintainers need to do the following to push out a release:

1. Make sure that all pending and mergeable pull requests are in
2. Close the corresponding
	 [milestone](https://github.com/jvoisin/snuffleupagus/milestones)
2. Run `valgrind` (by adding a `-m` after the `-q` in the Makefile) and check that everything is ok.
   Don't mind the python-related issues.
2. Run `cd src; phpize; ./configure --enable-snuffleupagus --enable-debug; scan-build make`
   and fix the possible issues.
3. Update the `src/php_snuffleupagus.h` according to [semantic versioning](https://semver.org/)
4. Update the changelog page in the documentation
5. Update the Debian changelog in `./debian/changelog` with `cd debian; dch`
6. Commit the result
7. Clean up the folder `make clean; git clean -xdf`
8. Create a tag for the release:

  ```sh
  git tag -s v$MAJOR.$MINOR.$PATCH -m "v$MAJOR.$MINOR.$PATCH"
  git push --tags
	git push origin master
  ```

9. Wait for the CI on the new tag branch to finish
10. Create the [release on github](https://github.com/jvoisin/snuffleupagus/releases)
11. Add the freshly built Debian packages from the CI to the release
12. Do the *secret release dance*
alt-php74-ioncube-loader/USER-GUIDE.txt000064400000026060150536141770013341 0ustar00ionCube Loader 14.4 User Guide
=====================================

This document describes the available php.ini configuration options of the
ionCube Loader that relate to processing of PHP encoded files, and also the
ionCube24 service. It also describes which encoded files can be run by each
ionCube Loader.

PERFORMANCE OF ENCODED FILES
----------------------------

We recommend that the encoded paths feature (see below) is used 
with encoded files in order to maximise performance.

ENCODED FILES  
-------------

INI entry: ioncube.loader.encoded_paths

Purpose:   Specify the locations of encoded files

  The ionCube Loader will normally examine a PHP file before processing
  to test whether it is encoded, and will run the file itself if necessary.
  Although this checking is very efficient, restricting which files the
  Loader tests for being encoded may give extra performance. If set to 
  a series of paths or files, only files in those locations are tested.

  Entries should be separated by a : on Unix and ; on Windows. 
  A path may be prefixed with + or - to add or remove that path from
  the possible locations. + is assumed if no character is given.


Examples: (... means ioncube.loader.encoded_paths)

  * Site with a single encoded module in /var/www/html/modules/RSS

... = "/var/www/html/modules/RSS"


  * As above, with a site configuration file encoded too.

... = "/var/www/html/modules/RSS:/var/www/html/config/config.php"


  * Encoded files may be anywhere except for /var/www/html/framework

... = "/:-/var/www/html/framework"


  * Site with most modules encoded except for one

... = "/var/www/html/modules:-/var/www/html/modules/plain"


  * As above, with an encoded config file in the plain directory

... = "/site/modules:-/site/modules/plain:/site/modules/plain/config.php"


Locations:

  The ioncube.loader.encoded_paths property can be set in a php.ini
  file, in a .htaccess file (when using Apache), in a .user.ini file
  (when using CGI PHP 5.3+) or using ini_set within a PHP script. In ini
  files only the last value will be used for the encoded_paths property. If
  you wish to build up the value in several lines then, for PHP 5.1+, you
  can use the following syntax:

ioncube.loader.encoded_paths = "/path1"  
ioncube.loader.encoded_paths = ${ioncube.loader.encoded_paths}":/path2"  
; etc...

LIMITATIONS OF LOADERS AND ENCODED FILES
----------------------------------------

Encoded files can, in general, run on versions of PHP equal to
or greater than the source language of the Encoder used to
produce them. So a file produced by the Encoder for PHP 7.2
can be run by the Loaders for PHP 7.2, 7.3 and 7.4, but 7.1. This 
means that the Loaders offer good backwards compatibility, 
however there are the following limitations:

  * The Loader for PHP 8.3 can run files produced by the PHP 8.2 and
    8.3 Encoders.

  * The Loader for PHP 8.2 can only run files produced for
    PHP 8.2. Updates for files produced for PHP 8.1 should
    be obtained to use them with PHP 8.2.

  * The Loader for PHP 8.1 can only run files produced for
    PHP 8.1.

  * The Loaders for PHP 7.1 through 7.4 can only run files 
    produced by the Encoders for PHP 7. 

  * The Loader for PHP 7.0 can only run files produced by the
    Encoder for PHP 5.6.

  * The Loaders for PHP 5.5 and PHP 5.6 cannot run files 
    produced by the PHP 4 Encoder.


IONCUBE24 : real-time intrusion protection and PHP error reporting
---------
### (Available for Linux 32 and 64 bit x86 servers using PHP 7)

ionCube24 (https://ioncube24.com) is an ionCube service that uses the
ionCube Loader to provide both real-time protection against the exploit of
website vulnerabilities and alerting of website errors.

Vulnerabilities in PHP applications are common, particularly in sites using 
Wordpress and other plugin based systems. Exploits result in website
defacement or customer data being compromised, and ionCube24 provides a 
uniquely powerful defense. 

PHP errors can cause intermittent or even persistent blank pages or errors for
visitors until discovered, and without active monitoring this could go
undetected indefinitely. ionCube24 active monitoring ensures you are always
aware of problems in your website code.

ionCube24 is free to try, with the server side support built into the Linux
Loaders as standard. With the Loader installed, ionCube24 can be activated
at any time to give active intrusion protection and error reporting.

## php.ini settings

ionCube24 has a powerful real-time web interface to configure, monitor and
manage things, and there are also settings that can be used in a php.ini
file as summarised below.

The setup process at https://ioncube24.com automatically gives the settings
that you need to get started, but you may wish to make changes yourself
once setup. The default values are given with each example.

### Global settings

INI entry: ic24.enable ; default 0

Purpose: Enable or disable all ionCube24 features. 

This defaults to 0 (off), and in this case no ionCube24 behaviour is
activated.

Example:

  ic24.enable = 1

----------

INI entry: ic24.api_access_key ; provided during setup

Purpose: An authentication key for adminstration requests. 

  This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.api_check_ip ; default 1

Purpose: Specify whether the IP for admin requests should be validated

  If set, ionCube24 refuses access to API functions unless the calling IP
  is a known ionCube IP address. This option should be left with the
  default setting unless web requests pass through a proxy and your site
  appears to be accessed from the IP of the proxy instead of ionCube. Note
  that access to API functions will still be authenticated by access key.

----------

INI entry: ic24.api_max_timeout ; default 7

Purpose: Maximum timeout period when sending notifications to ionCube24.

  The actual period is adaptive so that a brief increase in typical latency
  will favour a timeout followed by a retry rather than a longer than usual
  timeout.

----------

INI entry: ic24.home_dir ; no default

Purpose: The home directory for ionCube24 related system files. 

  A location outside of the web root is recommended.  It should be writable
  by the web server during startup.

Example:

ic24.home_dir = /var/www/ic24_home

----------

INI entry: ic24.update_domains_retry_interval ; default 30

Purpose: The number of seconds to wait before retrying a fetch of the set
of domains being managed.


### Security related settings

INI entry: ic24.sec.enable ; default "auto"

Purpose: Enable the intrusion protection feature of ionCube24.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

INI entry: ic24.sec.initial_state ; default 1

Purpose: The default for whether security should be enabled or
disabled. The default is to enable protection. Any files on a protected
domain will become blocked if they are changed, so setting this to 0 will
avoid accidental blocking when using ionCube24 for the first time.
Protection may be enabled and disabled using the ionCube24 control panel and
also via the User API.

Accepted values:

   * 1 : protection will be active when ionCube24 initialises.
   * 0 : protection will be disabled.

----------

INI entry: ic24.sec.initial_action ; default "block"

Purpose: The initial setting for how new and modified files should be
treated when about to execute. The default is to block. The action is taken
only if protection is enabled, and the setting may be changed via the
ionCube24 control panel.

Accepted values:

   * "block" : prevent execution of new or modified files
   * "allow" : allow execution of new or modified files

Note that depending on the notification settings, a notification may still
be generated when a new or modified file is about to execute even if it is
not blocked.

----------

INI entry: ic24.sec.initial_notify ; default "always"

Purpose: The initial setting for whether a notification is generated the 
first time an unacknowledged new or modified file is attempted to be
executed. This setting can be changed via the ionCube24 control panel.

Accepted values:

   * "always" : always notify of a new modification 
   * "once"   : only the first detected modification is reported
   * "never"  : never notify of new and modified files

----------

INI entry: ic24.sec.exclusion_key ; provided during setup

Purpose: A key that if present at the start of a file, will identify the
file as trusted. This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.sec.trusted_include_paths ; no default

Purpose: List paths from where files can be included and automatically
trusted.

Example:

ic24.sec.trusted_include_paths = "/var/cache:/var/cache2"

Directories can be excluded from the list by prefixing with a minus
character -. e.g.

"/var/cache:-/var/cache/subdir"

This is useful if your site creates and/or modifies files by itself from
time to time, e.g. in a cache directory. Requests that *directly* access
files on a trusted include path will be blocked but the file itself will
not be blocked, so requests that use the file as intended will still work.
See ioncube24.com for more details once signed up.  As an alternative, if
possible we recommend producing files that include the exclusion key.

----------

INI entry: ic24.sec.block_uploaded_files ; default 1

Purpose: If set, block any uploaded files in ionCube24 that are processed
using the standard PHP mechanism for uploaded files. This applies even if
the file is subsequently included and where included files being
automatically approved with the previous setting.

----------

INI entry: ic24.sec.block_stdin ; default 1

Purpose: Refuse code that PHP sees via stdin.  If disabled, code via
stdin will run without security checking as there is no filepath. This
setting should be left on as PHP would normally never receive a script via
stdin.

### PHP Error reporting settings

INI entry: ic24.phperr.enable ; default "auto"

Purpose: Enable reporting of PHP errors to ionCube24.  When enabled, any
non-ignored errors are reported to ionCube24 in realtime, triggering
alerting so errors can be investigated as necessary.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

### Deprecated settings

Deprecated settings are subject to removal in a future
release.

INI entry: ic24.phperr.ignore ; default 0

Purpose: Specify default error levels to always ignore for all domains.

Note that default and per-domain errors to ignore can also be set via the
web interface, and are combined with this setting. Leaving this unset and
using the web interface is recommended for maximum flexibility.

Example: 

ic24.phperr.ignore = E_NOTICE | E_DEPRECATED

(c) ionCube Ltd. 2025
alt-php74-ioncube-loader/USER-GUIDE.pdf000064400000115466150536142040013273 0ustar00%PDF-1.4
1 0 obj
<<
/Title (��Markdown To PDF)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20250130155421Z)
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 33  
813.500000  0]
endobj
9 0 obj
[0 /XYZ 33  
749.750000  0]
endobj
10 0 obj
[0 /XYZ 33  
700.250000  0]
endobj
11 0 obj
[0 /XYZ 33  
131.750000  0]
endobj
12 0 obj
[0 /XYZ 33  
296  0]
endobj
13 0 obj
[0 /XYZ 33  
97.2500000  0]
endobj
14 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [71.2500000  66.5000000  144.750000  75.5000000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 15 0 R
/Resources 17 0 R
/Annots 18 0 R
/MediaBox [0 0 595 842]
>>
endobj
17 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
18 0 obj
[ 14 0 R ]
endobj
15 0 obj
<<
/Length 16 0 R
/Filter /FlateDecode
>>
stream
x��][��8v~�_��FI���@w� �0l A�l���8;��Ϗ.TU�򱪾�(���H�\lR���_�ۗo��#y����|�r�RSd�I���ej�'�P�{��Ï�����s�����~�n�|���{ޡ������/�ɿ��{�_�]��.���#L�,/������Sd�Nu%���=������O�o�>���2)�T������魞�eZ	�s�e�]y��J7ߕ�5X��}�I.����/�ߟ���ㄪ�>Oʰ�WVEXx
=��12����E��?�fy���C���}�5eH��5�^���k���N��%y����׿tjJ!����َ�"�t��ӈ�Gre�s�n�L��)�s��ӈ�GL��=�FL7���,�#��u5yNկ�������|�[�k��ҎTi�=�]<>g<�
G>�#&UE���w ���D�o*D����
aϧ�����Ont)�}���o��ɻ�����/_���ɇ��Ǘ���xy��y�������sf}��6��&-��.#�wV�-�Ϡ��7��t�w�i5����Av
u٣�N5����}�i9>wQ�9�z�v-�-�Ң{��y�TM�K�պ9j
�M�0D0�p?O�|Lg��Y�����a`�9�
�����SL�I7�H˞]��
B�a�X���x�ρ��s,�WSJ�*xs�`����q���-��}���;�ۈqS7���i/ƪ@���~��S1���[^o&�'�^�/8ާ�s�B�+y�����q��6s�1��1w&8�co�����&��:���b�"��eBѷ��R�)g#�fW���x�c׌��H��s0�������ɮ�EVv�:�a�Y
�|��>2��ءӜ�ַ֊��El��|�_w�{�N��A<����v�V)a��-�ë��lr
�E
��Z��-e�`�->S��Y��xݵT�^k�;�
�1M�{�v��w��:I#�(@�(Yw\-t�9]�����4b�Tr:��9cG�<:�&� ^�CQ�j�t�U��	S|�3A�8g��M�^���c�@8Vðf���c��5;�s��@�9�>!�ٽ�5{�����%)�&ěpW7aMW�g7c�R��<����&M��o�ףO��{�Y��Ms���|�tFs�Z-��`�b|����~��z�?��^���{��G~�����o���bN�ҝ[�V���5t��8�q�f5*؈p�:H��a��K�u���–n_��99��F���] p�9��\rSݟ�LfG��Օ�6��` 1|���=ę0 <dz���#��ص�.�#��1J���*K�|�ɔU��T}���=��(��DT��?6��3��)Z���1��xG69Qp$�#�p���T�<��gbo/Į�j��2��|�#��?����������8*I�d�.6��u4r��Y&iRqC�
c���
��PF\Ƥń�<N"H�����,�U�щ�d�>L��N���L����4�шy��w�!�5a<t��k���2���g?�W�g��e�-镫��� @'-��~�7�?�$�h0W�.��-��m@$
�XL�^�3�
��ǁ��L�T(A����e�n����v�W��7����U��\KL�q,����j�^Y!��D���a�M����`p	n��$N&$0�J5��?",�~}�����3��d츮�M���rb�#�($fR��>m��~��E�ofw(n�K�ox,��ŰƄ�H�Z�)&�X�c�n�
3L]0�|�5���x� �b�X�Zڈ��׏��r�_��TK�WL$�W��p���,�9�&F�Q6ܾ����*u��կ9���?���{Z�ߙ���5� �u�_�9��L�O�!h��IH�˴{UN=K�$���ue��B&Bm?ץ��9���b$k�<Я��l���t�!:98"�D�Ah��� ���i㣗4J�r
�v�<b�x�U���9ۊ����E*��__�_ߚ�Y�a�T��[�b{h�l	������"���/MV
��L�/Y����1��1�s~�1�
��Ռ"�׿�Pu�ٰQΫ�p5ח/0oe2J�.�)�^��i�9�TM�&��cE�JkY�?��~��2/Êaeq��r4n).c<C��fD�P�L���ע��φʋc<8�½0�p��Y�k���7�х�k �Ţ7s֍�ni��;�%�҉���vF�c���ե����t��Y��oZ�Se�f��L'r18�X�.��s��K�)Y
8�\�`��v+�i+�$�RɯݗZ���BW��[^��(i���RiY�ʺ��T�V�W�a�2��Z����gԿ��$c���OA����cp�TG�_ ����7N�k����I�a��ğ�-�v)� P�H��\�0;�d��"h�2�W�� �x1��Ȓl�fpıF�âO�s�
(T;�⁀��#�L�I^�l��֯�hT�߮K��J(;�@A9ҒHKV�%Gߪ�T��<���y*��)��<��j0I�ku:OY��<eծUu��w3�d�ZK�<U�k�<��|�5�ɡ{�˯�JiCX�b��dži����~�,�җ��6<rf� �"Kr�7R#��,�(�F�7����aq4�R�.�7p��*�j��vPL��jx�ձ�M�:y9�:��Q��������T�V�:y1�:m|d�1P���`��k-�:���L���
2�g�C�w��߮T�6��5��cr3����-gtR4�7�r�J�4�9ጲZ8Y�!��(,�3Z�m���&E�KV&�n�������)�;����L�2o�2�iP�Vm~��
Jg��z������T�V�A�L�hP�M�o?T��L2v��5�ZH��i��¶8�8
��n�q)p����e!R�<i�B��*�iE�����Y���U��
;�p���� ��U~�m#���ԺS4�(b��]
&�v�Ni)�"�_۵�Q�`��L2v���#O#�MT�ՇQ6���r��֧r@��0p`/~Sj���B(��pձ��0�}�����9b��`�8/�M(��j�S�?Մ��xpx�6���|�v�E3R���.��,�Bԇ4y_�ƶ�03��؝yqY��f�Njj��豤��XǒZ^RK6U�Ϯ�ߖ�a�m�Y	�ӓ`f�ud��s�k߳�hޚ*�
�k�qo�����z�5$�����W��3�k���L*m��|�75/:QT��QS�i����T��bANx��(,~��VLW	'�;�l%�Z8��fn1WGe*^�v�3�s��ֶ�l�Uc�1�cKR��vC�u9��ܤ�;��~��M
[&��g��%_Y8P������IM5V�;��Sk�pT�3]��ϱxw6�j�SL��F��
|� S=`�=��k��T*GsT��b��i�V2T7��j&��G�	#�ln2�R�s�@�i<z����ʉ~����d�0�bB�O��m��"pC0�bN���K=���$���"m���F�{�|��C�P�	�8*��W6
����u��C�����W�2��gn����׳B�
��2_��a�*B\칺 k�@Fv�2FpL���g̼��L�C�1ta��3�Y�H���-�Ӊ��"!�*O>�9�.�[�J��c�p@���K��:u�%�ʑ]�E.j�4�WaY�W�R(�j����׃O�q)��1WF:����i*��=�ƛ��X�-��g1f޽����ύ��J
'V�%����ȓ��UO)���"�0R�s$<�O!ެx���fI3����A0	�?��^뵽�f��i��'�}���a�&lM�42,��
]ji��2�>t���ˠ��`�j�S�c)����;���&U�ݑ�2U���c�慜T���B����֡��ӉM��Y��ϱ���Y�XA�st�bނ6����s ��s?b]Gc�^?����)zLF���S��v<�|�����ݦ0��2�qc�w��왎(û/��-y�>y��~�����#y�!��!y��r0in-���D
)H� ��?�\_�سtY�b����1@ԭ_��)����($����Y3�`���D29K^˕1p�5�b����Mo����7��I~����`�ôue
�1��op��0�`�!�n3QA�V
���P!%��fxp(:�6-Æ��+E{��~���{~�W�v4 d�'pSI�o3ɳ��"�)�1I0�"pN�ΰ*�WRw!�}4�
!����9wV�4�a+d�6�u���S�x�w�1�1;���(��F�}3�s��Q&#�)�@�)LUbc���e�oQ��D���y����lQ�7"�
fQw0<�B3�yaX3�>C6�Ҭ��[fF%`�lw0D�z�fb܁��o]�G
�c� 
�a�"_��gS���`��d^����7#m^z��f��X|1}�sa�HP���,㛹W�욹W��i�^�YӀ��4soW�I�]�m�^=�̽��]��4so7�IƮ�p3��T�`��l;��~s��������n:�0��6m����f�.�,��h�>��J1�vw�x$���G�7+���G���j�ρ�ԍ��<խ��H�7���p��멡�ԍ��<ӯ���T?�/�((�'���ի}GQ�D�H��q^fv�f��
c>9����� ҃M�G0�-��gxැ�ߐ9�>�9�e�o��c�YX���*|��T��;�7�
��M�F?c*Py��ן#SA3��T��5�l�T�2�^66t>��y�_oqS��+'FSA�� �
�j�h��.��E�l�Ekѱ�sĢ�5����,�.��.�w�0c݌��<ӯ�8��}٭Ȣ7n��pBżm�!��84F����z\UjD�F��g��݅`D��Mp-u/��fNp-�N�,˱�ڌ��<խg�2�\Kk�*��ڌ��<ӯ���Z)
��z9�,��D1��Ĭ��-Eq(�8�@T�h��^.�y��$�������$D�
6��PPjG�`�������A��Ϯ'F�R;b�L��҂�&
Joc�欞�i�a"J��#8{��)�pb��:=��Q<ݴx�6:�/ة�|���jѲ��~[�&26N���ĝ>�#CnԒ�#�<;�F��&�rA1���d}5����w0���~$���
�t5�ڟ�$����r�PI��(�2U5�f��9�V7
{̰�c���q�1�v ����r�M�j��p��	�~�t�X:)�v��f1�:��=�#�3ŧp�!R�`�h��x|K�ix��"9����o�R���_ds��E6�\ds��m��{N��0
�Fy,�!{J�O��������I���ޜr�gK�Z�p���jڎ��~s�;g�;UZ���0XLM-Y�g�s�i5D��s�9ֽQ���s��Kp&����gT��nE�k�f���=���33#�7�g�����z�x�w���J�����	JR����zB�v�)�ka���
Ʒⵃ0�����X��Y����Ǟ�NL�G���9ܩ�O��e!�E�Fd�aD��X��\0�$�����S�kk�qo�"��Ҋ��q��|�5�������Yϭ��T59(j�p仼��W���=��A;�Nw<.=�A5�]�<���kF<�j��+��y�*�GT�'e���w�����7bo[&�L�.*���SN[����k#/���53c����.l9H:T96�a�=����#Bm�"T&L�`ج��T��M�p�f����)�
�L�VA���h��@����[Y�9֬SLu
�VC4ᢚVy��{��$�5.U��!�������Sl�)����ɫ��t��k��$��RzQ����x��{ʤ���3΂��������'��H�@����EaJ�%0F6c�JnJ�H�]~=���z$�K��o�=	�R�4�yp`<�k��i�R�@�u�[�ނ�@���< ��p�g��XL���Nل��ݴ>���׮�pc���_j�1�g|`LQ�L�)�Ѷ�>rS0��e�E)��*F�,�^���Y�ê����2X��j��wai�EU]�!�1~T�4^�E"�n���4��ӳ���W�1��r"�Fg&��2��oh�>#.<kU˗��ŀwP�ptk��]�s0l�Zk�����	�F��+����S�>��K~8�|z;�*�~N>�I�˙
endstream
endobj
16 0 obj
6379
endobj
20 0 obj
[1 /XYZ 33  
760.250000  0]
endobj
21 0 obj
[1 /XYZ 33  
672.500000  0]
endobj
22 0 obj
[1 /XYZ 33  
158.750000  0]
endobj
23 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [102  696.500000  175.500000  705.500000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
19 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 24 0 R
/Resources 26 0 R
/Annots 27 0 R
/MediaBox [0 0 595 842]
>>
endobj
26 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
27 0 obj
[ 23 0 R ]
endobj
24 0 obj
<<
/Length 25 0 R
/Filter /FlateDecode
>>
stream
x��][k�H~�_��Ȫ*�.`�maaL���C�dv���d��+�JmK꯺��QIrk㶫���:��\��o>F��#����-zr?o>l�8�I�_T�{������P�}���l�G�7����7���x���h��4�p���"�����_��~�����e��<�_�l��痿�$��TeQ�=�Z���?��V�H�"I�6ڨf,��߽x��=��K�gi�آ��mZ&����&o~���JuE5�迟6�V�?w]�X]���\�؎��:)�Ĕ��]�&�vm�w]X=Q�:Iҩ�V:��k3ݬm�w�~� ���c[׏���,R:z�5j���X��2���KtYq�۫��M�L[�C]�ݶ�b�iV�5:�LRl[t\6��hɷ-YlR�k�ٶ�q���Ӣ�ۊ�ߦ�{F5C;f�ʺgt�t����Ūf�[�kɒ�tG-ۏE�xf�w�j[��768S��c�<CЁʶ-*iሱ�Pccf�W��^�d��;�z�L=���h�N��z�n�gf��ZU“Ep�RU�7�����#P7��6�{C��Y˟k�6�	c���Sg��ʡVKM���ⳍ�vݞ���·u
�֔�􆟁3U�n��h(�.�����u+�d����pl�,`���L��Cڡ�CU�Wam���@��Ң��ū����[��k�G��YQ<6QY�5֞�:�������aLT��W�je�~Ō��%xl��q�4sd���{��p>�}��ӆ��q^�9 >-�B«������lY%�IBʾ��S/��2r�s�	�Jiӌ�Ϝ9��߆׍�q?�؄W�uX�1���0(>?��Q{��P�@s<���
�,���9Ƣ �A�=���fzռ��!Y����2��68��#��`��,����5�ش,�ʌs�72#���-<Z�!��y�(���&��H��1)�3�5�H�㑍p�L��i�׎
�(���(�Ö#�_�������LM߶�I�&��X��Ԝ�Y棢t��=,�O]�`��Lg�c��~��||�Dc<c��]����+F�y����L���M���*y,+S��<�V'T���і��1��P���o������"�yZK𹓃r���;u�Z+ĩS�wwF����윪�o��g܊�=�C�������i^w�3-������-o���
��ma�s�=-�|��[k7��V]|���kty]�����Ϗ���]^EWW��Me��Ԭ[:�-�����@z�x
Yj��$�S����x%�Q��Pnj,T��	.U��9%A�itzSQ6�`֩���qf9J�ך�����!v�Ѐ���=Ϻ1#M=�*�h�ŒӠ�]K��J�^��b''�U���@/Lo�N��:�dD00�h`��]�i�c��P�t!*��IE��|1�I���a*Ɣ���Hr	v�^�ƊNmՎ�9i��lL(�:D�d0�a�ztZ�дCr��H��uW}N�_]��.f�"�=���i�zi]iӥv,�-�#'���̽��AP%n�Ex=�;=���dG���lt��ӬC���Ɣ�8�'Iq
O%,&�
%#�F(�u���u�Y���%Ťp�"_�!r�* �	k	�L��̙�i�H*�S�h�u��u�OMYf�2�5��L��Z0e����u
_�ܨ�I �F�Dcӈ��Ri���U����х���"!���S�J�T#F�I��c��>ƶ��ƒ�k���-�u��Ze7}խ���q�Ͳ
eh��E�'��QO?E{
�	����`7�8z����6`�;���f\?.�w����:�昬7��M m�z���k�۽�た��'Z��^:~z�5����6*���06{�-0��S6/+ΚD�[�vL�'SJZM��RԢ3ؒ÷�?c`�{�Ƕ+Yp�v���
?��CN�=��X���~q��cv��Q�������>;�={C{����-����kf�:�EA�2\�c�(�py� �\}E^G���̉�t\&f'��e| ��Ӣ�ZZhDiaܢ�( %Q�2XQ�h�Y_��2��s�*︨_&N���.����?ӗ
UR+�n���Ƕ͜��"�! �TD*+�H%��0&UcLy�bLnj��1ݞ���0�|��б�ɔtn�H�zI�a@?��>�w��ZO?p���P��p���h��u�?�
����׀���3�����mx>pv�){J�vDxfzD�;��8"J7Ӂ�\8��Ԧ�eo{f��ɫ�2!�TBR�[̙��P�P5��LgL;�[ô���
=�`� �G��n�w�L<
�N�g�O�^��ee�,f��w�2�eW��:���F>���QO�u<gY.N+��
N��Q��xu���g�����5�s�5�iM�2E�y�!���!ѬvFV�t��)X���9'���5�i����j%VPa����%�.����z•���4��D&
��у��PQ��WӔ�K�	D��S�%�S��7f�Dtc(z���c(8���R��#�C�YSl"��S���)�CY��n"���N�}��1o����A�pd���%IJp���T���N�(:ĈR�2��Rr���o���[Ӭ_q��8N�_!��zb��I��b.\�\W5gj��AK�� 2��P9���R�����:5]~��2֣	�)U{}r4P��9㫢!�]�	N���Q:a��H2��ZF�Jx`8c��R�B�<�������L֑��ߕ3k���
ߜߐ��D�R"��rԱ��|��	��Ռ�]�����хSC$�褲�I�59f��]�*�jq�1/�|�cN��#�xl8����*4D�,\�œ�B����6�R���I�3��'զiQI||�OQD��a8���"56,v���f`{�1f�"��)Мq��
 ������E��dZ&\;��:)�:��.�-����I�zc�#X(7��&�J�Ya�sm������5)���r���6�U
�	˘v0T��|�:Õ�3�p4AUA�QSz��l����}���PWN0�o�f&
=P��$p-ҁ$�N-꘠�F��YWa�zeyqJ(�䭭5S@`r�D$�w�eʛ ��ں��k�K��]�ʚH��s-?��eO�C|����`�ū�]��NZ|�^�%�|�f�e{���oCA�L�;%���b\p�q�@�D��Y__q>.+Y�6��dwA��REsj�p�-�Fvi�+���75���g2���t"C��@������iA/L]&&�;ZTa4/J'c¢�u(Cp��"�ra�!,Z��|*Hyx���g�|�!�K��Ҥ���Ɋe^��9��[8P0*e0�D� :ZF�O�+Yu{�4�	�Ǻ7��8,��k�

��֙���%!�F�u�"�{8�؈;N4����\���p��sL�'%�]�G��f��n`竩�ʗ$
��W3���CwӟƼ1�NDY�
<j�?ؕKd=c!�Y��8C�s% vM3��%#v�L�j�|4n��
�3̮���!Z&����C���'�u�>��a`��_E�d��dM�*Ü���C��'�)ܽHת��J�b�	#8��%g��3�e���C�ݭ��$���t��s�;���?����i��fH�MUv�4�2N�~�Y�bE[dg���y�[��u�dE
�pL\���x��5p��_����G�gZ��%-��'�~�q?��i:p>�G{�;<86Ϩ�Z�)E{�Z����Ňo�F�����~������Utu]�����I�Ļ���{��MO(l���>H"=�������.��gڿ�tJ�/~�ǯ�߆Qc�~b&�^`�`�36<S쩹{f1#��<k�;�1��(���*�mN�]*�?�5���P	@�_\!�dR�2LX��%g�$H�&�@#|��
L�B�DR�T-���e��1��r�<Ӄ�#mu}q��O*��d͇2��ZD��S�|ژʒ.mj�c:ϙ�}���Oi��T�ޗ����T����}�m����-q�vY�b0�e�e3!��*u�2bh,�m}ߎ��s�ަ,�)���Z ���w���]�g�z�
S��p"e�0.L��>w$!�S�
�T�����Ϟ�ߊ��s�y����'�Mټ����uK�y.o�7��Ow	0��7�v0����bJcȂ��0��<��Q�;���Ս�Ӎ�@7�N7����tc�W7�N7���:��vtcD7�vd�u�<�=+r��E߽;2��d�=l��S
endstream
endobj
25 0 obj
4362
endobj
29 0 obj
[2 /XYZ 33  
122.750000  0]
endobj
28 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 30 0 R
/Resources 32 0 R
/Annots 33 0 R
/MediaBox [0 0 595 842]
>>
endobj
32 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
33 0 obj
[ ]
endobj
30 0 obj
<<
/Length 31 0 R
/Filter /FlateDecode
>>
stream
x��]߯۶~�_��QDR% ����A�a�C��+��h�
۟?ɢl�G��=�$�-��k]Q$ux~~����}��?��O�>��O7E�l��u��:�B׹�������/����͇͇�߯�a��?>��y�?k�����f:�s��/����������S.�V�����_UQVyը�n�/����߾�~k�Q�uQhm�Q�\F���EcrS��u�'}�޼����)U����\U��sS4ua�F�8�:Ӯ6Y]����������L�6j�U�v��z�-˹]٣G��4�i
�w�6���L���OY?�W��Oݤ_�J�٧�7�����/�k�cd�ʷ�+-+��ck�+��^�y��rp�m�T�)���T����NSTz|��J�'s�G�y���Q��NF�g���}{�iZb)lKC�g�m���>��c��P�mYE�������.�~��J��P����Ŗ芮�G���g�G�s��	���<�|�4��wľ���{�[PO�
�Q|O��RK�����liBQ`�0��R\n{�xf�',3b5����h�>;��\#>.��3��S�˕=�G�p�X�a�7P���]1�z�w�dn{�Tǣ����;�
�
�SL!�9��8^)�~�J��M���k5�S]���&NcO	��J1+
�5���g��A9�U̩'T�نs���;�g;0L���̿o�����$��E!�-�`�_��{��4|����w��s�Ѱ·�~�	֍?����ϡ�)>��,œj��h�,���Jg|^i�]T1l�5o�9�mc
���ŋ�|���kF�3r�
����R/~�hS{?��x^������#�1��+�s���O�!��7�K5Bã�xLU�v��5���`���ю
�C�d���L��L;w�s�<�Hfn�aC�Q
"�,��)d���u�=��D�ak��Q���X�c�/���r����X�a_�����a�8�!4�
a<�8��d�\���!�nʒH�����̬3ұJ��1��v���q4·&�!�:����坨�)�	{K�g�mh|�HD,����vCx�(l�|a�/~��i�*/Ϟ�h�S	O��P��/�DL�c��o���:M&1.Ӯ��T�(m����ДݷMfl���Ƙ�nli
��1��L?^�w�'�q6���l�w�'�W��>7�����7�v�%�R
�b��� v)��:î�����e�?�	̸(0�"f��eR�9�Ue����b�sZs���DZ=�AkΉA[�b��y$�+ft����b��Ġ-�xű쮸�}nor1��ދ4"��`�F�7o^˫��&%��f=G�i��.'~u��{J��$��D�hxw�Y��-����=
����'�m?����+)=Vڙ�R��q��@=Djh����F�ר�D
��$��0f��
f,8
*�<��v�̕#��=&U�EgM�W��:�D���R�wJ���hIK��H�C�T�X�w�J�dV�@� ]SPeF�L!�i�zj_JU���g�0)��l�X�{�q�2%c�)܏�M؟�%���?NȾ1=$��Uy�X���X��-���9F�m���}��G�5�<�k���G(��7��
�M�k��-9��5�I��6L���a��t%�2�0%u���l@1Ʀ	��X5!��	�V�l�F��HuW��>ӏ煐n�	!�gu?��Pwō�s�x��vJ=�:I�'|Xc	��W�J(I��'P�a�[N[���d.��=1Hٸ06>q&��u���O�sc�W���C��J1�2����Ʀ%ƣ�H(��*S�����4Ʉ`��.�:x � 6+�l��`� R"r��k�uJdu�%ci��Ho�Ա�t�3$қ���\۵%�PJ�? �u%��Y��jb�8%]�Y�D���Dz�B�x8Z��͛bo�ԁ��JJ��;��)���Q;����N�Kn�i��o�$x�#��G�:�DG�K��D��z�R�R�BZ���C(=�x�B�����l`bс�K����K��f'�����ޛ]��\OJqN)�aJL)α��M3�CJq��g��o��~:���v����9�.믘�}�o�]�~:���֏w����F��a����ڧUvd��F+�S�İ伳X{�d'6U�F6�l���%;Vdx1�����4�k�mz�|���bF��~<���5����cF�7�;��
�M��w��,��C	��"ӞR���͠d��u��o[p���Od\�L�FYe<I�E����7�(p�xJ|�t�;3�\?��[oF�쯘�}��K�s��o�x'f��f��Q1�	e�0�����dV�;�&J�ξ��Ғ~?�c�#�����0:���=r��VE��\]��~�6�p4�4d�0�"�R|�h�3fp������q�9!��;
��"��Ce��<�յ����N�s�s��J�d��ld����P���'[l��+D�8Z-aѽ��=ӆ�rO-8�("�q��XE�0�%��i��$Yr�E{����ej����A0ώ׊��'۴���2��ފ���_��������HA�̖�hG�
5�&7t1��wZ�zO@��.1��c\�9�33P��)*%�V�ܶx=Li"\	;Zq�!Y�:Q$kՅ��z��x��n�Kkԕ*�p�
"�qkPvk0�d�2���N���iķ���)����1���$�� *���s�E��f�p��:�W�4�Z�p�^��>q��f�w�/!x�a�jD����ڬ�V�\W�Q�Np�&zΚ)6��	�������%�X���v'�a��.��4G�]^۫�Ԉ�d�����i���D���ɋ�i���d!���(`E
�S05��d���0�	�<Z�;���l>�%�Clk�T63�j��U�˥�C�-M��z�D8�8Z�=�B1uK/e�i�*�A�_�C��d��=/i�B{��B؏�W�=<�9�<"Sۮ��
���a�����|�sD�����@t����x���M�E���h��D��<�=8��R�i���X
Y�e=3�G������b5�����Z��8�mw�u�xkd=I҄��0>t&Qg��%hG[��{�|�J��?M�-�N���rs�Ө�M��ȾZ2�_D�Mh�VM1�'&1X����{�e뙊�~Y4���p�q1���l���7�
Y�-07l�0�3eO��=?z`�����pNe+�&~jsK��e�zu��H���$|?�Q7�\S�e�R6��e�D�[`w?X@b0~��9.W7�`٬M٦DK)>s�M4�� ���yͮ���,���5b�p¨�!:FP�.ք������I�{Sp��)pS{��u��|kY�1�@ٜs�$u�U��������&�Z@c�h�jA�{�h��0o�;)�e���'�-b�2�#��E#���/���~I*:gAP�T�]��t�mA�==P9��K��Pxw�zp)�K]z�f��uD{2��T�}�+�	C��~.�P�M������R�C�q�{b�K�L�����`���h�
�>A��ݡ�'�*2�*���K6�R��H&�(T9VP�1�e_� !LX_�l.C�'��OW?�2hiLЖI|`����Zp�<�!��U�uHgL!�DJ��FHe�Dʞ{��%�����e�#tsʏ 
Hf\�E�W�[p˄%�y����C6%���~��@���jx�=p�O`�5�ҿ��0>O�r����lS�/
ܣj��d�s�=�Ze�rmp�=%�G���K��LJ"��Aհ����y��~�`рl����d�쌚|�nRluE�23N�Y����sƸ�rB��+3ZٜY��jFs���Q5�9�'K6�K������qn�\��ŝr�RUc.��JL�A&�ɸ�M�q�1u2���x=Tg5�
��y�@L���ك�Tp��)��0�?��*�P+
50�UYY�)Q�n(��2��F
��s��3����>T�X��H�e�
�@D%*�π�ek��j�8��L�,�Ra,�{�Ehk���u+�Eh[����"t�G+;c�iBUu�]�qY�y��������*+(�w��dmelj�륱RyY�x�?I�Y�fl��r��'�ɟ��<�]d�?�W����y��@��m7���@���u��'�M�gpZy�	�
�?�P�8�X��>&������͛�����������y��}����S#��t�Q����/OGKX-yu'qzO��9q�uQfz]j�W�'��q��PR��8.��g�Qp�
�5~���q�#�F0��v���BLj���ui���#��u� �<Ǫ<L�Lj�x���B��$eG�}S~R��1~s�Q`����]��g�F��A\����2�|&�Ō�JL`��tL�
�c�f��I���!�Ʌ���*��h�B6�?�5�r������9S�N1�_89�-�G;2Z���ឪ���LQ��\�S{b�Q�]�u���T�T�I5,�T�J����N�z(��_�����2�'Y-�WF����6�kO��C����T�}�T���V���M�}�3c���7��ucKS�o��g��k?u���订��k�w������~޼�f�l���U�m-w�c�UG+0�,?�
�i*v�2{@(��y���.���DTIej��Տ�"����s�T��T1,���i{̘ژv���D:����y��נ�;���C�a��l��
endstream
endobj
31 0 obj
4897
endobj
35 0 obj
[3 /XYZ 33  
765.500000  0]
endobj
36 0 obj
<<
/__WKANCHOR_2 8 0 R
/__WKANCHOR_4 9 0 R
/__WKANCHOR_6 10 0 R
/__WKANCHOR_a 11 0 R
/__WKANCHOR_8 12 0 R
/__WKANCHOR_c 13 0 R
/__WKANCHOR_e 20 0 R
/__WKANCHOR_g 21 0 R
/__WKANCHOR_i 22 0 R
/__WKANCHOR_k 29 0 R
/__WKANCHOR_m 35 0 R
>>
endobj
39 0 obj
<</Title (��PERFORMANCE OF ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_4
  /Count 0
  /Next 40 0 R
>>
endobj
40 0 obj
<</Title (��ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_6
  /Count 0
  /Next 41 0 R
  /Prev 39 0 R
>>
endobj
41 0 obj
<</Title (��LIMITATIONS OF LOADERS AND ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_8
  /Count 0
  /Next 42 0 R
  /Prev 40 0 R
>>
endobj
44 0 obj
<</Title (��\(Available for Linux 32 and 64 bit x86 servers using PHP 7\))
  /Parent 42 0 R
  /Dest /__WKANCHOR_c
  /Count 0
>>
endobj
42 0 obj
<</Title (��IONCUBE24 : real-time intrusion protection and PHP error reporting)
  /Parent 38 0 R
  /Dest /__WKANCHOR_a
  /Count 0
  /Next 43 0 R
  /Prev 41 0 R
  /First 44 0 R
  /Last 44 0 R
>>
endobj
45 0 obj
<</Title (��Global settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_g
  /Count 0
  /Next 46 0 R
>>
endobj
46 0 obj
<</Title (��Security related settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_i
  /Count 0
  /Next 47 0 R
  /Prev 45 0 R
>>
endobj
47 0 obj
<</Title (��PHP Error reporting settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_k
  /Count 0
  /Next 48 0 R
  /Prev 46 0 R
>>
endobj
48 0 obj
<</Title (��Deprecated settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_m
  /Count 0
  /Prev 47 0 R
>>
endobj
43 0 obj
<</Title (��php.ini settings)
  /Parent 38 0 R
  /Dest /__WKANCHOR_e
  /Count 0
  /Prev 42 0 R
  /First 45 0 R
  /Last 48 0 R
>>
endobj
38 0 obj
<</Title (��ionCube Loader 14.4 User Guide)
  /Parent 37 0 R
  /Dest /__WKANCHOR_2
  /Count 0
  /First 39 0 R
  /Last 43 0 R
>>
endobj
37 0 obj
<</Type /Outlines /First 38 0 R
/Last 38 0 R>>
endobj
49 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/Outlines 37 0 R
/PageMode /UseOutlines
/Dests 36 0 R
>>
endobj
34 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 50 0 R
/Resources 52 0 R
/Annots 53 0 R
/MediaBox [0 0 595 842]
>>
endobj
52 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
53 0 obj
[ ]
endobj
50 0 obj
<<
/Length 51 0 R
/Filter /FlateDecode
>>
stream
x��[mk�8��_��u�jIP
M��AI�>��d�X�e�����?9gc'��L��^wj'�F�g4�������MLf�/bI�ټ��w��'�g�_�Pҽ�нX��ⱸ-n��Ǣm���|(&M_E��|�{��Gh�k��I��W��%�����+_�M+�>~�����*�����~�c����e�Rk��jl�|>3��Rz]=���-C���hU}�.�W֧�(c�&j�ixO�0��F|}W��=v�a��a�:7:�Lsg��xW	S57��ߦ?��.��H��I���3M{�s��l]-I���NOI�;z�m�c1}�c���:]��J(-�E�γ沸/lHތ����<���B,>U�5u��O5����2Va;k�Q�DV�#�:�qʭ��QkZ�$��}ܚ6+�++�Bg<J�N�0�=�s6$�$��=�A�d�Z���>�X0m[���ܬ$׋Y�	��*6�
h�k/Tj��虦=
�v��uԞ�J-�=߶w�Pq����H��'���i±TU���N�X<�����i�j86���e����
+��=J۟guI�m�h����Zs$1Dt��Op�.����}�~h�w-�
�M]�E��w
�-c�"–�t��6C�@V�'~2�r� ����r���ϋw�~���BL�f�o���	�����f�s�i�9�E�/��3�h�69l�B�-%9~Hk�$��A�Ϸ�%���I�x<ж��8�C�Hە�9�'|Ɯ�<��H1尚���o����:��	ýÊ���4u,P��:r��������kF�Lɣ�2o�9�5JX8��o<ی�o��0w�5;j��V��-7q}�a�q�����U�'7�+�wr��^�t}ﵳ1A��o�qi{����"�� �LSZ�����T� ق��dž[-��
J<l-@�5�(�����l5��V(���H�Q���&��Xpu.��AI����X.�D+[K�h{A�y�4��T���8�7=����T���l�p5R�XX�Dl5&[��a	
��g�8&[X��=�$�A�2�A9[Ƒ�>/�U�F�=�l}8��l�q���kΜ���x��yo��Z�)�`Te���/m�(�%N���b(c�S|=Y
[�WN!��a�a�i�:��x‘|�����̄���.Y��3?��>r��b$�f�8�9ebNfb�-�Xqkx�F-��r=^�Y3�U74�}��GʚG{����ɚo��9��L��É�qW
�	���Ki�������i�G?X��8��3��N������돶*��)#�<��������aX�*N�{<��-2��sh�Q�aU?�T/�T2���F��a���F����g�.����13�ގS������ [�'�Y�����B֬�^:�� ��F�_�U�o��u��|˾V���-W��h�#�D���D��~3���
[�Gj�8�18��<���Lk�o�6��L?��K��]bT[^����'_0��ls��K��[��Y{XE�얞�]�^u�����H��Ȍ��d��}����jz�
endstream
endobj
51 0 obj
1581
endobj
54 0 obj
<< /Type /FontDescriptor
/FontName /QCCAAA+Roboto-Regular
/Flags 4 
/FontBBox [-736.816406 -270.996093 1148.43750 1056.15234 ]
/ItalicAngle 0 
/Ascent 927.734375 
/Descent -244.140625 
/CapHeight 927.734375 
/StemV 48.8281250 
/FontFile2 55 0 R
>>
endobj
55 0 obj
<<
/Length1 6976 
/Length 58 0 R
/Filter /FlateDecode
>>
stream
x�}X	\G����{�F�1+Ȍ�`�P`&�7�)ry" �9ܠ� ry+(*�&��&Fr�I0�$���[s=�xd�M6	0��g0׾���ꪯ���5B�
�L8B����j�=���bI��_�y=�����Н����q!l!���';Ư������삲*���`�B`l�1-���#d~&��UE$�,�v#�U����7�	Bh;��`:Rp����$��V,�-BGb�j���!K�������eD$$S�A�e�x?�4�C��Hm�9"'���B�j��S{5�A�M3ϥ����a����F9QG�5��S��rs���R�*Z9�%M1�_��$���Wq
{��Q�87���K��0Q.�LպA��t�'�蝝���>��y?p��rqQ�r����j���G�J�����J��˴HF���t4x�o��v�\�j��b��͍s�Kv�����}{\,�'�4��Sm��MAA;��Vo���m�����3�((D���'�.�J��^�Q�Y�˱
���˰�3Q�޸* ���5k�z�f����6�~�R��]�}��ȲF�uS��F7�� U
R�)u��Ͽ�c�}��q�C�O}��2��_b��LY9ik�=��W���h:�ցCq�[�x::��ip���V=��m���@��Z��)&���p�
�>�r���ө�͐��O��A����.I�C��dg����i�D���Q�Т�5(	�c^UR�w�h�m*�����x~I™��aT�s��=52b~������Y�%���,\'	���y2�� C.���
(����*����z�����<����zy�Yï\ޒ�]�$~X��Sl�&ž]�O=�ych0���b���4�>m���Ҹ=�GG2u�_8������
��g��_<r�9%���7ȝ+�Dv��4ȡ���	�P���*�����R�t�)lk�9��
[6}s�Ͽ(- z��7-��7/GpZ��->	����W��HNJH�O]pLTĬ�����8~�r�������Ӌq�9��~�-���e�B��ՙ�%�J�ʊ/Mݶ�K/TT� *��'6�(�ˁ�Z�=Hʚu�,7eew�wsr�^@�q��!�-@�,����<��t�[�w�3�Of�05�a���Y�L�{A画�-t�3���kȽ��"C�#e��	����B�5�shk�y�;�����[�}7�K�1�v���*�-�ta@#Q�$u�����;�	�i����s����E�1g�
@5E��c7��
N���7��7�aD�w�M[n�ݱ^Z��c�@85<��k���͟s���:���e�:���d���(%���z�r栱
�o�me�Ĝɀ�Q0��l���N�b�se%��f���[�fN(-?_��a�5�!A%ً�KČi.SfL���ٺz���}zf��5ST3f��Oܓ�`��ؔ$�Gf�`��C	���e�����S��7����h�Qy��j�Fx}CϳM�Qh&����fU�A���P\t!�R��C�.����:���g�C�����R��=0i�/�f�7��96Ԓ��|�8���g
�:Gc0���:���l�ε�!��j�C����_�!Ӻ���@lx�e�@L秅���榦ܬ�C�,���*���М��Q�us�L�O��{�ȎTo��q2_�}��3��-�Ȫpu��Ip)�y�f4��xk-i�O�x�8�e	��&7��Ouv@И��g0�T���� 6�gҁR�y��^��@��7�lc;r�&
��Y7s��R p���Wh�:l�<y��ox`����Bqp�9u��zl�Ĉ�fzt'HrS��{�,6\�75X���/���Ū��C�,k2�&� Β�Y^�I9DL���-9Ē�-�	�Aa�O��⋗�L]�E���	ډ�ا�c�-Y����!�`�^q�?����C�򲑃��܀́�Z���8�\��ҁ��O&%u/\0��{%��m�ɝƧ��ص�z����N@����{�y
�i��J����t��K�4L�Yf�)�e/_2�vU�\+/*�K�8�a�PV�|DĶ����Eb�5��h��um�z��\n܋Ѹ9i�:��s�w�^*e�>�M��8Z���U�8`XG
9}�M���-v���q��q;����|I8�ֿ���28����6:���;��>$i�y��:��yj_��"=nNN�w��,~��#b���bRӱ�r���<�ďCk[��;�b㫑[F'�#��caP�5��%�����f�6GF��n���}q=�h+���X�r��:7��{�{�
������*��l��H��F8-ԞY(3R{{��I�o!m�����.q��o�~��r3p����¹vH�R�V�W��`@;�?|I�ʸ�	�Z��i���an搋�=7��ws�,�g[�C�E����
w��Do�q{��e:�x�S��zE�Ͽ�3��Xc��Ajd�a��^�/�g?6ԇE�B�s!hw$�Ò�v�Ce~V8UT�NSz���m,�&<�f[h��4W��/q�H�`��i��\ø�ܔ��lQo�0I��ѰȲ����AK����	�	����[{N�7�F��5ԟ�i�z���?���A^��73��]�u���ĸ��Wr�?�,!>���w(������w삦ъ�d��9���
{�'��pn��_�&�S��{T��j��j��C��Q��Ć(8K�e�?������2w6]��NP�~s|�3T��x����]��[fa ��_h.^��\��u��,�o��!����Z��r"�s
ӡ��.8�Ҟ�K�钘��_�>p�fK�©���C�'�w���x&�47�$����1)� �.A�X�eV5<@�Q$!��H��$ǣ�?��o�,_��b|����1q�Lv��gs��ں���kSo�]I��s�<U\�矑��.*�-0��7_��7?6��tn�?����>2j���ܹR̟����2�����Ar@�\��;M�_�i.�]����P*��{�c}�F�I��a�S�r_��F��GLs@��t�,�L��Y	��e��Ξr-�
��VUmqۓ�l������%�^}��+d}�#~� ֈ_v���@<��
HqҨm�1����-M������_��N{09���Y�1����y~4��W�:V\��Oࡺz���K�û�z�
R���nc�C��

���?�;������@�|��@��k�M�/�Q
U2m@�Z����������{<�?����v�ֱ��1F���L]���2�)
�~*��w?�׉�22�\	��\s3�ف���ѠF�1�p���a4�bW�IH~%�~c~vVn�k���6|��
v=va!�[�Ö�ԯ��w�K@��O>�Ry�/�,X�b���+���4\��k~A�b��G�$���߁|T>SG���z��@CKmd�Ⱥ�Pl��[����V-^�i�[W6m鍈ظ����{[8/(�EO��^LY�r����1k�g�� $�nS`���d�͟��z+jU�h'����b.��r�zDox�XD�Gr8�'8�;0���koG��y5A��G`�_-�A�5�^�K�������~I��\���a`���Po�,���}F�nS�����1Q
O,[q�aIuٿoK�����mz1�v@n�,
-�킁D\����x���˽/��&`�6���G]��W
��5 �Y�ꖳ�{�5�ؑ�A�kX���.޴��k7â�%k
�Be��}�����O'�au��a ~S�8�ޅ�s���+^,*����k��$&���k����H���P\�
*-


(*	F���yi�C�<�,'&Noga[±Z]��1����3��19��;.������-{�t�)�'Xt�p��qw�s�����]�0/�\��uN���c�s��J���l����G���d���ؗ\~	q4��~�*`��w-eI��Ҙ��a�.�>"l��U[�]�t۶�G����u����/!��ի�ڒV�&�FF�F)�;�S�NB��Q_d���;W���4�.�q�����*��o�����K"A�L샩5Q�!;�/����ˌ��1u՚M��b�]� $h=Ƞc����G}��R:��eŌ��'�Wԥ�}�0R��Y���4��F�_�f��ZO1��]3�m���z0Ƃ�	T��x	9q{���0��0�=�*��7��� F�
��qęat;�T��b�?�����s�ϛ���<Y?��s2�7&^���4�8�yp����P��m��'?<�G�����1CvO�<S�����E����8�PvO���+�k%�����"��\�*�I%��r�!��<�C(�h�ů$|I��a�FҍEO'�]��U$Y(%�Kē�ƶY-�H=Bl�[D��3z�52�)�X�%�!]��8#�$�N��82�{�8��=r���1�I�lߏ'6^X��.��#d}�l������$
�x��Fҁe
�D��Ä��d:�Kƾ(,EXJ���C���+I&J�Dw�F�z��Ë$���,��x�O�D:�.��t#�;�rq\%w�����Z^�g�����`/L��B���p_��"d�&�Q��Z./���$����M�M��36l�ٺ��l�m���4f՘�1c��<6�IKd�#i�/;r�A��b�3�wZ���s�:��oX�<�oY�����u����d�
g�^@�HX?��)�z�Z�Ek��5k] n䶵.#N���Ǔx��IYGJH�"٤��P��o	��F��'�
#�$����"���w�Y�R+�H���8��֕�de���<<=U!FcV~�*�0m�jQ~�*�}*U�f�f�Td��X\o-�2,$ָ�X��H.��㒩H��fd�秖����Cg��V)�k�M�-��
��?�0���c��k�����x6�����x�p��EJ�-b����8�K~��'f��|d'
{
%��bO$�8�!‰ç�Ħ-++�3���rvjQjZv�lcI֜�����Ҍ�9�aA�qA�^�q��G+�
endstream
endobj
58 0 obj
5244
endobj
56 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Roboto-Regular
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 54 0 R
/CIDToGIDMap /Identity
/W [0 [440 241 566 547 646 547 557 526 246 534 540 559 336 557 557 261 643 512 676 592 546 519 869 324 481 241 557 344 557 626 707 195 557 270 745 469 564 611 548 682 866 647 707 651 589 880 339 345 492 240 503 557 557 562 448 210 564 557 557 557 557 618 274 409 631 317 237 ]
]
>>
endobj
57 0 obj
<< /Length 826 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0042> [<0069> <006F> <006E> <0043> <0075> <0062> <0065> <0020> <004C> <0061> <0064> <0072> <0031> <0034> <002E> <0055> <0073> <0047> <0054> <0068> <0063> <006D> <0074> <0076> <006C> <0070> <0066> <0067> <0050> <0048> <002C> <0032> <0049> <0077> <0079> <0045> <0052> <0046> <004F> <004D> <0041> <004E> <0044> <0053> <0057> <0028> <0029> <0078> <003A> <006B> <0035> <0033> <002B> <005F> <003B> <0071> <0037> <0038> <0030> <0036> <0042> <002D> <002F> <0056> <0022> <006A> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
6 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Roboto-Regular
/Encoding /Identity-H
/DescendantFonts [56 0 R]
/ToUnicode 57 0 R>>
endobj
59 0 obj
<< /Type /FontDescriptor
/FontName /QHCAAA+Consolas
/Flags 4 
/FontBBox [-432.128906 -302.246093 677.246093 1011.23046 ]
/ItalicAngle 0 
/Ascent 742.675781 
/Descent -257.324218 
/CapHeight 742.675781 
/StemV 70.3125000 
/FontFile2 60 0 R
>>
endobj
60 0 obj
<<
/Length1 11900 
/Length 63 0 R
/Filter /FlateDecode
>>
stream
x��yytǙgW7�� �H$��M���/�%ID @�hZ�%��x��-;vd[����$���x2Il����;M6;���y��y����Yٱw=~�l�W�
�e�X�+tuu�W���jR����8�P�������`����%Vf�Ux�o������c�hde��e��X�<�L�=<�����}���u<�<�6�����ߚ(ʌ�/.��[�ڨ'(ʢ�g6^��ێ��\MQ�a�͢�(1E��(
�;�kj��

i����E-�J�7��՛@��c�R]TwS���'hZ:E�)�o���bލ2S"j��D��̀�
8EJ�7;��J��:\��`��_G0P���K���f�$��Pe�_���!frMD��*U��@p@���h����.�;�c{��~Ra�K
d�R���D)SH*�*d����5��n��g���x�mv����5FCqQ�`�r����`tnZZ�T�*�R��^�����A6{��*'CN�r��`�>��{�#�3j7��2�L&/S�f���T��j��L=���S�ĔL�R���Xƿ,3�-f�N���(�c��"�Q6����*�uא����w���4j~<��+���wN�[L�M���X���}�d:1>��b���TZgecS��PsyE�R�r9C�};�B�e��[
��8]�a��
<��90��r"�����L
���Zde���[�o��k���}��:u4�&��Rt��k�e�R��ܳR����rW�<32|y�'X+˖;]����
�r��P���ڽ���!T(��ܭk�x��n~¼���sb�
`}h�?�(��üпep���@�}�����������7���V�3�N������4*�щ��	��W:�Ln�hW��~�ď�M!�,e1���NY(��pI6,R��I�y󌤦ʍ�yvx�|��Zv����ݡ�J�ԾW���x��Z���~|�������LTӆo`i]���.~!U�9s�,�o�޽���s�`���XOW�W�}�c���^�pT�ܾ@������Se������� n�x�;�j�[�*�]�������g6�r�F���3hd
�V�x�
b�΂f>O��:���
~B���yv�I�(�IN�cD����oyk�g\Nvpr���[������D|d�)d1��⨫�i�Ֆ;�Z��5ώ�AbF")�>��:��g��Ӄ[����clr����]��ju.w�	�3����_�V��h*l5�kg�:MqQQ�Fge��U�+*F��H��ZQkQ�����q��Vi���7�xt��壍�G�P�:���1?'�F�<�`����(�
�+ǝ��q����o�t+����;���yi|dϤB����~���@����;=�Z�����P���j�vn�xh���.g0������PR�˟S(d�B�!�����1��])*�����`Vi
T�؅�I���9�n�(U>恟���p�Q=�*�#�b�Q��9�/�ռxF24:>3������!�3�u�r��;w���b��^g9�H���G~z�>PQ�ӵ��/�xr_k��*�0[�
d?)hؐ�2�+RG�-(v�y�����3#���*�pEy������\�Ku~������(6Z<�mkG�.�͊f��p
��,���x�}k�7�܀=�T0/�hw(y@�k���PwV�������.?+���X��5L|5���Ţ"nJ����y����~:���k�6X��6�W)��\i���z}�~�}d��~���֦{����%�4>�Z�8R�p?{��$�L��bdU6���|fh�7/{�G�=�.W��eI���$�'��OdZ��3��$7w��Cj)������5�Ȇ��6���F���]��Lks�ɿ����ll��W[W��=911��BPf xO_s�ۣ׫U���ᕖ��;�5�xkL�B.���{&;�+���˂��\�+)�R"��Qc�F�F��hL*��Q�u{�몽����Y��P&/Ui�&�V�Ҫ4P�X�+�5���������OT<�"�V�Y�.V(����ʚ,j�m�B���ػ�c���Xs��-���%��������Kp��r��q��Ľ��V:tZTTR�**)���A��6�����֎�S˨�.r����t���
:�����j�]Q��ZSӾg�Ζ�r�x�"j�j��hJ���W@i�q�/p��k/����p���i�$wg��w�4�ɡ3�v�Gw�T榛�~��ysm�E����]���ij@5S�O�����ןC���;�7�����o���\'�큹e�8�~�5�G��[�,��u��h����Ք�d���х�7��O�(�=��"���)��]�ʆM�_���Fy�-�^j*�L�K
eE��R�J�5؞��EQiY��t�����Qo4����G�Ӛ
v��u��>���N	
����Z;B���aW�H�4��lY;�\�Y��e�C�@
�T��e1�Kp�9�/�&8/9�z�ZL0�r�|N��rhR�ĥ���/tZ��dc]�/��{����2UyECco��t�D]����Xg��Y�Q��~֊�Ck��McuMg���`��g���}�aZ2l�v�Y͞*����5��1xȫV�E�N�$T�	�6�h�p�
�!����`&X�=�����:�\NU)Bf���������3[����2}�	(��.��|��OZ�u���v��jF3�1C��"\��^��(�x2\���jƶd�������:�ƈDi���hktVZ�0�hc��M�`����\e	�\��ru�3���'8���4�%#��
�k�`�g�҉��v��)J3A7:
΂$d���^'2}-r��p�?�^G�}k��wf��K��B�S�cHI���M��Խ�zh3P�]�U'�t�[Q���v��5(WF��)�Ѩ$<�ug�}LƤ,1[�C㝡&���@Ն
��;jk�d��uLM�l<Ԥ7�45`T��
��u���D�I,�`���
G�%֘��'w��)�����q7���H$���bv���X+U�-.wm��6Y�J�i���qgW��Vo,.R��Zi0"SZf����}�m5�F�Z��c�`S(�(S�4z��+�^�5�f����Z0n�W��6{I�Q����Huj�F��i���
6-V��R�����b���#��k	�x�G?"u

 ��\�e�|��ܴq�=���3�\�LJ����v�{���xg�������B�A�W/}㟿8�}#uS�\�M5C����`d6e9��ʅ�NU�q6 ��ñ�R5�8�SƆ`CMS������'�`��r������G�5vn�:����YWoc���ͪ�6�"��@@�PG{Q���t5���DZ({�H.s�F+[�in�ꮩ1�D}$Q�J.�JD�
���q55�h�h���6�S
_��-�'Z^5���&*,f�s�4v��1'�ߥ� =�^G��;��z@�@TK�ԣ�Co�?���5Y�k���Alt�
���P��߼��͢�����:��l�{X!7�+��G�z�>���W?�W�f����6�5��9R�rt�X�w獡S�sTB��ǵ��:0
�������
F�NKꚚ�C�Cm�͵6�w�M���zg��\T��B�7:+��>X�hߧV�ڵk��'�M>���BB^懰+�4��x�v���o�ݻ�
�\VTl4y�[G{��n�9x|bp~�U���!}�ڵ��
�
�j8��U�ʖ��ZBc]����m]�ݽ}#��J��Q�QF�.ɈAP����}y�a��ƻ\�kFo";�.�?̈́W��_Y�~?q�CQ1He�s�P�wɝ�9!A�u�pb�G��M�b��깕/��ї�#���:���XG��B��v�N[n�V5�6�\.�f�d�]����U�@_�	�ҏ<u���^=B��=#Ǐ]~��N�]�=ǎ���ag�X�[
ٹ�n��9p\�ZY3z:�q�Ve)��w���vl��Zf�%U�D
!�ڲp�Cͽ}û"F�ƀ1�頻he��_s���
��_�D:�-Vi�1�Ev[}� .�Μ��{n�aO9�/��0����>�>��Nr��&�6�:Ɲ@��O�Пq�v	���W�ז8�~���7��&+Z��!��y,�8�
�ܕW��o+�{�vÁ��3��T��x�j�@��ׇ�;۷�����P(��궎�'��R��%]W���-��.g��嬘�5l0��[#�z��ҨG��o�j�����\")+-��ڂ�*����Q�,���=�q���\^P {<mm��ݶ��@�wV���K��S�E�o�Kk���_Ҷ��tPlz�;���I��p��
%�"H�T���=��x
z�"S�$kܴش����K��k��%1�y{uwˑ��t�[�ET��<[������juW
���=�������J�\����Ѷ�J�J���\Ύ��=m�J��~��N��r�ښ�G��|���nO��vt�ȑ�dNo��U��S旦ý[�pb��O�!����ƩGT��!w�yU��GE�����k��&������b�-T��P���SO��N�S7���N�\�{�C�Tn>Ư+c�����~���'�tW�؞H|���;��ػ붆�ɂ��ߌ��>X׍��m�w���~���|����g��
w�W�Y��d������������������� �z ~�q��"**������‘/s�G#���S�!���qxW���u�́���Cm�j�^lz�,������
hU���}���~��2��"mX?�0�[��]�p�e��;���ze��o���sc�ûv�j�t�8�ؤ�������]{�����F4E�H*"\<`1�h�{���+��O��yY�߁#�'���~��)ķط�ׅ%m����v��ȳ�K��F��5���D�Ǐ�YB)�/c��^��s��
wܖD�����]�F	�;���`�3p�m�p�@�愶�%h)a-�B�П��S	��C��	h^��Vh[x~��К��o�
<bd�����D����>A���oL#s��>�D�!J�>��.�'��şK�%A�i���NH�)}��t�
�>Q�O�JY�짲��Z�G~^���mE�bX1���⇊�ElQ+�n�z��۟%��멜=�B���B���ӧB_D ��S
�.�%0>%�TzW�PzP�R��q�/��'�&��W���WPy��/Bۋ� �ƒK�	�F	W���R�i�Oì
}������Q��@�)=r}	�	})u�	��C��~!���B_&�M��rj\���WP�J�ѧ�cB��J��Q߃J�j�:*�T��Pi*Ee��RY�^|��a$�$ԉ,�M%�b��06G�ûy��=��oW��c�uvG<�NeR�Y�7�^L���x*�c�	vw|n>�aw�2���X��m0	�6�d&�C�0�~�����R"�۹o����:-�ͻl7N����PJ�@YxKg@6��Ja�+h��0�,Qk�X ��1�<~3�w6�y^��fG��a�)NL��`��g�0�M����p���e��<�̥SK�x8�ZX'㱌�N��c�@�Ѵ�X�PUDh7�������/E��7���T*{7]�A>�P,���g�x���,�s��������~�҄�y�
4��^J�u��ό���%s"D�,Y���`�B��=��]�(�������2�[�'4Ä���=�%c��>9/��b��8���𔀧Cdk,JV����V|�f5�7ssz��ě�9�7)b�X��X�0�:��bLk(#�a��(C�����=*�'ފmrX�����eBiC�Q��E�+dw�;<�_\+C�()�k(����ܕ�3A,�[=}��2M�� c1�>���#���uZ�ܻ{B�;���M_H��$��9�2y�_ ��z��
҄A�	���狷-�	<�1�՘�9�x,ː��9��ab�$p��!F}I�)mX{KB8���;-ț\K�x��%�J+ٛ��y�[5�!���Uy��*�*)�Fn~�{zR���B�`��s��s4#؟�WΧp��lI�ov=��=8A�&�s���2#D���躟�OY�_�̟!=LPae]�9��3dn>�-�q{�/Ģ�l*�.ebl<�.�Ss���B<9�ƒ���Tr!��\NF�d�4��#K�l8�e�e�A6YH%S��p��Kf1��b,��C�&I=2N�#YȒ�|�p���Lx!�.ǣ�j6?cS�(�]Y�-��xf5�>�y�ga��T*
dR�H��3R�p�07���'c��t:�YL%��C;
��@0�$؉x2�Z��<F��Dx�
'�ex�ē��%���<V�.���f"��M��Tzv���˂�$I�q<F7)!��ԛZJ�ci�	V9�,C�_H�� �B?�I����i!��X2
��NPVd"�X���Xr4�����%��I,A�n���4�Ľ��B,NdZ�|>�f��l�
D�?�������$dk0Of>��cB3 ?�5����[�,6��D*�����e����6�
g�1vf�=N�`�lО	�yG[��%�<��E(�j�Z&����[����B���E���8�n�/5��.���.//�r���P���q~�6�%��C��,A�4A���9�x�lx&?��R�^��|�]ɫS��8����G��Wr���@.�1(���P,���pQRje׫�e�W��;���o ���ǕE����r<-���ȸYn���OU��M2�]�?�U�6�~mP�Ȅ|���#�T��r�f��3
���%K�˕˜>/+_�$I~�QIy=�o�i�ߍ�k{�P
�H=|*Erp�[�����_W�g16T���'8��c�l{7���]�dq�X��G�����ш�:�BL/��0!� ����ީ$�^U���������w�L'`	�M�#<P����i��V�]��|I�aWH�D*��)��9ň�2^j)���"vg�3K,n�XmU-1.��%R���/BY��0`���lx)���3���;�	
endstream
endobj
63 0 obj
7274
endobj
61 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Consolas
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 59 0 R
/CIDToGIDMap /Identity
/DW 545 >>
endobj
62 0 obj
<< /Length 742 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0036> [<0069> <006F> <006E> <0063> <0075> <0062> <0065> <002E> <006C> <0061> <0064> <0072> <005F> <0070> <0074> <0068> <0073> <003A> <003B> <002B> <002D> <002F> <0076> <0077> <006D> <0052> <0053> <0020> <003D> <0022> <0066> <0067> <006B> <0031> <0024> <007B> <007D> <0032> <0034> <0030> <0079> <0078> <0037> <0033> <0045> <004E> <004F> <0054> <0049> <0043> <007C> <0044> <0050> <0041> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Consolas
/Encoding /Identity-H
/DescendantFonts [61 0 R]
/ToUnicode 62 0 R>>
endobj
2 0 obj
<<
/Type /Pages
/Kids 
[
5 0 R
19 0 R
28 0 R
34 0 R
]
/Count 4
/ProcSet [/PDF /Text /ImageB /ImageC]
>>
endobj
xref
0 64
0000000000 65535 f 
0000000009 00000 n 
0000038255 00000 n 
0000000187 00000 n 
0000000282 00000 n 
0000000756 00000 n 
0000029337 00000 n 
0000038121 00000 n 
0000000319 00000 n 
0000000362 00000 n 
0000000405 00000 n 
0000000449 00000 n 
0000000493 00000 n 
0000000530 00000 n 
0000000574 00000 n 
0000001080 00000 n 
0000007535 00000 n 
0000000877 00000 n 
0000001053 00000 n 
0000007863 00000 n 
0000007556 00000 n 
0000007600 00000 n 
0000007644 00000 n 
0000007688 00000 n 
0000008188 00000 n 
0000012626 00000 n 
0000007985 00000 n 
0000008161 00000 n 
0000012691 00000 n 
0000012647 00000 n 
0000013009 00000 n 
0000017982 00000 n 
0000012813 00000 n 
0000012989 00000 n 
0000020361 00000 n 
0000018003 00000 n 
0000018047 00000 n 
0000020194 00000 n 
0000020020 00000 n 
0000018298 00000 n 
0000018452 00000 n 
0000018591 00000 n 
0000018987 00000 n 
0000019859 00000 n 
0000018784 00000 n 
0000019263 00000 n 
0000019391 00000 n 
0000019554 00000 n 
0000019723 00000 n 
0000020257 00000 n 
0000020679 00000 n 
0000022336 00000 n 
0000020483 00000 n 
0000020659 00000 n 
0000022357 00000 n 
0000022621 00000 n 
0000027977 00000 n 
0000028459 00000 n 
0000027956 00000 n 
0000029477 00000 n 
0000029735 00000 n 
0000037122 00000 n 
0000037327 00000 n 
0000037101 00000 n 
trailer
<<
/Size 64
/Info 1 0 R
/Root 49 0 R
>>
startxref
38374
%%EOF
alt-php74-ioncube-loader/LICENSE.txt000064400000025020150536142110012772 0ustar00LICENCE AGREEMENT FOR THE IONCUBE PHP LOADER, PROVIDED TO ENABLE THE USE
OF IONCUBE ENCODED FILES AND AS PART OF THE IONCUBE24 SERVICE (ioncube24.com)

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING THE
LOADER SOFTWARE. THE INSTALLATION AND/OR USE OR COPYING OF THE IONCUBE PHP
LOADER SOFTWARE INDICATES YOUR ACCEPTANCE OF THIS LICENCE AGREEMENT.  IF YOU
DO NOT ACCEPT THE TERMS OF THIS LICENCE AGREEMENT, DO NOT INSTALL, COPY
AND/OR USE THE LOADER SOFTWARE.

DEFINITIONS

The following definitions shall apply in this document:

LOADER shall mean the ionCube PHP Loader software package or collection 
of Loaders, including any modifications or upgrades to the software, used for
executing PHP scripts previously encoded with the ionCube PHP Encoder
software to render them non-humanly readable, and any associated
documentation or electronic or online materials relating to the software.

ENCODER shall mean any ionCube PHP Encoder software or service used for the
purpose of producing non-humanly readable encoded files from PHP scripts.

ENCODED FILE shall mean a non-humanly readable file produced by the 
Encoder and being derived from humanly readable PHP script source.

PROVIDER shall mean ionCube Ltd.

USER/YOU shall mean any entity who has downloaded or obtained through any
other means a version of the Loader software.


1 LICENSE ENTITLEMENT 

1.1 The Loader is provided without charge.  Title to the Loader does not pass
to the user in any circumstances.  The Loader is supplied as object code.

1.2 The provider grants a personal, non-transferable, non-exclusive licence to
use the Loader in accordance with the terms and conditions of this Licence
Agreement.

1.3 The installation or downloading and use of the Loader entitles the user
to install and use the Loader for its own internal lawful purposes.


2 DISTRIBUTION 

2.1 The Loader may be freely distributed to third parties alone or as 
part of a distribution containing other items provided that this license
is also included. 

2.2 The Loader may under no circumstances be branded as another product, 
whether distributed or not. 

2.3 Distribution as part of a commercial product is permitted provided such
distribution is in accordance with clauses 2.1 and 2.2 with respect to the 
Loader.


3 ANALYSIS / REVERSE ENGINEERING / MODIFICATION 

Except insofar as the user is permitted to do so in accordance with applicable
law:

3.1 Any analysis of the Loader and embedded data by any means and by
any entity whether human or otherwise and including but without limitation to
discover details of internal operation, to reverse engineer, to de-compile
object code, or to modify for the purposes of modifying behaviour is
forbidden.

3.2 Any analysis of encoded files by any means and by any entity whether human
or otherwise and including but without limitation to discover details of file
format or for the purposes of modifying behaviour or scope of their usage is
forbidden.


4 WARRANTY

THE LOADER SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
WARRANTIES INCLUDING BUT WITHOUT LIMITATION THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE ARE
DISCLAIMED. THE PROVIDER DOES NOT WARRANT THAT THE LOADER IS UNINTERRUPTED
OR ERROR FREE, NOR THAT THE OPERATION OF THE LOADER WILL FUNCTION IN
CONJUNCTION WITH ANY OTHER PRODUCT.  


5 LIMITATION OF LIABILITY 

5.1 IN NO EVENT WILL THE PROVIDER OF THE LOADER BE LIABLE TO THE USER OR ANY
PARTY FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR OTHER
CONSEQUENTIAL DAMAGES ARISING DIRECTLY OR INDIRECTLY FROM THIS LICENCE
AGREEMENT OR ANY USE OF THE LOADER OR ENCODED FILES, EVEN IF THE PROVIDER IS
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

5.2 THE LOADER IS PROVIDED ON AN "AS IS" BASIS.  THE PROVIDER EXCLUDES ALL
WARRANTIES, CONDITIONS, TERMS, UNDERTAKINGS AND REPRESENTATIONS (EXCLUDING
FRAUDULENT MISREPRESENTATION) OF ANY KIND, EXPRESS OR IMPLIED, STATUTORY OR
OTHERWISE IN CONNECTION WITH THE LOADER TO THE FULLEST EXTENT PERMITTED BY
LAW.

5.3 DOWNLOADING THE LOADER IS AT YOUR OWN RISK AND THE PROVIDER DOES NOT
ACCEPT LIABILITY FOR ANY DIRECT OR INDIRECT LOSS OR DAMAGE HOWSOEVER CAUSED AS
A RESULT OF ANY COMPUTER VIRUSES, BUGS, TROJAN HORSES, WORMS, SOFTWARE BOMBS
OR OTHER SIMILAR PROGRAMS ARISING FROM YOUR USE OF THE LOADER.  WHILST THE
PROVIDER WILL DO ITS BEST TO ENSURE THAT THE LOADER IS FREE FROM SUCH
DESTRUCTIVE PROGRAMS, IT IS YOUR RESPONSIBILITY TO TAKE REASONABLE PRECAUTIONS
TO SCAN FOR SUCH DESTRUCTIVE PROGRAMS DOWNLOADED FROM THE INTERNET.

5.4 THE PROVIDER'S MAXIMUM LIABILITY FOR ANY LOSS OR DAMAGE ARISING FROM THIS
LICENCE AGREEMENT SHALL IN ANY EVENT BE LIMITED IN THE SOLE DISCRETION OF THE
PROVIDER TO THE REPLACEMENT OF THE LOADER PRODUCT.

5.5 DUE TO THE NATURE OF THE INTERNET, THE PROVIDER CANNOT GUARANTEE THAT ANY
E-MAILS OR OTHER ELECTRONIC TRANSMISSIONS WILL BE SENT TO YOU OR RECEIVED BY
THE PROVIDER OR THAT THE CONTENT OF SUCH TRANSMISSIONS WILL BE SECURE DURING
TRANSMISSION.


6 BUG FIXING AND PRODUCT SUPPORT 

6.1 The provider will use reasonable endeavours to provide support to users.
The provider will at their discretion only provide support for the latest
release.

6.2 Support comprises of fault reporting via tickets and fault diagnosis,
recommendations on workarounds, and where reasonably possible a timely
resolution.

6.3 The user accepts that on occasion the ability of the provider to meet
anticipated or published support schedules may be impaired due to, but without
limitation, Internet service provider failures or software failures that
affect the ability to communicate for an indeterminate period.

6.4 The provider reserves the right to refuse to provide support at any time.

6.5 The provider wishes to maintain and offer a product of the highest
possible quality, and accordingly may from time to time and at its discretion
make product changes for the purpose of correcting behaviour in variance to
the published specification or the user's reasonable expectations. 

6.6 The provider reserves the right to charge for support where the user does
not have a valid support plan in place, or where the support offered exceeds
the scope of the active support plan.


7 PRODUCT UPGRADES

7.1 The provider may from time to time release product upgrades. These will
be provided free of charge and attempts made to provide a timely notification
to customers of the existence of any new release.


8 ERRORS AND OMISSIONS

Whilst reasonable endeavours are made to ensure the accuracy of documentation
concerning the details of the Loader, the user accepts the possibility of
inaccuracies in information presented in any format, including email
communications and online services. The provider shall under no circumstances
be liable for any events that arise as a result of unintentional inaccuracies
or omissions.


9 USER INDEMNITY

You agree to fully indemnify, defend and hold the provider harmless
immediately upon demand from and against all actions, liability, claims,
losses, damages, costs and expenses (including legal/attorney fees) incurred
by the provider arising directly or indirectly as a result of your breach of
this Licence Agreement.


10 INTELLECTUAL PROPERTY RIGHTS

10.1 The user acknowledges that the Loader and associated documentation and
materials contain proprietary information of the provider and are and shall
remain the exclusive property of the provider and/or its licensors and all
title, copyright, trade marks, trade names, patents and other intellectual
property rights therein of whatever nature shall remain the sole property of
the provider and/or its licensors.

10.2 No title to or rights of ownership, copyright or other intellectual
property in the Loader is transferred to the user (other than the licence
rights expressly granted in this Licence Agreement).


11 TERMINATION

11.1 The provider reserves the right to terminate this Licence Agreement
immediately by notice in writing against the user if the user is in breach of
any terms and conditions of this Licence Agreement.

11.2 Termination of this Licence Agreement for any reason shall be without
prejudice to any other rights or remedies of the provider which may have
arisen on or before the date of termination under this Licence Agreement or in
law.

11.3 The provisions of the following clauses shall survive any termination of
this agreement; clause 3, 5, 10 and 13.


12 GENERAL

12.1 The provider reserves the right to transfer or assign all or any of its
rights and duties and responsibilities set out in this Licence Agreement to
another party.

12.2 Headings have been included for convenience only and will not be used in
construing any provision of this Licence Agreement.

12.3 No delay or failure by the provider to exercise any powers, rights or
remedies under this Licence Agreement will operate as a waiver of them nor
will any single or partial exercise of any such powers, rights or remedies
include any other or further exercise of them.

12.4 If any part of this Licence Agreement is found by a court of competent
jurisdiction or other competent authority to be invalid, unlawful or
unenforceable then such part shall be severed from the remainder of this
Licence Agreement which will continue to be valid and enforceable to the
fullest extent permitted by applicable law.

12.5 This Licence Agreement including the documents or other sources referred
to herein supersede all prior representations, understandings and agreements
between the user and the provider relating to the Loader and sets forth the
entire agreement and understanding between the user and the provider relating
to the Loader.

12.6 Nothing in this Licence Agreement shall be deemed to constitute a
partnership between you and the provider nor constitute either party being an
agent of the other party.

12.7 This Agreement does not create any rights or benefits enforceable by any
person not a party to it (within the meaning of the U.K.Contracts (Rights of
Third Parties) Act 1999) except that a person who under clause 12.1 is a
permitted successor or assignee of the rights or benefits of the provider may
enforce such rights or benefits.


13 GOVERNING LAW AND JURISDICTION

This License Agreement and any issues relating thereto shall be construed and
interpreted in accordance with the laws of England and subject to the
exclusive jurisdiction of the English courts.

Copyright (c) 2002-2024 ionCube Ltd.          Last revised 23-April-2015
alt-php74-ioncube-loader/loader-wizard.php000064400000541746150536142160014453 0ustar00<?php // -*- c++ -*-

/** 
 * ionCube Loader install Wizard
 *
 * ionCube is a registered trademark of ionCube Ltd. 
 *
 * Copyright (c) ionCube Ltd. 2002-2022
 */


 

define ('ERROR_UNKNOWN_OS',1);
define ('ERROR_UNSUPPORTED_OS',2);
define ('ERROR_UNKNOWN_ARCH',3);
define ('ERROR_UNSUPPORTED_ARCH',4);
define ('ERROR_UNSUPPORTED_ARCH_OS',5);
define ('ERROR_WINDOWS_64_BIT',6);
define ('ERROR_PHP_UNSUPPORTED',7);
define ('ERROR_PHP_DEBUG_BUILD',8);
define ('ERROR_RUNTIME_EXT_DIR_NOT_FOUND',101);
define ('ERROR_RUNTIME_LOADER_FILE_NOT_FOUND',102);
define ('ERROR_INI_NOT_FIRST_ZE',201);
define ('ERROR_INI_WRONG_ZE_START',202);
define ('ERROR_INI_ZE_LINE_NOT_FOUND',203);
define ('ERROR_INI_LOADER_FILE_NOT_FOUND',204);
define ('ERROR_INI_NOT_FULL_PATH',205);
define ('ERROR_INI_NO_PATH',206);
define ('ERROR_INI_NOT_FOUND',207);
define ('ERROR_INI_NOT_READABLE',208);
define ('ERROR_INI_MULTIPLE_IC_LOADER_LINES',209);
define ('ERROR_INI_USER_INI_NOT_FOUND',210);
define ('ERROR_INI_USER_CANNOT_CREATE',211);
define ('ERROR_LOADER_UNEXPECTED_NAME',301);
define ('ERROR_LOADER_NOT_READABLE',302);
define ('ERROR_LOADER_PHP_MISMATCH',303);
define ('ERROR_LOADER_NONTS_PHP_TS',304);
define ('ERROR_LOADER_TS_PHP_NONTS',305);
define ('ERROR_LOADER_WRONG_OS',306);
define ('ERROR_LOADER_WRONG_ARCH',307);
define ('ERROR_LOADER_WRONG_GENERAL',308);
define ('ERROR_LOADER_WIN_SERVER_NONWIN',321);
define ('ERROR_LOADER_WIN_NONTS_PHP_TS',322);
define ('ERROR_LOADER_WIN_TS_PHP_NONTS',323);
define ('ERROR_LOADER_WIN_PHP_MISMATCH',324);
define ('ERROR_LOADER_WIN_COMPILER_MISMATCH',325);
define ('ERROR_LOADER_NOT_FOUND',380);
define ('ERROR_LOADER_PHP_VERSION_UNKNOWN',390);


define ('SERVER_UNKNOWN',0);
define ('HAS_PHP_INI',1);
define ('SERVER_SHARED',2); 
define ('SERVER_VPS',5); 
define ('SERVER_DEDICATED',7); 
define ('SERVER_LOCAL',9);

define ('IONCUBE_IP_ADDRESS',
			'94.101.154.134');
define  ('IONCUBE_ACCESS_ADDRESS',
			'lwaccess.ioncube.com');
define ('LOADERS_PAGE',
            'https://loaders.ioncube.com/'); 
define ('SUPPORT_SITE',
            'https://support.ioncube.com/');                                 
define ('WIZARD_SUPPORT_TICKET_DEPARTMENT',
			'3');
define ('LOADER_FORUM_URL',
            'https://forum.ioncube.com/viewforum.php?f=4');                  
define ('LOADERS_FAQ_URL',
            'https://www.ioncube.com/faqs/loaders.php');                     
define ('UNIX_ERRORS_URL',
            'https://www.ioncube.com/loaders/unix_startup_errors.php');      
define ('LOADER_WIZARD_URL',
            LOADERS_PAGE);                                                  
define ('ENCODER_URL',
            'https://www.ioncube.com/sa_encoder.php');                       
define ('LOADER_VERSION_URL',
            'https://www.ioncube.com/feeds/product_info/versions.php');    
define ('WIZARD_LATEST_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-wizard'); 
define ('PHP_COMPILERS_URL',
            LOADER_VERSION_URL . '?item=php-compilers');
define ('LOADER_PLATFORM_URL',
            LOADER_VERSION_URL . '?item=loader-platforms-all');   
define ('LOADER_LATEST_VERSIONS_URL',
            LOADER_VERSION_URL . '?item=loader-versions'); 
define ('LOADER_PHP_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-php-support'); 
define ('WIZARD_STATS_URL',
            'https://www.ioncube.com/feeds/stats/wizard.php');    
define ('IONCUBE_DOWNLOADS_SERVER',
            'https://downloads.ioncube.com/loader_downloads');          
define ('IONCUBE24_URL',
			'https://ioncube24.com');
define ('IONCUBE_CONNECT_TIMEOUT',4);

define ('DEFAULT_SELF','/ioncube/loader-wizard.php');
define ('LOADER_NAME_CHECK',true);
define ('LOADER_EXTENSION_NAME','ionCube Loader');
define ('LOADER_SUBDIR','ioncube');
define ('WINDOWS_IIS_LOADER_DIR', 'system32');
define ('ADDITIONAL_INI_FILE_NAME','00-ioncube.ini');
define ('UNIX_SYSTEM_LOADER_DIR','/usr/local/ioncube');
define ('RECENT_LOADER_VERSION','4.0.7');
define ('LATEST_LOADER_MAJOR_VERSION',12);
define ('LOADERS_PACKAGE_PREFIX','ioncube_loaders_');
define ('SESSION_LIFETIME_MINUTES',360);
define ('WIZARD_EXPIRY_MINUTES',2880);
define ('IONCUBE_WIZARD_EXPIRY_MINUTES',10080);
define ('MIN_INITIALISE_TIME',4);
define ('IC24_ENABLED_INI_PROPERTY',"ic24.enable");

    run();


function php4_http_build_query($formdata, $numeric_prefix = null, $key = null ) {
    $res = array();
    foreach ((array)$formdata as $k=>$v) {
        $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
        if ($key) $tmp_key = $key.'['.$tmp_key.']';
        if ( is_array($v) || is_object($v) ) {
            $res[] = php4_http_build_query($v, null , $tmp_key);
        } else {
            $res[] = $tmp_key."=".urlencode($v);
        }
   }
   $separator = ini_get('arg_separator.output');
   return implode($separator, $res);
}


function script_version()
{
    return "2.73";
}

function retrieve_latest_wizard_version()
{
    $v = false;

    $s = trim(remote_file_contents(WIZARD_LATEST_VERSION_URL));
    if (preg_match('/^\d+([.]\d+)*$/', $s)) {
        $v = $s;
    }

    return $v;
}

function latest_wizard_version()
{
    if (!isset($_SESSION['latest_wizard_version'])) {
        $_SESSION['latest_wizard_version'] = retrieve_latest_wizard_version();
    } 
    return $_SESSION['latest_wizard_version'];
}

function update_is_available($lv)
{
    if (is_numeric($lv)) {
        $lv_parts = explode('.',$lv);
        $script_parts = explode('.',script_version());
        return ($lv_parts[0] > $script_parts[0] || ($lv_parts[0] == $script_parts[0] && $lv_parts[1] > $script_parts[1]));
    } else {
        return null;
    }
}

function check_for_wizard_update($echo_message = false)
{
    $latest_version = latest_wizard_version();
    $update_available = update_is_available($latest_version);

    if ($update_available) {
        if ($echo_message) {
            echo '<p class="alert">An updated version of this Wizard script is available <a href="' . LOADER_WIZARD_URL . '">here</a>.</p>';
        }
        return $latest_version;
    } else {
        return $update_available;
    }
}


function remote_file_contents($url)
{
    $remote_file_opening = ini_get('allow_url_fopen');
    $contents = false;
    if (isset($_SESSION['timing_out']) && $_SESSION['timing_out']) {
        return false;
    }
    @session_write_close();
    $timing_out = 0;
    if ($remote_file_opening) {
        $fh = @fopen($url,'rb');
        if ($fh) {
            stream_set_blocking($fh,0);
            stream_set_timeout($fh,IONCUBE_CONNECT_TIMEOUT);
            while (!feof($fh)) {
                $result = fread($fh, 8192);
                $info = stream_get_meta_data($fh);
                $timing_out = $info['timed_out']?1:0;
                if ($timing_out) {
                    break;
                }
                if ($result !== false) {
                    $contents .= $result;
                } else {
                    break;
                }
            }
            fclose($fh);
        } else {
            $timing_out = 1;
        }
    } elseif (extension_loaded('curl')) {
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,IONCUBE_CONNECT_TIMEOUT);
            $output = curl_exec($ch);
            $info = curl_getinfo($ch);
            $timing_out = ($info['http_code'] >= 400)?1:0;
            curl_close($ch);

            if (is_string($output)) {
                $contents = $output;
            }
    } else {
        $timing_out = 1;
    }
    @session_start();
    $_SESSION['timing_out'] = $timing_out;
    return $contents;
}

function php_version()
{
    $v = explode('.',PHP_VERSION);

    return array(
           'major'      =>  $v[0],
           'minor'      =>  $v[1],
           'release'    =>  $v[2]);
}

function php_version_maj_min()
{
    $vprts = php_version();
    return ($vprts['major'] . '.' . $vprts['minor']);
}

function is_supported_php_version()
{
    $v = php_version(); 

    return ((($v['major'] == 4) && ($v['minor'] >= 1)) ||
      (($v['major'] == 5) && (($v['minor'] >= 1) || ($v['release'] >= 3))) ||
	  $v['major'] == 7 || ($v['major'] == 8 && $v['minor'] >= 1));
}

function is_php_version_or_greater($major,$minor,$release = 0)
{
    $version = php_version();
    return ($version['major'] > $major || 
            ($version['major'] == $major && $version['minor'] > $minor) ||
            ($version['major'] == $major && $version['minor'] == $minor && $version['release'] >= $release));
}

function ini_file_name()
{
    $sysinfo = get_sysinfo();
    return (!empty($sysinfo['PHP_INI'])?$sysinfo['PHP_INI_BASENAME']:'php.ini');
}

function get_remote_session_value($session_var,$remote_url,$default_function)
{
    if (!isset($_SESSION[$session_var])) {
        $serialised_res = remote_file_contents($remote_url);
        $unserialised_res = @unserialize($serialised_res);
        if (empty($unserialised_res)) {
            $unserialised_res = call_user_func($default_function);
        } else {
			$_SESSION['remote_access_successful'] = 1;
		}
        if (false === $unserialised_res) {
            $unserialised_res = '';
        }
        $_SESSION[$session_var] = $unserialised_res;
    }
    return $_SESSION[$session_var];
}

function get_file_contents($file)
{
    if (function_exists('file_get_contents')) {
        $strs = @file_get_contents($file);
    } else {
        $lines = @file($file);
        $strs = join(' ',$lines);
    }
    return $strs;
}

function default_platform_list()
{
    $platforms = array();


    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6', 'is_legacy' => 1,       'os_mod' => '_vc6',     'arch'=>'x86',  'dirname'=>'win32', 'us1-dir'=>'windows_vc6/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6 (Non-TS)',   'is_legacy' => 1,  'os_mod' => '_nonts_vc6',   'arch'=>'x86',  'dirname'=>'win32-nonts', 'us1-dir'=>'windows_vc6/x86-nonts' );

    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9',        'os_mod' => '_vc9',     'arch'=>'x86',  'dirname'=>'win32_vc9', 'us1-dir'=>'windows_vc9/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9 (Non-TS)',   'os_mod' => '_nonts_vc9',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc9', 'us1-dir'=>'windows_vc9/x86-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86',  'dirname'=>'win32_vc11', 'us1-dir'=>'windows_vc11/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc11', 'us1-dir'=>'windows_vc11/x86-nonts' );
	
	$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86-64',  'dirname'=>'win64_vc11', 'us1-dir'=>'windows_vc11/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc11', 'us1-dir'=>'windows_vc11/amd64-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86',  'dirname'=>'win32_vc14', 'us1-dir'=>'windows_vc14/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc14', 'us1-dir'=>'windows_vc14/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86-64',  'dirname'=>'win64_vc14', 'us1-dir'=>'windows_vc14/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc14', 'us1-dir'=>'windows_vc14/amd64-nonts' );
	
		 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86',  'dirname'=>'win32_vc15', 'us1-dir'=>'windows_vc15/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc15', 'us1-dir'=>'windows_vc15/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86-64',  'dirname'=>'win64_vc15', 'us1-dir'=>'windows_vc15/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc15', 'us1-dir'=>'windows_vc15/amd64-nonts' );

    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86',      'dirname'=>'linux_i686-glibc2.3.4', 'us1-dir'=>'linux/x86');
    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86-64',   'dirname'=>'linux_x86_64-glibc2.3.4', 'us1-dir'=>'linux/x86_64');
$platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc',      'dirname'=>'linux_ppc-glibc2.3.4','us1-dir'=>'linux/ppc');
            $platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc64',    'dirname'=>'linux_ppc64-glibc2.5','us1-dir'=>'linux/ppc64');
    

$platforms[] = array('os'=>'dra', 'os_human'=>'DragonFly', 'arch'=>'x86',      'dirname'=>'dragonfly_i386-1.7', 'us1-dir'=>'Dragonfly/x86');

$platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 4', 'os_mod'=>'_4',  'arch'=>'x86',      'dirname'=>'freebsd_i386-4.8', 'us1-dir'=>'FreeBSD/v4');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86',      'dirname'=>'freebsd_i386-6.2', 'us1-dir'=>'FreeBSD/v6/x86');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-6.2', 'us1-dir'=>'FreeBSD/v6/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86',      'dirname'=>'freebsd_i386-7.3', 'us1-dir'=>'FreeBSD/v7/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-7.3', 'us1-dir'=>'FreeBSD/v7/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86',      'dirname'=>'freebsd_i386-8.0', 'us1-dir'=>'FreeBSD/v8/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-8.0', 'us1-dir'=>'FreeBSD/v8/AMD64');
    
    $platforms[] = array('os'=>'bsd', 'os_human'=>'BSDi',     'is_legacy' => 1,           'arch'=>'x86',      'dirname'=>'bsdi_i386-4.3.1');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86',      'dirname'=>'netbsd_i386-2.1','us1-dir'=>'NetBSD/x86');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86-64',   'dirname'=>'netbsd_amd64-2.0','us1-dir'=>'NetBSD/x86_64');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.2', 'os_mod'=>'_4.2',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.2', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.5', 'os_mod'=>'_4.5',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.5', 'us1-dir'=>'OpenBSD/x86');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.6', 'os_mod'=>'_4.6',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.6', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.7', 'os_mod'=>'_4.7',  'arch'=>'x86-64', 'dirname'=>'openbsd_amd64-4.7', 'us1-dir' => 'OpenBSD/x86_64');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',    'is_legacy' => 1, 'arch'=>'ppc',      'dirname'=>'osx_powerpc-8.5','us1-dir'=>'OSX/ppc');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86',      'dirname'=>'osx_i386-8.11','us1-dir'=>'OSX/x86');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86-64',       'dirname'=>'osx_x86-64-10.2','us1-dir'=>'OSX/x86_64');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',  'is_legacy' => 1,          'arch'=>'sparc',    'dirname'=>'solaris_sparc-5.9', 'us1-dir'=>'Solaris/sparc');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',            'arch'=>'x86',      'dirname'=>'solaris_i386-5.10','us1-dir'=>'Solaris/x86');

    return $platforms;
}

function get_loader_platforms()
{
    return get_remote_session_value('loader_platform_info',LOADER_PLATFORM_URL,'default_platform_list');
}

function get_platforminfo()
{
    static $platforminfo;

    if (empty($platforminfo)) {
        $platforminfo = get_loader_platforms();
    }
    return $platforminfo;
}

function default_php_versions()
{
	return array();
}

function get_php_versions()
{
	return get_remote_session_value('php_version_info',LOADER_PHP_VERSION_URL,'default_php_versions');
}


function get_max_php_version_supported()
{
	static $max_php_version;
	
	if (empty($max_php_version)) {
		$php_versions = get_php_versions();
		
		$dirname = calc_dirname();
		
		if (array_key_exists($dirname,$php_versions)) {
			$max_php_version = $php_versions[$dirname];
		} else {
			$max_php_version = NULL;
		}
	}
	
	return $max_php_version;
}

function is_after_max_php_version_supported()
{
	$is_too_recent_php = false;
	
	$supported_php_version = get_max_php_version_supported();
	
	if (!is_null($supported_php_version)) {
		$pversion = php_version();
		
		$supported_parts = explode('.',$supported_php_version);
		$is_too_recent_php = ($supported_parts[0] < $pversion['major'] || ($supported_parts[0] == $pversion['major'] && $supported_parts[1] < $pversion['minor']));
	}
	
	if ($is_too_recent_php) {
		return $supported_php_version;
	} else {
		return false;
	}
}

function supported_os_variants($os_code,$arch_code)
{
    if (empty($os_code)) {
        return ERROR_UNKNOWN_OS;
    }
    if (empty($arch_code)) {
        return ERROR_UNKNOWN_ARCH;
    }

    $os_found = false;
    $arch_found = false;
    $os_arch_matches = array();
    $pinfo = get_platforminfo();

    foreach ($pinfo as $p) {
        if ($p['os'] == $os_code && $p['arch'] == $arch_code) {
            $os_arch_matches[$p['os_human']] = (isset($p['os_mod']))?(0 + (int) str_replace('_','',$p['os_mod'])):'';
        } 
        if ($p['os'] == $os_code) {
            $os_found = true;
        } elseif ($p['arch'] == $arch_code) {
            $arch_found = true;
        }
    }
    if (!empty($os_arch_matches)) {
        asort($os_arch_matches);
        return $os_arch_matches;
    } elseif (!$os_found) {
        return ERROR_UNSUPPORTED_OS;
    } elseif (!$arch_found) {
        return ERROR_UNSUPPORTED_ARCH;
    } else {
        return ERROR_UNSUPPORTED_ARCH_OS;
    }
}

function default_win_compilers()
{
    return array('VC6','VC9','VC11','VC14','VC15', 'VC16');
}

function supported_win_compilers()
{
    static $win_compilers;

    if (empty($win_compilers)) {
        $win_compilers = find_win_compilers();
    }
    return $win_compilers;
}

function find_win_compilers()
{
    return get_remote_session_value('php_compilers_info',PHP_COMPILERS_URL,'default_win_compilers');
}

function server_software_info()
{
    $ss = array('full' => '','short' => '');
    $ss['full'] = $_SERVER['SERVER_SOFTWARE'];

    if (preg_match('/apache/i', $ss['full'])) {
        $ss['short'] = 'Apache';
    } else if (preg_match('/IIS/',$ss['full'])) {
        $ss['short'] = 'IIS';
    } else {
        $ss['short'] = '';
    }
    return $ss;
}

function match_arch_pattern($str)
{
    $arch = null;
    $arch_patterns = array(
             'i.?86'        => 'x86',
             'x86[-_]64'    => 'x86',
             'x86'          => 'x86',
             'amd64'        => 'x86',
             'SMP Tue Jan 01 00:00:00 CEST 2000 all GNU\/Linux' => 'x86',
             'ppc64'        => 'ppc',
             'ppc'          => 'ppc',
             'powerpc'      => 'ppc',
             'sparc'        => 'sparc',
             'sun'          => 'sparc',
			 'armv7l'       => 'armv7l',
             'aarch64'      => 'aarch64'
         );

    foreach ($arch_patterns as $token => $a) {
        if (preg_match("/$token/i", $str)) {
          $arch = $a;
          break;
        }
    }
    return $arch;
}

function required_loader_arch($mach_info,$os_code,$wordsize)
{
    if ($os_code == 'win') {
        $arch = ($wordsize == 32)?'x86':'x86-64';
    } elseif (!empty($os_code)) {
        $arch = match_arch_pattern($mach_info);
        if ($wordsize == 64) {
            if ($arch == 'x86') {
                $arch = 'x86-64';
            } elseif ($arch == 'ppc') {
                $arch = 'ppc64';
            }
        }
    } else {
        $arch = ERROR_UNKNOWN_ARCH;
    }
    return $arch;
}

function uname($part = 'a')
{
    $result = '';
    if (!function_is_disabled('php_uname')) {
        $result = @php_uname($part);
    } elseif (function_exists('posix_uname') && !function_is_disabled('posix_uname')) {
        $posix_equivs = array(
                     'm' => 'machine',
                     'n' => 'nodename',
                     'r' => 'release',
                     's' => 'sysname'
                 );
        $puname = @posix_uname();
        if ($part == 'a' || !array_key_exists($part,$posix_equivs)) {
           $result = join(' ',$puname);
        } else {
           $result = $puname[$posix_equivs[$part]];
        }
    } else {
        if (!function_is_disabled('phpinfo')) {
            ob_start();
            phpinfo(INFO_GENERAL);
            $pinfo = ob_get_contents();
            ob_end_clean();
            if (preg_match('~System.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$match)) {
                $uname = $match[2];
                if ($part == 'r') {
                    if (!empty($uname) && preg_match('/\S+\s+\S+\s+([0-9.]+)/',$uname,$matchver)) {
                        $result = $matchver[1];
                    } else {
                        $result = '';
                    }
                } else {
                    $result = $uname;
                }
            }
        } else {
            $result = '';
        }
    }
    return $result;
}

function calc_word_size($os_code)
{
    $wordsize = null;
    if ('win' === $os_code) {
        ob_start();
        phpinfo(INFO_GENERAL);
        $pinfo = ob_get_contents();
        ob_end_clean();
        if (preg_match('~Compiler.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$compmatch)) {
            if (preg_match("/(VC[0-9]+)/i",$compmatch[2],$vcmatch)) {
                $compiler = strtoupper($vcmatch[1]);
            } elseif (stripos(trim($compmatch[2]),"Visual C++ 2019") === 0) {
                $compiler = 'VC16';
            } else {
                $compiler = 'VC6';
            }
        } else {
            $compiler = 'VC6';
        }
        if ($compiler === 'VC9' || $compiler === 'VC11' || $compiler === 'VC14' 
                || $compiler === 'VC15' || $compiler === 'VC16') {
			if (preg_match('~Architecture.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$archmatch)) {
				if (preg_match("/x64/i",$archmatch[2])) {
					$wordsize = 64;
				} else {
					$wordsize = 32;
				}
            } elseif (isset($_ENV['PROCESSOR_ARCHITECTURE']) && preg_match('~(amd64|x86-64|x86_64)~i',$_ENV['PROCESSOR_ARCHITECTURE'])) {
                if (preg_match('~Configure Command.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$confmatch)) {
                    if (preg_match('~(x64|lib64|system64)~i',$confmatch[2])) {
                        $wordsize = 64;
                    }
                }
            } else {
				$wordsize = 32;
			}
        }
    }
    if (empty($wordsize)) {
        $wordsize = ((-1^0xffffffff)?64:32);
    }
    return $wordsize;
}

function required_loader($unamestr = '')
{
    $un = empty($unamestr)?uname():$unamestr;

    $php_major_version = substr(PHP_VERSION,0,3);

    $os_name = substr($un,0,strpos($un,' '));
    $os_code = empty($os_name)?'':strtolower(substr($os_name,0,3));

    $wordsize = calc_word_size($os_code);

	if ($os_code == 'win' && $wordsize == 64 && $php_major_version < '5.5') {
        $arch = ERROR_WINDOWS_64_BIT;
	} else {
		$arch = required_loader_arch($un,$os_code,$wordsize);
	}
    if (!is_string($arch)) {
        return $arch;
    }
    $os_variants = supported_os_variants($os_code,$arch);
    if (!is_array($os_variants)) {
        return $os_variants;
    }

    $os_ver = '';
    if (preg_match('/([0-9.]+)/',uname('r'),$match)) {
        $os_ver = $match[1];
    }
    $os_ver_parts = preg_split('@\.@',$os_ver);

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $loader_sfix = (($os_code == 'win') ? 'dll' : 'so');
    $file = "ioncube_loader_{$os_code_h}_{$php_major_version}.{$loader_sfix}";

    if ($os_code == 'win') {
        $os_name = 'Windows';
        $file_ts = $file;
        $os_name_qual = 'Windows';
    } else {
        $os_names = array_keys($os_variants);
        if (count($os_variants) > 1) {
            $parts = explode(" ",$os_names[0]); 
            $os_name = $parts[0];
            $os_name_qual = $os_name . ' ' . $os_ver_parts[0] . '.' . $os_ver_parts[1];
        } else {
            $os_name = $os_names[0];
            $os_name_qual = $os_name;
        }
        $file_ts = "ioncube_loader_{$os_code_h}_{$php_major_version}_ts.{$loader_sfix}";
    }

    return array(
           'uname'      =>  $un,
           'arch'       =>  $arch,
           'oscode'     =>  $os_code,
           'oscode_h'   =>  $os_code_h,
           'osname'     =>  $os_name,
           'osnamequal' =>  $os_name_qual,
           'osvariants' =>  $os_variants,
           'osver'      =>  $os_ver,
           'osver2'     =>  $os_ver_parts,
           'file'       =>  $file,
           'file_ts'    =>  $file_ts,
           'wordsize'   =>  $wordsize
       );
}

function ic_system_info()
{
    $thread_safe = null;
    $debug_build = null;
    $cgi_cli = false;
	$is_fpm = false;
    $is_cgi = false;
    $is_cli = false;
    $php_ini_path = '';
    $php_ini_dir = '';
    $php_ini_add = '';
    $is_supported_compiler = true;
    $php_compiler = is_ms_windows()?'VC6':'';

    ob_start();
    phpinfo(INFO_GENERAL);
    $php_info = ob_get_contents();
    ob_end_clean();

    $breaker = (php_sapi_name() == 'cli')?"\n":'</tr>';
    $lines = explode($breaker,$php_info);
    foreach ($lines as $line) {
        if (preg_match('/command/i',$line)) {
          continue;
        }

        if (preg_match('/thread safety/i', $line)) {
          $thread_safe = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('/debug build/i', $line)) {
          $debug_build = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('~configuration file.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
          $php_ini_path = $match[2];

          if (!@file_exists($php_ini_path)) {
                $php_ini_path = '';
          }
        }
        if (preg_match('~dir for additional \.ini files.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_dir = $match[2];
            if (!@file_exists($php_ini_dir)) {
                $php_ini_dir = '';
            }
        }
        if (preg_match('~additional \.ini files parsed.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_add = $match[2];
        }
        if (preg_match('/compiler/i',$line)) {
            $supported_match = join('|',supported_win_compilers());
            $is_supported_compiler = preg_match("/($supported_match)/i",$line);
            if (preg_match("/(VC[0-9]+)/i",$line,$match)) {
                $php_compiler = strtoupper($match[1]);
            } elseif (preg_match("/Visual C\+\+ 2017/i",$line)) {
				$php_compiler = "VC15";
				$is_supported_compiler = true;
            } elseif (preg_match("/Visual C\+\+ 2019/i",$line)) {
				$php_compiler = "VC16";
				$is_supported_compiler = true;
			} else {
                $php_compiler = '';
            }
        }
    }
    $is_cgi = strpos(php_sapi_name(),'cgi') !== false;
    $is_cli = strpos(php_sapi_name(),'cli') !== false;
	$is_fpm = strpos(php_sapi_name(),'fpm-fcgi') !== false;
    $cgi_cli = $is_cgi || $is_cli;

    $ss = server_software_info();
	
	if ($is_fpm) {
		$ss['short'] = 'PHP-FPM';
		$ss['full'] = 'PHP-FPM ' . $ss['full'];
	}

    if (!$php_ini_path && function_exists('php_ini_loaded_file')) {
        $php_ini_path = php_ini_loaded_file();
        if ($php_ini_path === false) {
            $php_ini_path = '';
        }
    }
    if (!empty($php_ini_path)) {
        $real_path = @realpath($php_ini_path);
        if (false !== $real_path) {
            $php_ini_path = $real_path;
        }
    }

    $php_ini_basename = basename($php_ini_path);

    return array(
           'THREAD_SAFE'        => $thread_safe,
           'DEBUG_BUILD'        => $debug_build,
           'PHP_INI'            => $php_ini_path,
           'PHP_INI_BASENAME'   => $php_ini_basename,
           'PHP_INI_DIR'        => $php_ini_dir,
           'PHP_INI_ADDITIONAL' => $php_ini_add,
           'PHPRC'              => getenv('PHPRC'),
           'CGI_CLI'            => $cgi_cli,
           'IS_CGI'             => $is_cgi,
           'IS_CLI'             => $is_cli,
		   'IS_FPM'				=> $is_fpm,
           'PHP_COMPILER'       => $php_compiler,
           'SUPPORTED_COMPILER' => $is_supported_compiler,
           'FULL_SS'            => $ss['full'],
           'SS'                 => $ss['short']);
}

function is_possibly_dedicated_or_local()
{
    $sys = get_sysinfo();

    return (empty($sys['PHP_INI']) || !@file_exists($sys['PHP_INI']) || (is_readable($sys['PHP_INI']) && (0 !== strpos($sys['PHP_INI'],$_SERVER['DOCUMENT_ROOT']))));
}

function is_local()
{
    $ret = false;
    if ($_SERVER["SERVER_NAME"] == 'localhost') {
        $ret = true;
    } else {
        $ip_address = strtolower($_SERVER["REMOTE_ADDR"]);
        if (strpos(':',$ip_address) === false) {
            $ip_parts = explode('.',$ip_address);
            $ret = (($ip_parts[0] == 10) || 
                    ($ip_parts[0] == 172 && $ip_parts[1] >= 16 &&  $ip_parts[1] <= 31) ||
                    ($ip_parts[0] == 192 && $ip_parts[1] == 168));
        } else {
            $ret = ($ip_address == '::1') || (($ip_address[0] == 'f') && ($ip_address[1] >= 'c' && $ip_address[1] <= 'f'));
        }
    }
    return $ret;
}

function is_shared()
{
    return !is_local() && !is_possibly_dedicated_or_local();
}

function find_server_type($chosen_type = '',$type_must_be_chosen = false,$set_session = false)
{
    $server_type = SERVER_UNKNOWN;
    if (empty($chosen_type)) {
        if ($type_must_be_chosen) {
            $server_type = SERVER_UNKNOWN;
        } else {
            if (isset($_SESSION['server_type']) && $_SESSION['server_type'] != SERVER_UNKNOWN) {
                $server_type = $_SESSION['server_type'];
            } elseif (is_local()) {
                $server_type = SERVER_LOCAL;
            } elseif (!is_possibly_dedicated_or_local()) {
                $server_type = SERVER_SHARED;
            } else {
                $server_type = SERVER_UNKNOWN;
            } 
        }
    } else {
        switch ($chosen_type)  {
            case 's':
                $server_type = SERVER_SHARED;
                break;
            case 'd':
                $server_type = SERVER_DEDICATED;
                break;
            case 'l':
                $server_type = SERVER_LOCAL;
                break;
            default:
                $server_type = SERVER_UNKNOWN;
                break;
        }
    }
    if ($set_session) {
        $_SESSION['server_type'] = $server_type;
    }
    return $server_type;
}

function server_type_string()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_string = 'SHARED';
            break;
        case SERVER_LOCAL:
            $server_string = 'LOCAL';
            break;
        case SERVER_DEDICATED:
            $server_string = 'DEDICATED';
            break;
        default:
            $server_string = 'UNKNOWN';
            break;
    }
    return $server_string;
}

function server_type_code()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_char = 's';
            break;
        case SERVER_LOCAL:
            $server_char = 'l';
            break;
        case SERVER_DEDICATED:
            $server_char = 'd';
            break;
        default:
            $server_char = '';
            break;
    }
    return $server_char;
}

function get_sysinfo()
{
    static $sysinfo;

    if (empty($sysinfo)) {
        $sysinfo = ic_system_info();
    }
    return $sysinfo;
}

function get_loaderinfo()
{
    static $loader;

    if (empty($loader)) {
        $loader = required_loader();
    }
    return $loader;
}

function is_ms_windows()
{
    $loader_info = get_loaderinfo();
    return ($loader_info['oscode'] == 'win');
}

function function_is_disabled($fn_name)
{
    $disabled_functions=explode(',',ini_get('disable_functions'));
    return in_array($fn_name, $disabled_functions);
}

function selinux_is_enabled()
{
    $se_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('sestatus');
        $se_enabled = preg_match('/enabled/i',$cmd);
    }

    return $se_enabled;
}

function grsecurity_is_enabled()
{
    $gr_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('gradm -S');
        $gr_enabled = preg_match('/enabled/i',$cmd);
    }

    return $gr_enabled;
}

function threaded_and_not_cgi()
{
    $sys = get_sysinfo();
    return($sys['THREAD_SAFE'] && !$sys['IS_CGI']);
}

function is_restricted_server($only_safe_mode = false)
{
    $disable_functions = ini_get('disable_functions');
    $open_basedir = ini_get('open_basedir');
    $php_restrictions = !empty($disable_functions) || !empty($open_basedir);
    $system_restrictions = selinux_is_enabled() || grsecurity_is_enabled();
    $non_safe_mode_restrictions = $php_restrictions || $system_restrictions;
    return (ini_get('safe_mode') || (!$only_safe_mode && $non_safe_mode_restrictions));
}

function server_restriction_warnings()
{
    $warnings = array();

    if (find_server_type() == SERVER_SHARED) {
        if (is_restricted_server()) {
            $warnings[] = "Server restrictions are in place which might affect the operation of this Loader Wizard or prevent the installation of the Loader.";
        }
    } else {
        $warning_suffix = "This may affect the operation of this Loader Wizard.";
        if (ini_get('safe_mode')) {
            $warnings[] = "Safe mode is in effect on the server. " . $warning_suffix;
        } 
        $disabled_functions = ini_get('disable_functions');
        if (!empty($disabled_functions)) {
            $warnings[] = "Some functions are disabled through disable_functions. " . $warning_suffix;
        }
        $open_basedir = ini_get('open_basedir');
        if (!empty($open_basedir)) {
            $warnings[] = "Open basedir restrictions are in effect. " . $warning_suffix;
        }
    }
    return $warnings;
}

function own_php_ini_possible($only_safe_mode = false)
{
    $sysinfo = get_sysinfo();
    return ($sysinfo['CGI_CLI'] && !is_ms_windows() && !is_restricted_server($only_safe_mode));
}

function extension_dir()
{
    $extdir = ini_get('extension_dir');
    if ($extdir == './' || ($extdir == '.\\' && is_ms_windows())) {
        $extdir = '.';
    }
    return $extdir;
}

function possibly_selinux()
{
    $loaderinfo = get_loaderinfo();
    $se_env = (getenv("SELINUX_INIT"));
    return (strtolower($loaderinfo['osname']) == 'linux' && $se_env && ($se_env == 'Yes' || $se_env == '1'));
}

function ini_same_dir_as_wizard()
{
    $sys = get_sysinfo();
    return dirname($sys['PHP_INI']) == dirname(__FILE__); 
}

function extension_dir_path()
{
    $ext_dir = extension_dir();
    if ($ext_dir == '.' || (dirname($ext_dir) == '.')) {
        $ext_dir_path = @realpath($ext_dir);
    } else {
        $ext_dir_path = $ext_dir;
    }
    return $ext_dir_path;
}

function get_loader_name()
{
    $u = uname();
    $sys = get_sysinfo();
    $os = substr($u,0,strpos($u,' '));
    $os_code = strtolower(substr($u,0,3));

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $php_version = phpversion();
    $php_family = substr($php_version,0,3);

    $loader_sfix = (($os_code == 'win') ? '.dll' : (($sys['THREAD_SAFE'])?'_ts.so':'.so'));
    $loader_name="ioncube_loader_{$os_code_h}_{$php_family}{$loader_sfix}";

    return $loader_name;
}

function get_reqd_version($variants)
{
    $exact_match = false;
    $nearest_version = 0;
    $loader_info = get_loaderinfo();
    $os_version = $loader_info['osver2'][0] . '.' . $loader_info['osver2'][1];
    $os_version_major = $loader_info['osver2'][0];
    foreach ($variants as $v) {
        if ($v == $os_version || (is_int($v) && $v == $os_version_major)) {
            $exact_match = true;
            $nearest_version = $v;
            break;
        } elseif ($v > $os_version) {
            break;
        } else {
            $nearest_version = $v;
        }
    }
    return (array($nearest_version,$exact_match));
}

function get_default_loader_dir_webspace()
{
    return ($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . LOADER_SUBDIR);
}

function get_loader_location($loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = get_default_loader_dir_webspace();
    }
    $loader_name = get_loader_name(); 
    return ($loader_dir . DIRECTORY_SEPARATOR . $loader_name);
}

function get_loader_location_from_ini($php_ini = '')
{
    $errors = array();
    if (empty($php_ini)) {
        $sysinfo = get_sysinfo();
        $php_ini = $sysinfo['PHP_INI'];
    }
    if (!@file_exists($php_ini)) {
        if (empty($php_ini)) {
            $errors[ERROR_INI_NOT_FOUND] = "The configuration file could not be found.";
        } else {
            $errors[ERROR_INI_NOT_FOUND] = "The $php_ini file could not be found.";
        }
    } elseif (!is_readable($php_ini)) {
        $errors[ERROR_INI_NOT_READABLE] = "The $php_ini file could not be read.";
    }
    if (!empty($errors)) {
        return array('location' => '', 'errors' => $errors);
    } 
    $lines = file($php_ini);
    $ext_start = zend_extension_line_start();
    $wrong_ext_start = ($ext_start == 'zend_extension')?'zend_extension_ts':'zend_extension';
    $loader_path = '';
    $loader_name_match = "ioncube_loader";
    foreach ($lines as $l) {
        if (preg_match("/^\s*$ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$corr_matches)) {
            if (preg_match("/$loader_name_match/i",$corr_matches[1])) {
                if (!empty($loader_path)) {
                    $errors[ERROR_INI_MULTIPLE_IC_LOADER_LINES] = "It appears that multiple $ext_start lines for the ionCube Loader have been included in the configuration file, $php_ini.";
                }
                $loader_path = $corr_matches[1];
            } else {
                if (empty($loader_path)) {
                    $errors[ERROR_INI_NOT_FIRST_ZE] = "The ionCube Loader must be the first Zend extension listed in the configuration file, $php_ini.";
                }
            }
        }
        if (empty($loader_path)) {
            if (preg_match("/^\s*$wrong_ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$bad_start_matches)) {
                if (preg_match("/$loader_name_match/i",$bad_start_matches[1])) {
                    $bad_zend_ext_msg = "The line for the ionCube Loader in the configuration file, $php_ini, should start with $ext_start and <b>not</b> $wrong_ext_start.";
                    $errors[ERROR_INI_WRONG_ZE_START] = $bad_zend_ext_msg;
                    $loader_path = $bad_start_matches[1];
                }
            }
        }
    }
    $loader_path = trim($loader_path);
    if ($loader_path === '') {
        $errors[ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration file, $php_ini.";
    } elseif (!@file_exists($loader_path)) {
        $errors[ERROR_INI_LOADER_FILE_NOT_FOUND] = "The loader file  $loader_path, listed in the configuration file, $php_ini, does not exist or is not accessible.";
    } elseif (basename($loader_path) == $loader_path) {
        $errors[ERROR_INI_NOT_FULL_PATH] = "A full path must be specified for the loader file in the configuration file, $php_ini.";
    }
    return array('location' => $loader_path, 'errors' => $errors);
}

function zend_extension_line_missing($ini_path)
{
    $loader_loc = get_loader_location_from_ini($ini_path);
    return (!empty($loader_loc['errors']) && array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$loader_loc['errors']));
}

function find_additional_ioncube_ini()
{
    $sys = get_sysinfo();
    $ioncube_ini = '';

    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
        foreach ($ini_files as $f) {
            $fn = trim($f);
            $bfn = basename($fn);
            if (preg_match('/ioncube/i',$bfn)) {
                $ioncube_ini = $fn;
                break;
            }
        }
    }
    return $ioncube_ini;
}

function get_additional_ini_files()
{
    $sys = get_sysinfo();
    $ini_files = array();
    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
    }
    return (array_map('trim',$ini_files));
}

function all_ini_contents()
{
    $sys = get_sysinfo();
    $output = '';

    $output .= ";;; *MAIN INI FILE AT ${sys['PHP_INI']}* ;;;" . PHP_EOL;
    $output .= get_file_contents($sys['PHP_INI']);
    $other_inis = get_additional_ini_files();
    foreach ($other_inis as $inif) {
        $output .= ";;; *Additional ini file at $inif* ;;;" . PHP_EOL;
        $output .= get_file_contents($inif);
    }
    $here = unix_path_dir();
    $unrec_ini_files = unrecognised_inis_webspace($here);
    foreach ($unrec_ini_files as $urinif) {
        $output .= ";;; *UNRECOGNISED INI FILE at $urinif* ;;;" . PHP_EOL;
        $output .= get_file_contents($urinif);
    }
    return $output;
}

function scan_inis_for_loader()
{
    $ldloc = array('location' => '', 'errors' => array());
    $sysinfo = get_sysinfo();
    if (empty($sysinfo['PHP_INI'])) {
        $ini_files_not_found = array("Main ini file");
        $ini_file_list = get_additional_ini_files();
    } else {
        $ini_files_not_found = array();
        $ini_file_list = array_merge(array($sysinfo['PHP_INI']),get_additional_ini_files());
    }
    $server_type = find_server_type();
    $shared_server = SERVER_SHARED == $server_type;
    foreach ($ini_file_list as $f) {
        $ldloc = get_loader_location_from_ini($f);
        if (array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$ldloc['errors'])) {
            unset($ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND]);
        } 
        if ($shared_server && array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            if (false == user_ini_space_path($f)) {
                $ldloc['errors'][ERROR_INI_NOT_FOUND] = "A system ini file cannot be found or read by the Wizard - you cannot do anything about this on your shared server.";
            } else {
                $ldloc['errors'][ERROR_INI_USER_INI_NOT_FOUND] = $ldloc['errors'][ERROR_INI_NOT_FOUND];
            }
        } elseif (array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            $ini_files_not_found[] = $f;
        }
        if (!empty($ldloc['location'])) {
            break;
        }
    }
    if (!empty($ini_files_not_found)) {
        $plural = (count($ini_files_not_found) > 1)?"s":"";
        $ldloc['errors'][ERROR_INI_NOT_FOUND] = "The following ini file$plural could not be found by the Wizard: " . join(',',$ini_files_not_found);
        if (is_restricted_server()) {
            $ldloc['errors'][ERROR_INI_NOT_FOUND] .= "<br> This may be due to server restrictions in place.";
        }
    }
    if (empty($ldloc['location'])) {
        $ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration.";
    }
    return $ldloc;
}

function find_loader_filesystem()
{
    $ld_inst_dir = loader_install_dir(find_server_type());
    $loader_name = get_loader_name();
    $suggested_loader_path = $ld_inst_dir . DIRECTORY_SEPARATOR . $loader_name;
    if (@file_exists($suggested_loader_path)) {
        $location = $suggested_loader_path;
    } elseif (@file_exists($loader_name)) {
        $location = @realpath($loader_name);
    } else {
        $ld_loc = get_loader_location();
        if (@file_exists($ld_loc)) {
            $location = $ld_loc;
        } else {
            $location = '';
        }
    }
    return $location;
}

function find_loader($search_directories_if_not_ini = false)
{
    $sysinfo = get_sysinfo();
    $php_ini = $sysinfo['PHP_INI'];
    $rtl_path = get_runtime_loading_path_if_applicable();
    $location = '';
    $errors = array();

    if (!empty($rtl_path)) {
        $location = $rtl_path;
    } else {
        $loader_ini = scan_inis_for_loader();
        $location = $loader_ini['location'];
        $errors = $loader_ini['errors'];
    }
    if (empty($location) && (empty($errors) || $search_directories_if_not_ini)) {
        $errors = array(); 
        $location = find_loader_filesystem();
        if (empty($location)) {
            $errors[ERROR_LOADER_NOT_FOUND] = 'The loader file could not be found in standard locations.';
        }
    }
    if (!empty($errors)) {
        return $errors;
    } else {
        return $location;
    }
}

function zend_extension_line_start()
{
    $sysinfo = get_sysinfo();
    $is_53_or_later = is_php_version_or_greater(5,3);
    return (is_bool($sysinfo['THREAD_SAFE']) && $sysinfo['THREAD_SAFE'] && !$is_53_or_later ? 'zend_extension_ts' : 'zend_extension');
}

function ioncube_loader_version_information()
{
    $old_version = true;
    $liv = "";
    $lv = "";
    $mv = 0;
    if (function_exists('ioncube_loader_iversion')) {
        $liv = ioncube_loader_iversion();
        $lv = sprintf("%d.%d.%d", $liv / 10000, ($liv / 100) % 100, $liv % 100);

        $latest_version =  get_latestversion();

        $lat_parts = explode('.',$latest_version);
        $cur_parts = explode('.',$lv);

        if (($cur_parts[0] > $lat_parts[0]) || 
            ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] > $lat_parts[1]) ||
             ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] == $lat_parts[1] && $cur_parts[2] >= $lat_parts[2])) {
            $old_version = false;
        } else {
            $old_version = $latest_version;
        }
        $mv = $cur_parts[0];
    }
    return array($lv,$mv,$old_version);
}

function default_loader_version_info()
{
    return array();
}

function get_loader_version_info()
{
    return get_remote_session_value('loader_version_info',LOADER_LATEST_VERSIONS_URL,'default_loader_version_info');
}

function calc_platform()
{
    $platform = array();
    $platform_info = get_platforminfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($osvar,$exact_match) = get_reqd_version($loader['osvariants']);
    } else {
        $osvar = null;
        if (is_ms_windows()) {
            $sys = get_sysinfo();
            $phpc = (empty($sys['PHP_COMPILER']))?'vc6':strtolower($sys['PHP_COMPILER']); 
            $osvar = ($sys['THREAD_SAFE']?'':'nonts_') . $phpc;
        }
    }
    foreach ($platform_info as $p) {
        if ($p['os'] == $loader['oscode'] && $p['arch'] == $loader['arch'] && (empty($osvar) || $p['os_mod'] == "_" . $osvar)) {
            $platform = $p;
            break;
        }
    }
    return $platform;
}

function get_platform()
{
    static $this_platform;

    if (!isset($this_platform)) {
        $this_platform = calc_platform();
    }

    return $this_platform;
}

function is_legacy_platform()
{
    $platform = get_platform();
    return array_key_exists('is_legacy',$platform);
}

function calc_dirname()
{
    $dirname = '';
    $platform = get_platform();
    if (!empty($platform)) {
        $dirname = $platform['dirname'];
    }
    return $dirname;
}

function calc_loader_latest_version()
{
    $lv_info = get_loader_version_info();
    $latest_version = RECENT_LOADER_VERSION;
    if (!empty($lv_info)) {
        $dirname = calc_dirname();
      
        if (!empty($dirname)) {
            $compiler_specific_version = false;
            if (is_ms_windows()) {
                $sys = get_sysinfo();
                $phpc = strtolower($sys['PHP_COMPILER']);
                if (!empty($phpc)) {
                    $dirname_comp = $dirname . "_" . $phpc;
                    if (array_key_exists($dirname_comp,$lv_info)) {
                        $latest_version = $lv_info[$dirname_comp];
                        $compiler_specific_version = true;
                    }
                }
            }
            if (!$compiler_specific_version && array_key_exists($dirname,$lv_info)) {
                $latest_version = $lv_info[$dirname];
            }
        } 
    }
    return $latest_version;
}

function get_latestversion()
{
    static $latest_version;

    if (empty($latest_version)) {
        $latest_version = calc_loader_latest_version();
    }
    return $latest_version;
}


function runtime_loader_location()
{
    $loader_path = false;
    $ext_path = extension_dir_path();
    if ($ext_path !== false) {
        $id = $ext_path;
        $here = dirname(__FILE__);
        if (isset($id[1]) && $id[1] == ':') {
            $id = str_replace('\\','/',substr($id,2));
            $here = str_replace('\\','/',substr($here,2));
        }
        $rd=str_repeat('/..',substr_count($id,'/')).$here.'/';
        $i=strlen($rd);

        $loader_loc = DIRECTORY_SEPARATOR . basename($here) . DIRECTORY_SEPARATOR . get_loader_name();
        while($i--) {
            if($rd[$i]=='/') {
                $loader_path = runtime_location_exists($ext_path,$rd,$i,$loader_loc);
                if ($loader_path !== false) {
                    break;
                }
            }
        }

        if (!$loader_path && !empty($loader_loc) && @file_exists($loader_loc)) {
            $loader_path = basename($loader_loc);
        }
    }
    return $loader_path;
}

function runtime_location_exists($ext_dir,$path_str,$sep_pos,$loc_name)
{
    $sub_path = substr($path_str,0,$sep_pos);
    $lp = $sub_path . $loc_name;
    $fqlp = $ext_dir.$lp;

    if(@file_exists($fqlp)) {
        return $lp;
    } else {
        return false;
    }
}

function runtime_loading_is_possible() {
    return !((is_php_version_or_greater(5,2,5)) || is_restricted_server() || !ini_get('enable_dl') || !function_exists('dl') || function_is_disabled('dl') || threaded_and_not_cgi());
}

function shared_and_runtime_loading()
{
    return (find_server_type() == SERVER_SHARED && empty($_SESSION['use_ini_method']) && runtime_loading_is_possible());
}

function get_valid_runtime_loading_path($ignore_loading_check = false)
{
    if ($ignore_loading_check || runtime_loading_is_possible()) {
        return runtime_loader_location();
    } else {
        return false;
    }
}

function runtime_loading($rtl_path = null)
{
    if (empty($rtl_path)) {
        $rtl_path = get_valid_runtime_loading_path();
    }
    if (!empty($rtl_path) && @dl($rtl_path)) {
        return $rtl_path;
    } else {
        return false;
    }
}

function get_runtime_loading_path_if_applicable()
{
    $rtl = null;
    if (shared_and_runtime_loading()) {
        $rtl = get_valid_runtime_loading_path();
    }
    return $rtl;
}

function try_runtime_loading_if_applicable()
{
    $rtl_path = get_runtime_loading_path_if_applicable();
    if (!empty($rtl_path)) {
        return runtime_loading($rtl_path);
    } else {
        return $rtl_path;
    }
}

function runtime_loading_instructions()
{
    $default = get_default_address();
    echo '<h4>Runtime Loading Instructions</h4>';
    echo '<div class=panel>';
    echo '<p>On your shared server the Loader can be installed using the runtime loading method.';
    echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";

    if ('.' == extension_dir()) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        echo "Please note that on your system the Loader <em>must</em> be present in the same " . $dirphrase . " as the first encoded file accessed.";
    }
    echo '<ol>';
    loader_download_instructions(); 
    $loader_dir = loader_install_instructions(SERVER_SHARED,dirname(__FILE__));
    shared_test_instructions();
    echo '</ol>';
    echo '</div>';
}

function runtime_loading_errors()
{
    $errors = array();
    $ext_path = extension_dir_path();
    if (false === $ext_path) {
        $errors[ERROR_RUNTIME_EXT_DIR_NOT_FOUND] = "Extensions directory cannot be found.";
    } else {
        $expected_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . get_loader_name();
        if (!@file_exists($expected_file)) {
            $errors[ERROR_RUNTIME_LOADER_FILE_NOT_FOUND] = "The Loader file was expected to be at $expected_file but could not be found.";
        } else {
            $errors = loader_compatibility_test($expected_file);
        }
    }
    return $errors;
}


function windows_package_name()
{
    $sys = get_sysinfo();
	$loader = get_loaderinfo();
    return (LOADERS_PACKAGE_PREFIX . 'win' . '_' . ($sys['THREAD_SAFE']?'':'nonts_') . strtolower($sys['PHP_COMPILER']) .  '_' . $loader['arch']);
}

function unix_package_name()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($reqd_version,$exact_match) = get_reqd_version($loader['osvariants']);
        if ($reqd_version) {
            $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $reqd_version . '_' . $loader['arch'];
        } else {
            $basename = "";
        }
    } else {
        $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $loader['arch'];
    }
    return array($basename,$multiple_os_versions);
}

function loader_download_instructions()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;

    if (is_ms_windows()) {
        if (is_bool($sysinfo['THREAD_SAFE'])) {
            $download_str = '<li>Download the following archive of Windows ' . $sysinfo['PHP_COMPILER'];
            if (!$sysinfo['THREAD_SAFE']) {
                $download_str .= ' non-TS';
            }
            $download_str .= ' ' . $loader['arch'] . ' Loaders:';
            echo $download_str;
            $basename = windows_package_name();
            echo make_archive_list($basename,array('zip'));
            echo 'A Loaders archive can also be downloaded from <a href="' . LOADERS_PAGE . '" target="loaders">' . LOADERS_PAGE . '</a>.';
        } else {
            echo '<li>Download a Windows Loaders archive from <a href="' . LOADERS_PAGE  . '" target=loaders>here</a>. If PHP is built with thread safety disabled, use the Windows non-TS Loaders.';
        }
    } else {
        list($basename,$multiple_os_versions) = unix_package_name(); 
        if ($basename == "") {
            echo '<li>Download a ' . $loader['osname'] . ' ' . $loader['arch'] . ' Loaders archive from <a href="' . LOADERS_PAGE . '" target="loaders">here</a>.';
            echo "<br>Your system appears to be ${loader['osnamequal']} for ${loader['wordsize']} bit. If Loaders are not available for that exact release of ${loader['osname']}, Loaders built for an earlier release should work. Note that you may need to install back compatibility libraries for the operating system.";
            echo '<br>If you cannot find a suitable loader then please raise a ticket at <a href="'. SUPPORT_SITE . '">our support helpdesk</a>.';
        } else {
            echo '<li>Download one of the following archives of Loaders for ' . $loader['osnamequal'] . ' ' . $loader['arch'] . ':'; 
            if (SERVER_SHARED == find_server_type()) {
                $archives = array('zip','tar.gz');
            } else {
                $archives = array('tar.gz','zip');
            }
            echo make_archive_list($basename,$archives);
            echo "</p>";
            if ($multiple_os_versions && !$exact_match) {
                echo "<p>Note that you may need to install back compatibility libraries for  ${loader['osname']}.</p>";
            }
        }
    }

    echo '</li>';
}

function ini_dir()
{
    $sysinfo = get_sysinfo();
    $parent_dir = '';
    if (!empty($sysinfo['PHP_INI'])) {
        $parent_dir = dirname($sysinfo['PHP_INI']);
    } else {
        $parent_dir = $_SERVER["PHPRC"];
        if (@is_file($parent_dir)) {
            $parent_dir = dirname($parent_dir);
        }
    }
    return $parent_dir;
}

function unix_install_dir()
{
    $ext_dir = extension_dir_path();
    $cur_dir = @realpath('.');
    if (empty($ext_dir) || $ext_dir == $cur_dir) {
        $loader_dir = UNIX_SYSTEM_LOADER_DIR;
    } else {
        $loader_dir = $ext_dir;
    }
    return $loader_dir;
}

function windows_install_dir()
{
    $sysinfo = get_sysinfo();
    if ($sysinfo['SS'] == 'IIS') {
        if (false === ($ext_dir = extension_dir_path())) {
            $parent_dir = ini_dir();
            $ext_dir = $parent_dir . '\\ext';
            if (!empty($parent_dir) && @file_exists($ext_dir)) {
                $loader_dir = $ext_dir;
            } else {
                $loader_dir = $_SERVER['windir'] . '\\' . WINDOWS_IIS_LOADER_DIR;
            }
        } else {
            $loader_dir = $ext_dir;
        }
    } else {
        if (false === ($ext_dir = extension_dir_path())) {
			$parent_dir = ini_dir();
			$loader_dir = $parent_dir . '\\' . 'ioncube';
		} else {
			$loader_dir = $ext_dir;
		}
    }
    return $loader_dir;
}

function loader_install_dir($server_type)
{
    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $loader_dir = get_default_loader_dir_webspace();
    } elseif (is_ms_windows()) {
        $loader_dir = windows_install_dir();
    } else {
        $loader_dir = unix_install_dir();
    }
    return $loader_dir;
}

function writeable_directories()
{
    $root_path = @realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    $root_path_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
    $above_root_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/../cgi-bin");

    $paths = array();
    foreach (array($root_path,$above_root_path,$root_path_cgi_bin,$above_root_cgi_bin) as $p) {
        if (@is_writeable($p)) {
            $paths[] = $p;
        }
    }
    return $paths;
}

function loader_install_instructions($server_type,$loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = loader_install_dir($server_type);
    }
    if (SERVER_LOCAL == $server_type) {
        echo "<li>Put the Loader files in <code>$loader_dir</code></li>";
    } else {
        echo "<li>Transfer the Loaders to your web server and install in <code>$loader_dir</code></li>";
    }
    return $loader_dir;
}

function zend_extension_lines($loader_dir)
{
    $zend_extension_lines = array();
    $sysinfo = get_sysinfo();
    $qt = (is_ms_windows()?'"':'');
    $loader = get_loaderinfo();

    if (!is_bool($sysinfo['THREAD_SAFE']) || !$sysinfo['THREAD_SAFE']) {
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file'] . $qt;
        $zend_extension_lines[] = "zend_extension = " . $path;
    }
    if ((!is_bool($sysinfo['THREAD_SAFE']) && !is_php_version_or_greater(5,3)) || $sysinfo['THREAD_SAFE']) {
        $line_start = is_php_version_or_greater(5,3)?'zend_extension':'zend_extension_ts';
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file_ts'] . $qt;
        $zend_extension_lines[] = $line_start . " = " . $path;
    }
    return $zend_extension_lines;
}

function user_ini_base()
{
    $doc_root_path = realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    if (!empty($above_root_path) && @is_writeable($above_root_path)) {
        $start_path = $above_root_path;
    } else {
        $start_path = $doc_root_path;
    }
    return $start_path;
}

function user_ini_space_path($file)
{
    $user_base = user_ini_base();
    $fpath = @realpath($file);
    if (!empty($fpath) && (0 === strpos($fpath,$user_base))) {
        return $fpath;
    } else {
        return false;
    }
}

function default_ini_path()
{
    return (realpath($_SERVER['DOCUMENT_ROOT']));
}

function shared_ini_location()
{
    $phprc = getenv('PHPRC');
    if (!empty($phprc)) {
        $phprc_path = user_ini_space_path($phprc);
        if (false !== $phprc_path) {
            return $phprc_path;
        } else {
            return default_ini_path();
        }
    } else {
        return default_ini_path();
    }
}


function zend_extension_instructions($server_type,$loader_dir)
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();
    $editing_ini = true;

    $php_ini_name = ini_file_name();

    if (isset($sysinfo['PHP_INI']) && @file_exists($sysinfo['PHP_INI'])) {
        $php_ini_path = $sysinfo['PHP_INI'];
    } else {
        $php_ini_path = '';
    }

    if (is_bool($sysinfo['THREAD_SAFE'])) {
        $kwd = zend_extension_line_start();
    } else {
        $kwd = 'zend_extension/zend_extension_ts';
    }

    $server_type_code = server_type_code();

    $zend_extension_lines = zend_extension_lines($loader_dir);

    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $ini_dir = shared_ini_location();
        $php_ini_path = $ini_dir . DIRECTORY_SEPARATOR . $php_ini_name;
        if (@file_exists($php_ini_path)) {
            $edit_line = "<li>Edit the <code>$php_ini_name</code> in the <code>$ini_dir</code> directory";
            if (zend_extension_line_missing($php_ini_path) && @is_writeable($php_ini_path) && @is_writeable($ini_dir)) {
                if (function_exists('file_get_contents')) {
                    $ini_strs = @file_get_contents($php_ini_path);
                } else {
                    $lines = @file($php_ini_path);
                    $ini_strs = join(' ',$lines);
                }
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                        fwrite($fh,$zl . PHP_EOL);
                    }
                    fwrite($fh,$ini_strs);
                    fclose($fh);
                    $editing_ini = false;
                    echo "<li>Your php.ini file at $php_ini_path has been modified to include the necessary line for the ionCube Loader.";
                } else {
                    echo $edit_line;
                }
            } else {
               echo $edit_line;
            }
        } else {
            $download_ini_file = "<li><a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">Save this  <code>$php_ini_name</code> file</a> and upload it to <code>$ini_dir</code> (full path on your server).";
            if (@is_writeable($ini_dir)) {
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                       fwrite($fh,$zl . PHP_EOL);
                    }
                    if (!empty($sysinfo['PHP_INI']) && is_readable($sysinfo['PHP_INI'])) {
                        if (function_exists('file_get_contents')) {
                           $ini_strs = @file_get_contents($sysinfo['PHP_INI']);
                        } else {
                           $lines = @file($sysinfo['PHP_INI']);
                           $ini_strs = join(' ',$lines);
                        }
                        fwrite($fh,$ini_strs);
                    }
                    fclose($fh); 
                    echo "<li>A <code>$php_ini_name</code> file has been created for you in <code>$ini_dir</code>.";
                } else {
                    echo $download_ini_file;
                }
            } else {
                echo $download_ini_file;
            }
            $editing_ini = false;
        }
    } elseif (!empty($sysinfo['PHP_INI'])) {
        if (empty($sysinfo['PHP_INI_DIR'])) {
            echo "<li>Edit the file <code>${sysinfo['PHP_INI']}</code>";
        } else {
            $php_ini_path = find_additional_ioncube_ini();
            if (empty($php_ini_path)) {
                $php_ini_name = ADDITIONAL_INI_FILE_NAME;
                echo "<li><a href=\"$base&amp;page=phpconfig&amp;download=1&amp;newlinesonly=1&amp;ininame=$php_ini_name&amp;stype=$server_type_code\">Save this $php_ini_name file</a> and put it in your ini files directory, <code>${sysinfo['PHP_INI_DIR']}</code>";
                $editing_ini = false;
            } else {
                $php_ini_name = basename($php_ini_path);
                echo "<li>Edit the file <code>$php_ini_path</code>";
            }
        }
    } else {
        echo "<li>Edit the system <code>$php_ini_name</code> file";
    }
    if ($editing_ini) {
        echo " and <b>before</b> any other $kwd lines ensure that the following is included:<br>";
        foreach ($zend_extension_lines as $zl) {
            echo "<code>$zl</code><br>";
        }
        if (!empty($php_ini_path)) {
            if (zend_extension_line_missing($php_ini_path)) {
                echo "<a>Alternatively, replace your current <code>$php_ini_path</code> file with <a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">this new $php_ini_name file</a>."; 
            }
        }
    }
    echo '</li>';
}

function server_restart_instructions()
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();

    if ($sysinfo['SS']) {
		if ($sysinfo['SS'] == 'PHP-FPM') {
			echo "<li>Restart PHP-FPM.</li>";
		} else {
			echo "<li>Restart the ${sysinfo['SS']} server software.</li>";
		}
    } else {
        echo "<li>Restart the server software.</li>";
    }

    echo "<li>When the server software has restarted, <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the Loader</a>.</li>";

	if ($sysinfo['SS'] && $sysinfo['SS'] == 'PHP-FPM') {
		echo '<li>If the Loader installation failed, check the PHP-FPM error log file for errors.</li>';
    } elseif ($sysinfo['SS'] == 'Apache' && !is_ms_windows()) {
        echo '<li>If the Loader installation failed, check the Apache error log file for errors and see our guide to <a target="unix_errors" href="'. UNIX_ERRORS_URL . '">Unix related errors</a>.</li>';
    }
}

function shared_test_instructions()
{
    $base = get_base_address();
    echo "<li><a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">Click here to test the Loader</a>.</li>";
}

function link_to_php_ini_instructions()
{
    $default = get_default_address();
    echo "<p><a href=\"{$default}&amp;stype=s&amp;ini=1\">Please click here for instructions on using the php.ini method instead</a>.</p>";
}

function php_ini_instruction_list($server_type)
{
    echo '<h4>Installation Instructions</h4>';
    echo '<div class=panel>';
    echo '<ol>';

    loader_download_instructions(); 
    $loader_dir = loader_install_instructions($server_type);
    zend_extension_instructions($server_type,$loader_dir);
    if ($server_type != SERVER_SHARED || !own_php_ini_possible()) {
        server_restart_instructions();
    } else {
        shared_test_instructions();
    } 
    echo '</ol>';
    echo '</div>';
}

function php_ini_install_shared($give_preamble = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();
    if ($give_preamble) {
        echo "<p>On your <strong>shared</strong> server, the Loader should be installed using a <code>$php_ini_name</code> configuration file.";
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";
    }

    if (own_php_ini_possible()) {
        echo '<p>With your hosting account, you may be able to use your own PHP configuration file.</p>';
    } else {
        echo "<p>It appears that you cannot install the ionCube Loader using the <code>$php_ini_name</code> file. Your server provider or system administrator should be able to perform the installation for you. Please refer them to the following instructions.</p>";
    }

    php_ini_instruction_list(SERVER_SHARED);
}

function php_ini_install($server_type_desc = null, $server_type = SERVER_DEDICATED, $required = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();

    echo '<p>';
    if ($server_type_desc) {
        echo "For a <strong>$server_type_desc</strong> server ";
    } else {
        echo "For this server ";
    }

    if ($required) {
        echo "you should install the ionCube Loader using the <code>$php_ini_name</code> configuration file.";
    } else {
        echo "installing the ionCube Loader using the <code>$php_ini_name</code> file is recommended.";
    }
    if ($server_type_desc) {
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a $server_type_desc server</a>.)";
    }
    echo '</p>';
      
    php_ini_instruction_list($server_type);
}



function help_resources($error_list = array())
{
	$self = get_self();
    $base = get_base_address();
    $server_type_code = server_type_code();
    $server_type = find_server_type();
    $sysinfo = get_sysinfo();
    $resources = array(
            '<a target="_blank" href="' . LOADERS_FAQ_URL . '">ionCube Loaders FAQ</a>',
            '<a target="_blank" href="' . LOADER_FORUM_URL . '">ionCube Loader Forum</a>'
        );
    if (SERVER_SHARED != $server_type || own_php_ini_possible(true)) {
		$support_info = array ( 
			'department' 		=> WIZARD_SUPPORT_TICKET_DEPARTMENT,
			'subject' 			=> "ionCube Loader installation problem",
			'message' 			=> support_ticket_information()
		   );
		if (SERVER_LOCAL == $server_type && !info_should_be_disabled()) {
			$temp_files = system_info_temporary_files();
		} else {
			$temp_files = NULL;
		}
		if (!empty($temp_files)) {
			$support_info['ini'] = base64_encode(file_get_contents($temp_files['ini']));
			$support_info['phpinfo'] = base64_encode(file_get_contents($temp_files['phpinfo']));
			$support_info['additional'] = base64_encode(file_get_contents($temp_files['additional']));
			
			$loader_path = find_loader(true);
			if (is_string($loader_path)) {		
				$support_info['loader'] = base64_encode(file_get_contents($loader_path));
				$support_info['loader_name'] = basename($loader_path);
			} else {
				$support_info['loader'] = '';
				$support_info['loader_name'] = '';
			}
		} else {
			$support_info['ini'] = '';
			$support_info['phpinfo'] = '';
			$support_info['additional'] = '';
			$support_info['loader'] = '';
			$support_info['loader_name'] = '';
		}
		 
        $resources[2] = '<form action="' . SUPPORT_SITE . 'lw_index.php' .'" method="POST" id="support-ticket"><a href="" onclick="document.getElementById(\'support-ticket\').submit(); return false;">Raise a support ticket through our helpdesk</a>';
		$resources[2] .= '<input type="hidden" name="department" value="' . $support_info['department'] . '"/>';
		$resources[2] .= '<input type="hidden" name="subject" value="' . $support_info['subject'] . '"/>';
		$resources[2] .= '<input type="hidden" name="message" value="' . $support_info['message'] . '"/>';
		if (!empty($temp_files)) {
			$resources[2] .= '<input type="hidden" name="phpinfo" value="' . $support_info['phpinfo'] . '"/>';
			$resources[2] .= '<input type="hidden" name="ini" value="' . $support_info['ini'] . '"/>';
			$resources[2] .= '<input type="hidden" name="additional" value="' . $support_info['additional'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader" value="' . $support_info['loader'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader_name" value="' . $support_info['loader_name'] . '"/>';
		}
		$resources[2] .= '</form>';
    } 
	
    if (SERVER_SHARED == $server_type && own_php_ini_possible(true) && !user_ini_space_path($sysinfo['PHP_INI'])) {
        $resources[3] = '<strong>Please check with your host that you can create php.ini files that will override the system one.</strong>';
    }
    return $resources;
}

function system_info_temporary_files()
{
    $tmpfname_ini = get_tempnam("/tmp", "INI");
    $tmpfname_ini .= ".ini";
    $fh_ini = @fopen($tmpfname_ini,'wb');
    if ($fh_ini) {
        $config = all_ini_contents();
        fwrite($fh_ini,$config);
        fclose($fh_ini);
    } else {
        $tmpfname_ini = '';
    }

    $tmpfname_pinf = get_tempnam("/tmp", "PIN");
    $tmpfname_pinf .= ".html";
    $fh_pinfo = @fopen($tmpfname_pinf,'wb');
    if ($fh_pinfo) {
        ob_start();
        @phpinfo();
        $pinfo = ob_get_contents();
        ob_end_clean();
        fwrite($fh_pinfo,$pinfo);
        fclose($fh_pinfo);
    } else {
        $tmpfname_pinf = '';
    }

    $tmpfname_add = get_tempnam("/tmp", "ADD");
    $tmpfname_add .= ".html";
    $fh_add = @fopen($tmpfname_add,'wb');
    if ($fh_add) {
        ob_start();
        extra_page(false);
        $extra = ob_get_contents();
        ob_end_clean();
        fwrite($fh_add,$extra);
        fclose($fh_add);
    } else {
        $tmpfname_add = '';
    }

    if (empty($tmpfname_ini) || empty($tmpfname_pinf) || empty($tmpfname_add)) {
        return (array());
    } else {
        return (array('ini'           =>   $tmpfname_ini,
                      'phpinfo'       =>   $tmpfname_pinf,
                      'additional'    =>   $tmpfname_add));
    }
}

function get_tempnam($default_tmp_dir = '', $prefix = '')
{
	if (function_exists('sys_get_temp_dir')) {
		return tempnam(sys_get_temp_dir(),$prefix);
	} else {
		return @tempnam($default_tmp_dir, $prefix);
	}
}
function system_info_archive_page()
{
    info_disabled_check();
	$server_type = find_server_type();
	if (SERVER_LOCAL != $server_type) {
		exit;
	}
    $loader = find_loader(true);
    if (is_string($loader)) {
        $loader_file = $loader;
    } else {
        $loader_file = '';
    }
    $all_files = system_info_temporary_files();
    if (!empty($all_files)) {
        if (!empty($loader_file)) {
            $all_files['loader'] = $loader_file;
        }
        $archive_name =  get_tempnam('/tmp',"ARC");
        if (extension_loaded('zip')) {
            $archive_name .= '.zip';
            $zip = @new ZipArchive();
            $mode = @constant("ZIPARCHIVE::OVERWRITE");
            if (!$zip || $zip->open($archive_name, $mode)!==TRUE) {
                $archive_name = '';
            } else {
                foreach($all_files as $f) {
                    $zip->addFile($f,basename($f));
                }
                $zip->close();
            }
        } elseif (extension_loaded('zlib') && !is_ms_windows()) {
            $tar_name = $archive_name . ".tar";
            $all_files_str = join(' ',$all_files);
            $script = "tar -chf $tar_name $all_files_str";
            $result = @system($script,$retval);
            if ($result !== false) {
                $archive_name = $tar_name . '.gz';
                $zp = gzopen($archive_name,"w9");
                $tar_contents = get_file_contents($tar_name);
                gzwrite($zp,$tar_contents);
                gzclose($zp);
            } else {
                $archive_name = '';
            }
        } else {
            $archive_name = '';
        }
    } else {
        $archive_name = '';
    }
    if ($archive_name) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. $archive_name);
        @readfile($archive_name);
    } else {
        $self = get_self();
        $base = get_base_address();
        $server_type_code = server_type_code();
        heading();
        echo "<p>A downloadable archive of system information could not be created.<br> 
            <strong>Please save each of the following and then attach those files to the support ticket:</strong></p>"; 
        echo "<ul>";
        echo "<li><a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo()</a></li>";
        echo "<li><a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a></li>";
        echo "<li><a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional information</a></li>";
        echo "<li><a href=\"$self?page=loaderbin\">loader file</a></li>";
        echo "</ul>";
        footer(true);
    }
}

function support_ticket_information($error_list = array())
{
    $sys = get_sysinfo();
    $ld = get_loaderinfo();

    $ticket_strs = array();
    $ticket_strs[] = "PLEASE DO NOT REMOVE THE FOLLOWING INFORMATION\r\n";
    $ticket_strs[] = "==============\r\n";
    if (!empty($error_list)) {
        $ticket_strs[] = "[hr]";
        $ticket_strs[] = "ERRORS";
        $ticket_strs[] = "[table]";
        $ticket_strs[] = '[tr][td]' . join('[/td][/tr][tr][td]',$error_list) . '[/td][/tr]';
        $ticket_strs[] = "[/table]";
    }
    $ticket_strs[] = "[hr]";
    $ticket_strs[] = "SYSTEM INFORMATION";
    $info_lines = array();
    $info_lines["Wizard version"] = script_version();
    $info_lines["PHP uname"] = $ld['uname'];
    $info_lines["Machine architecture"] = $ld['arch'];
    $info_lines["Word size"] = $ld['wordsize'];
    $info_lines["Operating system"] = $ld['osname'] . ' ' . $ld['osver'];
    if (selinux_is_enabled() || possibly_selinux()) {
        $info_lines["Security enhancements"] = "SELinux";
    } elseif (grsecurity_is_enabled()) {
        $info_lines["Security enhancements"] = "Grsecurity";
    } else {
        $info_lines["Security enhancements"] = "None";
    }
    $info_lines["PHP version"] = PHP_VERSION; 
    if ($sys['DEBUG_BUILD']) {
        $info_lines["DEBUG BUILD"] = "DEBUG BUILD OF PHP";
    }
    if (!$sys['SUPPORTED_COMPILER']) {
        $info_lines["SUPPORTED PHP COMPILER"] = "FALSE";
        $info_lines["PHP COMPILER"] = $sys['PHP_COMPILER'];
    }
    $info_lines["Is CLI?"] = ($sys['IS_CLI']?"Yes":"No");
    $info_lines["Is CGI?"] = ($sys['IS_CGI']?"Yes":"No");
    $info_lines["Is thread-safe?"] = ($sys['THREAD_SAFE']?"Yes":"No");
    $info_lines["Web server"] = $sys['FULL_SS'];
    $info_lines["Server type"] = server_type_string();
    $info_lines["PHP ini file"] = $sys['PHP_INI'];
    if (!@file_exists($sys['PHP_INI'])) {
        $info_lines["Ini file found"] = "INI FILE NOT FOUND";
    } else {
        if (is_readable($sys['PHP_INI'])) {
            $info_lines["Ini file found"] = "INI FILE READABLE";
        } else {
            $fh = @fopen($sys['PHP_INI'],"rb");
            if ($fh === false) {
                $info_lines["Ini file found"] = "INI FILE FOUND BUT POSSIBLY NOT READABLE";
            } else {
                $info_lines["Ini file found"] = "INI FILE READABLE";
            }
        }
    }
    $info_lines["PHPRC"] = $sys['PHPRC'];
    $loader_path = find_loader();
    if (is_string($loader_path)) {
        $info_lines["Loader path"] =  $loader_path;
        $info_lines["Loader file size"] = filesize($loader_path) . " bytes.";
        $info_lines["Loader MD5 sum"] =  md5_file($loader_path);
    } else {
        $info_lines["Loader path"] =  "LOADER PATH NOT FOUND";
    }
    $server_type_code = server_type_code();
    if (!empty($_SESSION['hostprovider'])) {
      $info_lines['Hosting provider'] = $_SESSION['hostprovider'];
      $info_lines['Provider URL'] = $_SESSION['hosturl'];
    }
    $info_lines["Wizard script path"] = '[url]http://' . $_SERVER["HTTP_HOST"] . get_self() . '?stype='. $server_type_code . '[/url]';
    $ticket_strs[] = "[table]";
    foreach ($info_lines as $h => $i) {
        $value = (empty($i))?'EMPTY':$i;
        $ticket_strs[] = '[tr][td]' . $h . '[/td]' . '[td]' . $value . '[/td][/tr]';
    }
    $ticket_strs[] = '[/table]';
    $ticket_strs[] = '[hr]';
    $ticket_strs[] = "\r\n==============\r\n";
    $ticket_strs[] = "PLEASE ENTER ANY ADDITIONAL INFORMATION BELOW\r\n";

    $support_ticket_str = join('',$ticket_strs);
    return urlencode($support_ticket_str);
}

function wizard_stats_data($page_id)
{
    $data = array();

    try_runtime_loading_if_applicable();
    $sysinfo = get_sysinfo();
    $ldinfo = get_loaderinfo();

    $data['sessionid'] = session_id();
    $data['wizard_version'] = script_version();
    $data['server_type'] = server_type_code();
    $data['hostprovider'] = (isset($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $data['hosturl'] = (isset($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $data['page_id'] = $page_id;
    $data['loader_state'] = (extension_loaded(LOADER_EXTENSION_NAME))?'installed':'failure';
    $data['ini_location'] = $sysinfo['PHP_INI'];
    $data['is_cgi'] = ($sysinfo['IS_CGI'])?"yes":"no";
    $data['is_ts'] = ($sysinfo['THREAD_SAFE'])?"yes":"no";
    $data['arch'] = $ldinfo['arch'];
    $data['php_version'] = PHP_VERSION;
    $data['os'] = $ldinfo['osname'];
    $data['word_size'] = $ldinfo['wordsize'];
    $data['referrer'] =  $_SERVER["HTTP_HOST"] . get_self();

    return $data;
}

function send_stats($page_id = 'default')
{
    $server_type = find_server_type();
    $res = false;

    if (SERVER_LOCAL != $server_type) {
        $stats_data = wizard_stats_data($page_id);

        if (!isset($_SESSION['stats_sent'][$page_id][$stats_data['loader_state']])) {
            $url = WIZARD_STATS_URL;

            if (!empty($stats_data)) {
                if(function_exists('http_build_query')) {
                    $qparams = http_build_query($stats_data);
                } else {
                    $qparams = php4_http_build_query($stats_data);
                }
                $url .= '?' . $qparams;
                $res = remote_file_contents($url);
            }
            $_SESSION['stats_sent'][$page_id][$stats_data['loader_state']] = 1;
        } else {
            $res = true;
        }
    } else {
        $res = 'LOCAL';
    }
    return $res;
}

function os_arch_string_check($loader_str)
{
    $errors = array();
    if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_str,$os_matches)) {
        $loader_info = get_loaderinfo();
        $dirname = calc_dirname();
        $packed_osname = preg_replace('/\s/','',strtolower($loader_info['osname']));
        if (strtolower($dirname) != $os_matches[1] && $packed_osname != $os_matches[2]) {
            $errors[ERROR_LOADER_WRONG_OS] = "You have the wrong loader for your operating system, ". $loader_info['osname'] . ".";
        } else {
            $loader_wordsize = (strpos($os_matches[3],'64') === false)?32:64;
            if ($loader_info['arch'] != ($ap = required_loader_arch($os_matches[3],$loader_info['oscode'],$loader_wordsize))) {
                $err_str = "You have the wrong loader for your machine architecture.";
                $err_str .= " Your system is " . $loader_info['arch'];
                $err_str .= " but the loader you are using is for " . $ap . ".";
                $errors[ERROR_LOADER_WRONG_ARCH] = $err_str;
            }
        }
    }
    return $errors;
}

function get_loader_strings($loader_location)
{
    if (function_exists('file_get_contents')) {
        $loader_strs = @file_get_contents($loader_location);
    } else {
        $lines = @file($loader_location);
        $loader_strs = join(' ',$lines);
    }
    return $loader_strs;
}

function loader_system($loader_location)
{
    $loader_system = array();
    $loader_strs = get_loader_strings($loader_location);

    if (!empty($loader_strs)) {

        if (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
            $loader_system['oscode'] = 'win';
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '_nonts')?0:1;
			if (preg_match("/_localtime([0-9][0-9])/i",$loader_strs,$size_matches)) {
				$loader_system['wordsize'] = ($size_matches[1] == '64')?64:32;
			} else {
				$loader_system['wordsize'] = 32;
			}
            $loader_system['arch'] = ($loader_system['wordsize'] == 64)?'x86-64':'x86';
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
			if ($loader_system['php_version_major'] == 8 && $loader_system['php_version_minor'] >= 1) {
				$loader_system['compiler'] = 'VC16';
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] >= 2) {
				$loader_system['compiler'] = 'VC15'; 
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] < 2) {
				$loader_system['compiler'] = 'VC14'; 
			} elseif ($loader_system['php_version_major'] == 5 && $loader_system['php_version_minor'] >= 5) {
				$loader_system['compiler'] = 'VC11'; 
			} elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_system['compiler'] = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_system['compiler'] = 'VC6';
            }
        } elseif (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '-ts')?1:0;
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
            if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_strs,$os_matches)) {
                $loader_system['oscode'] = strtolower(substr($os_matches[2],0,3));
                $loader_system['wordsize'] = (strpos($os_matches[3],'64') === false)?32:64;
                $loader_system['arch'] = required_loader_arch($os_matches[3],$loader_system['oscode'],$loader_system['wordsize']);
                $loader_system['compiler'] = $os_matches[4];
            }
        }
        if (preg_match("/ionCube Loader Version\s+(\S+)/",$loader_strs,$loader_version)) {
            $loader_system['loader_version'] = $loader_version[1];
		} elseif (preg_match("/ioncube_loader_(\d{1,2}\.\d\.\d{1,2})\./",$loader_strs,$loader_version)){
			$loader_system['loader_version'] = $loader_version[1];
        } else {
            $loader_system['loader_version'] = 'UNKNOWN';
        }
        if (isset($loader_system['php_version_major'])) {
            $loader_system['php_version'] = $loader_system['php_version_major'] . '.' . $loader_system['php_version_minor'];
        }
    }
    return $loader_system;
}

function loader_compatibility_test($loader_location)
{
    $errors = array();

    $sysinfo = get_sysinfo();
    if (LOADER_NAME_CHECK) {
        $installed_loader_name = basename($loader_location);
        $expected_loader_name = get_loader_name();
        if ($installed_loader_name != $expected_loader_name) {
            $errors[ERROR_LOADER_UNEXPECTED_NAME] = "The installed loader (<code>$installed_loader_name</code>) does not have the name expected (<code>$expected_loader_name</code>) for your system. Please check that you have the correct loader for your system.";
        }
    }
    if (empty($errors) && !is_readable($loader_location)) {
        $execute_error = "The loader at $loader_location does not appear to be readable.";
        $execute_error .= "<br>Please check that it exists and is readable.";
        $execute_error .= "<br>Please also check the permissions of the containing ";
        $execute_error .= (is_ms_windows()?'folder':'directory') . '.';
		if ($sysinfo['SS'] == 'PHP-FPM') {
			$execute_error .= "<br>Please also check that PHP-FPM has been restarted.";
        } elseif (($sysinfo['SS'] == 'IIS') || !($sysinfo['IS_CGI'] || $sysinfo['IS_CLI'])) {
            $execute_error .= "<br>Please also check that the web server has been restarted.";
        }
        $execute_error .= ".";
        $errors[ERROR_LOADER_NOT_READABLE] = $execute_error;
    }
    $loader_strs = get_loader_strings($loader_location);
    $phpv = php_version(); 
    if (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
        if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
            $loader_php = $version_matches[1] . "." . $version_matches[2];
            $server_php =  $phpv['major'] . "." .  $phpv['minor'];
            $errors[ERROR_LOADER_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
        }
        if (is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'] && !is_ms_windows() && !(isset($version_matches[4]) && $version_matches[4] == '-ts')) {
            $errors[ERROR_LOADER_NONTS_PHP_TS] = "Your server is running a thread-safe version of PHP but the loader is not a thread-safe version.";
        } elseif (isset($version_matches[4]) && $version_matches[4] == '-ts' && !(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'])) {
            $errors[ERROR_LOADER_TS_PHP_NONTS] = "Your server is running a non-thread-safe version of PHP but the loader is a thread-safe version.";
        }
    } elseif (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
        if (!is_ms_windows()) {
            $errors[ERROR_LOADER_WIN_SERVER_NONWIN] = "You have a Windows loader but your server does not appear to be running Windows.";
        } else {
            if (isset($version_matches[4]) && $version_matches[4] == '_nonts' && is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) {
                $errors[ERROR_LOADER_WIN_NONTS_PHP_TS] = "You have the non-thread-safe version of the Windows loader but you need the thread-safe one.";
            } elseif (!(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) && !(isset($version_matches[4]) && $version_matches[4] == '_nonts')) {
                $errors[ERROR_LOADER_WIN_TS_PHP_NONTS] = "You have the thread-safe version of the Windows loader but you need the non-thread-safe one."; 
            }
            if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
                $loader_php = $version_matches[1] . "." . $version_matches[2];
                $server_php =  $phpv['major'] . "." .  $phpv['minor'];
                $errors[ERROR_LOADER_WIN_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
            }
                        
            if ($version_matches[1] == 8 && $version_matches[2] >= 1) {
                $loader_compiler = 'VC16';
            } elseif ($version_matches[1] == 7 && $version_matches[2] >= 2) {
                $loader_compiler = 'VC15'; 
            } elseif ($version_matches[1] == 7) {
                $loader_compiler = 'VC14'; 
            } elseif ($version_matches[1] == 5 && $version_matches[2] >= 5) {
                $loader_compiler = 'VC11'; 
            } elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_compiler = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_compiler = 'VC6';
            }
            if ($loader_compiler != $sysinfo['PHP_COMPILER']) {
                $errors[ERROR_LOADER_WIN_COMPILER_MISMATCH] = "Your loader was built using $loader_compiler but you need the loader built using ${sysinfo['PHP_COMPILER']}.";
            }
        }
    } else {
            $errors[ERROR_LOADER_PHP_VERSION_UNKNOWN] = "The PHP version for the loader cannot be determined - please check that you have a valid ionCube Loader.";
    } 
    $errors += os_arch_string_check($loader_strs);

    return $errors;
}


function shared_server()
{
    if (!$rtl_path = runtime_loading()) {
        if (empty($_SESSION['use_ini_method']) && runtime_loading_is_possible()) {
            runtime_loading_instructions();
        } else {
            php_ini_install_shared();
        }
    } else {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        echo "<p>The ionCube Loader $lv for PHP $phpv has been successfully installed.</p>";
        $is_legacy_loader = loader_major_version_instructions($mv);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,$newer_version);
        }
        successful_install_end_instructions($rtl_path);
    }
}

function dedicated_server()
{
    php_ini_install('dedicated or VPS', SERVER_DEDICATED, true);
}

function local_install()
{
    php_ini_install('local',SERVER_LOCAL, true);
}


function unregister_globals()
{
    if (!ini_get('register_globals')) {
        return;
    }

    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

function clear_session($persist = array())
{
    $persist['not_go_daddy'] = empty($_SESSION['not_go_daddy'])?0:1;
    $persist['use_ini_method'] = empty($_SESSION['use_ini_method'])?0:1;
    $persist['server_type'] = empty($_SESSION['server_type'])?SERVER_UNKNOWN:$_SESSION['server_type'];
    @session_destroy();
    $_SESSION = array();
    $_SESSION['CREATED'] = time();
    $_SESSION = $persist;
}

function can_archive()
{
	return (extension_loaded('zip') || (extension_loaded('zlib') && !is_ms_windows()));
}

function is_ioncube()
{
        return (($_SERVER["REMOTE_ADDR"] == IONCUBE_IP_ADDRESS) || ($_SERVER["REMOTE_ADDR"] == gethostbyname(IONCUBE_ACCESS_ADDRESS)));
}

function can_reach_ioncube()
{
	return (isset($_SESSION['remote_access_successful']));
}

function info_should_be_disabled($only_allow_ioncube = false)
{
    $elapsed = time() - max(filemtime(__FILE__),filectime(__FILE__));
	
	if (is_ioncube()) {
		$cutoff_time = IONCUBE_WIZARD_EXPIRY_MINUTES * 60;
	} else {
		if (!$only_allow_ioncube && !extension_loaded(LOADER_EXTENSION_NAME)) {
			$cutoff_time = WIZARD_EXPIRY_MINUTES * 60;
		} else {
			return true;
		}
	}
	
    return ($elapsed > $cutoff_time);
}

function info_disabled_text()
{
    return "The information you have tried to access has been disabled for security reasons. Please re-install this Loader Wizard script and try again.";
}

function info_disabled_check()
{
    if (info_should_be_disabled()) {
        heading();
        echo info_disabled_text();
        footer(true);
        exit;
    }
}

function run()
{

	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (preg_match('/googlebot/i',$user_agent)) {
		exit;
	}
    unregister_globals();
    if (is_php_version_or_greater(4,3,0)) {
        ini_set('session.use_only_cookies',1);
    }
    $session_ok = @session_start();

    if (!defined('PHP_EOL')) {
        if (is_ms_windows()) {
            define('PHP_EOL',"\r\n");
        } else {
            define('PHP_EOL',"\n");
        }
    }

    if (!isset($_SESSION['CREATED'])) {
        $_SESSION['CREATED'] = time();
    } elseif (time() - $_SESSION['CREATED'] > SESSION_LIFETIME_MINUTES * 60 ) {
        clear_session(); 
    }
    if (!isset($_SERVER)) $_SERVER =& $HTTP_SERVER_VARS;

    (php_sapi_name() == 'cli') && die("This script should only be run by a web server.\n");

    $page = get_request_parameter('page');
    $host = get_request_parameter('host');
    $clear = get_request_parameter('clear');
    $ini = get_request_parameter('ini');
    $timeout = get_request_parameter('timeout');

    if ($timeout) {
        $_SESSION['timing_out'] = 1;
        $_SESSION['initial_run'] = 0;
    }

    if (!empty($host)) {
        if ($host == 'ngd') {
            $_SESSION['not_go_daddy'] = 1;
        }
    }
    if (!empty($ini)) {
        $_SESSION['use_ini_method'] = 1;
    }

    if (!empty($clear)) {
        clear_session();
        unset($_SESSION['not_go_daddy']);
        unset($_SESSION['use_ini_method']);
        unset($_SESSION['server_type']);
    } else {
        $stype = get_request_parameter('stype');
        $hostprovider = get_request_parameter('hostprovider');
        $hosturl = get_request_parameter('hosturl');
        if (!empty($hostprovider)) {
            $_SESSION['hostprovider'] = $hostprovider;
            $_SESSION['hosturl'] = $hosturl;
        }
        $server_type = find_server_type($stype,false,true);
    }
    if ($session_ok && !$timeout && !isset($_SESSION['initial_run']) && empty($page)) {
        $_SESSION['initial_run'] = 1;
        initial_page();
        @session_write_close();
        exit;
    } else {
        $_SESSION['initial_run'] = 0;
    }

    if (empty($_SESSION['server_type'])) {
        $_SESSION['server_type'] = SERVER_UNKNOWN;
    }

    if (empty($page) || !function_exists($page . "_page")) {
        $page = get_default_page();
    } 

    $fn = "{$page}_page";
    $fn();

    @session_write_close();
    exit(0);
}

function wizardversion_page()
{
    $start_time = time();
    $wizard_version_only = get_request_parameter('wizard_only');
    $clear_session_info = get_request_parameter('clear_info');
    if ($clear_session_info) {
        unset($_SESSION['timing_out']);
        unset($_SESSION['latest_wizard_version']);
    }
    $wizard_version = latest_wizard_version();
    $message = '';
    if (false === $wizard_version) {
        $message = "0";
    } elseif (update_is_available($wizard_version)) {
        $message = "$wizard_version";
    } else {
        $message = "1";
    }
    echo $message;
    @session_write_close();
    exit(0);
}

function platforminfo_page()
{
    $message = '';
    $platforms = get_loader_platforms();
    $message = empty($platforms)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function loaderversion_page()
{
    $message = '';
    $loader_versions = get_loader_version_info();
    $message = empty($loader_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function compilerversion_page()
{
    $message = '';
    $compiler_versions = find_win_compilers();
    $message = empty($compiler_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function initial_page()
{
    $self = get_self();
    $start_page = get_default_address(false);
    $stage_timeout = 7000;
    $step_lag = 500;

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <style type="text/css">
        body {
            height: 100%;
            width: 100%;
        }
        </style>
        <script type="text/javascript">
        var timingOut = 0;
        var xmlHttpTimeout;
        var ajax;
        var statusPar;
        var stage_timeout = $stage_timeout;
        var step_lag = $step_lag;

        function checkNextStep(ajax,expected,continuation) {
            if (ajax.readyState==4 && ajax.status==200)
            {
                clearTimeout(xmlHttpTimeout);
                if (ajax.responseText == expected) {
                   setTimeout('',step_lag);
                   continuation();
                } else {
                   statusPar.innerHTML = 'Unable to check for update<br>script continuing';
                   setTimeout("window.location.href = '$start_page&timeout=1'",1000);
                }
            }
        }

        function getXmlHttp() {
            if (window.XMLHttpRequest) {
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xmlhttp;
        }
        var startMainLoaderWizard = function() {
            window.location.href = '$start_page';
        }
        var loaderVersionCheck = function() {
            statusPar.innerHTML = 'Stage 4/4: Getting latest loader versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",startMainLoaderWizard);
            }
            xmlHttp.open("GET","$self?page=loaderversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var platformCheck = function() {
            statusPar.innerHTML = 'Stage 3/4: Getting platform information';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",loaderVersionCheck);
            }
            xmlHttp.open("GET","$self?page=platforminfo",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var compilerVersionCheck = function() {
            statusPar.innerHTML = 'Stage 2/4: Getting compiler versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",platformCheck);
            }
            xmlHttp.open("GET","$self?page=compilerversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var startChecks = function() {
            statusPar = document.getElementById('status');
            statusPar.innerHTML = 'Stage 1/4: Getting Loader Wizard version';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",compilerVersionCheck);
            }
            xmlHttp.open("GET","$self?page=wizardversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        function ajaxTimeout(){
           ajax.abort();
           statusPar.innerHTML = 'Cannot reach server<br>script continuing';
           setTimeout("window.location.href = '$start_page&timeout=1'",1000);
        }
        </script>
    </head>
    <body>

    <div id="loading"><script type="text/javascript">document.write('<p>Initialising<br>ionCube Loader Wizard<br><span id="status"></span></p>');</script><p id="noscript">Your browser does not support JavaScript so the ionCube Loader Wizard initialisation cannot be made now. This script can get the latest loader version information from the ionCube server when you go to the next page.<br>Please choose one of the following. <br>If the script appears to hang please restart the script and choose the "NO" option.<br><br><br><a href="$start_page">YES - my server DOES have internet access</a><br><br><a href="$start_page&timeout=1">NO - my server does NOT have internet access</a></p></div>
    <script type="text/javascript">
        document.getElementById('noscript').style.display = 'none';
        window.onload = startChecks;
    </script>
    </body>
    </html>
EOT;
}

function default_page($loader_extension = LOADER_EXTENSION_NAME)
{
    $self = get_self();
    foreach (array('self') as $vn) {
        if (empty($$vn)) {
			$server_data = print_r($_SERVER,true);
            error("Unable to initialise ($vn)". ' $_SERVER is: ' . $server_data);
        }
    }

    heading();

    $wizard_update = check_for_wizard_update(true);

    $rtl = try_runtime_loading_if_applicable();

    $server_type = find_server_type();

    if (extension_loaded($loader_extension) && $server_type != SERVER_UNKNOWN) {
        loader_already_installed($rtl);
    } else {
        loader_not_installed();
    }
    send_stats('default');

    footer($wizard_update);
}

function uninstall_wizard_instructions()
{
    echo '<p><strong>For security reasons we advise that you remove this Wizard script from your server now that the ionCube Loader is installed.</strong></p>';
}

function contact_script_provider_instructions()
{
    echo '<p>Please contact the script provider if you do experience any problems running encoded files.</p>';
}

function may_need_to_copy_ini()
{
    $sys = get_sysinfo();
    if (ini_same_dir_as_wizard() && $sys['IS_CGI']) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        $ini = ini_file_name();
        echo "<p>Please note that if encoded files in a different $dirphrase from the Wizard fail then you should attempt to copy the $ini file to each $dirphrase in which you have encoded files.</p>";
    }
}

function ioncube_24_is_available()
{
	$loaderinfo = get_loaderinfo();
	$php_ver = php_version();
   
	return ($loaderinfo['oscode'] == 'lin' && (($php_ver['major'] == 5 && $php_ver['minor'] >= 3) || $php_ver['major'] > 5) );
}

function ioncube_24_is_enabled()
{
	$ic24_enabled = ini_get(IC24_ENABLED_INI_PROPERTY);
	return $ic24_enabled;
}

function ioncube_24_information()
{
    if (ioncube_24_is_available() && !ioncube_24_is_enabled()) {
        $self = get_self();
        echo '<div class="ic24">';
        echo '<div class="ic24graphic">';
        echo '<a target="_blank" href="' . IONCUBE24_URL . '"><img id="ic24logo" src="' . $self . '?page=ic24logo" alt="ionCube24 logo"></a>';
        echo '</div>';
        echo '<div id="ic24info">';
        echo '<p><strong>Bonus Features!</strong> The ionCube Loader can also give ';
        echo '<strong>real-time intrusion protection</strong> to protect against malware and <strong>PHP error reporting</strong> ';
        echo 'to alert when things go wrong on your website.</p>';
        echo '<p>These features are disabled by default but easily activated. ';
        echo '<strong><a target="_blank" href="' . IONCUBE24_URL . '">visit ioncube24.com</a></strong> to find out more.</p>';
        echo '</div>';
        echo '</div>';
    }
}

function cli_install_instructions()
{

	if (is_php_version_or_greater(5,3)) {
		$cli_loader_installed = shell_exec('php -r "echo extension_loaded(\"' . LOADER_EXTENSION_NAME . '\");"');
		
		if (!$cli_loader_installed) {
			$cli_php_ini_output = shell_exec("php --ini");
			
			$ini_loader_loc = scan_inis_for_loader();
		
			if (!is_null($cli_php_ini_output)) {
				echo '<div class="panel">';
				echo '<h4>Loader Installation for Command-Line (CLI) PHP</h4>';
				echo "<p>At present it does not look like the ionCube Loader is installed for command-line (CLI) PHP.</p>";
				echo "<p>Please note that if you need to run the CLI PHP, such as for <strong>cron jobs</strong>, then please ensure the zend_extension line for the ionCube Loader is included in your CLI PHP configuration.</p>";
				
				if (!empty($ini_loader_loc['location'])) {
					echo "<p>The zend_extension line that needs to be copied is:</p>";
					echo "<p><kbd>zend_extension = " . $ini_loader_loc['location'] . "</kbd></p>";
				}
				
				echo "<p>Your CLI PHP Configuration is:</p>";
				echo '<div class="terminal">';
				echo "<pre>";
				echo $cli_php_ini_output;
				echo "</pre>";
				echo '</div>';
				echo '</div>';
			}
		}
	}
}

function successful_install_end_instructions($rtl_path = null)
{
    if (empty($rtl_path)) {
        may_need_to_copy_ini();
    } elseif (is_string($rtl_path)) {
        echo "<p>The runtime loading method of installation was used with path <code>$rtl_path</code></p>";
    }
    contact_script_provider_instructions();
    if (is_legacy_platform()) {
        legacy_platform_instructions();
    }
	
	if (!is_ms_windows() && is_php_version_or_greater(5,3)) {
		cli_install_instructions();
	}
	
    uninstall_wizard_instructions();
	
	ioncube_24_information();
}

function loader_major_version_instructions($mv)
{
    if ($mv < LATEST_LOADER_MAJOR_VERSION) {
        echo "<p><strong>The installed version of the Loader cannot run files produced by the most recent ionCube Encoder.</strong>";
        echo " You will need a version " . LATEST_LOADER_MAJOR_VERSION . " ionCube Loader to run such files.</p>";
    }
    return ($mv < LATEST_LOADER_MAJOR_VERSION);
}

function loader_already_installed($rtl = null)
{
    list($lv,$mv,$newer_version) = ioncube_loader_version_information();
    $phpv = php_version_maj_min();
    $php_str = ' for PHP ' . $phpv;
    echo '<div class="success">';
    echo '<h4>Loader Installed</h4>';
    if ($newer_version) {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is <strong>already installed</strong> but it is an old version.';
        echo ' It is recommended that the Loader be upgraded to the latest version if possible.</p>';
        $know_latest_version = is_string($newer_version);
        $is_legacy_loader = loader_major_version_instructions($mv);
        echo '</div>';
        loader_upgrade_instructions($lv,$newer_version);
    } else {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is already installed and encoded files should run without problems.</p>'; 
        echo '</div>';
        $is_legacy_loader = loader_major_version_instructions($mv,true);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,true);
        }
    }

    successful_install_end_instructions($rtl);
}

function loader_upgrade_instructions($installed_version,$newer_version)
{
    if ($newer_version) {
        echo '<div class="panel">';
        echo '<h4>Loader Upgrade Instructions</h4>';
        $restart_needed = true;
        $server_type = find_server_type();
        if ($server_type == SERVER_SHARED || $server_type == SERVER_UNKNOWN) {
            $loader_path = find_loader(true);
            if (!is_string($loader_path) || false === user_ini_space_path($loader_path)) {
                $verb_case = ($server_type == SERVER_UNKNOWN)?"may":"will";
                echo "<p>Please note that you $verb_case need your system administrator to do the following to upgrade. The web server will need to be restarted after the loader file is changed.</p>";
            }
            $restart_needed = false;
        }
        if (is_string($newer_version)) {
            $version_str = "version $newer_version";
        } else {
            $version_str = "a newer version";
        }
        $loader_name =  get_loader_name();
        echo "<p>To upgrade from version $installed_version to $version_str of the ionCube Loader, please replace your existing loader file, $loader_name, with
            the file of the same name from one of the following packages:</p>";
        if (is_ms_windows()) {
            $basename = windows_package_name();
        } else {
            list($basename,$multiple_os_versions) = unix_package_name();
        }
        echo make_archive_list($basename,array('zip','tar.gz'));
        if ($restart_needed) {
            echo "<p>Once you have replaced the loader file please restart your web server.</p>";
        }
        echo '</div>';
    }
}

function legacy_platform_warning()
{
    $leg_warn = '<p><strong>You are on a platform on which ionCube Loaders are no longer being developed. ';
    $leg_warn .= 'Loaders on your platform may not be able to run files produced by the latest ionCube Encoder. ';
    $leg_warn .= 'Please switch, if possible, to a platform on which loaders are currently supported. ';
    $leg_warn .= 'A list of currently supported platforms is shown on our <a href="' . LOADERS_PAGE . '" target="loaders">loaders page</a>.</strong></p>';

    return $leg_warn;
}

function legacy_platform_instructions()
{
    echo legacy_platform_warning();
}

function loader_not_installed()
{
    $loader = get_loaderinfo();
    $sysinfo = get_sysinfo();

    $stype = get_request_parameter('stype');
    $manual_select = get_request_parameter('manual');
    $host_type = find_server_type($stype,$manual_select,true);

    if ($host_type != SERVER_UNKNOWN && is_array($loader) && !$sysinfo['DEBUG_BUILD']) {
        $warnings = server_restriction_warnings();
        if (is_legacy_platform()) {
            $warnings[] = legacy_platform_warning();
        }
        if (empty($_SESSION['use_ini_method']) && $host_type == SERVER_SHARED && runtime_loading_is_possible()) {
            $errors = runtime_loading_errors();
        } else {
            $errors = ini_loader_errors();
            $warnings = array_merge($warnings,ini_loader_warnings());
        }
        if (!empty($errors)) {
            if (count($errors) > 1) {
                $problem_str = "Please note that the following problems currently exist";
            } else {
                $problem_str = "Please note that the following problem currently exists";
            }
            echo '<div class="alert">' .$problem_str . ' with the ionCube Loader installation:';
            echo make_list($errors,"ul"); 
            echo '</div>';
        }
        if (!empty($warnings)) {
            $addword = empty($errors)?'':'also';
            $plural = (count($warnings)>1)?'s':'';
            echo '<div class="warning">';
            echo "Please note $addword the following issue$plural:";
            echo make_list($warnings,"ul"); 
            echo '</div>';
        }
    }
    if (!isset($stype)) {
        echo '<p>To use files that have been protected by the <a href="' . ENCODER_URL . '" target=encoder>ionCube PHP Encoder</a>, a component called the ionCube Loader must be installed.</p>';
    }

    if (!is_supported_php_version()) {
        echo '<p>Your server is running PHP version ' . PHP_VERSION . ' and is
                unsupported by ionCube Loaders.  Recommended PHP 4 versions are PHP 4.2 or higher, 
                PHP 5.1 or higher for PHP 5, PHP 7.1 or higher for PHP 7 and PHP 8.1 or higher for PHP 8. Please note that there is not an ionCube Loader for PHP 8.0.</p>';
	} elseif ($latest_supported_php_version = is_after_max_php_version_supported()) {
		echo '<strong>Your server is running PHP version ' . PHP_VERSION . ' and is
                currently unsupported by any ionCube Loaders. <br/>This may change in the future if a Loader is produced for your PHP platform.<br/>In the meantime please downgrade PHP to version ' . $latest_supported_php_version . '.</strong>';
    } elseif ($sysinfo['DEBUG_BUILD']) {
         echo '<p>Your server is currently running a debug build of PHP. The Loader cannot be installed with a debug build of PHP. Please ensure that PHP is reconfigured with debug disabled. Note that debug builds of PHP cannot help in debugging PHP scripts.</p>'; 
    } elseif (!is_array($loader)) {
        if ($loader == ERROR_WINDOWS_64_BIT) {
            echo '<p>Loaders for 64-bit PHP on Windows are not currently available. However, if you <b>install and run 32-bit PHP</b> the corresponding 32-bit loader for Windows should work.</p>';
            if ($sysinfo['THREAD_SAFE']) {
                echo '<li>Download one of the following archives of 32-bit Windows x86 loaders:';
            } else {
                echo '<li>Download one of the following archives of 32-bit Windows non-TS x86 loaders:';
            }
            echo make_archive_list(windows_package_name());
        } else {
            echo '<p>There may not be an ionCube Loader available for your type of system at the moment. However, if you create a <a href="'  . SUPPORT_SITE . '">support ticket</a> more advice and information may be available to assist. Please include the URL for this Wizard in your ticket.</p>';
        }
    } elseif (!$sysinfo['SUPPORTED_COMPILER']) {
        $supported_compilers = supported_win_compilers();
        $supported_compiler_string = join('/',$supported_compilers);
        echo '<p>At the current time the ionCube Loader requires PHP to be built with ' . $supported_compiler_string . '. Your PHP software has been built using ' . $sysinfo['PHP_COMPILER'] . '. Supported builds of PHP are available from <a href="https://windows.php.net/download/">PHP.net</a>.';
    } else {
        switch ($host_type) {
            case SERVER_SHARED:
                shared_server();
                break;
            case SERVER_DEDICATED:
                dedicated_server();
                break;
            case SERVER_LOCAL:
                local_install();
                break;
            default:
                echo server_selection_form();
                break;
        }
    }
}

function server_selection_form()
{
    $self = get_self();
    $timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?1:0;
    $hostprovider = (!empty($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $hostprovider = htmlspecialchars($hostprovider, ENT_QUOTES, 'UTF-8');
    $hosturl = (!empty($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $hosturl =  htmlspecialchars($hosturl, ENT_QUOTES, 'UTF-8');
    $form = <<<EOT
    <p>This Wizard will give you information on how to install the ionCube Loader.</p>
    <p>Please select the type of web server that you have and then click Next.</p>
    <script type=text/javascript>
        function trim(s) {
            return s.replace(/^\s+|\s+$/g,"");
        }
        function input_ok() {
            var l = document.getElementById('local');
            if (l.checked) {
                return true;
            } 

            var s = document.getElementById('shared');
            var d = document.getElementById('dedi');

            if (!s.checked && !d.checked) {
                alert("Please select one of the server types.");
                return false;
            } else {
                var hn = document.getElementById('hostprovider');
                var hu = document.getElementById('hosturl');
                var hostprovider = trim(hn.value);
                var hosturl = trim(hu.value);

                if (!hostprovider || !hosturl) {
                    alert("Please enter both a hosting provider name and their URL.");
                    return false;
                }
                if (hostprovider.length < 1) {
                    alert("The hosting provider name should be at least 1 character in length.");
                    return false;
                }
                if (!hosturl.match(/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+/)) {
                    alert("The hosting provider URL is invalid.");
                    return false;
                }
                if (hosturl.length < 4) {
                    alert("The hosting provider URL should be at least 4 characters in length.");
                    return false;
                }
            }
            return true;
        }
    </script>
    <form method=GET action=$self>
        <input type="hidden" name="page" value="default">
        <input type="hidden" name="timeout" value="$timeout">
        <input type=radio id=shared name=stype value=s onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=shared>Shared <small>(for example, server with FTP access only and no access to php.ini)</small></label><br>
        <input type=radio id=dedi name=stype value=d onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=dedi>Dedicated or VPS <small>(server with full root ssh access)</small></label><br>
        <div id="hostinginfo" style="display: none">If you are on a shared or dedicated server, please give your hosting provider and their URL:
            <table>
                <tr><td><label for=hostprovider>Name of your hosting provider</label></td><td><input type=text id="hostprovider" name=hostprovider value="$hostprovider"></td></tr>
                <tr><td><label for=hosturl>URL of your hosting provider</label></td><td><input type=text id="hosturl" name=hosturl value="$hosturl"></td></tr>
            </table>
        </div>
        <input type=radio id=local name=stype value=l onclick="document.getElementById('hostinginfo').style.display = 'none';"><label for=local>Local install</label>
        <p><input type=submit value=Next onclick="return (input_ok(this) && showOverlay());"></p>
    </form>
EOT;
    return $form;
}

function phpinfo_page()
{
    info_disabled_check();
    if (function_is_disabled('phpinfo')) {
        echo "phpinfo is disabled on this server";
    } else {
        @phpinfo();
    }
}

function loader_check_page($ext_name = LOADER_EXTENSION_NAME)
{
    heading();

    $rtl_path = try_runtime_loading_if_applicable();
	
    if (extension_loaded($ext_name)) {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        $php_str = ' for PHP ' . $phpv;
        echo '<div class="success">';
        echo '<h4>Loader Installed Successfully</h4>';
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' <strong>is installed</strong> and encoded files should run successfully.';
        if ($newer_version) {
            echo ' Please note though that you have an old version of the ionCube Loader.</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            loader_upgrade_instructions($lv,$newer_version);
        } else {
            echo '</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            if ($is_legacy_loader) {
                loader_upgrade_instructions($lv,true);
            }
        }
        successful_install_end_instructions($rtl_path);
    } else {
        echo '<div class="failure">';
        echo '<h4>Loader Not Installed</h4>';
        echo '<p>The ionCube Loader is <b>not</b> currently installed successfully.</p>';
	
        if (!is_null($rtl_path)) {
            echo '<p>Runtime loading was attempted but has failed.</p>';
            echo '</div>';
            $rt_errors = runtime_loading_errors();
            if (!empty($rt_errors)) {
                list_loader_errors($rt_errors);
            } 
            link_to_php_ini_instructions();
        } else {
            echo '</div>';
            list_loader_errors();
        }
    }
	
    send_stats('check');
    footer(true);
}

function ini_loader_errors()
{
    $errors = array();
    if (SERVER_SHARED == find_server_type() && !own_php_ini_possible(true)) {
        $errors[ERROR_INI_USER_CANNOT_CREATE] = "It appears that you are not be able to create your own ini files on your shared server. <br><strong>You will need to ask your server administrator to install the ionCube Loader for you.</strong>";
    }
    $loader_loc = find_loader(false);
    if (is_string($loader_loc)) {
        if (!shared_and_runtime_loading()) {
            $sys = get_sysinfo();
            if (empty($sys['PHP_INI'])) {
                $errors[ERROR_INI_NO_PATH] = 'No file path found for the PHP configuration file (php.ini).';
            } elseif (!@file_exists($sys['PHP_INI'])) {
                $errors[ERROR_INI_NOT_FOUND] = 'The PHP configuration file (' . $sys['PHP_INI'] .') cannot be found.';
            }
        }
        $errors = $errors + loader_compatibility_test($loader_loc);
    } else {
        $errors = $errors + $loader_loc;
        $fs_location = find_loader_filesystem();
        if (!empty($fs_location)) {
            $fs_loader_errors = loader_compatibility_test($fs_location);
            if (!empty($fs_loader_errors)) {
                $errors[ERROR_LOADER_WRONG_GENERAL] = "The loader file found at $fs_location is not the correct one for your system.";
            }
            $errors = $errors + $fs_loader_errors;
        }
    } 
    return $errors;
}

function unix_path_dir($dir = '')
{
    if (empty($dir)) {
        $dir = dirname(__FILE__);
    }
    if (is_ms_windows()) {
        $dir = str_replace('\\','/',substr($dir,2));
    }
    return $dir;
}

function unrecognised_inis_webspace($startdir)
{
    $ini_list = array();

    $ini_name = ini_file_name();
    $sys = get_sysinfo();
    $depth = substr_count($startdir,'/');

    $rel_path = '';
    $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
    for ($seps = 0; $seps < $depth; $seps++) {
        $full_ini_loc = @realpath($startdir . '/' . $rel_path) . DIRECTORY_SEPARATOR . $ini_name;
        if (@file_exists($full_ini_loc) && $sys['PHP_INI'] != $full_ini_loc) {
            $ini_list[] = @realpath($full_ini_loc);
        }

        if (dirname($full_ini_loc) == $rootpath) {
            break;
        }
        $rel_path .= '../';
    }
    return $ini_list;
}

function correct_loader_wrong_location()
{
    $loader_location_pair = array();
    $loader_location = find_loader_filesystem();
    if (is_string($loader_location) && !empty($loader_location)) {
        $loader_errors = loader_compatibility_test($loader_location);
        if (empty($loader_errors)) {
            $ini_loader = scan_inis_for_loader();
            if (!empty($ini_loader['location'])) {
                $ini_loader_errors = loader_compatibility_test($ini_loader['location']);
                if (!empty($ini_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = dirname($ini_loader['location']);
                }
            } else {
                $std_dir = loader_install_dir(find_server_type());
                $std_ld_path = $std_dir . DIRECTORY_SEPARATOR . get_loader_name();
                if (@file_exists($std_ld_path)) {
                    $stdloc_loader_errors = loader_compatibility_test($std_ld_path);
                } else {
                    $stdloc_loader_errors = array("Loader file does not exist.");
                }
                if (!empty($stdloc_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = $std_dir;
                }
            }
        }
    }
    return $loader_location_pair;
}

function ini_loader_warnings()
{
    $warnings = array();
    if (find_server_type() == SERVER_SHARED)
    {
        if (own_php_ini_possible()) {
            $sys = get_sysinfo();
            $ini_name = ini_file_name();
            $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
            $root_ini_file = $rootpath . DIRECTORY_SEPARATOR . $ini_name;
            $cgibinpath = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
            $cgibin_ini_file = (empty($cgibinpath))?'':$cgibinpath . DIRECTORY_SEPARATOR . $ini_name;
            $here = unix_path_dir();
            $ini_files = unrecognised_inis_webspace($here);
            $shared_ini_loc = shared_ini_location();
            $shared_ini_file = $shared_ini_loc . DIRECTORY_SEPARATOR . $ini_name;
            $ini_dir = dirname($sys['PHP_INI']);
            $all_ini_locations_used = !empty($ini_files);
            foreach ($ini_files as $full_ini_loc) {
                $advice = "The file $full_ini_loc is not being recognised by PHP.";
                $advice .= " Please check that the name and location of the file are correct.";
                if (!ini_same_dir_as_wizard()) {
                    $ini_loc_dir = dirname($full_ini_loc);
                    if (!@file_exists($shared_ini_file) && !empty($shared_ini_loc) && $ini_loc_dir != $shared_ini_loc && $ini_dir != $shared_ini_loc) {
                        $all_ini_locations_used = false;
                        $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $shared_ini_loc . "</code>.";
                    } else {
                        if (!@file_exists($root_ini_file) && $rootpath != $shared_ini_loc && $full_ini_loc != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $rootpath . "</code>.";
                        } 
                        if (!empty($cgibin_ini_file) && !@file_exists($cgibin_ini_file) && $cgibinpath != $shared_ini_loc && $full_ini_loc != $cgibinpath && $cgibinpath != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= "  Please try copying the <code>$full_ini_loc</code> file to <code>" . $cgibinpath . "</code>.";
                        }
                        $herepath = realpath($here);
                        $here_ini_file = $herepath . DIRECTORY_SEPARATOR . $ini_name;
                        if (!@file_exists($here_ini_file) && $herepath != $rootpath && $herepath != $cgibinpath) {
                            $all_ini_locations_used = false;
                            $advice .= " It may be necessary to copy the <code>$full_ini_loc</code> file to <code>$herepath</code> and to all " . (is_ms_windows()?'folders':'directories') . ' in which you have encoded files';
                        }
                    }
                } else {
                    $all_ini_locations_used = false;
                }
                $warnings[] = $advice;
            }
            if ($all_ini_locations_used) {
                $warnings[] = "<strong>It looks as if ini files are not being recognised in any of the standard locations in your webspace. Please contact your hosting provider to check whether you can create your own PHP ini file and where it should go.</strong>";
            }
        } else {
            if (own_php_ini_possible(true)) {
                $warnings[] = "You may not be able to create your own ini files on your shared server. <br><strong>You might need to ask your server administrator to install the ionCube Loader for you.</strong>";
            }
        }
    } else {
        $loader_dir_pair = correct_loader_wrong_location();
        if (!empty($loader_dir_pair)) {
            $advice = "The correct loader for your system has been found at <code>${loader_dir_pair['loader']}</code>."; 
            if ($loader_dir_pair['loader'] != $loader_dir_pair['newloc']) {
                $advice .= " Please copy the loader from <code>${loader_dir_pair['loader']}</code> to <code>${loader_dir_pair['newloc']}</code>.";
            }
            $warnings[] = $advice;
        }
    }
    return $warnings;
}

function list_loader_errors($errors = array(),$warnings = array(),$suggest_restart = true)
{
    $default = get_default_address();
    $retry_message = '';

    
    if (empty($errors)) {
        $errors = ini_loader_errors();
        if (empty($warnings)) {
            $warnings = ini_loader_warnings();
        }
    }
	
    if (!empty($errors)) {
        $try_again = '<a href="#" onClick="window.location.href=window.location.href">try again</a>';
	
        echo '<div class="alert">';
        if (count($errors) > 1) {
            echo 'The following problems have been found with the ionCube Loader installation:';
            $retry_message = "Please correct those errors and $try_again.";
        } else {
            echo 'The following problem has been found with the ionCube Loader installation:';
            $retry_message = "Please correct that error and $try_again.";
        }
        if (array_key_exists(ERROR_INI_USER_CANNOT_CREATE,$errors)) {
            $retry_message = '';
        }
        echo make_list($errors,"ul");
        echo '</div>';
        if (!empty($warnings)) {
            echo '<div class="warning">';
            echo 'Please also note the following:';
            echo make_list($warnings,"ul");
            echo '</div>';
        }
    } elseif (!empty($warnings)) {
        echo '<div class="warning">';
        echo 'There are the following potential problems:';
        echo make_list($warnings,"ul");
        echo '</div>';
    } elseif ($suggest_restart) {
        if (SERVER_SHARED == find_server_type()) {
            echo "<p>Please contact your server administrator about installing the ionCube Loader.</p>";
        } else {
            if (selinux_is_enabled()) {
                echo "<p>It appears that SELinux is enabled on your server. This might be solved by running the command <code>restorecon [full path to loader file]</code> as root.</p>";
            } elseif (grsecurity_is_enabled()) {
                echo "<p>It appears that grsecurity is enabled on your server. Please run the command, <code>execstack -c [full path to loader file]</code> and then restart your web server.</p>";
            } else {
                $sysinfo = get_sysinfo();
                $ss = $sysinfo['SS'];
				if ($ss == 'PHP-FPM') {
					echo "<p>Please check that PHP-FPM has been restarted.</p>";
                } elseif (!$sysinfo['CGI_CLI'] || is_ms_windows()) {
                    echo "<p>Please check that the $ss web server software has been restarted.</p>";
                } 
            }
        }
    }
    echo '<div>';
    echo $retry_message;
    echo " You may wish to view the following for further help:";
    echo make_list(help_resources($errors),"ul");
    echo '<a href="' . $default . '">Click here to go back to the start of the Loader Wizard</a>.</div>';
}

function phpconfig_page()
{
    info_disabled_check();
    $sys = get_sysinfo();
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        } else {
			if (!preg_match('`^.*\.ini$`',$ini_file_name) || preg_match('`/`',$ini_file_name) || preg_match('`\\\`',$ini_file_name)) {
				die("Illegal file name $ini_file_name");
			}
		}
        header('Content-Type: text/plain');
        header('Content-Disposition: attachment; filename=' . $ini_file_name);
    } else {
        header('Content-Type: text/plain');
    }
    $exclude_original = get_request_parameter('newlinesonly');
    $prepend = get_request_parameter('prepend');
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    if (!empty($exclude_original) || !empty($prepend)) {
        $loader_dir = loader_install_dir($server_type);
        $zend_lines = zend_extension_lines($loader_dir);
        echo join(PHP_EOL,$zend_lines);
        echo PHP_EOL;
    }
    if (empty($ini_file_name) || empty($sys['PHP_INI_DIR']) || ($sys['PHP_INI_BASENAME'] == $ini_file_name)) {
        $original_ini_file = isset($sys['PHP_INI'])?$sys['PHP_INI']:'';
    } else {
        $original_ini_file = $sys['PHP_INI_DIR'] . DIRECTORY_SEPARATOR . $ini_file_name;
    }
    if (empty($exclude_original) && !empty($original_ini_file) && @file_exists($original_ini_file)) {
        if (!empty($download)) {
            @readfile($original_ini_file);
        } else {
            echo all_ini_contents();
        } 
    }
}

function extra_page($check_access_to_info = true)
{
    if ($check_access_to_info) {
		info_disabled_check();
	}
    heading();
    $sys = get_sysinfo();
    $ini_loader = scan_inis_for_loader();
    $ini_loader_path = $ini_loader['location'];
    $loader_path = find_loader(true);
    $ldinf = get_loaderinfo();
    $self = get_self();
    echo "<h4>Additional Information</h4>";
    echo "<table>";
    $lines = array();
    if (is_string($loader_path)) {
        $lines['Loader is at'] = $loader_path;
        $loader_system = loader_system($loader_path);
        if (!empty($loader_system)) {
            $lines['Loader OS code'] = $loader_system['oscode'];
            $lines['Loader architecture'] = $loader_system['arch'];
            $lines['Loader word size'] = $loader_system['wordsize'];
            $lines['Loader PHP version'] = $loader_system['php_version'];
            $lines['Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Loader compiler'] = $loader_system['compiler'];
            $lines['Loader version'] = $loader_system['loader_version'];
            $lines['File size is'] = filesize($loader_path) . " bytes.";
            $lines['MD5 sum is'] = md5_file($loader_path);
        }
        $lines['Loader file'] = "<a href=\"$self?page=loaderbin\">Download loader file</a>";
    } else {
        $lines['Loader file'] = "Loader cannot be found.";
    }
    $lines['Loader found in ini file'] = empty($ini_loader_path)?"No":"Yes";
    if (!empty($ini_loader_path) && (!is_string($loader_path) || $ini_loader_path != $loader_path)) {
        $lines['Loader location found in ini file'] =  $ini_loader_path;
        $loader_system = loader_system($ini_loader_path);
        if (!empty($loader_system)) {
            $lines['Ini Loader OS code'] = $loader_system['oscode'];
            $lines['Ini Loader architecture'] = $loader_system['arch'];
            $lines['Ini Loader word size'] = $loader_system['wordsize'];
            $lines['Ini Loader PHP version'] = $loader_system['php_version'];
            $lines['Ini Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Ini Loader compiler'] = $loader_system['compiler'];
            $lines['Ini Loader version'] = $loader_system['loader_version'];
        }
    }
    $lines["OS extra security"] = (selinux_is_enabled() || possibly_selinux())?"SELinux":(grsecurity_is_enabled()?"Grsecurity":"None");
    $lines['PHPRC is'] = $sys['PHPRC'];
    $lines['INI DIR is'] = $sys['PHP_INI_DIR'];
    $lines['Additional INI files'] = $sys['PHP_INI_ADDITIONAL'];
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    $lines['Server type is'] = server_type_string();
    $lines["PHP uname"] = $ldinf['uname'];
    $lines['Server word size is'] = $ldinf['wordsize'];
    $lines['Disabled functions'] = ini_get('disable_functions');
    $writeable_dirs = writeable_directories();
    $lines['Writeable loader locations'] = (empty($writeable_dirs))?"<em>None</em>":join(", ",$writeable_dirs);
    if (!empty($_SESSION['hostprovider'])) {
        $lines['Hosting provider'] = $_SESSION['hostprovider'];
        $lines['Provider URL'] = $_SESSION['hosturl'];
    }
    foreach ($lines as $h => $i) {
        $v = (empty($i))?'<em>EMPTY</em>':$i;
        echo '<tr><th>'. $h . ':</th>' . '<td>' . $v . '</td></tr>';
    }
    echo "</table>";
    footer(true);
}

function loaderbin_page()
{
    info_disabled_check();
    $loader_path = find_loader(true);
    if (is_string($loader_path)) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. basename($loader_path));
        @readfile($loader_path);
    }
}



function GoDaddy_root($html_root = '')
{
    if (empty($_SESSION['not_go_daddy']) && empty($_SESSION['godaddy_root'])) {
        $godaddy_pattern = "[\\/]home[\\/]content[\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z]+[\\/]html";

        if (empty($html_root)) {
            $html_root =  $_SERVER['DOCUMENT_ROOT'];
        }
        if (preg_match("@$godaddy_pattern@i",$html_root,$matches)) {
            $_SESSION['godaddy_root'] = $matches[0];
        } else {
            $_SESSION['not_go_daddy'] = 1;
            $_SESSION['godaddy_root'] = '';
        } 
    } elseif (!empty($_SESSION['not_go_daddy'])) {
        $_SESSION['godaddy_root'] = '';
    }
    if (!empty($_SESSION['godaddy_root'])) {
        $_SESSION['hostprovider'] = 'GoDaddy';
        $_SESSION['hosturl'] = 'www.godaddy.com';
    }
    return $_SESSION['godaddy_root'];
}

function GoDaddy_windows_instructions()
{
    $instr = "It appears that you are hosted on a Windows server at GoDaddy.<br/>";
    $instr .= "Please change to a Linux hosting plan at GoDaddy.<br />";
    $instr .=  "If you <a href=\"https://help.godaddy.com/\">contact their support team</a> they should be able to switch you to a Linux server.";

    echo $instr;
}

function GoDaddy_linux_instructions($html_dir)
{
    $base = get_base_address();
    $loader_name = get_loader_name();
    $zend_extension_line="<code>zend_extension = $html_dir/ioncube/$loader_name</code>";
    $php_ini_name = is_php_version_or_greater(5,0)?'php5.ini':'php.ini';
    $ini_path = $html_dir . '/' . $php_ini_name;

    $instr = array();
    $instr[] = 'In your html directory, ' . $html_dir . ', create a sub-directory called <b>ioncube</b>.';
    if (@file_exists($ini_path)) {
       $instr[] = "Edit the $php_ini_name in your  $html_dir and add the following line to the <b>top</b> of the file:<br>" . $zend_extension_line ;
    } else {
        $instr[] = "<a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=s&amp;download=1&amp;prepend=1\">Save this $php_ini_name file</a> and upload it to your html directory, $html_dir";
    }
    $instr[] = 'Download the <a target="_blank" href="' . IONCUBE_DOWNLOADS_SERVER . '"/ioncube_loaders_lin_x86.zip">Linux ionCube Loaders</a>.';
    $instr[] = 'Unzip the loaders and upload them into the ioncube directory you created previously.';
    $instr[] = 'The encoded files should now be working.';

    echo '<div class=panel>';
    echo (make_list($instr));
    echo '</div>';
}

function GoDaddy_page()
{
    $base = get_base_address();

    heading();

        $inst_str = '<h4>GoDaddy Installation Instructions</h4>';
        $inst_str .= '<p>It appears that you are hosted with GoDaddy (<a target="_blank" href="https://www.godaddy.com/">www.godaddy.com</a>). ';
        $inst_str .= "If that is <b>not</b> the case then please <a href=\"$base&amp;page=default&amp;host=ngd\">click here to go to the main page of this installation wizard</a>.</p>";
        $inst_str .= "<p>If you have already installed the loader then please <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the loader</a>.</p>";

        echo $inst_str;

        if (is_ms_windows()) {
            GoDaddy_windows_instructions();
        } else {
            GoDaddy_linux_instructions($_SESSION['godaddy_root']);
        }

    send_stats('gd_default');

    footer(true);
}



function get_request_parameter($param_name)
{
    static $request_array;

    if (!isset($request_array)) {
        if (isset($_GET)) {
            $request_array = $_GET;
        } elseif (isset($HTTP_GET_VARS)) {
            $request_array = $HTTP_GET_VARS;
        }
    }

    if (isset($request_array[$param_name])) {
        $return_value = strip_tags($request_array[$param_name]);
    } else {
        $return_value = null;
    }
    return $return_value;
}

function make_list($list_items,$list_type='ol')
{
    $html = '';
    if (!empty($list_items)) {
        $html .= "<$list_type>";
        $html .= '<li>';
        $html .= join('</li><li>',$list_items);
        $html .= '</li>';
        $html .= "</$list_type>";
    }
    return $html;
} 

function make_archive_list($basename,$archives_list = array(),$download_server = IONCUBE_DOWNLOADS_SERVER)
{
    if (empty($archives_list)) {
        $archives_list = array('tar.gz','zip');
    }

    foreach ($archives_list as $a) {
        $link_text = $a;
        $ext_sep = '.';
        $archive_list[] = "<a href=\"$download_server/$basename$ext_sep$a\">$link_text</a>";
    }

    return make_list($archive_list,"ul");
}

function error($m)
{
    die("<b>ERROR:</b> <span class=\"error\">$m</span><p>Please help us improve this script by <a href=\"". SUPPORT_SITE . "\">reporting this error</a> and including the URL to the script so that we can test it.");
}


function filter_server_input($server_var)
{
	$res = htmlspecialchars($_SERVER[$server_var], ENT_QUOTES, "UTF-8");
	return $res;
}

function failsafe_get_self()
{
    $result = '';
    $sfn = filter_server_input('SCRIPT_FILENAME');
    $dr = $_SERVER['DOCUMENT_ROOT'];
    if (!empty($sfn) && !empty($dr)) {
        if ($dr == '/' || $dr == '\\') {
            $result = $sfn;
        } else {
            $drpos = strpos($sfn,$dr);
            if ($drpos === 0) {
                $drlen = strlen($dr);
                $result = substr($sfn,$drlen);
            }
        }
        $result = str_replace('\\','/',$result);
    }
    if (empty($result)) {
        $result = DEFAULT_SELF;
    }
    return $result;
}

function get_self()
{ 
	$page = '';
    if (empty($_SERVER['PHP_SELF'])) {
        if (empty($_SERVER['SCRIPT_NAME'])) {
            if (empty($_SERVER['REQUEST_URI'])) {
                $page = failsafe_get_self();
            } else {
                $page = filter_server_input('REQUEST_URI');
            }
        } else {
            $page = filter_server_input('SCRIPT_NAME');
        }
    } else {
        $page = filter_server_input('PHP_SELF');
    }
	return $page;
}

function get_default_page()
{
    $godaddy_root = GoDaddy_root();
    if (empty($godaddy_root)) {
         $page = 'default';
    } else {
         $page = 'GoDaddy';
    }
    return $page;
}

function get_base_address()
{
    $self = get_self();
    $remote_timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?'timeout=1':'timeout=0';
    $using_ini = (isset($_SESSION['use_ini_method']) && $_SESSION['use_ini_method'])?'ini=1':'ini=0';
    return $self . '?' . $remote_timeout . '&' . $using_ini;
}

function get_default_address($include_timeout = true)
{
    if ($include_timeout) {
        $base =  get_base_address();
        $base .= "&amp;";
    } else {
        $base = get_self();
        $base .= "?";
    }
    $page = get_default_page();

    return $base . 'page=' . $page;
}

function heading()
{
    $self = get_self();

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <meta name="robots" content="noindex, nofollow">
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <script type="text/javascript">
            function showOverlay()
            {
                document.getElementById('overlay').style.display = 'block';
                return true;
            }

            function hideOverlay()
            {
                document.getElementById('overlay').style.display = 'none';
                return true;
            }
        </script>
    </head>
    <body onload="hideOverlay()">
    <div id="overlay">
        <div id="inner_overlay">Checking server configuration<br>Please wait</div>
    </div>
    <div id="header">
        <img src="?page=logo" alt="ionCube logo">
    </div>
	<div id="important">
	<h3 class="important">IMPORTANT: Ensure that This Script Is Removed When No Longer Required</h3>
	</div>
    <div id="main">
    <h2>ionCube Loader Wizard</h2>
EOT;
}

function footer($update_info = null)
{
    $self = get_self();
    $base = get_base_address();
    $default = get_default_address(false);
    $year = gmdate("Y");

    echo "</div>";
    echo "<div id=\"footer\">" .
    "Copyright ionCube Ltd. 2002-$year | " .
    "Loader Wizard version " . script_version() . " ";

    if ($update_info === true) {
        $update_info = check_for_wizard_update(false);  
    }
    $loader_wizard_loc = LOADER_WIZARD_URL;
    $wizard_version_string =<<<EOT
    <script type="text/javascript">
    var xmlhttp;
    function version_check()
    { 
        var body = document.getElementsByTagName('body')[0];
        var ldel = document.getElementById('loading');
        if (!ldel) {
            body.innerHTML += '<div id="loading"></div>';
            ldel = document.getElementById('loading');
        }
        ldel.innerHTML = '<p>Retrieving Wizard version information<br>Please wait</p>';
        ldel.style.display = 'block';
        ldel.style.height = '300px';
        ldel.style.left = '200px';
        ldel.style.border = '4px #660000 solid';
        if (window.XMLHttpRequest) {
            xmlhttp=new XMLHttpRequest();
        } else {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            var loadedOkay = 0;
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                var wizardversion = xmlhttp.responseText;
                var msg;
                clearTimeout(xmlHttpTimeout);
                buttons = '';
                if (wizardversion == '1') {
                    msg = 'You have the current version of the<br>ionCube Loader Wizard'; 
                } else if (wizardversion != '0') {
                    msg = 'A new version, ' + wizardversion + ', of the loader wizard is available';
                    buttons = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; window.open(\'$loader_wizard_loc\'); return false">Get new version</button> &nbsp;'; 
                } else {
                    msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
                }
                buttons += '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>'; 
                ldel.innerHTML = '<p>' + msg +  '<br>' + buttons + '</p>';
            }
        }
        xmlhttp.open("GET",'$self?page=wizardversion&wizard_only=1&clear_info=1',true);
        xmlhttp.send();
        var xmlHttpTimeout=setTimeout(ajaxTimeout,7000);
    }
    function ajaxTimeout(){
       xmlhttp.abort();
       msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
       button = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>';
       var ldel = document.getElementById('loading');
       ldel.innerHTML = '<p>' + msg +  '<br>' + button + '</p>';
    }
    </script>
EOT;

    $wizard_version_string .= '('; 
    if ($update_info === null) {
        $wizard_version_string .= '<a target="_blank" href="' . $loader_wizard_loc . '" onclick="version_check();return false;">check for new version</a>';
    } else if ($update_info !== false) {
        $wizard_version_string .= '<a href="' . LOADERS_PAGE .'" target="_blank">download version ' . $update_info . '</a>';
    } else {
        $wizard_version_string .=  "current";
    }
    $wizard_version_string .= ')'; 
    echo $wizard_version_string;

    $server_type_code = server_type_code();
	
	if (!info_should_be_disabled(true)) {
		echo " | <a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo</a>";
		echo " | <a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a>";
		echo " | <a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional</a>";
	}

    echo " | <a href=\"$default\" onclick=\"showOverlay();\">wizard start</a>";
    echo " | <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">loader test</a>";
    echo ' | <a href="' . LOADERS_PAGE . '" target="loaders">loaders</a>';

    echo "</div>\n";
    echo "\n</body></html>\n";
}

function css_page()
{
    header('Content-Type: text/css');
    echo <<<EOT
    body {
        font-family: verdana, helvetica, arial, sans-serif;
        font-size: 10pt;
        line-height: 150%;
        margin: 0px;
        min-height: 400px;
        position: relative;
    }

    code {
        color: #c00080;
    }

    li {
        margin-top: 10px;
    }
    #overlay {
        display: block;
        z-index: 100;
        position: absolute;
        top: 0;
        left: 0;
        padding: 0;
        margin: 0;
        width: 100%;
        height: 100%;
        background-color: white;
    }
    #inner_overlay {
        display: block;
        z-index: 100;
        position: absolute;
        font-size: 200%;
        color: #660000;
        top: 50%;
        left: 25%;
        width: 460px;
        height: 460px;
        line-height: 200%;
        text-align: center;
        vertical-align: middle;
    }

    #loading {
        display: block;
        position: absolute;
        top: 33%;
        left: 25%;
        margin: auto;
        height: 320px;
        width: 460px;
        padding: 4px;
        color: #660000;
        background-color: white;
        z-index: 100;
    }

    #loading p {
        position: absolute;
        margin-top: 10px;
        text-align: center;
        vertical-align: middle;
        padding-left: 40px;
        padding-right: 30px;
        font-size: 200%;
        line-height: 200%;
    }

    #loading p span#status{
        font-size: 60%;
        line-height: 120%;
    }
    #loading p#noscript {
        font-size: 120%;
        line-height: 120%;
        position: absolute;
        text-align: left;
        padding-top: 10px;
        bottom: 0;
    }
    #loading p#noscript a {
        text-align: center;
    }

    #loading button {
        margin-top: 20px;
        line-height: 100%;
        padding-top: 4px;
        padding-bottom: 4px;
    }


    h4 {
        margin-bottom: 0;
        padding-bottom: 4px;
    }

    p,#main div {
        max-width: 1000px;
        width: 75%;
    }

    #hostinginfo {
        margin-top: 10px;
        margin-left: 20px;
    }
    #hostinginfo table {
        font-size: 1.00em;
    }
    #hostinginfo table td {
        padding-right: 4px;
    }
    #hostinginfo input {
        margin-top: 6px;
    }

    #hostinginfo label {
        margin-left: 6px;
    }

    th {
        text-align: left;
    }
	
	#important {
		margin-top: 12px;
	} 
	h3.important {
		margin: 0;
		border: 0;
        border-top: 1px solid #660000;
		border-bottom: 1px solid #660000;
        padding: 1ex 0 1ex 0;
        background-color: #CB2430;
		text-align: center;
        color: #ffffff; 
        width: 100%;
	}

    .alert {
        margin: 2ex 0;
        border: 1px solid #660000;
        padding: 1ex 1em;
        background-color: #ffeeee;
        color: #660000; 
        width: 75%;
    }

    .warning {
        margin: 2ex 0;
        border: 1px solid #FFBF00;
        padding: 1ex 1em;
        background-color: #FDF5E6;
        color: #000000; 
        width: 75%;
    }

    .success {
        margin: 2ex 0;
        border: 1px solid #006600;
        padding: 1ex 1em;
        background-color: #EEFFEE;
        color: #000000; 
        width: 75%;
    }

    .error {
        color: #FF0000;
    }

    .panel {
        border: 1px solid #c0c0c0;
        background-color: #f0f0f0;
        width: 75%;
        padding: 1ex 1em;
    }
	
	.terminal {
		border: none;
		background-color: #000000;
		color: #ffffff;
		width: 50%;
		padding: 1ex 1em;
	}

    #header {
        background: #fff;
    }

    #footer {
        border-top: 1px solid #404040;
        margin-top: 20px;
        padding-top: 10px;
        padding-left: 20px;
        font-size: 75%;
        text-align: left;
    }

    #main {
        margin: 20px;
    }
	
	
	#main .ic24 {
		position: relative;
		width: 75%;
		height: auto;
		border-width: 1px 1px 1px 1px;
		border-style: solid;
		border-color: #4B8DF8;   
		background-color: #EFEFFF;
		padding: 12px;
		padding-top: 16px;
		padding-bottom: 8px;
		margin-top: 20px;
		overflow: hidden;
	}
	
	#main .ic24 p {
		width: 100%;
	}
	
	
	#main .ic24graphic {
		position: relative;
		width: auto;
		height: auto;
		border: none;
		padding: 0px;
		padding-right: 16px;
		margin: 0px;
		float: left;
		
	}
	
	#main #ic24info {
		position: relative;
		width: auto;
		height: auto;
		float: left;
	}
	
	#main #ic24info a {
		color: #0B4DB8;
		text-decoration: none;
	}
	
	#main #ic24logo {
		max-width: 132px;
		max-height: 132px;
	}
	
EOT;
}

function logo_page()
{
$img_encoded = 'iVBORw0KGgoAAAANSUhEUgAAAakAAACABAMAAABD1osiAAAAKlBMVEUAAAAAAADnHCwAAAAAAAAAAAAAAAAAAABMCQ4AAADnHCznHCznHCwAAAAjcBE1AAAADHRSTlMAeDRHwSqg4BJl/PLTJLuIAAAF1UlEQVR42u2by4vTQBzHp3TTzR6EBtfXYS/+BZW6Pg6FFavgoRDBBx4KFd+HQgWFvQQqiuJhoeL7sP+LR0EPlj6yPfz+F5NMZ77TmmJjM3ZT5nNpOzvNzGcev5lMusxgMBgMBoPBYDAYDAaDwWDQwel5YRnC/jkvbZYdjFV2MFbZwVhlB2OVIVZyb2HIED/n5AfLEj/nhWUJY5UdjFV2MFbZwVgdMqzNZydXz2qrf59Kq2a1NmTsRnfVrLZOfj3VrrkrZuVb/dpBvZEJqzOOc5TNQ75rjXKDtV+ZsNoi6rJ52OhZwxONwiGwsi46zqnt1Kx8r7N8q/wmRfhP3BSsrK7VW/u13krDysGwT8o5kvilxa2YZ/U2eulEC0KhCTlLCo0UrPYff7Tfe+2lWt0glTT6qjB02e0eW6ZVjiZYaF4hq+eXlmll1yik75TL5eMeDVOxsj89hNQyrN5QyDFRm9GCVmCZVrYXBr4OE9w8ZFbBCNr+x646ycAhs/o3moFUj62Y1UY4/txVs9oLrAZs1azCAVhaNSsLgXNpVt/+dlNXZAplx4mLiXecU5hHhcBqN6lV/p3znk1xEYUltfr+t0J/4dN1jwKGWIg+VKuBdL5JAQ9EYj34ILOAjWq12lG+eE2xsk9EF/7CFN7WKOCpq9kK2/CTyp93mFUbpyKRZmwNi2oX4Y0dfgULd8QL4vRdvVavJ+6XYLVPIQjmHq9xAqvbJBTa8paTBCOtVpZHY1DrSmCF7flABotBIiuLJM+RQdJJO1qoVnUKqfLh1pBWrX10YVu0ciuRVXjlfpUiXGSmp85xdFaaT7thZUV95I5DRldaDYJPT8oXmyQqnYP0nFZetL23tgjtsT/e8uc9mKa3XsFqL3Rpy3YsCSufhwmrJgbeGmo/jxUCjd2UzWWFg1EuEzv6rJoY4ftyQapghBRElda5cxKrEfaPvGPWw+Esyx1ps8pHhaP0LqxK8p7KZwFHklt1kEqNcbsNcFfT12a1zgtEv7WFVZehB93xUGVJrPg7MXgPxotDUWlCV5dVhYtgjhV5KuLd+jixktjqYHoHmVcLw9fSt2ry8lDBlrAqKomN5FZI5aX0+Rztqmk7uqywtGKhRQ+KmbeT3AoDDN89gsJQBQ1WWFrFpmgkIruq2kpuhWCASFNBYXxN1GGFKk1XqqLWiXjeOvpv3n2gpBDm4dtL1aqnyaqAcA2bGCu0d3Ir5GkSPasKsFlO3WpNGf68P3wdVhs84tRIRZ/VEUwWfIyxwo4puRUiDh0+q2jntnJWOf6aplVv+VZ5VGMBq3tlhQuarNYnw3V9Zgzkr8PFYiByAi0xcM7ILva+7kJWNeyktVoV5l2FeSI1kluh8UKrlnar6dv2qNhejBVG6yDeaifOajg5X9tR4sH/sLIIBeFTjJV4JMImmd5KNmGFvHxfyV9Guq2mDvnQc9NWyIuOBWrD2BSzZ4fsHi6rzUq26cRdY2e2VSU+ChJ6IDdh1Zi+wylAVa9VfWqu+2y2VYFiO6uGzHsTVj01WOxgsOq3KqB0nMbMsLK96fNxKVASgrDCSogcHjpbq5WNg1WcVsRY4Zi3i1Xblqm7OLFXrHbRWn2GxUG/FduX0yIHwRlWFomD3ojrT+Vxje+KE3tYiQ6ym3JJKKidnW9rscJkuSwOiUdsphXO5P2724y9PPOI+njMMSyxOzWiTViF7/0v4kS6gzEcZA0545X0WbFmVClnk1B4vJXsDYArcPzXitUxCnhW5f070SyXHGfTw1jUYVUgMGKzrTBKQQk/LonYzSlWxToyFuOapaXRim2hqd2/WbFbJEBlLTx8k1a1QNmaai0eUMBAp5XVFFIdNtMqVqs/nhmvpGQuSJRWUmHoMsl5klzRacWsE4Sn3TOswMtH9Mfvbj+L36JNWrFzUgqcE6ofdf8X9PXN6qWjbF5eOverV51ye/ICd+NCWv549er0ha3o69vMYDAYDAaDwWAwGAwGg8FgSJffF2mwYDNbStYAAAAASUVORK5CYII=';

    header('Content-Type: image/png');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}

function ic24logo_page()
{
	$img_encoded = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6b3NiPSJodHRwOi8vd3d3Lm9wZW5zd2F0Y2hib29rLm9yZy91cmkvMjAwOS9vc2IiCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB2ZXJzaW9uPSIxLjAiCiAgIHdpZHRoPSI2OTAiCiAgIGhlaWdodD0iNjkxLjI1IgogICB2aWV3Qm94PSIwIDAgNTUyIDU1MyIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgaWQ9InN2ZzMwMzUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImlvbkN1YmUyNF9jdWJlLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwODMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzQ5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTM1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzMzkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzMxIgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTMzMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzMjUiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzI3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NSIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4ODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NzMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODc1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDEiCiAgICAgICB4MT0iNDQzNS40NDI0IgogICAgICAgeTE9IjI5NDkuMDQyIgogICAgICAgeDI9IjQ4MzQuMzkyMSIKICAgICAgIHkyPSIyOTQ5LjA0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTgiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjAiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxOCIKICAgICBpZD0ibmFtZWR2aWV3MzA4MSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC45NjUzODc0IgogICAgIGlua3NjYXBlOmN4PSI3MjQuNTI3MjIiCiAgICAgaW5rc2NhcGU6Y3k9IjMzMy4xMTQ1MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMzAzNSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMCIKICAgICBmaXQtbWFyZ2luLWxlZnQ9IjAiCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIKICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDM3Ij4KQ3JlYXRlZCBieSBwb3RyYWNlIDEuMTEsIHdyaXR0ZW4gYnkgUGV0ZXIgU2VsaW5nZXIgMjAwMS0yMDEzCjxyZGY6UkRGPgogIDxjYzpXb3JrCiAgICAgcmRmOmFib3V0PSIiPgogICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICA8ZGM6dHlwZQogICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICA8L2NjOldvcms+CjwvcmRmOlJERj4KPC9tZXRhZGF0YT4KICA8ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMSwwLDAsLTAuMSwtNCw1NTcpIgogICAgIGlkPSJnMzAzOSIKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO3N0cm9rZTpub25lIj4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIC0yLDg2OCAtMyw4NjcgLTg2NywzIC04NjgsMiAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA0MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDMiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDM4MjcsNTU2MyBjIC00LC0zIC03LC0zOTUgLTcsLTg3MCBsIDAsLTg2MyA4NzAsMCA4NzAsMCAwLDg3MCAwLDg3MCAtODYzLDAgYyAtNDc1LDAgLTg2NywtMyAtODcwLC03IHoiCiAgICAgICBpZD0icGF0aDMwNDUiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDI4MDAgMCwtODcwIDg2OCwyIDg2NywzIDMsODY4IDIsODY3IC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDciCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDE5MzAsMjgwMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiBtIDEwMzUsNjMwIGMgODAsLTMxIDE1NCwtMTAyIDE5MSwtMTgzIDI1LC01NCAyOCwtNzQgMjksLTE1NyAwLC0xOTAgLTc0LC0zMTggLTM0NCwtNTkyIGwgLTE3NCwtMTc4IDI3NiwwIDI3NywwIDAsLTgwIDAsLTgwIC00MDcsMiAtNDA4LDMgLTMsNTYgLTMsNTUgMTgxLDE3NCBjIDM1NSwzMzkgNDUyLDQ5MyA0MjMsNjY3IC0xOSwxMDYgLTcxLDE2MiAtMTcyLDE4NCAtOTIsMjAgLTIwMiwtNiAtMjkzLC02OSBsIC00NiwtMzEgLTI2LDU4IGMgLTE0LDMyIC0yNiw2MiAtMjYsNjYgMCwyMiAxNDcsOTkgMjI4LDEyMCA4MiwyMSAyMjEsMTQgMjk3LC0xNSB6IgogICAgICAgaWQ9InBhdGgzMDQ5IgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAzODIyLDI4MDMgMywtODY4IDg2OCwtMyA4NjcsLTIgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAyLC04NjcgeiBtIDExNzgsMjQyIDAsLTM5NSA5MCwwIDkwLDAgMCwtNzAgMCwtNzAgLTkwLDAgLTkwLDAgMCwtMTcwIDAsLTE3MCAtODUsMCAtODUsMCAwLDE3MCAwLDE3MCAtMjkwLDAgLTI5MCwwIDAsNjMgMCw2NCAyODEsNDAxIDI4MSw0MDIgOTQsMCA5NCwwIDAsLTM5NSB6IgogICAgICAgaWQ9InBhdGgzMDUxIgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA0NzkwLDMxNzMgYyAtMjQsLTQzIC0xMTEsLTE3MiAtMTk1LC0yODggLTgzLC0xMTUgLTE1NSwtMjE2IC0xNTksLTIyMiAtNiwtMTAgMzUsLTEzIDE5MywtMTMgbCAxOTksMCA0LDI5OCBjIDIsMTYzIDMsMjk4IDIsMzAwIC0xLDIgLTIxLC0zMiAtNDQsLTc1IHoiCiAgICAgICBpZD0icGF0aDMwNTMiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NTM0MSk7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTg1MTYsMTc0MyBjIC0zLC04MzUgLTksLTE1NTMgLTEyLC0xNTk1IGwgLTYsLTc4IDE3MCwwIDE3MCwwIDcsODggYyAzLDQ4IDksMTI3IDEzLDE3NiBsIDcsODkgNDAsLTU5IGMgNTMsLTc3IDE2MCwtMTgxIDIyOSwtMjIzIDEyOCwtNzcgMjQ4LC0xMTEgNDIxLC0xMTggMjEwLC05IDM4NywzOCA1NTIsMTQ3IDI3NiwxODEgNDM4LDQ4MiA0NzQsODc5IDM5LDQzMyAtMTA1LDgzOSAtMzc1LDEwNTYgLTE1NSwxMjUgLTMzMCwxODUgLTU0MSwxODUgLTE5OSwwIC0zNTcsLTQwIC00OTMsLTEyNiAtNzEsLTQ1IC0xODMsLTE1MyAtMjI1LC0yMTkgbCAtMzIsLTUwIC0zLDY4MyAtMiw2ODIgLTE5NCwwIC0xOTQsMCAtNiwtMTUxNyB6IG0gMTE1NSwyMjMgYyAxNDksLTMyIDMwNSwtMTQ4IDM4OCwtMjg5IDc5LC0xMzUgMTIxLC0zMTMgMTIxLC01MTIgMCwtMTk2IC0zNSwtMzU2IC0xMDgsLTUwMCAtNDMsLTg0IC0xNzEsLTIxNyAtMjQ5LC0yNTggLTc3LC00MSAtMTkyLC02NyAtMjk0LC02NyAtMTE2LDAgLTE3NywxMyAtMjc4LDYyIC0xNDYsNjkgLTI1OCwyMDMgLTMxNywzNzggLTE3LDQ5IC0xOSw4OCAtMTksMzYwIDAsMzA1IDAsMzA1IDI3LDM4NSAzNywxMDkgOTEsMTk2IDE2OSwyNzUgNzQsNzQgMTkwLDE0MSAyODYsMTY0IDc2LDE5IDE5MSwxOSAyNzQsMiB6IgogICAgICAgaWQ9InBhdGgzMDU1IgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE3NCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTQ2MTAsMzEzOSBjIC01MTgsLTY1IC05NDQsLTM1NyAtMTE2NCwtNzk3IC0xNDEsLTI4MCAtMjAxLC02MzYgLTE2NiwtOTgzIDcyLC03MTEgNDgwLC0xMTc3IDExNDcsLTEzMTAgMjExLC00MiA1NTcsLTM2IDgxMywxMiAxMTksMjMgMzIwLDg2IDMyNiwxMDMgNiwxNyAtNzIsMzExIC04MiwzMDkgLTUsLTEgLTQ5LC0xNiAtOTcsLTMzIC0xNDcsLTUyIC0yNjIsLTcxIC00NzAsLTc3IC0yMTAsLTYgLTMyMCw0IC00NTcsNDQgLTQzNywxMjYgLTcwNSw0NzIgLTc2MSw5NzkgLTE1LDE0MCAtNSwzODggMjAsNTE0IDYwLDI5OSAxOTgsNTM2IDQwMyw2OTAgMjIzLDE2OSA0NzIsMjM4IDgwOCwyMjcgMTg0LC02IDMwNywtMjggNDQyLC03OCA0NiwtMTYgODksLTMxIDk2LC0zMiA5LC0xIDMwLDQ5IDYyLDE1MyAyNyw4NSA0OCwxNTUgNDcsMTU2IC01Miw0MCAtMjc2LDEwMSAtNDU3LDEyMyAtOTcsMTMgLTQxNCwxMiAtNTEwLDAgeiIKICAgICAgIGlkPSJwYXRoMzA1NyIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNzApIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczNzAsMjg1NSAwLC0xOTUgMjEwLDAgMjEwLDAgMCwxOTUgMCwxOTUgLTIxMCwwIC0yMTAsMCAwLC0xOTUgeiIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNjYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIzODg2LDMwMjQgYyAtOTksLTE4IC0yNjQsLTczIC0zNDgsLTExNSAtNzEsLTM1IC0yMTgsLTEzMCAtMjM3LC0xNTMgLTEwLC0xMiAwLC00MCA1MCwtMTUwIDM0LC03NSA2MywtMTM2IDY1LC0xMzYgMSwwIDM2LDI0IDc3LDUzIDE2NiwxMTkgMzI0LDE3NiA1MTMsMTg0IDMwOCwxNCA1MDMsLTEwOCA1ODAsLTM2MiAxNCwtNDYgMTksLTkzIDE5LC0yMDAgLTEsLTE3MSAtMTksLTI0NyAtMTAwLC00MTAgLTEzMCwtMjYxIC0zODAsLTU0MyAtMTA0NCwtMTE4MCBsIC0yNTAsLTI0MCAtMSwtMTIyIDAsLTEyMyA5MzUsMCA5MzUsMCAwLDE2NSAwLDE2NSAtNjU3LDAgLTY1NywwIDEwOSwxMDEgYyA2MSw1NiAyMTgsMjEwIDM1MCwzNDMgMzQyLDM0NSA1MTgsNTYzIDYzNCw3ODYgMTc5LDM0NSAxOTgsNjc4IDU3LDk2NSAtODEsMTYzIC0xODgsMjcwIC0zNTEsMzUxIC0xNDEsNzAgLTIxOSw4NiAtNDI1LDkwIC0xMjUsMiAtMTk4LC0xIC0yNTQsLTEyIHoiCiAgICAgICBpZD0icGF0aDMwNjEiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE2MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMjY2ODEsMjk3NyBjIC02LC04IC0yOTksLTQyNSAtNjUxLC05MjggbCAtNjQwLC05MTQgMCwtMTMyIDAsLTEzMyA2ODAsMCA2ODAsMCAwLC00MDAgMCwtNDAwIDE4NSwwIDE4NSwwIDAsNDAwIDAsNDAwIDIwNSwwIDIwNSwwIDAsMTU1IDAsMTU1IC0yMDUsMCAtMjA1LDAgMCw5MDUgMCw5MDUgLTIxNCwwIGMgLTE2NiwwIC0yMTYsLTMgLTIyNSwtMTMgeiBtIDcxLC0xMDg0IC0zLC03MTMgLTQ4MCwwIGMgLTM4MiwwIC00NzksMyAtNDczLDEzIDUsNiAxNjYsMjMwIDM1OCw0OTcgMzQ3LDQ4MSAzOTksNTYwIDUzMCw3OTggMzgsNjggNjksMTIyIDcwLDEyMCAwLC0yIDAsLTMyNCAtMiwtNzE1IHoiCiAgICAgICBpZD0icGF0aDMwNjMiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE1OCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTE5MjcsMjI4OCBjIC0xMDgsLTEwIC0yNDgsLTU1IC0zNDEsLTExMCAtODIsLTQ4IC0yMDMsLTE2MCAtMjQ3LC0yMjkgLTE3LC0yNyAtMzQsLTQ3IC0zOCwtNDQgLTMsNCAtMTAsODIgLTE2LDE3MyBsIC0xMCwxNjcgLTE3OSwzIC0xNzgsMiA2LC00NyBjIDQsLTI3IDksLTUxNyAxMiwtMTA5MCBsIDYsLTEwNDMgMTk5LDAgMTk4LDAgMyw3MjcgMyw3MjggMzEsNzIgYyAxMTMsMjYwIDM0MSwzOTggNTk4LDM2MiAxNjQsLTIyIDI3NiwtMTAzIDM0NiwtMjUxIDczLC0xNTQgNzIsLTE0OCA3NywtOTM1IGwgNSwtNzAzIDE5NCwwIDE5NCwwIDAsNzIzIGMgMCw3OTYgLTIsODI0IC02Miw5OTcgLTEyMSwzNDcgLTQyMCw1MzMgLTgwMSw0OTggeiIKICAgICAgIGlkPSJwYXRoMzA2NSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNTQpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczOTAsMTE4MCAwLC0xMTEwIDE5MCwwIDE5MCwwIDAsMTExMCAwLDExMTAgLTE5MCwwIC0xOTAsMCAwLC0xMTEwIHoiCiAgICAgICBpZD0icGF0aDMwNjciCiAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMTUwKSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA5MTk5LDIyODAgYyAtMjIwLC0zNyAtNDE4LC0xMzggLTU3MCwtMjg5IC0xNTAsLTE1MSAtMjQyLC0zMjkgLTI5NSwtNTcxIC0yNiwtMTE5IC0yNywtNDI5IC0xLC01NDcgNTIsLTI0NCAxNDksLTQyNiAzMDUsLTU3NSAxODcsLTE3OCAzOTYsLTI2NCA2NjgsLTI3NSA1MDAsLTIxIDkxMiwyNTEgMTA2NSw3MDQgNTQsMTYxIDY0LDIzMCA2Myw0NDggMCwxNjcgLTMsMjE1IC0yMSwyOTEgLTEwMyw0NDEgLTM5MCw3MzAgLTgwMyw4MDggLTg3LDE3IC0zMjYsMjAgLTQxMSw2IHogbSAzMzQsLTMwNSBjIDI1NSwtNjYgNDM4LC0zMDggNDg3LC02NDQgMTcsLTExNiA4LC0zNDMgLTE4LC00NDIgLTY0LC0yNDMgLTE5NywtNDIzIC0zNzQsLTUwOCAtMTA1LC01MCAtMTg0LC02NiAtMjk2LC01OCAtMjIxLDE1IC0zOTMsMTM2IC01MDgsMzU5IC02NiwxMjkgLTk1LDI1MCAtMTAxLDQyNSAtMTEsMzA4IDY3LDU0NSAyMzYsNzE0IDgxLDgxIDE1OCwxMjYgMjYxLDE1MyA3MywxOSAyNDEsMjAgMzEzLDEgeiIKICAgICAgIGlkPSJwYXRoMzA2OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNDYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIxNzUwLDIyNzUgYyAtMzUyLC03MCAtNjExLC0zMDUgLTczOSwtNjY4IC01OCwtMTY1IC03NSwtMjcxIC03NSwtNDc3IC0xLC0yMDQgMTAsLTI3OSA2NiwtNDQ3IDExOSwtMzYwIDQyMCwtNTk4IDgyNiwtNjUzIDEyNywtMTggMzkyLC04IDU0MiwyMCAxMjIsMjIgMzYwLDk2IDM2MCwxMTEgMCwxOCAtNjMsMjY0IC02OSwyNzEgLTMsNCAtNTEsLTggLTEwNiwtMjcgLTE1NCwtNTEgLTI3MiwtNjggLTQ3NSwtNjggLTIwMywwIC0yNzgsMTUgLTQwOSw4MyAtMjE0LDExMSAtMzI4LDMwMiAtMzU2LDU5OCBsIC03LDcyIDc2NSwwIGMgNjg4LDAgNzY1LDIgNzcxLDE2IDEyLDMyIDYsMzAzIC05LDM5MCAtNDMsMjQ0IC0xMzQsNDMzIC0yNzcsNTcwIC0xMTUsMTEyIC0yMzUsMTc0IC00MDAsMjA4IC05NCwxOSAtMzE0LDIwIC00MDgsMSB6IG0gMzUzLC0yOTUgYyAyMDcsLTY0IDMzOCwtMjU3IDM2MywtNTM1IGwgNywtNzUgLTU3NywwIC01NzYsMCAwLDIzIGMgMCw1MiA0MiwxODcgODYsMjc1IDgyLDE2OCAyMjcsMjkyIDM3NCwzMjEgMzAsNiA2NCwxMyA3NSwxNSA0MSwxMCAxODUsLTUgMjQ4LC0yNCB6IgogICAgICAgaWQ9InBhdGgzMDcxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE0MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gNDAsOTEwIDAsLTg3MCA4NjgsMiA4NjcsMyAzLDg2OCAyLDg2NyAtODcwLDAgLTg3MCwwIDAsLTg3MCB6IgogICAgICAgaWQ9InBhdGgzMDc1IgogICAgICAgc3R5bGU9ImZpbGw6I2MwMWQyZTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDkxMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA3NyIKICAgICAgIHN0eWxlPSJmaWxsOiNjMDFkMmU7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMzgyMCw5MTAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNzkiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICA8L2c+Cjwvc3ZnPgo=';
	header('Content-Type: image/svg+xml');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}
alt-php74-ioncube-loader/README.txt000064400000007751150536142230012663 0ustar00                            The ionCube Loader 
                            ------------------

This package contains:

* ionCube Loaders

* a Loader Wizard script to assist with Loader installation (loader-wizard.php)

* the License document for use of the Loader and encoded files (LICENSE.txt)

* User Guide describing options that can be configured through a php.ini file.  
  There are options that may improve performance, particularly with files on
  a network drive. Options for the ionCube24 intrusion protection and PHP error
  reporting service (ioncube24.com) are also described.


INSTALLATION
============

Quick Guide for experienced system admins
-----------------------------------------

The Loader is a PHP engine extension, so should be referenced with 
a zend_extension line in a php.ini file. It must be the first engine
extension to be installed. 

The Loader must be for the correct operating system, match the 
PHP version, and for whether PHP is built as thread-safe (TS) or not. 
All information required for installing is available on a phpinfo page. 

For example, if your web server is 64 bit Linux, thread safety is disabled,
PHP is version 8.1.8, the main php.ini file is /etc/php.ini and you
have unpacked Loaders to /usr/local/ioncube, you would:

1) edit /etc/php.ini
2) at the top of the php.ini file add

zend_extension = /usr/local/ioncube/ioncube_loader_lin_8.1.so

3) restart the PHP environment (i.e. Apache, php-fpm, etc.)

4) Check a phpinfo page and the Loader should show up in the Zend Engine box.


Assisted Installation with the Loader Wizard
--------------------------------------------

1. Upload the contents of this package to a directory/folder called ioncube
   within the top level of your web scripts area. This is sometimes called the
   "web root" or "document root". Common names for this location are "www",
   "public_html", and "htdocs", but it may be different on your server.

2. Launch the Loader Wizard script in your browser. For example:
     https://yourdomain/ioncube/loader-wizard.php

   If the wizard is not found, check carefully the location on your server
   where you uploaded the Loaders and the wizard script. 

3. Follow the steps given by the Loader Wizard. If you have full access to the 
   server then installation should be easy. If your hosting plan is more limited, 
   you may need to ask your hosting provider for assistance. 

4. The Loader Wizard can automatically create a ticket in our support system
   if installation is unsuccessful, and we are happy to assist in that case.

   YouTube with a search for "ioncube loader wizard" also gives some helpful 
   examples of installation.


WHERE TO INSTALL THE LOADERS
============================

The Loader Wizard should be used to guide the installation process but the
following are the standard locations for the Loader files. Loader file
packages can be obtained from https://www.ioncube.com/loaders.php

Please check that you have the correct package of Loaders for your system.

Installing to a remote SHARED server
------------------------------------

* Upload the Loader files to a directory/folder called ioncube within your
  main web scripts area.  (This will probably be where you placed the
  loader-wizard.php script.)


Installing to a remote UNIX/LINUX DEDICATED or VPS server
---------------------------------------------------------

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, /usr/local/ioncube


** Installing to a remote WINDOWS DEDICATED or VPS server

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, C:\windows\system32


64-BIT LOADERS FOR WINDOWS
--------------------------

64-bit Loaders for Windows are available for PHP 5.5 upwards.
The Loader Wizard will not give directions for installing 64-bit Loaders for
any earlier version of PHP 5.

Copyright (c) 2002-2025 ionCube Ltd.           Last revised January 2025
alt-php84-ioncube-loader/USER-GUIDE.txt000064400000026060150536261270013340 0ustar00ionCube Loader 14.4 User Guide
=====================================

This document describes the available php.ini configuration options of the
ionCube Loader that relate to processing of PHP encoded files, and also the
ionCube24 service. It also describes which encoded files can be run by each
ionCube Loader.

PERFORMANCE OF ENCODED FILES
----------------------------

We recommend that the encoded paths feature (see below) is used 
with encoded files in order to maximise performance.

ENCODED FILES  
-------------

INI entry: ioncube.loader.encoded_paths

Purpose:   Specify the locations of encoded files

  The ionCube Loader will normally examine a PHP file before processing
  to test whether it is encoded, and will run the file itself if necessary.
  Although this checking is very efficient, restricting which files the
  Loader tests for being encoded may give extra performance. If set to 
  a series of paths or files, only files in those locations are tested.

  Entries should be separated by a : on Unix and ; on Windows. 
  A path may be prefixed with + or - to add or remove that path from
  the possible locations. + is assumed if no character is given.


Examples: (... means ioncube.loader.encoded_paths)

  * Site with a single encoded module in /var/www/html/modules/RSS

... = "/var/www/html/modules/RSS"


  * As above, with a site configuration file encoded too.

... = "/var/www/html/modules/RSS:/var/www/html/config/config.php"


  * Encoded files may be anywhere except for /var/www/html/framework

... = "/:-/var/www/html/framework"


  * Site with most modules encoded except for one

... = "/var/www/html/modules:-/var/www/html/modules/plain"


  * As above, with an encoded config file in the plain directory

... = "/site/modules:-/site/modules/plain:/site/modules/plain/config.php"


Locations:

  The ioncube.loader.encoded_paths property can be set in a php.ini
  file, in a .htaccess file (when using Apache), in a .user.ini file
  (when using CGI PHP 5.3+) or using ini_set within a PHP script. In ini
  files only the last value will be used for the encoded_paths property. If
  you wish to build up the value in several lines then, for PHP 5.1+, you
  can use the following syntax:

ioncube.loader.encoded_paths = "/path1"  
ioncube.loader.encoded_paths = ${ioncube.loader.encoded_paths}":/path2"  
; etc...

LIMITATIONS OF LOADERS AND ENCODED FILES
----------------------------------------

Encoded files can, in general, run on versions of PHP equal to
or greater than the source language of the Encoder used to
produce them. So a file produced by the Encoder for PHP 7.2
can be run by the Loaders for PHP 7.2, 7.3 and 7.4, but 7.1. This 
means that the Loaders offer good backwards compatibility, 
however there are the following limitations:

  * The Loader for PHP 8.3 can run files produced by the PHP 8.2 and
    8.3 Encoders.

  * The Loader for PHP 8.2 can only run files produced for
    PHP 8.2. Updates for files produced for PHP 8.1 should
    be obtained to use them with PHP 8.2.

  * The Loader for PHP 8.1 can only run files produced for
    PHP 8.1.

  * The Loaders for PHP 7.1 through 7.4 can only run files 
    produced by the Encoders for PHP 7. 

  * The Loader for PHP 7.0 can only run files produced by the
    Encoder for PHP 5.6.

  * The Loaders for PHP 5.5 and PHP 5.6 cannot run files 
    produced by the PHP 4 Encoder.


IONCUBE24 : real-time intrusion protection and PHP error reporting
---------
### (Available for Linux 32 and 64 bit x86 servers using PHP 7)

ionCube24 (https://ioncube24.com) is an ionCube service that uses the
ionCube Loader to provide both real-time protection against the exploit of
website vulnerabilities and alerting of website errors.

Vulnerabilities in PHP applications are common, particularly in sites using 
Wordpress and other plugin based systems. Exploits result in website
defacement or customer data being compromised, and ionCube24 provides a 
uniquely powerful defense. 

PHP errors can cause intermittent or even persistent blank pages or errors for
visitors until discovered, and without active monitoring this could go
undetected indefinitely. ionCube24 active monitoring ensures you are always
aware of problems in your website code.

ionCube24 is free to try, with the server side support built into the Linux
Loaders as standard. With the Loader installed, ionCube24 can be activated
at any time to give active intrusion protection and error reporting.

## php.ini settings

ionCube24 has a powerful real-time web interface to configure, monitor and
manage things, and there are also settings that can be used in a php.ini
file as summarised below.

The setup process at https://ioncube24.com automatically gives the settings
that you need to get started, but you may wish to make changes yourself
once setup. The default values are given with each example.

### Global settings

INI entry: ic24.enable ; default 0

Purpose: Enable or disable all ionCube24 features. 

This defaults to 0 (off), and in this case no ionCube24 behaviour is
activated.

Example:

  ic24.enable = 1

----------

INI entry: ic24.api_access_key ; provided during setup

Purpose: An authentication key for adminstration requests. 

  This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.api_check_ip ; default 1

Purpose: Specify whether the IP for admin requests should be validated

  If set, ionCube24 refuses access to API functions unless the calling IP
  is a known ionCube IP address. This option should be left with the
  default setting unless web requests pass through a proxy and your site
  appears to be accessed from the IP of the proxy instead of ionCube. Note
  that access to API functions will still be authenticated by access key.

----------

INI entry: ic24.api_max_timeout ; default 7

Purpose: Maximum timeout period when sending notifications to ionCube24.

  The actual period is adaptive so that a brief increase in typical latency
  will favour a timeout followed by a retry rather than a longer than usual
  timeout.

----------

INI entry: ic24.home_dir ; no default

Purpose: The home directory for ionCube24 related system files. 

  A location outside of the web root is recommended.  It should be writable
  by the web server during startup.

Example:

ic24.home_dir = /var/www/ic24_home

----------

INI entry: ic24.update_domains_retry_interval ; default 30

Purpose: The number of seconds to wait before retrying a fetch of the set
of domains being managed.


### Security related settings

INI entry: ic24.sec.enable ; default "auto"

Purpose: Enable the intrusion protection feature of ionCube24.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

INI entry: ic24.sec.initial_state ; default 1

Purpose: The default for whether security should be enabled or
disabled. The default is to enable protection. Any files on a protected
domain will become blocked if they are changed, so setting this to 0 will
avoid accidental blocking when using ionCube24 for the first time.
Protection may be enabled and disabled using the ionCube24 control panel and
also via the User API.

Accepted values:

   * 1 : protection will be active when ionCube24 initialises.
   * 0 : protection will be disabled.

----------

INI entry: ic24.sec.initial_action ; default "block"

Purpose: The initial setting for how new and modified files should be
treated when about to execute. The default is to block. The action is taken
only if protection is enabled, and the setting may be changed via the
ionCube24 control panel.

Accepted values:

   * "block" : prevent execution of new or modified files
   * "allow" : allow execution of new or modified files

Note that depending on the notification settings, a notification may still
be generated when a new or modified file is about to execute even if it is
not blocked.

----------

INI entry: ic24.sec.initial_notify ; default "always"

Purpose: The initial setting for whether a notification is generated the 
first time an unacknowledged new or modified file is attempted to be
executed. This setting can be changed via the ionCube24 control panel.

Accepted values:

   * "always" : always notify of a new modification 
   * "once"   : only the first detected modification is reported
   * "never"  : never notify of new and modified files

----------

INI entry: ic24.sec.exclusion_key ; provided during setup

Purpose: A key that if present at the start of a file, will identify the
file as trusted. This value is provided when adding a server to ionCube24.

----------

INI entry: ic24.sec.trusted_include_paths ; no default

Purpose: List paths from where files can be included and automatically
trusted.

Example:

ic24.sec.trusted_include_paths = "/var/cache:/var/cache2"

Directories can be excluded from the list by prefixing with a minus
character -. e.g.

"/var/cache:-/var/cache/subdir"

This is useful if your site creates and/or modifies files by itself from
time to time, e.g. in a cache directory. Requests that *directly* access
files on a trusted include path will be blocked but the file itself will
not be blocked, so requests that use the file as intended will still work.
See ioncube24.com for more details once signed up.  As an alternative, if
possible we recommend producing files that include the exclusion key.

----------

INI entry: ic24.sec.block_uploaded_files ; default 1

Purpose: If set, block any uploaded files in ionCube24 that are processed
using the standard PHP mechanism for uploaded files. This applies even if
the file is subsequently included and where included files being
automatically approved with the previous setting.

----------

INI entry: ic24.sec.block_stdin ; default 1

Purpose: Refuse code that PHP sees via stdin.  If disabled, code via
stdin will run without security checking as there is no filepath. This
setting should be left on as PHP would normally never receive a script via
stdin.

### PHP Error reporting settings

INI entry: ic24.phperr.enable ; default "auto"

Purpose: Enable reporting of PHP errors to ionCube24.  When enabled, any
non-ignored errors are reported to ionCube24 in realtime, triggering
alerting so errors can be investigated as necessary.

Accepted values:

   * "auto" (default) - allow setting from the ionCube24 control panel.
   * 1 : always enabled.
   * 0 : disabled.

----------

### Deprecated settings

Deprecated settings are subject to removal in a future
release.

INI entry: ic24.phperr.ignore ; default 0

Purpose: Specify default error levels to always ignore for all domains.

Note that default and per-domain errors to ignore can also be set via the
web interface, and are combined with this setting. Leaving this unset and
using the web interface is recommended for maximum flexibility.

Example: 

ic24.phperr.ignore = E_NOTICE | E_DEPRECATED

(c) ionCube Ltd. 2025
alt-php84-ioncube-loader/USER-GUIDE.pdf000064400000115466150536261270013303 0ustar00%PDF-1.4
1 0 obj
<<
/Title (��Markdown To PDF)
/Creator (��wkhtmltopdf 0.12.4)
/Producer (��Qt 4.8.7)
/CreationDate (D:20250130155421Z)
>>
endobj
3 0 obj
<<
/Type /ExtGState
/SA true
/SM 0.02
/ca 1.0
/CA 1.0
/AIS false
/SMask /None>>
endobj
4 0 obj
[/Pattern /DeviceRGB]
endobj
8 0 obj
[0 /XYZ 33  
813.500000  0]
endobj
9 0 obj
[0 /XYZ 33  
749.750000  0]
endobj
10 0 obj
[0 /XYZ 33  
700.250000  0]
endobj
11 0 obj
[0 /XYZ 33  
131.750000  0]
endobj
12 0 obj
[0 /XYZ 33  
296  0]
endobj
13 0 obj
[0 /XYZ 33  
97.2500000  0]
endobj
14 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [71.2500000  66.5000000  144.750000  75.5000000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
5 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 15 0 R
/Resources 17 0 R
/Annots 18 0 R
/MediaBox [0 0 595 842]
>>
endobj
17 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
18 0 obj
[ 14 0 R ]
endobj
15 0 obj
<<
/Length 16 0 R
/Filter /FlateDecode
>>
stream
x��][��8v~�_��FI���@w� �0l A�l���8;��Ϗ.TU�򱪾�(���H�\lR���_�ۗo��#y����|�r�RSd�I���ej�'�P�{��Ï�����s�����~�n�|���{ޡ������/�ɿ��{�_�]��.���#L�,/������Sd�Nu%���=������O�o�>���2)�T������魞�eZ	�s�e�]y��J7ߕ�5X��}�I.����/�ߟ���ㄪ�>Oʰ�WVEXx
=��12����E��?�fy���C���}�5eH��5�^���k���N��%y����׿tjJ!����َ�"�t��ӈ�Gre�s�n�L��)�s��ӈ�GL��=�FL7���,�#��u5yNկ�������|�[�k��ҎTi�=�]<>g<�
G>�#&UE���w ���D�o*D����
aϧ�����Ont)�}���o��ɻ�����/_���ɇ��Ǘ���xy��y�������sf}��6��&-��.#�wV�-�Ϡ��7��t�w�i5����Av
u٣�N5����}�i9>wQ�9�z�v-�-�Ң{��y�TM�K�պ9j
�M�0D0�p?O�|Lg��Y�����a`�9�
�����SL�I7�H˞]��
B�a�X���x�ρ��s,�WSJ�*xs�`����q���-��}���;�ۈqS7���i/ƪ@���~��S1���[^o&�'�^�/8ާ�s�B�+y�����q��6s�1��1w&8�co�����&��:���b�"��eBѷ��R�)g#�fW���x�c׌��H��s0�������ɮ�EVv�:�a�Y
�|��>2��ءӜ�ַ֊��El��|�_w�{�N��A<����v�V)a��-�ë��lr
�E
��Z��-e�`�->S��Y��xݵT�^k�;�
�1M�{�v��w��:I#�(@�(Yw\-t�9]�����4b�Tr:��9cG�<:�&� ^�CQ�j�t�U��	S|�3A�8g��M�^���c�@8Vðf���c��5;�s��@�9�>!�ٽ�5{�����%)�&ěpW7aMW�g7c�R��<����&M��o�ףO��{�Y��Ms���|�tFs�Z-��`�b|����~��z�?��^���{��G~�����o���bN�ҝ[�V���5t��8�q�f5*؈p�:H��a��K�u���–n_��99��F���] p�9��\rSݟ�LfG��Օ�6��` 1|���=ę0 <dz���#��ص�.�#��1J���*K�|�ɔU��T}���=��(��DT��?6��3��)Z���1��xG69Qp$�#�p���T�<��gbo/Į�j��2��|�#��?����������8*I�d�.6��u4r��Y&iRqC�
c���
��PF\Ƥń�<N"H�����,�U�щ�d�>L��N���L����4�шy��w�!�5a<t��k���2���g?�W�g��e�-镫��� @'-��~�7�?�$�h0W�.��-��m@$
�XL�^�3�
��ǁ��L�T(A����e�n����v�W��7����U��\KL�q,����j�^Y!��D���a�M����`p	n��$N&$0�J5��?",�~}�����3��d츮�M���rb�#�($fR��>m��~��E�ofw(n�K�ox,��ŰƄ�H�Z�)&�X�c�n�
3L]0�|�5���x� �b�X�Zڈ��׏��r�_��TK�WL$�W��p���,�9�&F�Q6ܾ����*u��կ9���?���{Z�ߙ���5� �u�_�9��L�O�!h��IH�˴{UN=K�$���ue��B&Bm?ץ��9���b$k�<Я��l���t�!:98"�D�Ah��� ���i㣗4J�r
�v�<b�x�U���9ۊ����E*��__�_ߚ�Y�a�T��[�b{h�l	������"���/MV
��L�/Y����1��1�s~�1�
��Ռ"�׿�Pu�ٰQΫ�p5ח/0oe2J�.�)�^��i�9�TM�&��cE�JkY�?��~��2/Êaeq��r4n).c<C��fD�P�L���ע��φʋc<8�½0�p��Y�k���7�х�k �Ţ7s֍�ni��;�%�҉���vF�c���ե����t��Y��oZ�Se�f��L'r18�X�.��s��K�)Y
8�\�`��v+�i+�$�RɯݗZ���BW��[^��(i���RiY�ʺ��T�V�W�a�2��Z����gԿ��$c���OA����cp�TG�_ ����7N�k����I�a��ğ�-�v)� P�H��\�0;�d��"h�2�W�� �x1��Ȓl�fpıF�âO�s�
(T;�⁀��#�L�I^�l��֯�hT�߮K��J(;�@A9ҒHKV�%Gߪ�T��<���y*��)��<��j0I�ku:OY��<eծUu��w3�d�ZK�<U�k�<��|�5�ɡ{�˯�JiCX�b��dži����~�,�җ��6<rf� �"Kr�7R#��,�(�F�7����aq4�R�.�7p��*�j��vPL��jx�ձ�M�:y9�:��Q��������T�V�:y1�:m|d�1P���`��k-�:���L���
2�g�C�w��߮T�6��5��cr3����-gtR4�7�r�J�4�9ጲZ8Y�!��(,�3Z�m���&E�KV&�n�������)�;����L�2o�2�iP�Vm~��
Jg��z������T�V�A�L�hP�M�o?T��L2v��5�ZH��i��¶8�8
��n�q)p����e!R�<i�B��*�iE�����Y���U��
;�p���� ��U~�m#���ԺS4�(b��]
&�v�Ni)�"�_۵�Q�`��L2v���#O#�MT�ՇQ6���r��֧r@��0p`/~Sj���B(��pձ��0�}�����9b��`�8/�M(��j�S�?Մ��xpx�6���|�v�E3R���.��,�Bԇ4y_�ƶ�03��؝yqY��f�Njj��豤��XǒZ^RK6U�Ϯ�ߖ�a�m�Y	�ӓ`f�ud��s�k߳�hޚ*�
�k�qo�����z�5$�����W��3�k���L*m��|�75/:QT��QS�i����T��bANx��(,~��VLW	'�;�l%�Z8��fn1WGe*^�v�3�s��ֶ�l�Uc�1�cKR��vC�u9��ܤ�;��~��M
[&��g��%_Y8P������IM5V�;��Sk�pT�3]��ϱxw6�j�SL��F��
|� S=`�=��k��T*GsT��b��i�V2T7��j&��G�	#�ln2�R�s�@�i<z����ʉ~����d�0�bB�O��m��"pC0�bN���K=���$���"m���F�{�|��C�P�	�8*��W6
����u��C�����W�2��gn����׳B�
��2_��a�*B\칺 k�@Fv�2FpL���g̼��L�C�1ta��3�Y�H���-�Ӊ��"!�*O>�9�.�[�J��c�p@���K��:u�%�ʑ]�E.j�4�WaY�W�R(�j����׃O�q)��1WF:����i*��=�ƛ��X�-��g1f޽����ύ��J
'V�%����ȓ��UO)���"�0R�s$<�O!ެx���fI3����A0	�?��^뵽�f��i��'�}���a�&lM�42,��
]ji��2�>t���ˠ��`�j�S�c)����;���&U�ݑ�2U���c�慜T���B����֡��ӉM��Y��ϱ���Y�XA�st�bނ6����s ��s?b]Gc�^?����)zLF���S��v<�|�����ݦ0��2�qc�w��왎(û/��-y�>y��~�����#y�!��!y��r0in-���D
)H� ��?�\_�سtY�b����1@ԭ_��)����($����Y3�`���D29K^˕1p�5�b����Mo����7��I~����`�ôue
�1��op��0�`�!�n3QA�V
���P!%��fxp(:�6-Æ��+E{��~���{~�W�v4 d�'pSI�o3ɳ��"�)�1I0�"pN�ΰ*�WRw!�}4�
!����9wV�4�a+d�6�u���S�x�w�1�1;���(��F�}3�s��Q&#�)�@�)LUbc���e�oQ��D���y����lQ�7"�
fQw0<�B3�yaX3�>C6�Ҭ��[fF%`�lw0D�z�fb܁��o]�G
�c� 
�a�"_��gS���`��d^����7#m^z��f��X|1}�sa�HP���,㛹W�욹W��i�^�YӀ��4soW�I�]�m�^=�̽��]��4so7�IƮ�p3��T�`��l;��~s��������n:�0��6m����f�.�,��h�>��J1�vw�x$���G�7+���G���j�ρ�ԍ��<խ��H�7���p��멡�ԍ��<ӯ���T?�/�((�'���ի}GQ�D�H��q^fv�f��
c>9����� ҃M�G0�-��gxැ�ߐ9�>�9�e�o��c�YX���*|��T��;�7�
��M�F?c*Py��ן#SA3��T��5�l�T�2�^66t>��y�_oqS��+'FSA�� �
�j�h��.��E�l�Ekѱ�sĢ�5����,�.��.�w�0c݌��<ӯ�8��}٭Ȣ7n��pBżm�!��84F����z\UjD�F��g��݅`D��Mp-u/��fNp-�N�,˱�ڌ��<խg�2�\Kk�*��ڌ��<ӯ���Z)
��z9�,��D1��Ĭ��-Eq(�8�@T�h��^.�y��$�������$D�
6��PPjG�`�������A��Ϯ'F�R;b�L��҂�&
Joc�欞�i�a"J��#8{��)�pb��:=��Q<ݴx�6:�/ة�|���jѲ��~[�&26N���ĝ>�#CnԒ�#�<;�F��&�rA1���d}5����w0���~$���
�t5�ڟ�$����r�PI��(�2U5�f��9�V7
{̰�c���q�1�v ����r�M�j��p��	�~�t�X:)�v��f1�:��=�#�3ŧp�!R�`�h��x|K�ix��"9����o�R���_ds��E6�\ds��m��{N��0
�Fy,�!{J�O��������I���ޜr�gK�Z�p���jڎ��~s�;g�;UZ���0XLM-Y�g�s�i5D��s�9ֽQ���s��Kp&����gT��nE�k�f���=���33#�7�g�����z�x�w���J�����	JR����zB�v�)�ka���
Ʒⵃ0�����X��Y����Ǟ�NL�G���9ܩ�O��e!�E�Fd�aD��X��\0�$�����S�kk�qo�"��Ҋ��q��|�5�������Yϭ��T59(j�p仼��W���=��A;�Nw<.=�A5�]�<���kF<�j��+��y�*�GT�'e���w�����7bo[&�L�.*���SN[����k#/���53c����.l9H:T96�a�=����#Bm�"T&L�`ج��T��M�p�f����)�
�L�VA���h��@����[Y�9֬SLu
�VC4ᢚVy��{��$�5.U��!�������Sl�)����ɫ��t��k��$��RzQ����x��{ʤ���3΂��������'��H�@����EaJ�%0F6c�JnJ�H�]~=���z$�K��o�=	�R�4�yp`<�k��i�R�@�u�[�ނ�@���< ��p�g��XL���Nل��ݴ>���׮�pc���_j�1�g|`LQ�L�)�Ѷ�>rS0��e�E)��*F�,�^���Y�ê����2X��j��wai�EU]�!�1~T�4^�E"�n���4��ӳ���W�1��r"�Fg&��2��oh�>#.<kU˗��ŀwP�ptk��]�s0l�Zk�����	�F��+����S�>��K~8�|z;�*�~N>�I�˙
endstream
endobj
16 0 obj
6379
endobj
20 0 obj
[1 /XYZ 33  
760.250000  0]
endobj
21 0 obj
[1 /XYZ 33  
672.500000  0]
endobj
22 0 obj
[1 /XYZ 33  
158.750000  0]
endobj
23 0 obj
<<
/Type /Annot
/Subtype /Link
/Rect [102  696.500000  175.500000  705.500000 ]
/Border [0 0 0]
/A <<
/Type /Action
/S /URI
/URI (https://ioncube24.com)
>>
>>
endobj
19 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 24 0 R
/Resources 26 0 R
/Annots 27 0 R
/MediaBox [0 0 595 842]
>>
endobj
26 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
27 0 obj
[ 23 0 R ]
endobj
24 0 obj
<<
/Length 25 0 R
/Filter /FlateDecode
>>
stream
x��][k�H~�_��Ȫ*�.`�maaL���C�dv���d��+�JmK꯺��QIrk㶫���:��\��o>F��#����-zr?o>l�8�I�_T�{������P�}���l�G�7����7���x���h��4�p���"�����_��~�����e��<�_�l��痿�$��TeQ�=�Z���?��V�H�"I�6ڨf,��߽x��=��K�gi�آ��mZ&����&o~���JuE5�迟6�V�?w]�X]���\�؎��:)�Ĕ��]�&�vm�w]X=Q�:Iҩ�V:��k3ݬm�w�~� ���c[׏���,R:z�5j���X��2���KtYq�۫��M�L[�C]�ݶ�b�iV�5:�LRl[t\6��hɷ-YlR�k�ٶ�q���Ӣ�ۊ�ߦ�{F5C;f�ʺgt�t����Ūf�[�kɒ�tG-ۏE�xf�w�j[��768S��c�<CЁʶ-*iሱ�Pccf�W��^�d��;�z�L=���h�N��z�n�gf��ZU“Ep�RU�7�����#P7��6�{C��Y˟k�6�	c���Sg��ʡVKM���ⳍ�vݞ���·u
�֔�􆟁3U�n��h(�.�����u+�d����pl�,`���L��Cڡ�CU�Wam���@��Ң��ū����[��k�G��YQ<6QY�5֞�:�������aLT��W�je�~Ō��%xl��q�4sd���{��p>�}��ӆ��q^�9 >-�B«������lY%�IBʾ��S/��2r�s�	�Jiӌ�Ϝ9��߆׍�q?�؄W�uX�1���0(>?��Q{��P�@s<���
�,���9Ƣ �A�=���fzռ��!Y����2��68��#��`��,����5�ش,�ʌs�72#���-<Z�!��y�(���&��H��1)�3�5�H�㑍p�L��i�׎
�(���(�Ö#�_�������LM߶�I�&��X��Ԝ�Y棢t��=,�O]�`��Lg�c��~��||�Dc<c��]����+F�y����L���M���*y,+S��<�V'T���і��1��P���o������"�yZK𹓃r���;u�Z+ĩS�wwF����윪�o��g܊�=�C�������i^w�3-������-o���
��ma�s�=-�|��[k7��V]|���kty]�����Ϗ���]^EWW��Me��Ԭ[:�-�����@z�x
Yj��$�S����x%�Q��Pnj,T��	.U��9%A�itzSQ6�`֩���qf9J�ך�����!v�Ѐ���=Ϻ1#M=�*�h�ŒӠ�]K��J�^��b''�U���@/Lo�N��:�dD00�h`��]�i�c��P�t!*��IE��|1�I���a*Ɣ���Hr	v�^�ƊNmՎ�9i��lL(�:D�d0�a�ztZ�дCr��H��uW}N�_]��.f�"�=���i�zi]iӥv,�-�#'���̽��AP%n�Ex=�;=���dG���lt��ӬC���Ɣ�8�'Iq
O%,&�
%#�F(�u���u�Y���%Ťp�"_�!r�* �	k	�L��̙�i�H*�S�h�u��u�OMYf�2�5��L��Z0e����u
_�ܨ�I �F�Dcӈ��Ri���U����х���"!���S�J�T#F�I��c��>ƶ��ƒ�k���-�u��Ze7}խ���q�Ͳ
eh��E�'��QO?E{
�	����`7�8z����6`�;���f\?.�w����:�昬7��M m�z���k�۽�た��'Z��^:~z�5����6*���06{�-0��S6/+ΚD�[�vL�'SJZM��RԢ3ؒ÷�?c`�{�Ƕ+Yp�v���
?��CN�=��X���~q��cv��Q�������>;�={C{����-����kf�:�EA�2\�c�(�py� �\}E^G���̉�t\&f'��e| ��Ӣ�ZZhDiaܢ�( %Q�2XQ�h�Y_��2��s�*︨_&N���.����?ӗ
UR+�n���Ƕ͜��"�! �TD*+�H%��0&UcLy�bLnj��1ݞ���0�|��б�ɔtn�H�zI�a@?��>�w��ZO?p���P��p���h��u�?�
����׀���3�����mx>pv�){J�vDxfzD�;��8"J7Ӂ�\8��Ԧ�eo{f��ɫ�2!�TBR�[̙��P�P5��LgL;�[ô���
=�`� �G��n�w�L<
�N�g�O�^��ee�,f��w�2�eW��:���F>���QO�u<gY.N+��
N��Q��xu���g�����5�s�5�iM�2E�y�!���!ѬvFV�t��)X���9'���5�i����j%VPa����%�.����z•���4��D&
��у��PQ��WӔ�K�	D��S�%�S��7f�Dtc(z���c(8���R��#�C�YSl"��S���)�CY��n"���N�}��1o����A�pd���%IJp���T���N�(:ĈR�2��Rr���o���[Ӭ_q��8N�_!��zb��I��b.\�\W5gj��AK�� 2��P9���R�����:5]~��2֣	�)U{}r4P��9㫢!�]�	N���Q:a��H2��ZF�Jx`8c��R�B�<�������L֑��ߕ3k���
ߜߐ��D�R"��rԱ��|��	��Ռ�]�����хSC$�褲�I�59f��]�*�jq�1/�|�cN��#�xl8����*4D�,\�œ�B����6�R���I�3��'զiQI||�OQD��a8���"56,v���f`{�1f�"��)Мq��
 ������E��dZ&\;��:)�:��.�-����I�zc�#X(7��&�J�Ya�sm������5)���r���6�U
�	˘v0T��|�:Õ�3�p4AUA�QSz��l����}���PWN0�o�f&
=P��$p-ҁ$�N-꘠�F��YWa�zeyqJ(�䭭5S@`r�D$�w�eʛ ��ں��k�K��]�ʚH��s-?��eO�C|����`�ū�]��NZ|�^�%�|�f�e{���oCA�L�;%���b\p�q�@�D��Y__q>.+Y�6��dwA��REsj�p�-�Fvi�+���75���g2���t"C��@������iA/L]&&�;ZTa4/J'c¢�u(Cp��"�ra�!,Z��|*Hyx���g�|�!�K��Ҥ���Ɋe^��9��[8P0*e0�D� :ZF�O�+Yu{�4�	�Ǻ7��8,��k�

��֙���%!�F�u�"�{8�؈;N4����\���p��sL�'%�]�G��f��n`竩�ʗ$
��W3���CwӟƼ1�NDY�
<j�?ؕKd=c!�Y��8C�s% vM3��%#v�L�j�|4n��
�3̮���!Z&����C���'�u�>��a`��_E�d��dM�*Ü���C��'�)ܽHת��J�b�	#8��%g��3�e���C�ݭ��$���t��s�;���?����i��fH�MUv�4�2N�~�Y�bE[dg���y�[��u�dE
�pL\���x��5p��_����G�gZ��%-��'�~�q?��i:p>�G{�;<86Ϩ�Z�)E{�Z����Ňo�F�����~������Utu]�����I�Ļ���{��MO(l���>H"=�������.��gڿ�tJ�/~�ǯ�߆Qc�~b&�^`�`�36<S쩹{f1#��<k�;�1��(���*�mN�]*�?�5���P	@�_\!�dR�2LX��%g�$H�&�@#|��
L�B�DR�T-���e��1��r�<Ӄ�#mu}q��O*��d͇2��ZD��S�|ژʒ.mj�c:ϙ�}���Oi��T�ޗ����T����}�m����-q�vY�b0�e�e3!��*u�2bh,�m}ߎ��s�ަ,�)���Z ���w���]�g�z�
S��p"e�0.L��>w$!�S�
�T�����Ϟ�ߊ��s�y����'�Mټ����uK�y.o�7��Ow	0��7�v0����bJcȂ��0��<��Q�;���Ս�Ӎ�@7�N7����tc�W7�N7���:��vtcD7�vd�u�<�=+r��E߽;2��d�=l��S
endstream
endobj
25 0 obj
4362
endobj
29 0 obj
[2 /XYZ 33  
122.750000  0]
endobj
28 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 30 0 R
/Resources 32 0 R
/Annots 33 0 R
/MediaBox [0 0 595 842]
>>
endobj
32 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
33 0 obj
[ ]
endobj
30 0 obj
<<
/Length 31 0 R
/Filter /FlateDecode
>>
stream
x��]߯۶~�_��QDR% ����A�a�C��+��h�
۟?ɢl�G��=�$�-��k]Q$ux~~����}��?��O�>��O7E�l��u��:�B׹�������/����͇͇�߯�a��?>��y�?k�����f:�s��/����������S.�V�����_UQVyը�n�/����߾�~k�Q�uQhm�Q�\F���EcrS��u�'}�޼����)U����\U��sS4ua�F�8�:Ӯ6Y]����������L�6j�U�v��z�-˹]٣G��4�i
�w�6���L���OY?�W��Oݤ_�J�٧�7�����/�k�cd�ʷ�+-+��ck�+��^�y��rp�m�T�)���T����NSTz|��J�'s�G�y���Q��NF�g���}{�iZb)lKC�g�m���>��c��P�mYE�������.�~��J��P����Ŗ芮�G���g�G�s��	���<�|�4��wľ���{�[PO�
�Q|O��RK�����liBQ`�0��R\n{�xf�',3b5����h�>;��\#>.��3��S�˕=�G�p�X�a�7P���]1�z�w�dn{�Tǣ����;�
�
�SL!�9��8^)�~�J��M���k5�S]���&NcO	��J1+
�5���g��A9�U̩'T�نs���;�g;0L���̿o�����$��E!�-�`�_��{��4|����w��s�Ѱ·�~�	֍?����ϡ�)>��,œj��h�,���Jg|^i�]T1l�5o�9�mc
���ŋ�|���kF�3r�
����R/~�hS{?��x^������#�1��+�s���O�!��7�K5Bã�xLU�v��5���`���ю
�C�d���L��L;w�s�<�Hfn�aC�Q
"�,��)d���u�=��D�ak��Q���X�c�/���r����X�a_�����a�8�!4�
a<�8��d�\���!�nʒH�����̬3ұJ��1��v���q4·&�!�:����坨�)�	{K�g�mh|�HD,����vCx�(l�|a�/~��i�*/Ϟ�h�S	O��P��/�DL�c��o���:M&1.Ӯ��T�(m����ДݷMfl���Ƙ�nli
��1��L?^�w�'�q6���l�w�'�W��>7�����7�v�%�R
�b��� v)��:î�����e�?�	̸(0�"f��eR�9�Ue����b�sZs���DZ=�AkΉA[�b��y$�+ft����b��Ġ-�xű쮸�}nor1��ދ4"��`�F�7o^˫��&%��f=G�i��.'~u��{J��$��D�hxw�Y��-����=
����'�m?����+)=Vڙ�R��q��@=Djh����F�ר�D
��$��0f��
f,8
*�<��v�̕#��=&U�EgM�W��:�D���R�wJ���hIK��H�C�T�X�w�J�dV�@� ]SPeF�L!�i�zj_JU���g�0)��l�X�{�q�2%c�)܏�M؟�%���?NȾ1=$��Uy�X���X��-���9F�m���}��G�5�<�k���G(��7��
�M�k��-9��5�I��6L���a��t%�2�0%u���l@1Ʀ	��X5!��	�V�l�F��HuW��>ӏ煐n�	!�gu?��Pwō�s�x��vJ=�:I�'|Xc	��W�J(I��'P�a�[N[���d.��=1Hٸ06>q&��u���O�sc�W���C��J1�2����Ʀ%ƣ�H(��*S�����4Ʉ`��.�:x � 6+�l��`� R"r��k�uJdu�%ci��Ho�Ա�t�3$қ���\۵%�PJ�? �u%��Y��jb�8%]�Y�D���Dz�B�x8Z��͛bo�ԁ��JJ��;��)���Q;����N�Kn�i��o�$x�#��G�:�DG�K��D��z�R�R�BZ���C(=�x�B�����l`bс�K����K��f'�����ޛ]��\OJqN)�aJL)α��M3�CJq��g��o��~:���v����9�.믘�}�o�]�~:���֏w����F��a����ڧUvd��F+�S�İ伳X{�d'6U�F6�l���%;Vdx1�����4�k�mz�|���bF��~<���5����cF�7�;��
�M��w��,��C	��"ӞR���͠d��u��o[p���Od\�L�FYe<I�E����7�(p�xJ|�t�;3�\?��[oF�쯘�}��K�s��o�x'f��f��Q1�	e�0�����dV�;�&J�ξ��Ғ~?�c�#�����0:���=r��VE��\]��~�6�p4�4d�0�"�R|�h�3fp������q�9!��;
��"��Ce��<�յ����N�s�s��J�d��ld����P���'[l��+D�8Z-aѽ��=ӆ�rO-8�("�q��XE�0�%��i��$Yr�E{����ej����A0ώ׊��'۴���2��ފ���_��������HA�̖�hG�
5�&7t1��wZ�zO@��.1��c\�9�33P��)*%�V�ܶx=Li"\	;Zq�!Y�:Q$kՅ��z��x��n�Kkԕ*�p�
"�qkPvk0�d�2���N���iķ���)����1���$�� *���s�E��f�p��:�W�4�Z�p�^��>q��f�w�/!x�a�jD����ڬ�V�\W�Q�Np�&zΚ)6��	�������%�X���v'�a��.��4G�]^۫�Ԉ�d�����i���D���ɋ�i���d!���(`E
�S05��d���0�	�<Z�;���l>�%�Clk�T63�j��U�˥�C�-M��z�D8�8Z�=�B1uK/e�i�*�A�_�C��d��=/i�B{��B؏�W�=<�9�<"Sۮ��
���a�����|�sD�����@t����x���M�E���h��D��<�=8��R�i���X
Y�e=3�G������b5�����Z��8�mw�u�xkd=I҄��0>t&Qg��%hG[��{�|�J��?M�-�N���rs�Ө�M��ȾZ2�_D�Mh�VM1�'&1X����{�e뙊�~Y4���p�q1���l���7�
Y�-07l�0�3eO��=?z`�����pNe+�&~jsK��e�zu��H���$|?�Q7�\S�e�R6��e�D�[`w?X@b0~��9.W7�`٬M٦DK)>s�M4�� ���yͮ���,���5b�p¨�!:FP�.ք������I�{Sp��)pS{��u��|kY�1�@ٜs�$u�U��������&�Z@c�h�jA�{�h��0o�;)�e���'�-b�2�#��E#���/���~I*:gAP�T�]��t�mA�==P9��K��Pxw�zp)�K]z�f��uD{2��T�}�+�	C��~.�P�M������R�C�q�{b�K�L�����`���h�
�>A��ݡ�'�*2�*���K6�R��H&�(T9VP�1�e_� !LX_�l.C�'��OW?�2hiLЖI|`����Zp�<�!��U�uHgL!�DJ��FHe�Dʞ{��%�����e�#tsʏ 
Hf\�E�W�[p˄%�y����C6%���~��@���jx�=p�O`�5�ҿ��0>O�r����lS�/
ܣj��d�s�=�Ze�rmp�=%�G���K��LJ"��Aհ����y��~�`рl����d�쌚|�nRluE�23N�Y����sƸ�rB��+3ZٜY��jFs���Q5�9�'K6�K������qn�\��ŝr�RUc.��JL�A&�ɸ�M�q�1u2���x=Tg5�
��y�@L���ك�Tp��)��0�?��*�P+
50�UYY�)Q�n(��2��F
��s��3����>T�X��H�e�
�@D%*�π�ek��j�8��L�,�Ra,�{�Ehk���u+�Eh[����"t�G+;c�iBUu�]�qY�y��������*+(�w��dmelj�륱RyY�x�?I�Y�fl��r��'�ɟ��<�]d�?�W����y��@��m7���@���u��'�M�gpZy�	�
�?�P�8�X��>&������͛�����������y��}����S#��t�Q����/OGKX-yu'qzO��9q�uQfz]j�W�'��q��PR��8.��g�Qp�
�5~���q�#�F0��v���BLj���ui���#��u� �<Ǫ<L�Lj�x���B��$eG�}S~R��1~s�Q`����]��g�F��A\����2�|&�Ō�JL`��tL�
�c�f��I���!�Ʌ���*��h�B6�?�5�r������9S�N1�_89�-�G;2Z���ឪ���LQ��\�S{b�Q�]�u���T�T�I5,�T�J����N�z(��_�����2�'Y-�WF����6�kO��C����T�}�T���V���M�}�3c���7��ucKS�o��g��k?u���订��k�w������~޼�f�l���U�m-w�c�UG+0�,?�
�i*v�2{@(��y���.���DTIej��Տ�"����s�T��T1,���i{̘ژv���D:����y��נ�;���C�a��l��
endstream
endobj
31 0 obj
4897
endobj
35 0 obj
[3 /XYZ 33  
765.500000  0]
endobj
36 0 obj
<<
/__WKANCHOR_2 8 0 R
/__WKANCHOR_4 9 0 R
/__WKANCHOR_6 10 0 R
/__WKANCHOR_a 11 0 R
/__WKANCHOR_8 12 0 R
/__WKANCHOR_c 13 0 R
/__WKANCHOR_e 20 0 R
/__WKANCHOR_g 21 0 R
/__WKANCHOR_i 22 0 R
/__WKANCHOR_k 29 0 R
/__WKANCHOR_m 35 0 R
>>
endobj
39 0 obj
<</Title (��PERFORMANCE OF ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_4
  /Count 0
  /Next 40 0 R
>>
endobj
40 0 obj
<</Title (��ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_6
  /Count 0
  /Next 41 0 R
  /Prev 39 0 R
>>
endobj
41 0 obj
<</Title (��LIMITATIONS OF LOADERS AND ENCODED FILES)
  /Parent 38 0 R
  /Dest /__WKANCHOR_8
  /Count 0
  /Next 42 0 R
  /Prev 40 0 R
>>
endobj
44 0 obj
<</Title (��\(Available for Linux 32 and 64 bit x86 servers using PHP 7\))
  /Parent 42 0 R
  /Dest /__WKANCHOR_c
  /Count 0
>>
endobj
42 0 obj
<</Title (��IONCUBE24 : real-time intrusion protection and PHP error reporting)
  /Parent 38 0 R
  /Dest /__WKANCHOR_a
  /Count 0
  /Next 43 0 R
  /Prev 41 0 R
  /First 44 0 R
  /Last 44 0 R
>>
endobj
45 0 obj
<</Title (��Global settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_g
  /Count 0
  /Next 46 0 R
>>
endobj
46 0 obj
<</Title (��Security related settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_i
  /Count 0
  /Next 47 0 R
  /Prev 45 0 R
>>
endobj
47 0 obj
<</Title (��PHP Error reporting settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_k
  /Count 0
  /Next 48 0 R
  /Prev 46 0 R
>>
endobj
48 0 obj
<</Title (��Deprecated settings)
  /Parent 43 0 R
  /Dest /__WKANCHOR_m
  /Count 0
  /Prev 47 0 R
>>
endobj
43 0 obj
<</Title (��php.ini settings)
  /Parent 38 0 R
  /Dest /__WKANCHOR_e
  /Count 0
  /Prev 42 0 R
  /First 45 0 R
  /Last 48 0 R
>>
endobj
38 0 obj
<</Title (��ionCube Loader 14.4 User Guide)
  /Parent 37 0 R
  /Dest /__WKANCHOR_2
  /Count 0
  /First 39 0 R
  /Last 43 0 R
>>
endobj
37 0 obj
<</Type /Outlines /First 38 0 R
/Last 38 0 R>>
endobj
49 0 obj
<<
/Type /Catalog
/Pages 2 0 R
/Outlines 37 0 R
/PageMode /UseOutlines
/Dests 36 0 R
>>
endobj
34 0 obj
<<
/Type /Page
/Parent 2 0 R
/Contents 50 0 R
/Resources 52 0 R
/Annots 53 0 R
/MediaBox [0 0 595 842]
>>
endobj
52 0 obj
<<
/ColorSpace <<
/PCSp 4 0 R
/CSp /DeviceRGB
/CSpg /DeviceGray
>>
/ExtGState <<
/GSa 3 0 R
>>
/Pattern <<
>>
/Font <<
/F6 6 0 R
/F7 7 0 R
>>
/XObject <<
>>
>>
endobj
53 0 obj
[ ]
endobj
50 0 obj
<<
/Length 51 0 R
/Filter /FlateDecode
>>
stream
x��[mk�8��_��u�jIP
M��AI�>��d�X�e�����?9gc'��L��^wj'�F�g4�������MLf�/bI�ټ��w��'�g�_�Pҽ�нX��ⱸ-n��Ǣm���|(&M_E��|�{��Gh�k��I��W��%�����+_�M+�>~�����*�����~�c����e�Rk��jl�|>3��Rz]=���-C���hU}�.�W֧�(c�&j�ixO�0��F|}W��=v�a��a�:7:�Lsg��xW	S57��ߦ?��.��H��I���3M{�s��l]-I���NOI�;z�m�c1}�c���:]��J(-�E�γ沸/lHތ����<���B,>U�5u��O5����2Va;k�Q�DV�#�:�qʭ��QkZ�$��}ܚ6+�++�Bg<J�N�0�=�s6$�$��=�A�d�Z���>�X0m[���ܬ$׋Y�	��*6�
h�k/Tj��虦=
�v��uԞ�J-�=߶w�Pq����H��'���i±TU���N�X<�����i�j86���e����
+��=J۟guI�m�h����Zs$1Dt��Op�.����}�~h�w-�
�M]�E��w
�-c�"–�t��6C�@V�'~2�r� ����r���ϋw�~���BL�f�o���	�����f�s�i�9�E�/��3�h�69l�B�-%9~Hk�$��A�Ϸ�%���I�x<ж��8�C�Hە�9�'|Ɯ�<��H1尚���o����:��	ýÊ���4u,P��:r��������kF�Lɣ�2o�9�5JX8��o<ی�o��0w�5;j��V��-7q}�a�q�����U�'7�+�wr��^�t}ﵳ1A��o�qi{����"�� �LSZ�����T� ق��dž[-��
J<l-@�5�(�����l5��V(���H�Q���&��Xpu.��AI����X.�D+[K�h{A�y�4��T���8�7=����T���l�p5R�XX�Dl5&[��a	
��g�8&[X��=�$�A�2�A9[Ƒ�>/�U�F�=�l}8��l�q���kΜ���x��yo��Z�)�`Te���/m�(�%N���b(c�S|=Y
[�WN!��a�a�i�:��x‘|�����̄���.Y��3?��>r��b$�f�8�9ebNfb�-�Xqkx�F-��r=^�Y3�U74�}��GʚG{����ɚo��9��L��É�qW
�	���Ki�������i�G?X��8��3��N������돶*��)#�<��������aX�*N�{<��-2��sh�Q�aU?�T/�T2���F��a���F����g�.����13�ގS������ [�'�Y�����B֬�^:�� ��F�_�U�o��u��|˾V���-W��h�#�D���D��~3���
[�Gj�8�18��<���Lk�o�6��L?��K��]bT[^����'_0��ls��K��[��Y{XE�얞�]�^u�����H��Ȍ��d��}����jz�
endstream
endobj
51 0 obj
1581
endobj
54 0 obj
<< /Type /FontDescriptor
/FontName /QCCAAA+Roboto-Regular
/Flags 4 
/FontBBox [-736.816406 -270.996093 1148.43750 1056.15234 ]
/ItalicAngle 0 
/Ascent 927.734375 
/Descent -244.140625 
/CapHeight 927.734375 
/StemV 48.8281250 
/FontFile2 55 0 R
>>
endobj
55 0 obj
<<
/Length1 6976 
/Length 58 0 R
/Filter /FlateDecode
>>
stream
x�}X	\G����{�F�1+Ȍ�`�P`&�7�)ry" �9ܠ� ry+(*�&��&Fr�I0�$���[s=�xd�M6	0��g0׾���ꪯ���5B�
�L8B����j�=���bI��_�y=�����Н����q!l!���';Ư������삲*���`�B`l�1-���#d~&��UE$�,�v#�U����7�	Bh;��`:Rp����$��V,�-BGb�j���!K�������eD$$S�A�e�x?�4�C��Hm�9"'���B�j��S{5�A�M3ϥ����a����F9QG�5��S��rs���R�*Z9�%M1�_��$���Wq
{��Q�87���K��0Q.�LպA��t�'�蝝���>��y?p��rqQ�r����j���G�J�����J��˴HF���t4x�o��v�\�j��b��͍s�Kv�����}{\,�'�4��Sm��MAA;��Vo���m�����3�((D���'�.�J��^�Q�Y�˱
���˰�3Q�޸* ���5k�z�f����6�~�R��]�}��ȲF�uS��F7�� U
R�)u��Ͽ�c�}��q�C�O}��2��_b��LY9ik�=��W���h:�ցCq�[�x::��ip���V=��m���@��Z��)&���p�
�>�r���ө�͐��O��A����.I�C��dg����i�D���Q�Т�5(	�c^UR�w�h�m*�����x~I™��aT�s��=52b~������Y�%���,\'	���y2�� C.���
(����*����z�����<����zy�Yï\ޒ�]�$~X��Sl�&ž]�O=�ych0���b���4�>m���Ҹ=�GG2u�_8������
��g��_<r�9%���7ȝ+�Dv��4ȡ���	�P���*�����R�t�)lk�9��
[6}s�Ͽ(- z��7-��7/GpZ��->	����W��HNJH�O]pLTĬ�����8~�r�������Ӌq�9��~�-���e�B��ՙ�%�J�ʊ/Mݶ�K/TT� *��'6�(�ˁ�Z�=Hʚu�,7eew�wsr�^@�q��!�-@�,����<��t�[�w�3�Of�05�a���Y�L�{A画�-t�3���kȽ��"C�#e��	����B�5�shk�y�;�����[�}7�K�1�v���*�-�ta@#Q�$u�����;�	�i����s����E�1g�
@5E��c7��
N���7��7�aD�w�M[n�ݱ^Z��c�@85<��k���͟s���:���e�:���d���(%���z�r栱
�o�me�Ĝɀ�Q0��l���N�b�se%��f���[�fN(-?_��a�5�!A%ً�KČi.SfL���ٺz���}zf��5ST3f��Oܓ�`��ؔ$�Gf�`��C	���e�����S��7����h�Qy��j�Fx}CϳM�Qh&����fU�A���P\t!�R��C�.����:���g�C�����R��=0i�/�f�7��96Ԓ��|�8���g
�:Gc0���:���l�ε�!��j�C����_�!Ӻ���@lx�e�@L秅���榦ܬ�C�,���*���М��Q�us�L�O��{�ȎTo��q2_�}��3��-�Ȫpu��Ip)�y�f4��xk-i�O�x�8�e	��&7��Ouv@И��g0�T���� 6�gҁR�y��^��@��7�lc;r�&
��Y7s��R p���Wh�:l�<y��ox`����Bqp�9u��zl�Ĉ�fzt'HrS��{�,6\�75X���/���Ū��C�,k2�&� Β�Y^�I9DL���-9Ē�-�	�Aa�O��⋗�L]�E���	ډ�ا�c�-Y����!�`�^q�?����C�򲑃��܀́�Z���8�\��ҁ��O&%u/\0��{%��m�ɝƧ��ص�z����N@����{�y
�i��J����t��K�4L�Yf�)�e/_2�vU�\+/*�K�8�a�PV�|DĶ����Eb�5��h��um�z��\n܋Ѹ9i�:��s�w�^*e�>�M��8Z���U�8`XG
9}�M���-v���q��q;����|I8�ֿ���28����6:���;��>$i�y��:��yj_��"=nNN�w��,~��#b���bRӱ�r���<�ďCk[��;�b㫑[F'�#��caP�5��%�����f�6GF��n���}q=�h+���X�r��:7��{�{�
������*��l��H��F8-ԞY(3R{{��I�o!m�����.q��o�~��r3p����¹vH�R�V�W��`@;�?|I�ʸ�	�Z��i���an搋�=7��ws�,�g[�C�E����
w��Do�q{��e:�x�S��zE�Ͽ�3��Xc��Ajd�a��^�/�g?6ԇE�B�s!hw$�Ò�v�Ce~V8UT�NSz���m,�&<�f[h��4W��/q�H�`��i��\ø�ܔ��lQo�0I��ѰȲ����AK����	�	����[{N�7�F��5ԟ�i�z���?���A^��73��]�u���ĸ��Wr�?�,!>���w(������w삦ъ�d��9���
{�'��pn��_�&�S��{T��j��j��C��Q��Ć(8K�e�?������2w6]��NP�~s|�3T��x����]��[fa ��_h.^��\��u��,�o��!����Z��r"�s
ӡ��.8�Ҟ�K�钘��_�>p�fK�©���C�'�w���x&�47�$����1)� �.A�X�eV5<@�Q$!��H��$ǣ�?��o�,_��b|����1q�Lv��gs��ں���kSo�]I��s�<U\�矑��.*�-0��7_��7?6��tn�?����>2j���ܹR̟����2�����Ar@�\��;M�_�i.�]����P*��{�c}�F�I��a�S�r_��F��GLs@��t�,�L��Y	��e��Ξr-�
��VUmqۓ�l������%�^}��+d}�#~� ֈ_v���@<��
HqҨm�1����-M������_��N{09���Y�1����y~4��W�:V\��Oࡺz���K�û�z�
R���nc�C��

���?�;������@�|��@��k�M�/�Q
U2m@�Z����������{<�?����v�ֱ��1F���L]���2�)
�~*��w?�׉�22�\	��\s3�ف���ѠF�1�p���a4�bW�IH~%�~c~vVn�k���6|��
v=va!�[�Ö�ԯ��w�K@��O>�Ry�/�,X�b���+���4\��k~A�b��G�$���߁|T>SG���z��@CKmd�Ⱥ�Pl��[����V-^�i�[W6m鍈ظ����{[8/(�EO��^LY�r����1k�g�� $�nS`���d�͟��z+jU�h'����b.��r�zDox�XD�Gr8�'8�;0���koG��y5A��G`�_-�A�5�^�K�������~I��\���a`���Po�,���}F�nS�����1Q
O,[q�aIuٿoK�����mz1�v@n�,
-�킁D\����x���˽/��&`�6���G]��W
��5 �Y�ꖳ�{�5�ؑ�A�kX���.޴��k7â�%k
�Be��}�����O'�au��a ~S�8�ޅ�s���+^,*����k��$&���k����H���P\�
*-


(*	F���yi�C�<�,'&Noga[±Z]��1����3��19��;.������-{�t�)�'Xt�p��qw�s�����]�0/�\��uN���c�s��J���l����G���d���ؗ\~	q4��~�*`��w-eI��Ҙ��a�.�>"l��U[�]�t۶�G����u����/!��ի�ڒV�&�FF�F)�;�S�NB��Q_d���;W���4�.�q�����*��o�����K"A�L샩5Q�!;�/����ˌ��1u՚M��b�]� $h=Ƞc����G}��R:��eŌ��'�Wԥ�}�0R��Y���4��F�_�f��ZO1��]3�m���z0Ƃ�	T��x	9q{���0��0�=�*��7��� F�
��qęat;�T��b�?�����s�ϛ���<Y?��s2�7&^���4�8�yp����P��m��'?<�G�����1CvO�<S�����E����8�PvO���+�k%�����"��\�*�I%��r�!��<�C(�h�ů$|I��a�FҍEO'�]��U$Y(%�Kē�ƶY-�H=Bl�[D��3z�52�)�X�%�!]��8#�$�N��82�{�8��=r���1�I�lߏ'6^X��.��#d}�l������$
�x��Fҁe
�D��Ä��d:�Kƾ(,EXJ���C���+I&J�Dw�F�z��Ë$���,��x�O�D:�.��t#�;�rq\%w�����Z^�g�����`/L��B���p_��"d�&�Q��Z./���$����M�M��36l�ٺ��l�m���4f՘�1c��<6�IKd�#i�/;r�A��b�3�wZ���s�:��oX�<�oY�����u����d�
g�^@�HX?��)�z�Z�Ek��5k] n䶵.#N���Ǔx��IYGJH�"٤��P��o	��F��'�
#�$����"���w�Y�R+�H���8��֕�de���<<=U!FcV~�*�0m�jQ~�*�}*U�f�f�Td��X\o-�2,$ָ�X��H.��㒩H��fd�秖����Cg��V)�k�M�-��
��?�0���c��k�����x6�����x�p��EJ�-b����8�K~��'f��|d'
{
%��bO$�8�!‰ç�Ħ-++�3���rvjQjZv�lcI֜�����Ҍ�9�aA�qA�^�q��G+�
endstream
endobj
58 0 obj
5244
endobj
56 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Roboto-Regular
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 54 0 R
/CIDToGIDMap /Identity
/W [0 [440 241 566 547 646 547 557 526 246 534 540 559 336 557 557 261 643 512 676 592 546 519 869 324 481 241 557 344 557 626 707 195 557 270 745 469 564 611 548 682 866 647 707 651 589 880 339 345 492 240 503 557 557 562 448 210 564 557 557 557 557 618 274 409 631 317 237 ]
]
>>
endobj
57 0 obj
<< /Length 826 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0042> [<0069> <006F> <006E> <0043> <0075> <0062> <0065> <0020> <004C> <0061> <0064> <0072> <0031> <0034> <002E> <0055> <0073> <0047> <0054> <0068> <0063> <006D> <0074> <0076> <006C> <0070> <0066> <0067> <0050> <0048> <002C> <0032> <0049> <0077> <0079> <0045> <0052> <0046> <004F> <004D> <0041> <004E> <0044> <0053> <0057> <0028> <0029> <0078> <003A> <006B> <0035> <0033> <002B> <005F> <003B> <0071> <0037> <0038> <0030> <0036> <0042> <002D> <002F> <0056> <0022> <006A> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
6 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Roboto-Regular
/Encoding /Identity-H
/DescendantFonts [56 0 R]
/ToUnicode 57 0 R>>
endobj
59 0 obj
<< /Type /FontDescriptor
/FontName /QHCAAA+Consolas
/Flags 4 
/FontBBox [-432.128906 -302.246093 677.246093 1011.23046 ]
/ItalicAngle 0 
/Ascent 742.675781 
/Descent -257.324218 
/CapHeight 742.675781 
/StemV 70.3125000 
/FontFile2 60 0 R
>>
endobj
60 0 obj
<<
/Length1 11900 
/Length 63 0 R
/Filter /FlateDecode
>>
stream
x��yytǙgW7�� �H$��M���/�%ID @�hZ�%��x��-;vd[����$���x2Il����;M6;���y��y����Yٱw=~�l�W�
�e�X�+tuu�W���jR����8�P�������`����%Vf�Ux�o������c�hde��e��X�<�L�=<�����}���u<�<�6�����ߚ(ʌ�/.��[�ڨ'(ʢ�g6^��ێ��\MQ�a�͢�(1E��(
�;�kj��

i����E-�J�7��՛@��c�R]TwS���'hZ:E�)�o���bލ2S"j��D��̀�
8EJ�7;��J��:\��`��_G0P���K���f�$��Pe�_���!frMD��*U��@p@���h����.�;�c{��~Ra�K
d�R���D)SH*�*d����5��n��g���x�mv����5FCqQ�`�r����`tnZZ�T�*�R��^�����A6{��*'CN�r��`�>��{�#�3j7��2�L&/S�f���T��j��L=���S�ĔL�R���Xƿ,3�-f�N���(�c��"�Q6����*�uא����w���4j~<��+���wN�[L�M���X���}�d:1>��b���TZgecS��PsyE�R�r9C�};�B�e��[
��8]�a��
<��90��r"�����L
���Zde���[�o��k���}��:u4�&��Rt��k�e�R��ܳR����rW�<32|y�'X+˖;]����
�r��P���ڽ���!T(��ܭk�x��n~¼���sb�
`}h�?�(��üпep���@�}�����������7���V�3�N������4*�щ��	��W:�Ln�hW��~�ď�M!�,e1���NY(��pI6,R��I�y󌤦ʍ�yvx�|��Zv����ݡ�J�ԾW���x��Z���~|�������LTӆo`i]���.~!U�9s�,�o�޽���s�`���XOW�W�}�c���^�pT�ܾ@������Se������� n�x�;�j�[�*�]�������g6�r�F���3hd
�V�x�
b�΂f>O��:���
~B���yv�I�(�IN�cD����oyk�g\Nvpr���[������D|d�)d1��⨫�i�Ֆ;�Z��5ώ�AbF")�>��:��g��Ӄ[����clr����]��ju.w�	�3����_�V��h*l5�kg�:MqQQ�Fge��U�+*F��H��ZQkQ�����q��Vi���7�xt��壍�G�P�:���1?'�F�<�`����(�
�+ǝ��q����o�t+����;���yi|dϤB����~���@����;=�Z�����P���j�vn�xh���.g0������PR�˟S(d�B�!�����1��])*�����`Vi
T�؅�I���9�n�(U>恟���p�Q=�*�#�b�Q��9�/�ռxF24:>3������!�3�u�r��;w���b��^g9�H���G~z�>PQ�ӵ��/�xr_k��*�0[�
d?)hؐ�2�+RG�-(v�y�����3#���*�pEy������\�Ku~������(6Z<�mkG�.�͊f��p
��,���x�}k�7�܀=�T0/�hw(y@�k���PwV�������.?+���X��5L|5���Ţ"nJ����y����~:���k�6X��6�W)��\i���z}�~�}d��~���֦{����%�4>�Z�8R�p?{��$�L��bdU6���|fh�7/{�G�=�.W��eI���$�'��OdZ��3��$7w��Cj)������5�Ȇ��6���F���]��Lks�ɿ����ll��W[W��=911��BPf xO_s�ۣ׫U���ᕖ��;�5�xkL�B.���{&;�+���˂��\�+)�R"��Qc�F�F��hL*��Q�u{�몽����Y��P&/Ui�&�V�Ҫ4P�X�+�5���������OT<�"�V�Y�.V(����ʚ,j�m�B���ػ�c���Xs��-���%��������Kp��r��q��Ľ��V:tZTTR�**)���A��6�����֎�S˨�.r����t���
:�����j�]Q��ZSӾg�Ζ�r�x�"j�j��hJ���W@i�q�/p��k/����p���i�$wg��w�4�ɡ3�v�Gw�T榛�~��ysm�E����]���ij@5S�O�����ןC���;�7�����o���\'�큹e�8�~�5�G��[�,��u��h����Ք�d���х�7��O�(�=��"���)��]�ʆM�_���Fy�-�^j*�L�K
eE��R�J�5؞��EQiY��t�����Qo4����G�Ӛ
v��u��>���N	
����Z;B���aW�H�4��lY;�\�Y��e�C�@
�T��e1�Kp�9�/�&8/9�z�ZL0�r�|N��rhR�ĥ���/tZ��dc]�/��{����2UyECco��t�D]����Xg��Y�Q��~֊�Ck��McuMg���`��g���}�aZ2l�v�Y͞*����5��1xȫV�E�N�$T�	�6�h�p�
�!����`&X�=�����:�\NU)Bf���������3[����2}�	(��.��|��OZ�u���v��jF3�1C��"\��^��(�x2\���jƶd�������:�ƈDi���hktVZ�0�hc��M�`����\e	�\��ru�3���'8���4�%#��
�k�`�g�҉��v��)J3A7:
΂$d���^'2}-r��p�?�^G�}k��wf��K��B�S�cHI���M��Խ�zh3P�]�U'�t�[Q���v��5(WF��)�Ѩ$<�ug�}LƤ,1[�C㝡&���@Ն
��;jk�d��uLM�l<Ԥ7�45`T��
��u���D�I,�`���
G�%֘��'w��)�����q7���H$���bv���X+U�-.wm��6Y�J�i���qgW��Vo,.R��Zi0"SZf����}�m5�F�Z��c�`S(�(S�4z��+�^�5�f����Z0n�W��6{I�Q����Huj�F��i���
6-V��R�����b���#��k	�x�G?"u

 ��\�e�|��ܴq�=���3�\�LJ����v�{���xg�������B�A�W/}㟿8�}#uS�\�M5C����`d6e9��ʅ�NU�q6 ��ñ�R5�8�SƆ`CMS������'�`��r������G�5vn�:����YWoc���ͪ�6�"��@@�PG{Q���t5���DZ({�H.s�F+[�in�ꮩ1�D}$Q�J.�JD�
���q55�h�h���6�S
_��-�'Z^5���&*,f�s�4v��1'�ߥ� =�^G��;��z@�@TK�ԣ�Co�?���5Y�k���Alt�
���P��߼��͢�����:��l�{X!7�+��G�z�>���W?�W�f����6�5��9R�rt�X�w獡S�sTB��ǵ��:0
�������
F�NKꚚ�C�Cm�͵6�w�M���zg��\T��B�7:+��>X�hߧV�ڵk��'�M>���BB^懰+�4��x�v���o�ݻ�
�\VTl4y�[G{��n�9x|bp~�U���!}�ڵ��
�
�j8��U�ʖ��ZBc]����m]�ݽ}#��J��Q�QF�.ɈAP����}y�a��ƻ\�kFo";�.�?̈́W��_Y�~?q�CQ1He�s�P�wɝ�9!A�u�pb�G��M�b��깕/��ї�#���:���XG��B��v�N[n�V5�6�\.�f�d�]����U�@_�	�ҏ<u���^=B��=#Ǐ]~��N�]�=ǎ���ag�X�[
ٹ�n��9p\�ZY3z:�q�Ve)��w���vl��Zf�%U�D
!�ڲp�Cͽ}û"F�ƀ1�頻he��_s���
��_�D:�-Vi�1�Ev[}� .�Μ��{n�aO9�/��0����>�>��Nr��&�6�:Ɲ@��O�Пq�v	���W�ז8�~���7��&+Z��!��y,�8�
�ܕW��o+�{�vÁ��3��T��x�j�@��ׇ�;۷�����P(��궎�'��R��%]W���-��.g��嬘�5l0��[#�z��ҨG��o�j�����\")+-��ڂ�*����Q�,���=�q���\^P {<mm��ݶ��@�wV���K��S�E�o�Kk���_Ҷ��tPlz�;���I��p��
%�"H�T���=��x
z�"S�$kܴش����K��k��%1�y{uwˑ��t�[�ET��<[������juW
���=�������J�\����Ѷ�J�J���\Ύ��=m�J��~��N��r�ښ�G��|���nO��vt�ȑ�dNo��U��S旦ý[�pb��O�!����ƩGT��!w�yU��GE�����k��&������b�-T��P���SO��N�S7���N�\�{�C�Tn>Ư+c�����~���'�tW�؞H|���;��ػ붆�ɂ��ߌ��>X׍��m�w���~���|����g��
w�W�Y��d������������������� �z ~�q��"**������‘/s�G#���S�!���qxW���u�́���Cm�j�^lz�,������
hU���}���~��2��"mX?�0�[��]�p�e��;���ze��o���sc�ûv�j�t�8�ؤ�������]{�����F4E�H*"\<`1�h�{���+��O��yY�߁#�'���~��)ķط�ׅ%m����v��ȳ�K��F��5���D�Ǐ�YB)�/c��^��s��
wܖD�����]�F	�;���`�3p�m�p�@�愶�%h)a-�B�П��S	��C��	h^��Vh[x~��К��o�
<bd�����D����>A���oL#s��>�D�!J�>��.�'��şK�%A�i���NH�)}��t�
�>Q�O�JY�짲��Z�G~^���mE�bX1���⇊�ElQ+�n�z��۟%��멜=�B���B���ӧB_D ��S
�.�%0>%�TzW�PzP�R��q�/��'�&��W���WPy��/Bۋ� �ƒK�	�F	W���R�i�Oì
}������Q��@�)=r}	�	})u�	��C��~!���B_&�M��rj\���WP�J�ѧ�cB��J��Q߃J�j�:*�T��Pi*Ee��RY�^|��a$�$ԉ,�M%�b��06G�ûy��=��oW��c�uvG<�NeR�Y�7�^L���x*�c�	vw|n>�aw�2���X��m0	�6�d&�C�0�~�����R"�۹o����:-�ͻl7N����PJ�@YxKg@6��Ja�+h��0�,Qk�X ��1�<~3�w6�y^��fG��a�)NL��`��g�0�M����p���e��<�̥SK�x8�ZX'㱌�N��c�@�Ѵ�X�PUDh7�������/E��7���T*{7]�A>�P,���g�x���,�s��������~�҄�y�
4��^J�u��ό���%s"D�,Y���`�B��=��]�(�������2�[�'4Ä���=�%c��>9/��b��8���𔀧Cdk,JV����V|�f5�7ssz��ě�9�7)b�X��X�0�:��bLk(#�a��(C�����=*�'ފmrX�����eBiC�Q��E�+dw�;<�_\+C�()�k(����ܕ�3A,�[=}��2M�� c1�>���#���uZ�ܻ{B�;���M_H��$��9�2y�_ ��z��
҄A�	���狷-�	<�1�՘�9�x,ː��9��ab�$p��!F}I�)mX{KB8���;-ț\K�x��%�J+ٛ��y�[5�!���Uy��*�*)�Fn~�{zR���B�`��s��s4#؟�WΧp��lI�ov=��=8A�&�s���2#D���躟�OY�_�̟!=LPae]�9��3dn>�-�q{�/Ģ�l*�.ebl<�.�Ss���B<9�ƒ���Tr!��\NF�d�4��#K�l8�e�e�A6YH%S��p��Kf1��b,��C�&I=2N�#YȒ�|�p���Lx!�.ǣ�j6?cS�(�]Y�-��xf5�>�y�ga��T*
dR�H��3R�p�07���'c��t:�YL%��C;
��@0�$؉x2�Z��<F��Dx�
'�ex�ē��%���<V�.���f"��M��Tzv���˂�$I�q<F7)!��ԛZJ�ci�	V9�,C�_H�� �B?�I����i!��X2
��NPVd"�X���Xr4�����%��I,A�n���4�Ľ��B,NdZ�|>�f��l�
D�?�������$dk0Of>��cB3 ?�5����[�,6��D*�����e����6�
g�1vf�=N�`�lО	�yG[��%�<��E(�j�Z&����[����B���E���8�n�/5��.���.//�r���P���q~�6�%��C��,A�4A���9�x�lx&?��R�^��|�]ɫS��8����G��Wr���@.�1(���P,���pQRje׫�e�W��;���o ���ǕE����r<-���ȸYn���OU��M2�]�?�U�6�~mP�Ȅ|���#�T��r�f��3
���%K�˕˜>/+_�$I~�QIy=�o�i�ߍ�k{�P
�H=|*Erp�[�����_W�g16T���'8��c�l{7���]�dq�X��G�����ш�:�BL/��0!� ����ީ$�^U���������w�L'`	�M�#<P����i��V�]��|I�aWH�D*��)��9ň�2^j)���"vg�3K,n�XmU-1.��%R���/BY��0`���lx)���3���;�	
endstream
endobj
63 0 obj
7274
endobj
61 0 obj
<< /Type /Font
/Subtype /CIDFontType2
/BaseFont /Consolas
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
/FontDescriptor 59 0 R
/CIDToGIDMap /Identity
/DW 545 >>
endobj
62 0 obj
<< /Length 742 >>
stream
/CIDInit /ProcSet findresource begin
12 dict begin
begincmap
/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def
/CMapName /Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000> <FFFF>
endcodespacerange
2 beginbfrange
<0000> <0000> <0000>
<0001> <0036> [<0069> <006F> <006E> <0063> <0075> <0062> <0065> <002E> <006C> <0061> <0064> <0072> <005F> <0070> <0074> <0068> <0073> <003A> <003B> <002B> <002D> <002F> <0076> <0077> <006D> <0052> <0053> <0020> <003D> <0022> <0066> <0067> <006B> <0031> <0024> <007B> <007D> <0032> <0034> <0030> <0079> <0078> <0037> <0033> <0045> <004E> <004F> <0054> <0049> <0043> <007C> <0044> <0050> <0041> ]
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

endstream
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /Consolas
/Encoding /Identity-H
/DescendantFonts [61 0 R]
/ToUnicode 62 0 R>>
endobj
2 0 obj
<<
/Type /Pages
/Kids 
[
5 0 R
19 0 R
28 0 R
34 0 R
]
/Count 4
/ProcSet [/PDF /Text /ImageB /ImageC]
>>
endobj
xref
0 64
0000000000 65535 f 
0000000009 00000 n 
0000038255 00000 n 
0000000187 00000 n 
0000000282 00000 n 
0000000756 00000 n 
0000029337 00000 n 
0000038121 00000 n 
0000000319 00000 n 
0000000362 00000 n 
0000000405 00000 n 
0000000449 00000 n 
0000000493 00000 n 
0000000530 00000 n 
0000000574 00000 n 
0000001080 00000 n 
0000007535 00000 n 
0000000877 00000 n 
0000001053 00000 n 
0000007863 00000 n 
0000007556 00000 n 
0000007600 00000 n 
0000007644 00000 n 
0000007688 00000 n 
0000008188 00000 n 
0000012626 00000 n 
0000007985 00000 n 
0000008161 00000 n 
0000012691 00000 n 
0000012647 00000 n 
0000013009 00000 n 
0000017982 00000 n 
0000012813 00000 n 
0000012989 00000 n 
0000020361 00000 n 
0000018003 00000 n 
0000018047 00000 n 
0000020194 00000 n 
0000020020 00000 n 
0000018298 00000 n 
0000018452 00000 n 
0000018591 00000 n 
0000018987 00000 n 
0000019859 00000 n 
0000018784 00000 n 
0000019263 00000 n 
0000019391 00000 n 
0000019554 00000 n 
0000019723 00000 n 
0000020257 00000 n 
0000020679 00000 n 
0000022336 00000 n 
0000020483 00000 n 
0000020659 00000 n 
0000022357 00000 n 
0000022621 00000 n 
0000027977 00000 n 
0000028459 00000 n 
0000027956 00000 n 
0000029477 00000 n 
0000029735 00000 n 
0000037122 00000 n 
0000037327 00000 n 
0000037101 00000 n 
trailer
<<
/Size 64
/Info 1 0 R
/Root 49 0 R
>>
startxref
38374
%%EOF
alt-php84-ioncube-loader/LICENSE.txt000064400000025020150536261270013004 0ustar00LICENCE AGREEMENT FOR THE IONCUBE PHP LOADER, PROVIDED TO ENABLE THE USE
OF IONCUBE ENCODED FILES AND AS PART OF THE IONCUBE24 SERVICE (ioncube24.com)

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING THE
LOADER SOFTWARE. THE INSTALLATION AND/OR USE OR COPYING OF THE IONCUBE PHP
LOADER SOFTWARE INDICATES YOUR ACCEPTANCE OF THIS LICENCE AGREEMENT.  IF YOU
DO NOT ACCEPT THE TERMS OF THIS LICENCE AGREEMENT, DO NOT INSTALL, COPY
AND/OR USE THE LOADER SOFTWARE.

DEFINITIONS

The following definitions shall apply in this document:

LOADER shall mean the ionCube PHP Loader software package or collection 
of Loaders, including any modifications or upgrades to the software, used for
executing PHP scripts previously encoded with the ionCube PHP Encoder
software to render them non-humanly readable, and any associated
documentation or electronic or online materials relating to the software.

ENCODER shall mean any ionCube PHP Encoder software or service used for the
purpose of producing non-humanly readable encoded files from PHP scripts.

ENCODED FILE shall mean a non-humanly readable file produced by the 
Encoder and being derived from humanly readable PHP script source.

PROVIDER shall mean ionCube Ltd.

USER/YOU shall mean any entity who has downloaded or obtained through any
other means a version of the Loader software.


1 LICENSE ENTITLEMENT 

1.1 The Loader is provided without charge.  Title to the Loader does not pass
to the user in any circumstances.  The Loader is supplied as object code.

1.2 The provider grants a personal, non-transferable, non-exclusive licence to
use the Loader in accordance with the terms and conditions of this Licence
Agreement.

1.3 The installation or downloading and use of the Loader entitles the user
to install and use the Loader for its own internal lawful purposes.


2 DISTRIBUTION 

2.1 The Loader may be freely distributed to third parties alone or as 
part of a distribution containing other items provided that this license
is also included. 

2.2 The Loader may under no circumstances be branded as another product, 
whether distributed or not. 

2.3 Distribution as part of a commercial product is permitted provided such
distribution is in accordance with clauses 2.1 and 2.2 with respect to the 
Loader.


3 ANALYSIS / REVERSE ENGINEERING / MODIFICATION 

Except insofar as the user is permitted to do so in accordance with applicable
law:

3.1 Any analysis of the Loader and embedded data by any means and by
any entity whether human or otherwise and including but without limitation to
discover details of internal operation, to reverse engineer, to de-compile
object code, or to modify for the purposes of modifying behaviour is
forbidden.

3.2 Any analysis of encoded files by any means and by any entity whether human
or otherwise and including but without limitation to discover details of file
format or for the purposes of modifying behaviour or scope of their usage is
forbidden.


4 WARRANTY

THE LOADER SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
WARRANTIES INCLUDING BUT WITHOUT LIMITATION THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE ARE
DISCLAIMED. THE PROVIDER DOES NOT WARRANT THAT THE LOADER IS UNINTERRUPTED
OR ERROR FREE, NOR THAT THE OPERATION OF THE LOADER WILL FUNCTION IN
CONJUNCTION WITH ANY OTHER PRODUCT.  


5 LIMITATION OF LIABILITY 

5.1 IN NO EVENT WILL THE PROVIDER OF THE LOADER BE LIABLE TO THE USER OR ANY
PARTY FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR OTHER
CONSEQUENTIAL DAMAGES ARISING DIRECTLY OR INDIRECTLY FROM THIS LICENCE
AGREEMENT OR ANY USE OF THE LOADER OR ENCODED FILES, EVEN IF THE PROVIDER IS
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

5.2 THE LOADER IS PROVIDED ON AN "AS IS" BASIS.  THE PROVIDER EXCLUDES ALL
WARRANTIES, CONDITIONS, TERMS, UNDERTAKINGS AND REPRESENTATIONS (EXCLUDING
FRAUDULENT MISREPRESENTATION) OF ANY KIND, EXPRESS OR IMPLIED, STATUTORY OR
OTHERWISE IN CONNECTION WITH THE LOADER TO THE FULLEST EXTENT PERMITTED BY
LAW.

5.3 DOWNLOADING THE LOADER IS AT YOUR OWN RISK AND THE PROVIDER DOES NOT
ACCEPT LIABILITY FOR ANY DIRECT OR INDIRECT LOSS OR DAMAGE HOWSOEVER CAUSED AS
A RESULT OF ANY COMPUTER VIRUSES, BUGS, TROJAN HORSES, WORMS, SOFTWARE BOMBS
OR OTHER SIMILAR PROGRAMS ARISING FROM YOUR USE OF THE LOADER.  WHILST THE
PROVIDER WILL DO ITS BEST TO ENSURE THAT THE LOADER IS FREE FROM SUCH
DESTRUCTIVE PROGRAMS, IT IS YOUR RESPONSIBILITY TO TAKE REASONABLE PRECAUTIONS
TO SCAN FOR SUCH DESTRUCTIVE PROGRAMS DOWNLOADED FROM THE INTERNET.

5.4 THE PROVIDER'S MAXIMUM LIABILITY FOR ANY LOSS OR DAMAGE ARISING FROM THIS
LICENCE AGREEMENT SHALL IN ANY EVENT BE LIMITED IN THE SOLE DISCRETION OF THE
PROVIDER TO THE REPLACEMENT OF THE LOADER PRODUCT.

5.5 DUE TO THE NATURE OF THE INTERNET, THE PROVIDER CANNOT GUARANTEE THAT ANY
E-MAILS OR OTHER ELECTRONIC TRANSMISSIONS WILL BE SENT TO YOU OR RECEIVED BY
THE PROVIDER OR THAT THE CONTENT OF SUCH TRANSMISSIONS WILL BE SECURE DURING
TRANSMISSION.


6 BUG FIXING AND PRODUCT SUPPORT 

6.1 The provider will use reasonable endeavours to provide support to users.
The provider will at their discretion only provide support for the latest
release.

6.2 Support comprises of fault reporting via tickets and fault diagnosis,
recommendations on workarounds, and where reasonably possible a timely
resolution.

6.3 The user accepts that on occasion the ability of the provider to meet
anticipated or published support schedules may be impaired due to, but without
limitation, Internet service provider failures or software failures that
affect the ability to communicate for an indeterminate period.

6.4 The provider reserves the right to refuse to provide support at any time.

6.5 The provider wishes to maintain and offer a product of the highest
possible quality, and accordingly may from time to time and at its discretion
make product changes for the purpose of correcting behaviour in variance to
the published specification or the user's reasonable expectations. 

6.6 The provider reserves the right to charge for support where the user does
not have a valid support plan in place, or where the support offered exceeds
the scope of the active support plan.


7 PRODUCT UPGRADES

7.1 The provider may from time to time release product upgrades. These will
be provided free of charge and attempts made to provide a timely notification
to customers of the existence of any new release.


8 ERRORS AND OMISSIONS

Whilst reasonable endeavours are made to ensure the accuracy of documentation
concerning the details of the Loader, the user accepts the possibility of
inaccuracies in information presented in any format, including email
communications and online services. The provider shall under no circumstances
be liable for any events that arise as a result of unintentional inaccuracies
or omissions.


9 USER INDEMNITY

You agree to fully indemnify, defend and hold the provider harmless
immediately upon demand from and against all actions, liability, claims,
losses, damages, costs and expenses (including legal/attorney fees) incurred
by the provider arising directly or indirectly as a result of your breach of
this Licence Agreement.


10 INTELLECTUAL PROPERTY RIGHTS

10.1 The user acknowledges that the Loader and associated documentation and
materials contain proprietary information of the provider and are and shall
remain the exclusive property of the provider and/or its licensors and all
title, copyright, trade marks, trade names, patents and other intellectual
property rights therein of whatever nature shall remain the sole property of
the provider and/or its licensors.

10.2 No title to or rights of ownership, copyright or other intellectual
property in the Loader is transferred to the user (other than the licence
rights expressly granted in this Licence Agreement).


11 TERMINATION

11.1 The provider reserves the right to terminate this Licence Agreement
immediately by notice in writing against the user if the user is in breach of
any terms and conditions of this Licence Agreement.

11.2 Termination of this Licence Agreement for any reason shall be without
prejudice to any other rights or remedies of the provider which may have
arisen on or before the date of termination under this Licence Agreement or in
law.

11.3 The provisions of the following clauses shall survive any termination of
this agreement; clause 3, 5, 10 and 13.


12 GENERAL

12.1 The provider reserves the right to transfer or assign all or any of its
rights and duties and responsibilities set out in this Licence Agreement to
another party.

12.2 Headings have been included for convenience only and will not be used in
construing any provision of this Licence Agreement.

12.3 No delay or failure by the provider to exercise any powers, rights or
remedies under this Licence Agreement will operate as a waiver of them nor
will any single or partial exercise of any such powers, rights or remedies
include any other or further exercise of them.

12.4 If any part of this Licence Agreement is found by a court of competent
jurisdiction or other competent authority to be invalid, unlawful or
unenforceable then such part shall be severed from the remainder of this
Licence Agreement which will continue to be valid and enforceable to the
fullest extent permitted by applicable law.

12.5 This Licence Agreement including the documents or other sources referred
to herein supersede all prior representations, understandings and agreements
between the user and the provider relating to the Loader and sets forth the
entire agreement and understanding between the user and the provider relating
to the Loader.

12.6 Nothing in this Licence Agreement shall be deemed to constitute a
partnership between you and the provider nor constitute either party being an
agent of the other party.

12.7 This Agreement does not create any rights or benefits enforceable by any
person not a party to it (within the meaning of the U.K.Contracts (Rights of
Third Parties) Act 1999) except that a person who under clause 12.1 is a
permitted successor or assignee of the rights or benefits of the provider may
enforce such rights or benefits.


13 GOVERNING LAW AND JURISDICTION

This License Agreement and any issues relating thereto shall be construed and
interpreted in accordance with the laws of England and subject to the
exclusive jurisdiction of the English courts.

Copyright (c) 2002-2024 ionCube Ltd.          Last revised 23-April-2015
alt-php84-ioncube-loader/loader-wizard.php000064400000541746150536261270014460 0ustar00<?php // -*- c++ -*-

/** 
 * ionCube Loader install Wizard
 *
 * ionCube is a registered trademark of ionCube Ltd. 
 *
 * Copyright (c) ionCube Ltd. 2002-2022
 */


 

define ('ERROR_UNKNOWN_OS',1);
define ('ERROR_UNSUPPORTED_OS',2);
define ('ERROR_UNKNOWN_ARCH',3);
define ('ERROR_UNSUPPORTED_ARCH',4);
define ('ERROR_UNSUPPORTED_ARCH_OS',5);
define ('ERROR_WINDOWS_64_BIT',6);
define ('ERROR_PHP_UNSUPPORTED',7);
define ('ERROR_PHP_DEBUG_BUILD',8);
define ('ERROR_RUNTIME_EXT_DIR_NOT_FOUND',101);
define ('ERROR_RUNTIME_LOADER_FILE_NOT_FOUND',102);
define ('ERROR_INI_NOT_FIRST_ZE',201);
define ('ERROR_INI_WRONG_ZE_START',202);
define ('ERROR_INI_ZE_LINE_NOT_FOUND',203);
define ('ERROR_INI_LOADER_FILE_NOT_FOUND',204);
define ('ERROR_INI_NOT_FULL_PATH',205);
define ('ERROR_INI_NO_PATH',206);
define ('ERROR_INI_NOT_FOUND',207);
define ('ERROR_INI_NOT_READABLE',208);
define ('ERROR_INI_MULTIPLE_IC_LOADER_LINES',209);
define ('ERROR_INI_USER_INI_NOT_FOUND',210);
define ('ERROR_INI_USER_CANNOT_CREATE',211);
define ('ERROR_LOADER_UNEXPECTED_NAME',301);
define ('ERROR_LOADER_NOT_READABLE',302);
define ('ERROR_LOADER_PHP_MISMATCH',303);
define ('ERROR_LOADER_NONTS_PHP_TS',304);
define ('ERROR_LOADER_TS_PHP_NONTS',305);
define ('ERROR_LOADER_WRONG_OS',306);
define ('ERROR_LOADER_WRONG_ARCH',307);
define ('ERROR_LOADER_WRONG_GENERAL',308);
define ('ERROR_LOADER_WIN_SERVER_NONWIN',321);
define ('ERROR_LOADER_WIN_NONTS_PHP_TS',322);
define ('ERROR_LOADER_WIN_TS_PHP_NONTS',323);
define ('ERROR_LOADER_WIN_PHP_MISMATCH',324);
define ('ERROR_LOADER_WIN_COMPILER_MISMATCH',325);
define ('ERROR_LOADER_NOT_FOUND',380);
define ('ERROR_LOADER_PHP_VERSION_UNKNOWN',390);


define ('SERVER_UNKNOWN',0);
define ('HAS_PHP_INI',1);
define ('SERVER_SHARED',2); 
define ('SERVER_VPS',5); 
define ('SERVER_DEDICATED',7); 
define ('SERVER_LOCAL',9);

define ('IONCUBE_IP_ADDRESS',
			'94.101.154.134');
define  ('IONCUBE_ACCESS_ADDRESS',
			'lwaccess.ioncube.com');
define ('LOADERS_PAGE',
            'https://loaders.ioncube.com/'); 
define ('SUPPORT_SITE',
            'https://support.ioncube.com/');                                 
define ('WIZARD_SUPPORT_TICKET_DEPARTMENT',
			'3');
define ('LOADER_FORUM_URL',
            'https://forum.ioncube.com/viewforum.php?f=4');                  
define ('LOADERS_FAQ_URL',
            'https://www.ioncube.com/faqs/loaders.php');                     
define ('UNIX_ERRORS_URL',
            'https://www.ioncube.com/loaders/unix_startup_errors.php');      
define ('LOADER_WIZARD_URL',
            LOADERS_PAGE);                                                  
define ('ENCODER_URL',
            'https://www.ioncube.com/sa_encoder.php');                       
define ('LOADER_VERSION_URL',
            'https://www.ioncube.com/feeds/product_info/versions.php');    
define ('WIZARD_LATEST_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-wizard'); 
define ('PHP_COMPILERS_URL',
            LOADER_VERSION_URL . '?item=php-compilers');
define ('LOADER_PLATFORM_URL',
            LOADER_VERSION_URL . '?item=loader-platforms-all');   
define ('LOADER_LATEST_VERSIONS_URL',
            LOADER_VERSION_URL . '?item=loader-versions'); 
define ('LOADER_PHP_VERSION_URL',
            LOADER_VERSION_URL . '?item=loader-php-support'); 
define ('WIZARD_STATS_URL',
            'https://www.ioncube.com/feeds/stats/wizard.php');    
define ('IONCUBE_DOWNLOADS_SERVER',
            'https://downloads.ioncube.com/loader_downloads');          
define ('IONCUBE24_URL',
			'https://ioncube24.com');
define ('IONCUBE_CONNECT_TIMEOUT',4);

define ('DEFAULT_SELF','/ioncube/loader-wizard.php');
define ('LOADER_NAME_CHECK',true);
define ('LOADER_EXTENSION_NAME','ionCube Loader');
define ('LOADER_SUBDIR','ioncube');
define ('WINDOWS_IIS_LOADER_DIR', 'system32');
define ('ADDITIONAL_INI_FILE_NAME','00-ioncube.ini');
define ('UNIX_SYSTEM_LOADER_DIR','/usr/local/ioncube');
define ('RECENT_LOADER_VERSION','4.0.7');
define ('LATEST_LOADER_MAJOR_VERSION',12);
define ('LOADERS_PACKAGE_PREFIX','ioncube_loaders_');
define ('SESSION_LIFETIME_MINUTES',360);
define ('WIZARD_EXPIRY_MINUTES',2880);
define ('IONCUBE_WIZARD_EXPIRY_MINUTES',10080);
define ('MIN_INITIALISE_TIME',4);
define ('IC24_ENABLED_INI_PROPERTY',"ic24.enable");

    run();


function php4_http_build_query($formdata, $numeric_prefix = null, $key = null ) {
    $res = array();
    foreach ((array)$formdata as $k=>$v) {
        $tmp_key = urlencode(is_int($k) ? $numeric_prefix.$k : $k);
        if ($key) $tmp_key = $key.'['.$tmp_key.']';
        if ( is_array($v) || is_object($v) ) {
            $res[] = php4_http_build_query($v, null , $tmp_key);
        } else {
            $res[] = $tmp_key."=".urlencode($v);
        }
   }
   $separator = ini_get('arg_separator.output');
   return implode($separator, $res);
}


function script_version()
{
    return "2.73";
}

function retrieve_latest_wizard_version()
{
    $v = false;

    $s = trim(remote_file_contents(WIZARD_LATEST_VERSION_URL));
    if (preg_match('/^\d+([.]\d+)*$/', $s)) {
        $v = $s;
    }

    return $v;
}

function latest_wizard_version()
{
    if (!isset($_SESSION['latest_wizard_version'])) {
        $_SESSION['latest_wizard_version'] = retrieve_latest_wizard_version();
    } 
    return $_SESSION['latest_wizard_version'];
}

function update_is_available($lv)
{
    if (is_numeric($lv)) {
        $lv_parts = explode('.',$lv);
        $script_parts = explode('.',script_version());
        return ($lv_parts[0] > $script_parts[0] || ($lv_parts[0] == $script_parts[0] && $lv_parts[1] > $script_parts[1]));
    } else {
        return null;
    }
}

function check_for_wizard_update($echo_message = false)
{
    $latest_version = latest_wizard_version();
    $update_available = update_is_available($latest_version);

    if ($update_available) {
        if ($echo_message) {
            echo '<p class="alert">An updated version of this Wizard script is available <a href="' . LOADER_WIZARD_URL . '">here</a>.</p>';
        }
        return $latest_version;
    } else {
        return $update_available;
    }
}


function remote_file_contents($url)
{
    $remote_file_opening = ini_get('allow_url_fopen');
    $contents = false;
    if (isset($_SESSION['timing_out']) && $_SESSION['timing_out']) {
        return false;
    }
    @session_write_close();
    $timing_out = 0;
    if ($remote_file_opening) {
        $fh = @fopen($url,'rb');
        if ($fh) {
            stream_set_blocking($fh,0);
            stream_set_timeout($fh,IONCUBE_CONNECT_TIMEOUT);
            while (!feof($fh)) {
                $result = fread($fh, 8192);
                $info = stream_get_meta_data($fh);
                $timing_out = $info['timed_out']?1:0;
                if ($timing_out) {
                    break;
                }
                if ($result !== false) {
                    $contents .= $result;
                } else {
                    break;
                }
            }
            fclose($fh);
        } else {
            $timing_out = 1;
        }
    } elseif (extension_loaded('curl')) {
            $ch = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,IONCUBE_CONNECT_TIMEOUT);
            $output = curl_exec($ch);
            $info = curl_getinfo($ch);
            $timing_out = ($info['http_code'] >= 400)?1:0;
            curl_close($ch);

            if (is_string($output)) {
                $contents = $output;
            }
    } else {
        $timing_out = 1;
    }
    @session_start();
    $_SESSION['timing_out'] = $timing_out;
    return $contents;
}

function php_version()
{
    $v = explode('.',PHP_VERSION);

    return array(
           'major'      =>  $v[0],
           'minor'      =>  $v[1],
           'release'    =>  $v[2]);
}

function php_version_maj_min()
{
    $vprts = php_version();
    return ($vprts['major'] . '.' . $vprts['minor']);
}

function is_supported_php_version()
{
    $v = php_version(); 

    return ((($v['major'] == 4) && ($v['minor'] >= 1)) ||
      (($v['major'] == 5) && (($v['minor'] >= 1) || ($v['release'] >= 3))) ||
	  $v['major'] == 7 || ($v['major'] == 8 && $v['minor'] >= 1));
}

function is_php_version_or_greater($major,$minor,$release = 0)
{
    $version = php_version();
    return ($version['major'] > $major || 
            ($version['major'] == $major && $version['minor'] > $minor) ||
            ($version['major'] == $major && $version['minor'] == $minor && $version['release'] >= $release));
}

function ini_file_name()
{
    $sysinfo = get_sysinfo();
    return (!empty($sysinfo['PHP_INI'])?$sysinfo['PHP_INI_BASENAME']:'php.ini');
}

function get_remote_session_value($session_var,$remote_url,$default_function)
{
    if (!isset($_SESSION[$session_var])) {
        $serialised_res = remote_file_contents($remote_url);
        $unserialised_res = @unserialize($serialised_res);
        if (empty($unserialised_res)) {
            $unserialised_res = call_user_func($default_function);
        } else {
			$_SESSION['remote_access_successful'] = 1;
		}
        if (false === $unserialised_res) {
            $unserialised_res = '';
        }
        $_SESSION[$session_var] = $unserialised_res;
    }
    return $_SESSION[$session_var];
}

function get_file_contents($file)
{
    if (function_exists('file_get_contents')) {
        $strs = @file_get_contents($file);
    } else {
        $lines = @file($file);
        $strs = join(' ',$lines);
    }
    return $strs;
}

function default_platform_list()
{
    $platforms = array();


    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6', 'is_legacy' => 1,       'os_mod' => '_vc6',     'arch'=>'x86',  'dirname'=>'win32', 'us1-dir'=>'windows_vc6/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC6 (Non-TS)',   'is_legacy' => 1,  'os_mod' => '_nonts_vc6',   'arch'=>'x86',  'dirname'=>'win32-nonts', 'us1-dir'=>'windows_vc6/x86-nonts' );

    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9',        'os_mod' => '_vc9',     'arch'=>'x86',  'dirname'=>'win32_vc9', 'us1-dir'=>'windows_vc9/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC9 (Non-TS)',   'os_mod' => '_nonts_vc9',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc9', 'us1-dir'=>'windows_vc9/x86-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86',  'dirname'=>'win32_vc11', 'us1-dir'=>'windows_vc11/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc11', 'us1-dir'=>'windows_vc11/x86-nonts' );
	
	$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11',        'os_mod' => '_vc11',     'arch'=>'x86-64',  'dirname'=>'win64_vc11', 'us1-dir'=>'windows_vc11/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC11 (Non-TS)',   'os_mod' => '_nonts_vc11',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc11', 'us1-dir'=>'windows_vc11/amd64-nonts' );
	
	 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86',  'dirname'=>'win32_vc14', 'us1-dir'=>'windows_vc14/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc14', 'us1-dir'=>'windows_vc14/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14',        'os_mod' => '_vc14',     'arch'=>'x86-64',  'dirname'=>'win64_vc14', 'us1-dir'=>'windows_vc14/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC14 (Non-TS)',   'os_mod' => '_nonts_vc14',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc14', 'us1-dir'=>'windows_vc14/amd64-nonts' );
	
		 $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86',  'dirname'=>'win32_vc15', 'us1-dir'=>'windows_vc15/x86' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86',  'dirname'=>'win32-nonts_vc15', 'us1-dir'=>'windows_vc15/x86-nonts' );
	
		$platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15',        'os_mod' => '_vc15',     'arch'=>'x86-64',  'dirname'=>'win64_vc15', 'us1-dir'=>'windows_vc15/amd64' );
    $platforms[] = array('os'=>'win', 'os_human'=>'Windows VC15 (Non-TS)',   'os_mod' => '_nonts_vc15',   'arch'=>'x86-64',  'dirname'=>'win64-nonts_vc15', 'us1-dir'=>'windows_vc15/amd64-nonts' );

    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86',      'dirname'=>'linux_i686-glibc2.3.4', 'us1-dir'=>'linux/x86');
    $platforms[] = array('os'=>'lin', 'os_human'=>'Linux',              'arch'=>'x86-64',   'dirname'=>'linux_x86_64-glibc2.3.4', 'us1-dir'=>'linux/x86_64');
$platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc',      'dirname'=>'linux_ppc-glibc2.3.4','us1-dir'=>'linux/ppc');
            $platforms[] = array('os'=>'lin','os_human'=>'Linux',               'arch'=>'ppc64',    'dirname'=>'linux_ppc64-glibc2.5','us1-dir'=>'linux/ppc64');
    

$platforms[] = array('os'=>'dra', 'os_human'=>'DragonFly', 'arch'=>'x86',      'dirname'=>'dragonfly_i386-1.7', 'us1-dir'=>'Dragonfly/x86');

$platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 4', 'os_mod'=>'_4',  'arch'=>'x86',      'dirname'=>'freebsd_i386-4.8', 'us1-dir'=>'FreeBSD/v4');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86',      'dirname'=>'freebsd_i386-6.2', 'us1-dir'=>'FreeBSD/v6/x86');

    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 6', 'os_mod'=>'_6',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-6.2', 'us1-dir'=>'FreeBSD/v6/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86',      'dirname'=>'freebsd_i386-7.3', 'us1-dir'=>'FreeBSD/v7/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 7', 'os_mod'=>'_7',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-7.3', 'us1-dir'=>'FreeBSD/v7/AMD64');


    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86',      'dirname'=>'freebsd_i386-8.0', 'us1-dir'=>'FreeBSD/v8/x86');
    $platforms[] = array('os'=>'fre', 'os_human'=>'FreeBSD 8', 'os_mod'=>'_8',  'arch'=>'x86-64',   'dirname'=>'freebsd_amd64-8.0', 'us1-dir'=>'FreeBSD/v8/AMD64');
    
    $platforms[] = array('os'=>'bsd', 'os_human'=>'BSDi',     'is_legacy' => 1,           'arch'=>'x86',      'dirname'=>'bsdi_i386-4.3.1');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86',      'dirname'=>'netbsd_i386-2.1','us1-dir'=>'NetBSD/x86');
    $platforms[] = array('os'=>'net', 'os_human'=>'NetBSD',             'arch'=>'x86-64',   'dirname'=>'netbsd_amd64-2.0','us1-dir'=>'NetBSD/x86_64');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.2', 'os_mod'=>'_4.2',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.2', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.5', 'os_mod'=>'_4.5',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.5', 'us1-dir'=>'OpenBSD/x86');
    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.6', 'os_mod'=>'_4.6',  'arch'=>'x86',  'dirname'=>'openbsd_i386-4.6', 'us1-dir'=>'OpenBSD/x86');

    $platforms[] = array('os'=>'ope', 'os_human'=>'OpenBSD 4.7', 'os_mod'=>'_4.7',  'arch'=>'x86-64', 'dirname'=>'openbsd_amd64-4.7', 'us1-dir' => 'OpenBSD/x86_64');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',    'is_legacy' => 1, 'arch'=>'ppc',      'dirname'=>'osx_powerpc-8.5','us1-dir'=>'OSX/ppc');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86',      'dirname'=>'osx_i386-8.11','us1-dir'=>'OSX/x86');

    $platforms[] = array('os'=>'dar', 'os_human'=>'OS X',               'arch'=>'x86-64',       'dirname'=>'osx_x86-64-10.2','us1-dir'=>'OSX/x86_64');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',  'is_legacy' => 1,          'arch'=>'sparc',    'dirname'=>'solaris_sparc-5.9', 'us1-dir'=>'Solaris/sparc');

    $platforms[] = array('os'=>'sun', 'os_human'=>'Solaris',            'arch'=>'x86',      'dirname'=>'solaris_i386-5.10','us1-dir'=>'Solaris/x86');

    return $platforms;
}

function get_loader_platforms()
{
    return get_remote_session_value('loader_platform_info',LOADER_PLATFORM_URL,'default_platform_list');
}

function get_platforminfo()
{
    static $platforminfo;

    if (empty($platforminfo)) {
        $platforminfo = get_loader_platforms();
    }
    return $platforminfo;
}

function default_php_versions()
{
	return array();
}

function get_php_versions()
{
	return get_remote_session_value('php_version_info',LOADER_PHP_VERSION_URL,'default_php_versions');
}


function get_max_php_version_supported()
{
	static $max_php_version;
	
	if (empty($max_php_version)) {
		$php_versions = get_php_versions();
		
		$dirname = calc_dirname();
		
		if (array_key_exists($dirname,$php_versions)) {
			$max_php_version = $php_versions[$dirname];
		} else {
			$max_php_version = NULL;
		}
	}
	
	return $max_php_version;
}

function is_after_max_php_version_supported()
{
	$is_too_recent_php = false;
	
	$supported_php_version = get_max_php_version_supported();
	
	if (!is_null($supported_php_version)) {
		$pversion = php_version();
		
		$supported_parts = explode('.',$supported_php_version);
		$is_too_recent_php = ($supported_parts[0] < $pversion['major'] || ($supported_parts[0] == $pversion['major'] && $supported_parts[1] < $pversion['minor']));
	}
	
	if ($is_too_recent_php) {
		return $supported_php_version;
	} else {
		return false;
	}
}

function supported_os_variants($os_code,$arch_code)
{
    if (empty($os_code)) {
        return ERROR_UNKNOWN_OS;
    }
    if (empty($arch_code)) {
        return ERROR_UNKNOWN_ARCH;
    }

    $os_found = false;
    $arch_found = false;
    $os_arch_matches = array();
    $pinfo = get_platforminfo();

    foreach ($pinfo as $p) {
        if ($p['os'] == $os_code && $p['arch'] == $arch_code) {
            $os_arch_matches[$p['os_human']] = (isset($p['os_mod']))?(0 + (int) str_replace('_','',$p['os_mod'])):'';
        } 
        if ($p['os'] == $os_code) {
            $os_found = true;
        } elseif ($p['arch'] == $arch_code) {
            $arch_found = true;
        }
    }
    if (!empty($os_arch_matches)) {
        asort($os_arch_matches);
        return $os_arch_matches;
    } elseif (!$os_found) {
        return ERROR_UNSUPPORTED_OS;
    } elseif (!$arch_found) {
        return ERROR_UNSUPPORTED_ARCH;
    } else {
        return ERROR_UNSUPPORTED_ARCH_OS;
    }
}

function default_win_compilers()
{
    return array('VC6','VC9','VC11','VC14','VC15', 'VC16');
}

function supported_win_compilers()
{
    static $win_compilers;

    if (empty($win_compilers)) {
        $win_compilers = find_win_compilers();
    }
    return $win_compilers;
}

function find_win_compilers()
{
    return get_remote_session_value('php_compilers_info',PHP_COMPILERS_URL,'default_win_compilers');
}

function server_software_info()
{
    $ss = array('full' => '','short' => '');
    $ss['full'] = $_SERVER['SERVER_SOFTWARE'];

    if (preg_match('/apache/i', $ss['full'])) {
        $ss['short'] = 'Apache';
    } else if (preg_match('/IIS/',$ss['full'])) {
        $ss['short'] = 'IIS';
    } else {
        $ss['short'] = '';
    }
    return $ss;
}

function match_arch_pattern($str)
{
    $arch = null;
    $arch_patterns = array(
             'i.?86'        => 'x86',
             'x86[-_]64'    => 'x86',
             'x86'          => 'x86',
             'amd64'        => 'x86',
             'SMP Tue Jan 01 00:00:00 CEST 2000 all GNU\/Linux' => 'x86',
             'ppc64'        => 'ppc',
             'ppc'          => 'ppc',
             'powerpc'      => 'ppc',
             'sparc'        => 'sparc',
             'sun'          => 'sparc',
			 'armv7l'       => 'armv7l',
             'aarch64'      => 'aarch64'
         );

    foreach ($arch_patterns as $token => $a) {
        if (preg_match("/$token/i", $str)) {
          $arch = $a;
          break;
        }
    }
    return $arch;
}

function required_loader_arch($mach_info,$os_code,$wordsize)
{
    if ($os_code == 'win') {
        $arch = ($wordsize == 32)?'x86':'x86-64';
    } elseif (!empty($os_code)) {
        $arch = match_arch_pattern($mach_info);
        if ($wordsize == 64) {
            if ($arch == 'x86') {
                $arch = 'x86-64';
            } elseif ($arch == 'ppc') {
                $arch = 'ppc64';
            }
        }
    } else {
        $arch = ERROR_UNKNOWN_ARCH;
    }
    return $arch;
}

function uname($part = 'a')
{
    $result = '';
    if (!function_is_disabled('php_uname')) {
        $result = @php_uname($part);
    } elseif (function_exists('posix_uname') && !function_is_disabled('posix_uname')) {
        $posix_equivs = array(
                     'm' => 'machine',
                     'n' => 'nodename',
                     'r' => 'release',
                     's' => 'sysname'
                 );
        $puname = @posix_uname();
        if ($part == 'a' || !array_key_exists($part,$posix_equivs)) {
           $result = join(' ',$puname);
        } else {
           $result = $puname[$posix_equivs[$part]];
        }
    } else {
        if (!function_is_disabled('phpinfo')) {
            ob_start();
            phpinfo(INFO_GENERAL);
            $pinfo = ob_get_contents();
            ob_end_clean();
            if (preg_match('~System.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$match)) {
                $uname = $match[2];
                if ($part == 'r') {
                    if (!empty($uname) && preg_match('/\S+\s+\S+\s+([0-9.]+)/',$uname,$matchver)) {
                        $result = $matchver[1];
                    } else {
                        $result = '';
                    }
                } else {
                    $result = $uname;
                }
            }
        } else {
            $result = '';
        }
    }
    return $result;
}

function calc_word_size($os_code)
{
    $wordsize = null;
    if ('win' === $os_code) {
        ob_start();
        phpinfo(INFO_GENERAL);
        $pinfo = ob_get_contents();
        ob_end_clean();
        if (preg_match('~Compiler.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$compmatch)) {
            if (preg_match("/(VC[0-9]+)/i",$compmatch[2],$vcmatch)) {
                $compiler = strtoupper($vcmatch[1]);
            } elseif (stripos(trim($compmatch[2]),"Visual C++ 2019") === 0) {
                $compiler = 'VC16';
            } else {
                $compiler = 'VC6';
            }
        } else {
            $compiler = 'VC6';
        }
        if ($compiler === 'VC9' || $compiler === 'VC11' || $compiler === 'VC14' 
                || $compiler === 'VC15' || $compiler === 'VC16') {
			if (preg_match('~Architecture.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$archmatch)) {
				if (preg_match("/x64/i",$archmatch[2])) {
					$wordsize = 64;
				} else {
					$wordsize = 32;
				}
            } elseif (isset($_ENV['PROCESSOR_ARCHITECTURE']) && preg_match('~(amd64|x86-64|x86_64)~i',$_ENV['PROCESSOR_ARCHITECTURE'])) {
                if (preg_match('~Configure Command.*?(</B></td><TD ALIGN="left">| => |v">)([^<]*)~i',$pinfo,$confmatch)) {
                    if (preg_match('~(x64|lib64|system64)~i',$confmatch[2])) {
                        $wordsize = 64;
                    }
                }
            } else {
				$wordsize = 32;
			}
        }
    }
    if (empty($wordsize)) {
        $wordsize = ((-1^0xffffffff)?64:32);
    }
    return $wordsize;
}

function required_loader($unamestr = '')
{
    $un = empty($unamestr)?uname():$unamestr;

    $php_major_version = substr(PHP_VERSION,0,3);

    $os_name = substr($un,0,strpos($un,' '));
    $os_code = empty($os_name)?'':strtolower(substr($os_name,0,3));

    $wordsize = calc_word_size($os_code);

	if ($os_code == 'win' && $wordsize == 64 && $php_major_version < '5.5') {
        $arch = ERROR_WINDOWS_64_BIT;
	} else {
		$arch = required_loader_arch($un,$os_code,$wordsize);
	}
    if (!is_string($arch)) {
        return $arch;
    }
    $os_variants = supported_os_variants($os_code,$arch);
    if (!is_array($os_variants)) {
        return $os_variants;
    }

    $os_ver = '';
    if (preg_match('/([0-9.]+)/',uname('r'),$match)) {
        $os_ver = $match[1];
    }
    $os_ver_parts = preg_split('@\.@',$os_ver);

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $loader_sfix = (($os_code == 'win') ? 'dll' : 'so');
    $file = "ioncube_loader_{$os_code_h}_{$php_major_version}.{$loader_sfix}";

    if ($os_code == 'win') {
        $os_name = 'Windows';
        $file_ts = $file;
        $os_name_qual = 'Windows';
    } else {
        $os_names = array_keys($os_variants);
        if (count($os_variants) > 1) {
            $parts = explode(" ",$os_names[0]); 
            $os_name = $parts[0];
            $os_name_qual = $os_name . ' ' . $os_ver_parts[0] . '.' . $os_ver_parts[1];
        } else {
            $os_name = $os_names[0];
            $os_name_qual = $os_name;
        }
        $file_ts = "ioncube_loader_{$os_code_h}_{$php_major_version}_ts.{$loader_sfix}";
    }

    return array(
           'uname'      =>  $un,
           'arch'       =>  $arch,
           'oscode'     =>  $os_code,
           'oscode_h'   =>  $os_code_h,
           'osname'     =>  $os_name,
           'osnamequal' =>  $os_name_qual,
           'osvariants' =>  $os_variants,
           'osver'      =>  $os_ver,
           'osver2'     =>  $os_ver_parts,
           'file'       =>  $file,
           'file_ts'    =>  $file_ts,
           'wordsize'   =>  $wordsize
       );
}

function ic_system_info()
{
    $thread_safe = null;
    $debug_build = null;
    $cgi_cli = false;
	$is_fpm = false;
    $is_cgi = false;
    $is_cli = false;
    $php_ini_path = '';
    $php_ini_dir = '';
    $php_ini_add = '';
    $is_supported_compiler = true;
    $php_compiler = is_ms_windows()?'VC6':'';

    ob_start();
    phpinfo(INFO_GENERAL);
    $php_info = ob_get_contents();
    ob_end_clean();

    $breaker = (php_sapi_name() == 'cli')?"\n":'</tr>';
    $lines = explode($breaker,$php_info);
    foreach ($lines as $line) {
        if (preg_match('/command/i',$line)) {
          continue;
        }

        if (preg_match('/thread safety/i', $line)) {
          $thread_safe = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('/debug build/i', $line)) {
          $debug_build = (preg_match('/(enabled|yes)/i', $line) != 0);
        }

        if (preg_match('~configuration file.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
          $php_ini_path = $match[2];

          if (!@file_exists($php_ini_path)) {
                $php_ini_path = '';
          }
        }
        if (preg_match('~dir for additional \.ini files.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_dir = $match[2];
            if (!@file_exists($php_ini_dir)) {
                $php_ini_dir = '';
            }
        }
        if (preg_match('~additional \.ini files parsed.*(</B></td><TD ALIGN="left">| => |v">)([^ <]*)~i',$line,$match)) {
            $php_ini_add = $match[2];
        }
        if (preg_match('/compiler/i',$line)) {
            $supported_match = join('|',supported_win_compilers());
            $is_supported_compiler = preg_match("/($supported_match)/i",$line);
            if (preg_match("/(VC[0-9]+)/i",$line,$match)) {
                $php_compiler = strtoupper($match[1]);
            } elseif (preg_match("/Visual C\+\+ 2017/i",$line)) {
				$php_compiler = "VC15";
				$is_supported_compiler = true;
            } elseif (preg_match("/Visual C\+\+ 2019/i",$line)) {
				$php_compiler = "VC16";
				$is_supported_compiler = true;
			} else {
                $php_compiler = '';
            }
        }
    }
    $is_cgi = strpos(php_sapi_name(),'cgi') !== false;
    $is_cli = strpos(php_sapi_name(),'cli') !== false;
	$is_fpm = strpos(php_sapi_name(),'fpm-fcgi') !== false;
    $cgi_cli = $is_cgi || $is_cli;

    $ss = server_software_info();
	
	if ($is_fpm) {
		$ss['short'] = 'PHP-FPM';
		$ss['full'] = 'PHP-FPM ' . $ss['full'];
	}

    if (!$php_ini_path && function_exists('php_ini_loaded_file')) {
        $php_ini_path = php_ini_loaded_file();
        if ($php_ini_path === false) {
            $php_ini_path = '';
        }
    }
    if (!empty($php_ini_path)) {
        $real_path = @realpath($php_ini_path);
        if (false !== $real_path) {
            $php_ini_path = $real_path;
        }
    }

    $php_ini_basename = basename($php_ini_path);

    return array(
           'THREAD_SAFE'        => $thread_safe,
           'DEBUG_BUILD'        => $debug_build,
           'PHP_INI'            => $php_ini_path,
           'PHP_INI_BASENAME'   => $php_ini_basename,
           'PHP_INI_DIR'        => $php_ini_dir,
           'PHP_INI_ADDITIONAL' => $php_ini_add,
           'PHPRC'              => getenv('PHPRC'),
           'CGI_CLI'            => $cgi_cli,
           'IS_CGI'             => $is_cgi,
           'IS_CLI'             => $is_cli,
		   'IS_FPM'				=> $is_fpm,
           'PHP_COMPILER'       => $php_compiler,
           'SUPPORTED_COMPILER' => $is_supported_compiler,
           'FULL_SS'            => $ss['full'],
           'SS'                 => $ss['short']);
}

function is_possibly_dedicated_or_local()
{
    $sys = get_sysinfo();

    return (empty($sys['PHP_INI']) || !@file_exists($sys['PHP_INI']) || (is_readable($sys['PHP_INI']) && (0 !== strpos($sys['PHP_INI'],$_SERVER['DOCUMENT_ROOT']))));
}

function is_local()
{
    $ret = false;
    if ($_SERVER["SERVER_NAME"] == 'localhost') {
        $ret = true;
    } else {
        $ip_address = strtolower($_SERVER["REMOTE_ADDR"]);
        if (strpos(':',$ip_address) === false) {
            $ip_parts = explode('.',$ip_address);
            $ret = (($ip_parts[0] == 10) || 
                    ($ip_parts[0] == 172 && $ip_parts[1] >= 16 &&  $ip_parts[1] <= 31) ||
                    ($ip_parts[0] == 192 && $ip_parts[1] == 168));
        } else {
            $ret = ($ip_address == '::1') || (($ip_address[0] == 'f') && ($ip_address[1] >= 'c' && $ip_address[1] <= 'f'));
        }
    }
    return $ret;
}

function is_shared()
{
    return !is_local() && !is_possibly_dedicated_or_local();
}

function find_server_type($chosen_type = '',$type_must_be_chosen = false,$set_session = false)
{
    $server_type = SERVER_UNKNOWN;
    if (empty($chosen_type)) {
        if ($type_must_be_chosen) {
            $server_type = SERVER_UNKNOWN;
        } else {
            if (isset($_SESSION['server_type']) && $_SESSION['server_type'] != SERVER_UNKNOWN) {
                $server_type = $_SESSION['server_type'];
            } elseif (is_local()) {
                $server_type = SERVER_LOCAL;
            } elseif (!is_possibly_dedicated_or_local()) {
                $server_type = SERVER_SHARED;
            } else {
                $server_type = SERVER_UNKNOWN;
            } 
        }
    } else {
        switch ($chosen_type)  {
            case 's':
                $server_type = SERVER_SHARED;
                break;
            case 'd':
                $server_type = SERVER_DEDICATED;
                break;
            case 'l':
                $server_type = SERVER_LOCAL;
                break;
            default:
                $server_type = SERVER_UNKNOWN;
                break;
        }
    }
    if ($set_session) {
        $_SESSION['server_type'] = $server_type;
    }
    return $server_type;
}

function server_type_string()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_string = 'SHARED';
            break;
        case SERVER_LOCAL:
            $server_string = 'LOCAL';
            break;
        case SERVER_DEDICATED:
            $server_string = 'DEDICATED';
            break;
        default:
            $server_string = 'UNKNOWN';
            break;
    }
    return $server_string;
}

function server_type_code()
{
    $server_code = find_server_type();
    switch ($server_code) {
        case SERVER_SHARED:
            $server_char = 's';
            break;
        case SERVER_LOCAL:
            $server_char = 'l';
            break;
        case SERVER_DEDICATED:
            $server_char = 'd';
            break;
        default:
            $server_char = '';
            break;
    }
    return $server_char;
}

function get_sysinfo()
{
    static $sysinfo;

    if (empty($sysinfo)) {
        $sysinfo = ic_system_info();
    }
    return $sysinfo;
}

function get_loaderinfo()
{
    static $loader;

    if (empty($loader)) {
        $loader = required_loader();
    }
    return $loader;
}

function is_ms_windows()
{
    $loader_info = get_loaderinfo();
    return ($loader_info['oscode'] == 'win');
}

function function_is_disabled($fn_name)
{
    $disabled_functions=explode(',',ini_get('disable_functions'));
    return in_array($fn_name, $disabled_functions);
}

function selinux_is_enabled()
{
    $se_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('sestatus');
        $se_enabled = preg_match('/enabled/i',$cmd);
    }

    return $se_enabled;
}

function grsecurity_is_enabled()
{
    $gr_enabled = false;

    if (!is_ms_windows()) {
        $cmd = @shell_exec('gradm -S');
        $gr_enabled = preg_match('/enabled/i',$cmd);
    }

    return $gr_enabled;
}

function threaded_and_not_cgi()
{
    $sys = get_sysinfo();
    return($sys['THREAD_SAFE'] && !$sys['IS_CGI']);
}

function is_restricted_server($only_safe_mode = false)
{
    $disable_functions = ini_get('disable_functions');
    $open_basedir = ini_get('open_basedir');
    $php_restrictions = !empty($disable_functions) || !empty($open_basedir);
    $system_restrictions = selinux_is_enabled() || grsecurity_is_enabled();
    $non_safe_mode_restrictions = $php_restrictions || $system_restrictions;
    return (ini_get('safe_mode') || (!$only_safe_mode && $non_safe_mode_restrictions));
}

function server_restriction_warnings()
{
    $warnings = array();

    if (find_server_type() == SERVER_SHARED) {
        if (is_restricted_server()) {
            $warnings[] = "Server restrictions are in place which might affect the operation of this Loader Wizard or prevent the installation of the Loader.";
        }
    } else {
        $warning_suffix = "This may affect the operation of this Loader Wizard.";
        if (ini_get('safe_mode')) {
            $warnings[] = "Safe mode is in effect on the server. " . $warning_suffix;
        } 
        $disabled_functions = ini_get('disable_functions');
        if (!empty($disabled_functions)) {
            $warnings[] = "Some functions are disabled through disable_functions. " . $warning_suffix;
        }
        $open_basedir = ini_get('open_basedir');
        if (!empty($open_basedir)) {
            $warnings[] = "Open basedir restrictions are in effect. " . $warning_suffix;
        }
    }
    return $warnings;
}

function own_php_ini_possible($only_safe_mode = false)
{
    $sysinfo = get_sysinfo();
    return ($sysinfo['CGI_CLI'] && !is_ms_windows() && !is_restricted_server($only_safe_mode));
}

function extension_dir()
{
    $extdir = ini_get('extension_dir');
    if ($extdir == './' || ($extdir == '.\\' && is_ms_windows())) {
        $extdir = '.';
    }
    return $extdir;
}

function possibly_selinux()
{
    $loaderinfo = get_loaderinfo();
    $se_env = (getenv("SELINUX_INIT"));
    return (strtolower($loaderinfo['osname']) == 'linux' && $se_env && ($se_env == 'Yes' || $se_env == '1'));
}

function ini_same_dir_as_wizard()
{
    $sys = get_sysinfo();
    return dirname($sys['PHP_INI']) == dirname(__FILE__); 
}

function extension_dir_path()
{
    $ext_dir = extension_dir();
    if ($ext_dir == '.' || (dirname($ext_dir) == '.')) {
        $ext_dir_path = @realpath($ext_dir);
    } else {
        $ext_dir_path = $ext_dir;
    }
    return $ext_dir_path;
}

function get_loader_name()
{
    $u = uname();
    $sys = get_sysinfo();
    $os = substr($u,0,strpos($u,' '));
    $os_code = strtolower(substr($u,0,3));

    $os_code_h = ($os_code == 'dar' ? 'mac' : $os_code);

    $php_version = phpversion();
    $php_family = substr($php_version,0,3);

    $loader_sfix = (($os_code == 'win') ? '.dll' : (($sys['THREAD_SAFE'])?'_ts.so':'.so'));
    $loader_name="ioncube_loader_{$os_code_h}_{$php_family}{$loader_sfix}";

    return $loader_name;
}

function get_reqd_version($variants)
{
    $exact_match = false;
    $nearest_version = 0;
    $loader_info = get_loaderinfo();
    $os_version = $loader_info['osver2'][0] . '.' . $loader_info['osver2'][1];
    $os_version_major = $loader_info['osver2'][0];
    foreach ($variants as $v) {
        if ($v == $os_version || (is_int($v) && $v == $os_version_major)) {
            $exact_match = true;
            $nearest_version = $v;
            break;
        } elseif ($v > $os_version) {
            break;
        } else {
            $nearest_version = $v;
        }
    }
    return (array($nearest_version,$exact_match));
}

function get_default_loader_dir_webspace()
{
    return ($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . LOADER_SUBDIR);
}

function get_loader_location($loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = get_default_loader_dir_webspace();
    }
    $loader_name = get_loader_name(); 
    return ($loader_dir . DIRECTORY_SEPARATOR . $loader_name);
}

function get_loader_location_from_ini($php_ini = '')
{
    $errors = array();
    if (empty($php_ini)) {
        $sysinfo = get_sysinfo();
        $php_ini = $sysinfo['PHP_INI'];
    }
    if (!@file_exists($php_ini)) {
        if (empty($php_ini)) {
            $errors[ERROR_INI_NOT_FOUND] = "The configuration file could not be found.";
        } else {
            $errors[ERROR_INI_NOT_FOUND] = "The $php_ini file could not be found.";
        }
    } elseif (!is_readable($php_ini)) {
        $errors[ERROR_INI_NOT_READABLE] = "The $php_ini file could not be read.";
    }
    if (!empty($errors)) {
        return array('location' => '', 'errors' => $errors);
    } 
    $lines = file($php_ini);
    $ext_start = zend_extension_line_start();
    $wrong_ext_start = ($ext_start == 'zend_extension')?'zend_extension_ts':'zend_extension';
    $loader_path = '';
    $loader_name_match = "ioncube_loader";
    foreach ($lines as $l) {
        if (preg_match("/^\s*$ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$corr_matches)) {
            if (preg_match("/$loader_name_match/i",$corr_matches[1])) {
                if (!empty($loader_path)) {
                    $errors[ERROR_INI_MULTIPLE_IC_LOADER_LINES] = "It appears that multiple $ext_start lines for the ionCube Loader have been included in the configuration file, $php_ini.";
                }
                $loader_path = $corr_matches[1];
            } else {
                if (empty($loader_path)) {
                    $errors[ERROR_INI_NOT_FIRST_ZE] = "The ionCube Loader must be the first Zend extension listed in the configuration file, $php_ini.";
                }
            }
        }
        if (empty($loader_path)) {
            if (preg_match("/^\s*$wrong_ext_start\s*=\s*\"?([^\"]+)\"?/i",$l,$bad_start_matches)) {
                if (preg_match("/$loader_name_match/i",$bad_start_matches[1])) {
                    $bad_zend_ext_msg = "The line for the ionCube Loader in the configuration file, $php_ini, should start with $ext_start and <b>not</b> $wrong_ext_start.";
                    $errors[ERROR_INI_WRONG_ZE_START] = $bad_zend_ext_msg;
                    $loader_path = $bad_start_matches[1];
                }
            }
        }
    }
    $loader_path = trim($loader_path);
    if ($loader_path === '') {
        $errors[ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration file, $php_ini.";
    } elseif (!@file_exists($loader_path)) {
        $errors[ERROR_INI_LOADER_FILE_NOT_FOUND] = "The loader file  $loader_path, listed in the configuration file, $php_ini, does not exist or is not accessible.";
    } elseif (basename($loader_path) == $loader_path) {
        $errors[ERROR_INI_NOT_FULL_PATH] = "A full path must be specified for the loader file in the configuration file, $php_ini.";
    }
    return array('location' => $loader_path, 'errors' => $errors);
}

function zend_extension_line_missing($ini_path)
{
    $loader_loc = get_loader_location_from_ini($ini_path);
    return (!empty($loader_loc['errors']) && array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$loader_loc['errors']));
}

function find_additional_ioncube_ini()
{
    $sys = get_sysinfo();
    $ioncube_ini = '';

    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
        foreach ($ini_files as $f) {
            $fn = trim($f);
            $bfn = basename($fn);
            if (preg_match('/ioncube/i',$bfn)) {
                $ioncube_ini = $fn;
                break;
            }
        }
    }
    return $ioncube_ini;
}

function get_additional_ini_files()
{
    $sys = get_sysinfo();
    $ini_files = array();
    if (!empty($sys['PHP_INI_ADDITIONAL']) && !preg_match('/(none)/i',$sys['PHP_INI_ADDITIONAL'])) {
        $ini_files = explode(',',$sys['PHP_INI_ADDITIONAL']);
    }
    return (array_map('trim',$ini_files));
}

function all_ini_contents()
{
    $sys = get_sysinfo();
    $output = '';

    $output .= ";;; *MAIN INI FILE AT ${sys['PHP_INI']}* ;;;" . PHP_EOL;
    $output .= get_file_contents($sys['PHP_INI']);
    $other_inis = get_additional_ini_files();
    foreach ($other_inis as $inif) {
        $output .= ";;; *Additional ini file at $inif* ;;;" . PHP_EOL;
        $output .= get_file_contents($inif);
    }
    $here = unix_path_dir();
    $unrec_ini_files = unrecognised_inis_webspace($here);
    foreach ($unrec_ini_files as $urinif) {
        $output .= ";;; *UNRECOGNISED INI FILE at $urinif* ;;;" . PHP_EOL;
        $output .= get_file_contents($urinif);
    }
    return $output;
}

function scan_inis_for_loader()
{
    $ldloc = array('location' => '', 'errors' => array());
    $sysinfo = get_sysinfo();
    if (empty($sysinfo['PHP_INI'])) {
        $ini_files_not_found = array("Main ini file");
        $ini_file_list = get_additional_ini_files();
    } else {
        $ini_files_not_found = array();
        $ini_file_list = array_merge(array($sysinfo['PHP_INI']),get_additional_ini_files());
    }
    $server_type = find_server_type();
    $shared_server = SERVER_SHARED == $server_type;
    foreach ($ini_file_list as $f) {
        $ldloc = get_loader_location_from_ini($f);
        if (array_key_exists(ERROR_INI_ZE_LINE_NOT_FOUND,$ldloc['errors'])) {
            unset($ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND]);
        } 
        if ($shared_server && array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            if (false == user_ini_space_path($f)) {
                $ldloc['errors'][ERROR_INI_NOT_FOUND] = "A system ini file cannot be found or read by the Wizard - you cannot do anything about this on your shared server.";
            } else {
                $ldloc['errors'][ERROR_INI_USER_INI_NOT_FOUND] = $ldloc['errors'][ERROR_INI_NOT_FOUND];
            }
        } elseif (array_key_exists(ERROR_INI_NOT_FOUND,$ldloc['errors'])) {
            $ini_files_not_found[] = $f;
        }
        if (!empty($ldloc['location'])) {
            break;
        }
    }
    if (!empty($ini_files_not_found)) {
        $plural = (count($ini_files_not_found) > 1)?"s":"";
        $ldloc['errors'][ERROR_INI_NOT_FOUND] = "The following ini file$plural could not be found by the Wizard: " . join(',',$ini_files_not_found);
        if (is_restricted_server()) {
            $ldloc['errors'][ERROR_INI_NOT_FOUND] .= "<br> This may be due to server restrictions in place.";
        }
    }
    if (empty($ldloc['location'])) {
        $ldloc['errors'][ERROR_INI_ZE_LINE_NOT_FOUND] = "The necessary zend_extension line could not be found in the configuration.";
    }
    return $ldloc;
}

function find_loader_filesystem()
{
    $ld_inst_dir = loader_install_dir(find_server_type());
    $loader_name = get_loader_name();
    $suggested_loader_path = $ld_inst_dir . DIRECTORY_SEPARATOR . $loader_name;
    if (@file_exists($suggested_loader_path)) {
        $location = $suggested_loader_path;
    } elseif (@file_exists($loader_name)) {
        $location = @realpath($loader_name);
    } else {
        $ld_loc = get_loader_location();
        if (@file_exists($ld_loc)) {
            $location = $ld_loc;
        } else {
            $location = '';
        }
    }
    return $location;
}

function find_loader($search_directories_if_not_ini = false)
{
    $sysinfo = get_sysinfo();
    $php_ini = $sysinfo['PHP_INI'];
    $rtl_path = get_runtime_loading_path_if_applicable();
    $location = '';
    $errors = array();

    if (!empty($rtl_path)) {
        $location = $rtl_path;
    } else {
        $loader_ini = scan_inis_for_loader();
        $location = $loader_ini['location'];
        $errors = $loader_ini['errors'];
    }
    if (empty($location) && (empty($errors) || $search_directories_if_not_ini)) {
        $errors = array(); 
        $location = find_loader_filesystem();
        if (empty($location)) {
            $errors[ERROR_LOADER_NOT_FOUND] = 'The loader file could not be found in standard locations.';
        }
    }
    if (!empty($errors)) {
        return $errors;
    } else {
        return $location;
    }
}

function zend_extension_line_start()
{
    $sysinfo = get_sysinfo();
    $is_53_or_later = is_php_version_or_greater(5,3);
    return (is_bool($sysinfo['THREAD_SAFE']) && $sysinfo['THREAD_SAFE'] && !$is_53_or_later ? 'zend_extension_ts' : 'zend_extension');
}

function ioncube_loader_version_information()
{
    $old_version = true;
    $liv = "";
    $lv = "";
    $mv = 0;
    if (function_exists('ioncube_loader_iversion')) {
        $liv = ioncube_loader_iversion();
        $lv = sprintf("%d.%d.%d", $liv / 10000, ($liv / 100) % 100, $liv % 100);

        $latest_version =  get_latestversion();

        $lat_parts = explode('.',$latest_version);
        $cur_parts = explode('.',$lv);

        if (($cur_parts[0] > $lat_parts[0]) || 
            ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] > $lat_parts[1]) ||
             ($cur_parts[0] == $lat_parts[0] && $cur_parts[1] == $lat_parts[1] && $cur_parts[2] >= $lat_parts[2])) {
            $old_version = false;
        } else {
            $old_version = $latest_version;
        }
        $mv = $cur_parts[0];
    }
    return array($lv,$mv,$old_version);
}

function default_loader_version_info()
{
    return array();
}

function get_loader_version_info()
{
    return get_remote_session_value('loader_version_info',LOADER_LATEST_VERSIONS_URL,'default_loader_version_info');
}

function calc_platform()
{
    $platform = array();
    $platform_info = get_platforminfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($osvar,$exact_match) = get_reqd_version($loader['osvariants']);
    } else {
        $osvar = null;
        if (is_ms_windows()) {
            $sys = get_sysinfo();
            $phpc = (empty($sys['PHP_COMPILER']))?'vc6':strtolower($sys['PHP_COMPILER']); 
            $osvar = ($sys['THREAD_SAFE']?'':'nonts_') . $phpc;
        }
    }
    foreach ($platform_info as $p) {
        if ($p['os'] == $loader['oscode'] && $p['arch'] == $loader['arch'] && (empty($osvar) || $p['os_mod'] == "_" . $osvar)) {
            $platform = $p;
            break;
        }
    }
    return $platform;
}

function get_platform()
{
    static $this_platform;

    if (!isset($this_platform)) {
        $this_platform = calc_platform();
    }

    return $this_platform;
}

function is_legacy_platform()
{
    $platform = get_platform();
    return array_key_exists('is_legacy',$platform);
}

function calc_dirname()
{
    $dirname = '';
    $platform = get_platform();
    if (!empty($platform)) {
        $dirname = $platform['dirname'];
    }
    return $dirname;
}

function calc_loader_latest_version()
{
    $lv_info = get_loader_version_info();
    $latest_version = RECENT_LOADER_VERSION;
    if (!empty($lv_info)) {
        $dirname = calc_dirname();
      
        if (!empty($dirname)) {
            $compiler_specific_version = false;
            if (is_ms_windows()) {
                $sys = get_sysinfo();
                $phpc = strtolower($sys['PHP_COMPILER']);
                if (!empty($phpc)) {
                    $dirname_comp = $dirname . "_" . $phpc;
                    if (array_key_exists($dirname_comp,$lv_info)) {
                        $latest_version = $lv_info[$dirname_comp];
                        $compiler_specific_version = true;
                    }
                }
            }
            if (!$compiler_specific_version && array_key_exists($dirname,$lv_info)) {
                $latest_version = $lv_info[$dirname];
            }
        } 
    }
    return $latest_version;
}

function get_latestversion()
{
    static $latest_version;

    if (empty($latest_version)) {
        $latest_version = calc_loader_latest_version();
    }
    return $latest_version;
}


function runtime_loader_location()
{
    $loader_path = false;
    $ext_path = extension_dir_path();
    if ($ext_path !== false) {
        $id = $ext_path;
        $here = dirname(__FILE__);
        if (isset($id[1]) && $id[1] == ':') {
            $id = str_replace('\\','/',substr($id,2));
            $here = str_replace('\\','/',substr($here,2));
        }
        $rd=str_repeat('/..',substr_count($id,'/')).$here.'/';
        $i=strlen($rd);

        $loader_loc = DIRECTORY_SEPARATOR . basename($here) . DIRECTORY_SEPARATOR . get_loader_name();
        while($i--) {
            if($rd[$i]=='/') {
                $loader_path = runtime_location_exists($ext_path,$rd,$i,$loader_loc);
                if ($loader_path !== false) {
                    break;
                }
            }
        }

        if (!$loader_path && !empty($loader_loc) && @file_exists($loader_loc)) {
            $loader_path = basename($loader_loc);
        }
    }
    return $loader_path;
}

function runtime_location_exists($ext_dir,$path_str,$sep_pos,$loc_name)
{
    $sub_path = substr($path_str,0,$sep_pos);
    $lp = $sub_path . $loc_name;
    $fqlp = $ext_dir.$lp;

    if(@file_exists($fqlp)) {
        return $lp;
    } else {
        return false;
    }
}

function runtime_loading_is_possible() {
    return !((is_php_version_or_greater(5,2,5)) || is_restricted_server() || !ini_get('enable_dl') || !function_exists('dl') || function_is_disabled('dl') || threaded_and_not_cgi());
}

function shared_and_runtime_loading()
{
    return (find_server_type() == SERVER_SHARED && empty($_SESSION['use_ini_method']) && runtime_loading_is_possible());
}

function get_valid_runtime_loading_path($ignore_loading_check = false)
{
    if ($ignore_loading_check || runtime_loading_is_possible()) {
        return runtime_loader_location();
    } else {
        return false;
    }
}

function runtime_loading($rtl_path = null)
{
    if (empty($rtl_path)) {
        $rtl_path = get_valid_runtime_loading_path();
    }
    if (!empty($rtl_path) && @dl($rtl_path)) {
        return $rtl_path;
    } else {
        return false;
    }
}

function get_runtime_loading_path_if_applicable()
{
    $rtl = null;
    if (shared_and_runtime_loading()) {
        $rtl = get_valid_runtime_loading_path();
    }
    return $rtl;
}

function try_runtime_loading_if_applicable()
{
    $rtl_path = get_runtime_loading_path_if_applicable();
    if (!empty($rtl_path)) {
        return runtime_loading($rtl_path);
    } else {
        return $rtl_path;
    }
}

function runtime_loading_instructions()
{
    $default = get_default_address();
    echo '<h4>Runtime Loading Instructions</h4>';
    echo '<div class=panel>';
    echo '<p>On your shared server the Loader can be installed using the runtime loading method.';
    echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";

    if ('.' == extension_dir()) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        echo "Please note that on your system the Loader <em>must</em> be present in the same " . $dirphrase . " as the first encoded file accessed.";
    }
    echo '<ol>';
    loader_download_instructions(); 
    $loader_dir = loader_install_instructions(SERVER_SHARED,dirname(__FILE__));
    shared_test_instructions();
    echo '</ol>';
    echo '</div>';
}

function runtime_loading_errors()
{
    $errors = array();
    $ext_path = extension_dir_path();
    if (false === $ext_path) {
        $errors[ERROR_RUNTIME_EXT_DIR_NOT_FOUND] = "Extensions directory cannot be found.";
    } else {
        $expected_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . get_loader_name();
        if (!@file_exists($expected_file)) {
            $errors[ERROR_RUNTIME_LOADER_FILE_NOT_FOUND] = "The Loader file was expected to be at $expected_file but could not be found.";
        } else {
            $errors = loader_compatibility_test($expected_file);
        }
    }
    return $errors;
}


function windows_package_name()
{
    $sys = get_sysinfo();
	$loader = get_loaderinfo();
    return (LOADERS_PACKAGE_PREFIX . 'win' . '_' . ($sys['THREAD_SAFE']?'':'nonts_') . strtolower($sys['PHP_COMPILER']) .  '_' . $loader['arch']);
}

function unix_package_name()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;
    if (is_array($loader) && array_key_exists('osvariants',$loader) && is_array($loader['osvariants'])) {
        $versions = array_values($loader['osvariants']);
        $multiple_os_versions = !empty($versions[0]);
    }
    if ($multiple_os_versions) {
        list($reqd_version,$exact_match) = get_reqd_version($loader['osvariants']);
        if ($reqd_version) {
            $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $reqd_version . '_' . $loader['arch'];
        } else {
            $basename = "";
        }
    } else {
        $basename = LOADERS_PACKAGE_PREFIX . $loader['oscode'] . '_' . $loader['arch'];
    }
    return array($basename,$multiple_os_versions);
}

function loader_download_instructions()
{
    $sysinfo = get_sysinfo();
    $loader = get_loaderinfo();
    $multiple_os_versions = false;

    if (is_ms_windows()) {
        if (is_bool($sysinfo['THREAD_SAFE'])) {
            $download_str = '<li>Download the following archive of Windows ' . $sysinfo['PHP_COMPILER'];
            if (!$sysinfo['THREAD_SAFE']) {
                $download_str .= ' non-TS';
            }
            $download_str .= ' ' . $loader['arch'] . ' Loaders:';
            echo $download_str;
            $basename = windows_package_name();
            echo make_archive_list($basename,array('zip'));
            echo 'A Loaders archive can also be downloaded from <a href="' . LOADERS_PAGE . '" target="loaders">' . LOADERS_PAGE . '</a>.';
        } else {
            echo '<li>Download a Windows Loaders archive from <a href="' . LOADERS_PAGE  . '" target=loaders>here</a>. If PHP is built with thread safety disabled, use the Windows non-TS Loaders.';
        }
    } else {
        list($basename,$multiple_os_versions) = unix_package_name(); 
        if ($basename == "") {
            echo '<li>Download a ' . $loader['osname'] . ' ' . $loader['arch'] . ' Loaders archive from <a href="' . LOADERS_PAGE . '" target="loaders">here</a>.';
            echo "<br>Your system appears to be ${loader['osnamequal']} for ${loader['wordsize']} bit. If Loaders are not available for that exact release of ${loader['osname']}, Loaders built for an earlier release should work. Note that you may need to install back compatibility libraries for the operating system.";
            echo '<br>If you cannot find a suitable loader then please raise a ticket at <a href="'. SUPPORT_SITE . '">our support helpdesk</a>.';
        } else {
            echo '<li>Download one of the following archives of Loaders for ' . $loader['osnamequal'] . ' ' . $loader['arch'] . ':'; 
            if (SERVER_SHARED == find_server_type()) {
                $archives = array('zip','tar.gz');
            } else {
                $archives = array('tar.gz','zip');
            }
            echo make_archive_list($basename,$archives);
            echo "</p>";
            if ($multiple_os_versions && !$exact_match) {
                echo "<p>Note that you may need to install back compatibility libraries for  ${loader['osname']}.</p>";
            }
        }
    }

    echo '</li>';
}

function ini_dir()
{
    $sysinfo = get_sysinfo();
    $parent_dir = '';
    if (!empty($sysinfo['PHP_INI'])) {
        $parent_dir = dirname($sysinfo['PHP_INI']);
    } else {
        $parent_dir = $_SERVER["PHPRC"];
        if (@is_file($parent_dir)) {
            $parent_dir = dirname($parent_dir);
        }
    }
    return $parent_dir;
}

function unix_install_dir()
{
    $ext_dir = extension_dir_path();
    $cur_dir = @realpath('.');
    if (empty($ext_dir) || $ext_dir == $cur_dir) {
        $loader_dir = UNIX_SYSTEM_LOADER_DIR;
    } else {
        $loader_dir = $ext_dir;
    }
    return $loader_dir;
}

function windows_install_dir()
{
    $sysinfo = get_sysinfo();
    if ($sysinfo['SS'] == 'IIS') {
        if (false === ($ext_dir = extension_dir_path())) {
            $parent_dir = ini_dir();
            $ext_dir = $parent_dir . '\\ext';
            if (!empty($parent_dir) && @file_exists($ext_dir)) {
                $loader_dir = $ext_dir;
            } else {
                $loader_dir = $_SERVER['windir'] . '\\' . WINDOWS_IIS_LOADER_DIR;
            }
        } else {
            $loader_dir = $ext_dir;
        }
    } else {
        if (false === ($ext_dir = extension_dir_path())) {
			$parent_dir = ini_dir();
			$loader_dir = $parent_dir . '\\' . 'ioncube';
		} else {
			$loader_dir = $ext_dir;
		}
    }
    return $loader_dir;
}

function loader_install_dir($server_type)
{
    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $loader_dir = get_default_loader_dir_webspace();
    } elseif (is_ms_windows()) {
        $loader_dir = windows_install_dir();
    } else {
        $loader_dir = unix_install_dir();
    }
    return $loader_dir;
}

function writeable_directories()
{
    $root_path = @realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    $root_path_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
    $above_root_cgi_bin = @realpath($_SERVER['DOCUMENT_ROOT'] . "/../cgi-bin");

    $paths = array();
    foreach (array($root_path,$above_root_path,$root_path_cgi_bin,$above_root_cgi_bin) as $p) {
        if (@is_writeable($p)) {
            $paths[] = $p;
        }
    }
    return $paths;
}

function loader_install_instructions($server_type,$loader_dir = '')
{
    if (empty($loader_dir)) {
        $loader_dir = loader_install_dir($server_type);
    }
    if (SERVER_LOCAL == $server_type) {
        echo "<li>Put the Loader files in <code>$loader_dir</code></li>";
    } else {
        echo "<li>Transfer the Loaders to your web server and install in <code>$loader_dir</code></li>";
    }
    return $loader_dir;
}

function zend_extension_lines($loader_dir)
{
    $zend_extension_lines = array();
    $sysinfo = get_sysinfo();
    $qt = (is_ms_windows()?'"':'');
    $loader = get_loaderinfo();

    if (!is_bool($sysinfo['THREAD_SAFE']) || !$sysinfo['THREAD_SAFE']) {
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file'] . $qt;
        $zend_extension_lines[] = "zend_extension = " . $path;
    }
    if ((!is_bool($sysinfo['THREAD_SAFE']) && !is_php_version_or_greater(5,3)) || $sysinfo['THREAD_SAFE']) {
        $line_start = is_php_version_or_greater(5,3)?'zend_extension':'zend_extension_ts';
        $path = $qt . $loader_dir . DIRECTORY_SEPARATOR . $loader['file_ts'] . $qt;
        $zend_extension_lines[] = $line_start . " = " . $path;
    }
    return $zend_extension_lines;
}

function user_ini_base()
{
    $doc_root_path = realpath($_SERVER['DOCUMENT_ROOT']);
    $above_root_path = @realpath($_SERVER['DOCUMENT_ROOT'] . "/..");
    if (!empty($above_root_path) && @is_writeable($above_root_path)) {
        $start_path = $above_root_path;
    } else {
        $start_path = $doc_root_path;
    }
    return $start_path;
}

function user_ini_space_path($file)
{
    $user_base = user_ini_base();
    $fpath = @realpath($file);
    if (!empty($fpath) && (0 === strpos($fpath,$user_base))) {
        return $fpath;
    } else {
        return false;
    }
}

function default_ini_path()
{
    return (realpath($_SERVER['DOCUMENT_ROOT']));
}

function shared_ini_location()
{
    $phprc = getenv('PHPRC');
    if (!empty($phprc)) {
        $phprc_path = user_ini_space_path($phprc);
        if (false !== $phprc_path) {
            return $phprc_path;
        } else {
            return default_ini_path();
        }
    } else {
        return default_ini_path();
    }
}


function zend_extension_instructions($server_type,$loader_dir)
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();
    $editing_ini = true;

    $php_ini_name = ini_file_name();

    if (isset($sysinfo['PHP_INI']) && @file_exists($sysinfo['PHP_INI'])) {
        $php_ini_path = $sysinfo['PHP_INI'];
    } else {
        $php_ini_path = '';
    }

    if (is_bool($sysinfo['THREAD_SAFE'])) {
        $kwd = zend_extension_line_start();
    } else {
        $kwd = 'zend_extension/zend_extension_ts';
    }

    $server_type_code = server_type_code();

    $zend_extension_lines = zend_extension_lines($loader_dir);

    if (SERVER_SHARED == $server_type && own_php_ini_possible()) {
        $ini_dir = shared_ini_location();
        $php_ini_path = $ini_dir . DIRECTORY_SEPARATOR . $php_ini_name;
        if (@file_exists($php_ini_path)) {
            $edit_line = "<li>Edit the <code>$php_ini_name</code> in the <code>$ini_dir</code> directory";
            if (zend_extension_line_missing($php_ini_path) && @is_writeable($php_ini_path) && @is_writeable($ini_dir)) {
                if (function_exists('file_get_contents')) {
                    $ini_strs = @file_get_contents($php_ini_path);
                } else {
                    $lines = @file($php_ini_path);
                    $ini_strs = join(' ',$lines);
                }
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                        fwrite($fh,$zl . PHP_EOL);
                    }
                    fwrite($fh,$ini_strs);
                    fclose($fh);
                    $editing_ini = false;
                    echo "<li>Your php.ini file at $php_ini_path has been modified to include the necessary line for the ionCube Loader.";
                } else {
                    echo $edit_line;
                }
            } else {
               echo $edit_line;
            }
        } else {
            $download_ini_file = "<li><a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">Save this  <code>$php_ini_name</code> file</a> and upload it to <code>$ini_dir</code> (full path on your server).";
            if (@is_writeable($ini_dir)) {
                $fh = @fopen($php_ini_path,"wb");
                if ($fh !== false) {
                    foreach ($zend_extension_lines as $zl) {
                       fwrite($fh,$zl . PHP_EOL);
                    }
                    if (!empty($sysinfo['PHP_INI']) && is_readable($sysinfo['PHP_INI'])) {
                        if (function_exists('file_get_contents')) {
                           $ini_strs = @file_get_contents($sysinfo['PHP_INI']);
                        } else {
                           $lines = @file($sysinfo['PHP_INI']);
                           $ini_strs = join(' ',$lines);
                        }
                        fwrite($fh,$ini_strs);
                    }
                    fclose($fh); 
                    echo "<li>A <code>$php_ini_name</code> file has been created for you in <code>$ini_dir</code>.";
                } else {
                    echo $download_ini_file;
                }
            } else {
                echo $download_ini_file;
            }
            $editing_ini = false;
        }
    } elseif (!empty($sysinfo['PHP_INI'])) {
        if (empty($sysinfo['PHP_INI_DIR'])) {
            echo "<li>Edit the file <code>${sysinfo['PHP_INI']}</code>";
        } else {
            $php_ini_path = find_additional_ioncube_ini();
            if (empty($php_ini_path)) {
                $php_ini_name = ADDITIONAL_INI_FILE_NAME;
                echo "<li><a href=\"$base&amp;page=phpconfig&amp;download=1&amp;newlinesonly=1&amp;ininame=$php_ini_name&amp;stype=$server_type_code\">Save this $php_ini_name file</a> and put it in your ini files directory, <code>${sysinfo['PHP_INI_DIR']}</code>";
                $editing_ini = false;
            } else {
                $php_ini_name = basename($php_ini_path);
                echo "<li>Edit the file <code>$php_ini_path</code>";
            }
        }
    } else {
        echo "<li>Edit the system <code>$php_ini_name</code> file";
    }
    if ($editing_ini) {
        echo " and <b>before</b> any other $kwd lines ensure that the following is included:<br>";
        foreach ($zend_extension_lines as $zl) {
            echo "<code>$zl</code><br>";
        }
        if (!empty($php_ini_path)) {
            if (zend_extension_line_missing($php_ini_path)) {
                echo "<a>Alternatively, replace your current <code>$php_ini_path</code> file with <a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=$server_type_code&amp;download=1&amp;prepend=1\">this new $php_ini_name file</a>."; 
            }
        }
    }
    echo '</li>';
}

function server_restart_instructions()
{
    $sysinfo = get_sysinfo();
    $base = get_base_address();

    if ($sysinfo['SS']) {
		if ($sysinfo['SS'] == 'PHP-FPM') {
			echo "<li>Restart PHP-FPM.</li>";
		} else {
			echo "<li>Restart the ${sysinfo['SS']} server software.</li>";
		}
    } else {
        echo "<li>Restart the server software.</li>";
    }

    echo "<li>When the server software has restarted, <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the Loader</a>.</li>";

	if ($sysinfo['SS'] && $sysinfo['SS'] == 'PHP-FPM') {
		echo '<li>If the Loader installation failed, check the PHP-FPM error log file for errors.</li>';
    } elseif ($sysinfo['SS'] == 'Apache' && !is_ms_windows()) {
        echo '<li>If the Loader installation failed, check the Apache error log file for errors and see our guide to <a target="unix_errors" href="'. UNIX_ERRORS_URL . '">Unix related errors</a>.</li>';
    }
}

function shared_test_instructions()
{
    $base = get_base_address();
    echo "<li><a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">Click here to test the Loader</a>.</li>";
}

function link_to_php_ini_instructions()
{
    $default = get_default_address();
    echo "<p><a href=\"{$default}&amp;stype=s&amp;ini=1\">Please click here for instructions on using the php.ini method instead</a>.</p>";
}

function php_ini_instruction_list($server_type)
{
    echo '<h4>Installation Instructions</h4>';
    echo '<div class=panel>';
    echo '<ol>';

    loader_download_instructions(); 
    $loader_dir = loader_install_instructions($server_type);
    zend_extension_instructions($server_type,$loader_dir);
    if ($server_type != SERVER_SHARED || !own_php_ini_possible()) {
        server_restart_instructions();
    } else {
        shared_test_instructions();
    } 
    echo '</ol>';
    echo '</div>';
}

function php_ini_install_shared($give_preamble = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();
    if ($give_preamble) {
        echo "<p>On your <strong>shared</strong> server, the Loader should be installed using a <code>$php_ini_name</code> configuration file.";
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a shared server</a>.)</p>";
    }

    if (own_php_ini_possible()) {
        echo '<p>With your hosting account, you may be able to use your own PHP configuration file.</p>';
    } else {
        echo "<p>It appears that you cannot install the ionCube Loader using the <code>$php_ini_name</code> file. Your server provider or system administrator should be able to perform the installation for you. Please refer them to the following instructions.</p>";
    }

    php_ini_instruction_list(SERVER_SHARED);
}

function php_ini_install($server_type_desc = null, $server_type = SERVER_DEDICATED, $required = true)
{
    $php_ini_name = ini_file_name();
    $default = get_default_address();

    echo '<p>';
    if ($server_type_desc) {
        echo "For a <strong>$server_type_desc</strong> server ";
    } else {
        echo "For this server ";
    }

    if ($required) {
        echo "you should install the ionCube Loader using the <code>$php_ini_name</code> configuration file.";
    } else {
        echo "installing the ionCube Loader using the <code>$php_ini_name</code> file is recommended.";
    }
    if ($server_type_desc) {
        echo " (<a href=\"{$default}&amp;manual=1\">Please click here if you are <strong>not</strong> on a $server_type_desc server</a>.)";
    }
    echo '</p>';
      
    php_ini_instruction_list($server_type);
}



function help_resources($error_list = array())
{
	$self = get_self();
    $base = get_base_address();
    $server_type_code = server_type_code();
    $server_type = find_server_type();
    $sysinfo = get_sysinfo();
    $resources = array(
            '<a target="_blank" href="' . LOADERS_FAQ_URL . '">ionCube Loaders FAQ</a>',
            '<a target="_blank" href="' . LOADER_FORUM_URL . '">ionCube Loader Forum</a>'
        );
    if (SERVER_SHARED != $server_type || own_php_ini_possible(true)) {
		$support_info = array ( 
			'department' 		=> WIZARD_SUPPORT_TICKET_DEPARTMENT,
			'subject' 			=> "ionCube Loader installation problem",
			'message' 			=> support_ticket_information()
		   );
		if (SERVER_LOCAL == $server_type && !info_should_be_disabled()) {
			$temp_files = system_info_temporary_files();
		} else {
			$temp_files = NULL;
		}
		if (!empty($temp_files)) {
			$support_info['ini'] = base64_encode(file_get_contents($temp_files['ini']));
			$support_info['phpinfo'] = base64_encode(file_get_contents($temp_files['phpinfo']));
			$support_info['additional'] = base64_encode(file_get_contents($temp_files['additional']));
			
			$loader_path = find_loader(true);
			if (is_string($loader_path)) {		
				$support_info['loader'] = base64_encode(file_get_contents($loader_path));
				$support_info['loader_name'] = basename($loader_path);
			} else {
				$support_info['loader'] = '';
				$support_info['loader_name'] = '';
			}
		} else {
			$support_info['ini'] = '';
			$support_info['phpinfo'] = '';
			$support_info['additional'] = '';
			$support_info['loader'] = '';
			$support_info['loader_name'] = '';
		}
		 
        $resources[2] = '<form action="' . SUPPORT_SITE . 'lw_index.php' .'" method="POST" id="support-ticket"><a href="" onclick="document.getElementById(\'support-ticket\').submit(); return false;">Raise a support ticket through our helpdesk</a>';
		$resources[2] .= '<input type="hidden" name="department" value="' . $support_info['department'] . '"/>';
		$resources[2] .= '<input type="hidden" name="subject" value="' . $support_info['subject'] . '"/>';
		$resources[2] .= '<input type="hidden" name="message" value="' . $support_info['message'] . '"/>';
		if (!empty($temp_files)) {
			$resources[2] .= '<input type="hidden" name="phpinfo" value="' . $support_info['phpinfo'] . '"/>';
			$resources[2] .= '<input type="hidden" name="ini" value="' . $support_info['ini'] . '"/>';
			$resources[2] .= '<input type="hidden" name="additional" value="' . $support_info['additional'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader" value="' . $support_info['loader'] . '"/>';
			$resources[2] .= '<input type="hidden" name="loader_name" value="' . $support_info['loader_name'] . '"/>';
		}
		$resources[2] .= '</form>';
    } 
	
    if (SERVER_SHARED == $server_type && own_php_ini_possible(true) && !user_ini_space_path($sysinfo['PHP_INI'])) {
        $resources[3] = '<strong>Please check with your host that you can create php.ini files that will override the system one.</strong>';
    }
    return $resources;
}

function system_info_temporary_files()
{
    $tmpfname_ini = get_tempnam("/tmp", "INI");
    $tmpfname_ini .= ".ini";
    $fh_ini = @fopen($tmpfname_ini,'wb');
    if ($fh_ini) {
        $config = all_ini_contents();
        fwrite($fh_ini,$config);
        fclose($fh_ini);
    } else {
        $tmpfname_ini = '';
    }

    $tmpfname_pinf = get_tempnam("/tmp", "PIN");
    $tmpfname_pinf .= ".html";
    $fh_pinfo = @fopen($tmpfname_pinf,'wb');
    if ($fh_pinfo) {
        ob_start();
        @phpinfo();
        $pinfo = ob_get_contents();
        ob_end_clean();
        fwrite($fh_pinfo,$pinfo);
        fclose($fh_pinfo);
    } else {
        $tmpfname_pinf = '';
    }

    $tmpfname_add = get_tempnam("/tmp", "ADD");
    $tmpfname_add .= ".html";
    $fh_add = @fopen($tmpfname_add,'wb');
    if ($fh_add) {
        ob_start();
        extra_page(false);
        $extra = ob_get_contents();
        ob_end_clean();
        fwrite($fh_add,$extra);
        fclose($fh_add);
    } else {
        $tmpfname_add = '';
    }

    if (empty($tmpfname_ini) || empty($tmpfname_pinf) || empty($tmpfname_add)) {
        return (array());
    } else {
        return (array('ini'           =>   $tmpfname_ini,
                      'phpinfo'       =>   $tmpfname_pinf,
                      'additional'    =>   $tmpfname_add));
    }
}

function get_tempnam($default_tmp_dir = '', $prefix = '')
{
	if (function_exists('sys_get_temp_dir')) {
		return tempnam(sys_get_temp_dir(),$prefix);
	} else {
		return @tempnam($default_tmp_dir, $prefix);
	}
}
function system_info_archive_page()
{
    info_disabled_check();
	$server_type = find_server_type();
	if (SERVER_LOCAL != $server_type) {
		exit;
	}
    $loader = find_loader(true);
    if (is_string($loader)) {
        $loader_file = $loader;
    } else {
        $loader_file = '';
    }
    $all_files = system_info_temporary_files();
    if (!empty($all_files)) {
        if (!empty($loader_file)) {
            $all_files['loader'] = $loader_file;
        }
        $archive_name =  get_tempnam('/tmp',"ARC");
        if (extension_loaded('zip')) {
            $archive_name .= '.zip';
            $zip = @new ZipArchive();
            $mode = @constant("ZIPARCHIVE::OVERWRITE");
            if (!$zip || $zip->open($archive_name, $mode)!==TRUE) {
                $archive_name = '';
            } else {
                foreach($all_files as $f) {
                    $zip->addFile($f,basename($f));
                }
                $zip->close();
            }
        } elseif (extension_loaded('zlib') && !is_ms_windows()) {
            $tar_name = $archive_name . ".tar";
            $all_files_str = join(' ',$all_files);
            $script = "tar -chf $tar_name $all_files_str";
            $result = @system($script,$retval);
            if ($result !== false) {
                $archive_name = $tar_name . '.gz';
                $zp = gzopen($archive_name,"w9");
                $tar_contents = get_file_contents($tar_name);
                gzwrite($zp,$tar_contents);
                gzclose($zp);
            } else {
                $archive_name = '';
            }
        } else {
            $archive_name = '';
        }
    } else {
        $archive_name = '';
    }
    if ($archive_name) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. $archive_name);
        @readfile($archive_name);
    } else {
        $self = get_self();
        $base = get_base_address();
        $server_type_code = server_type_code();
        heading();
        echo "<p>A downloadable archive of system information could not be created.<br> 
            <strong>Please save each of the following and then attach those files to the support ticket:</strong></p>"; 
        echo "<ul>";
        echo "<li><a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo()</a></li>";
        echo "<li><a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a></li>";
        echo "<li><a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional information</a></li>";
        echo "<li><a href=\"$self?page=loaderbin\">loader file</a></li>";
        echo "</ul>";
        footer(true);
    }
}

function support_ticket_information($error_list = array())
{
    $sys = get_sysinfo();
    $ld = get_loaderinfo();

    $ticket_strs = array();
    $ticket_strs[] = "PLEASE DO NOT REMOVE THE FOLLOWING INFORMATION\r\n";
    $ticket_strs[] = "==============\r\n";
    if (!empty($error_list)) {
        $ticket_strs[] = "[hr]";
        $ticket_strs[] = "ERRORS";
        $ticket_strs[] = "[table]";
        $ticket_strs[] = '[tr][td]' . join('[/td][/tr][tr][td]',$error_list) . '[/td][/tr]';
        $ticket_strs[] = "[/table]";
    }
    $ticket_strs[] = "[hr]";
    $ticket_strs[] = "SYSTEM INFORMATION";
    $info_lines = array();
    $info_lines["Wizard version"] = script_version();
    $info_lines["PHP uname"] = $ld['uname'];
    $info_lines["Machine architecture"] = $ld['arch'];
    $info_lines["Word size"] = $ld['wordsize'];
    $info_lines["Operating system"] = $ld['osname'] . ' ' . $ld['osver'];
    if (selinux_is_enabled() || possibly_selinux()) {
        $info_lines["Security enhancements"] = "SELinux";
    } elseif (grsecurity_is_enabled()) {
        $info_lines["Security enhancements"] = "Grsecurity";
    } else {
        $info_lines["Security enhancements"] = "None";
    }
    $info_lines["PHP version"] = PHP_VERSION; 
    if ($sys['DEBUG_BUILD']) {
        $info_lines["DEBUG BUILD"] = "DEBUG BUILD OF PHP";
    }
    if (!$sys['SUPPORTED_COMPILER']) {
        $info_lines["SUPPORTED PHP COMPILER"] = "FALSE";
        $info_lines["PHP COMPILER"] = $sys['PHP_COMPILER'];
    }
    $info_lines["Is CLI?"] = ($sys['IS_CLI']?"Yes":"No");
    $info_lines["Is CGI?"] = ($sys['IS_CGI']?"Yes":"No");
    $info_lines["Is thread-safe?"] = ($sys['THREAD_SAFE']?"Yes":"No");
    $info_lines["Web server"] = $sys['FULL_SS'];
    $info_lines["Server type"] = server_type_string();
    $info_lines["PHP ini file"] = $sys['PHP_INI'];
    if (!@file_exists($sys['PHP_INI'])) {
        $info_lines["Ini file found"] = "INI FILE NOT FOUND";
    } else {
        if (is_readable($sys['PHP_INI'])) {
            $info_lines["Ini file found"] = "INI FILE READABLE";
        } else {
            $fh = @fopen($sys['PHP_INI'],"rb");
            if ($fh === false) {
                $info_lines["Ini file found"] = "INI FILE FOUND BUT POSSIBLY NOT READABLE";
            } else {
                $info_lines["Ini file found"] = "INI FILE READABLE";
            }
        }
    }
    $info_lines["PHPRC"] = $sys['PHPRC'];
    $loader_path = find_loader();
    if (is_string($loader_path)) {
        $info_lines["Loader path"] =  $loader_path;
        $info_lines["Loader file size"] = filesize($loader_path) . " bytes.";
        $info_lines["Loader MD5 sum"] =  md5_file($loader_path);
    } else {
        $info_lines["Loader path"] =  "LOADER PATH NOT FOUND";
    }
    $server_type_code = server_type_code();
    if (!empty($_SESSION['hostprovider'])) {
      $info_lines['Hosting provider'] = $_SESSION['hostprovider'];
      $info_lines['Provider URL'] = $_SESSION['hosturl'];
    }
    $info_lines["Wizard script path"] = '[url]http://' . $_SERVER["HTTP_HOST"] . get_self() . '?stype='. $server_type_code . '[/url]';
    $ticket_strs[] = "[table]";
    foreach ($info_lines as $h => $i) {
        $value = (empty($i))?'EMPTY':$i;
        $ticket_strs[] = '[tr][td]' . $h . '[/td]' . '[td]' . $value . '[/td][/tr]';
    }
    $ticket_strs[] = '[/table]';
    $ticket_strs[] = '[hr]';
    $ticket_strs[] = "\r\n==============\r\n";
    $ticket_strs[] = "PLEASE ENTER ANY ADDITIONAL INFORMATION BELOW\r\n";

    $support_ticket_str = join('',$ticket_strs);
    return urlencode($support_ticket_str);
}

function wizard_stats_data($page_id)
{
    $data = array();

    try_runtime_loading_if_applicable();
    $sysinfo = get_sysinfo();
    $ldinfo = get_loaderinfo();

    $data['sessionid'] = session_id();
    $data['wizard_version'] = script_version();
    $data['server_type'] = server_type_code();
    $data['hostprovider'] = (isset($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $data['hosturl'] = (isset($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $data['page_id'] = $page_id;
    $data['loader_state'] = (extension_loaded(LOADER_EXTENSION_NAME))?'installed':'failure';
    $data['ini_location'] = $sysinfo['PHP_INI'];
    $data['is_cgi'] = ($sysinfo['IS_CGI'])?"yes":"no";
    $data['is_ts'] = ($sysinfo['THREAD_SAFE'])?"yes":"no";
    $data['arch'] = $ldinfo['arch'];
    $data['php_version'] = PHP_VERSION;
    $data['os'] = $ldinfo['osname'];
    $data['word_size'] = $ldinfo['wordsize'];
    $data['referrer'] =  $_SERVER["HTTP_HOST"] . get_self();

    return $data;
}

function send_stats($page_id = 'default')
{
    $server_type = find_server_type();
    $res = false;

    if (SERVER_LOCAL != $server_type) {
        $stats_data = wizard_stats_data($page_id);

        if (!isset($_SESSION['stats_sent'][$page_id][$stats_data['loader_state']])) {
            $url = WIZARD_STATS_URL;

            if (!empty($stats_data)) {
                if(function_exists('http_build_query')) {
                    $qparams = http_build_query($stats_data);
                } else {
                    $qparams = php4_http_build_query($stats_data);
                }
                $url .= '?' . $qparams;
                $res = remote_file_contents($url);
            }
            $_SESSION['stats_sent'][$page_id][$stats_data['loader_state']] = 1;
        } else {
            $res = true;
        }
    } else {
        $res = 'LOCAL';
    }
    return $res;
}

function os_arch_string_check($loader_str)
{
    $errors = array();
    if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_str,$os_matches)) {
        $loader_info = get_loaderinfo();
        $dirname = calc_dirname();
        $packed_osname = preg_replace('/\s/','',strtolower($loader_info['osname']));
        if (strtolower($dirname) != $os_matches[1] && $packed_osname != $os_matches[2]) {
            $errors[ERROR_LOADER_WRONG_OS] = "You have the wrong loader for your operating system, ". $loader_info['osname'] . ".";
        } else {
            $loader_wordsize = (strpos($os_matches[3],'64') === false)?32:64;
            if ($loader_info['arch'] != ($ap = required_loader_arch($os_matches[3],$loader_info['oscode'],$loader_wordsize))) {
                $err_str = "You have the wrong loader for your machine architecture.";
                $err_str .= " Your system is " . $loader_info['arch'];
                $err_str .= " but the loader you are using is for " . $ap . ".";
                $errors[ERROR_LOADER_WRONG_ARCH] = $err_str;
            }
        }
    }
    return $errors;
}

function get_loader_strings($loader_location)
{
    if (function_exists('file_get_contents')) {
        $loader_strs = @file_get_contents($loader_location);
    } else {
        $lines = @file($loader_location);
        $loader_strs = join(' ',$lines);
    }
    return $loader_strs;
}

function loader_system($loader_location)
{
    $loader_system = array();
    $loader_strs = get_loader_strings($loader_location);

    if (!empty($loader_strs)) {

        if (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
            $loader_system['oscode'] = 'win';
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '_nonts')?0:1;
			if (preg_match("/_localtime([0-9][0-9])/i",$loader_strs,$size_matches)) {
				$loader_system['wordsize'] = ($size_matches[1] == '64')?64:32;
			} else {
				$loader_system['wordsize'] = 32;
			}
            $loader_system['arch'] = ($loader_system['wordsize'] == 64)?'x86-64':'x86';
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
			if ($loader_system['php_version_major'] == 8 && $loader_system['php_version_minor'] >= 1) {
				$loader_system['compiler'] = 'VC16';
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] >= 2) {
				$loader_system['compiler'] = 'VC15'; 
			} elseif ($loader_system['php_version_major'] == 7 && $loader_system['php_version_minor'] < 2) {
				$loader_system['compiler'] = 'VC14'; 
			} elseif ($loader_system['php_version_major'] == 5 && $loader_system['php_version_minor'] >= 5) {
				$loader_system['compiler'] = 'VC11'; 
			} elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_system['compiler'] = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_system['compiler'] = 'VC6';
            }
        } elseif (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
            $loader_system['thread_safe'] = (isset($version_matches[4]) && $version_matches[4] == '-ts')?1:0;
            $loader_system['php_version_major'] = $version_matches[1];
            $loader_system['php_version_minor'] = $version_matches[2];
            if (preg_match("/target os:\s*(([^_]+)_([^-]*)-([[:graph:]]*))/i",$loader_strs,$os_matches)) {
                $loader_system['oscode'] = strtolower(substr($os_matches[2],0,3));
                $loader_system['wordsize'] = (strpos($os_matches[3],'64') === false)?32:64;
                $loader_system['arch'] = required_loader_arch($os_matches[3],$loader_system['oscode'],$loader_system['wordsize']);
                $loader_system['compiler'] = $os_matches[4];
            }
        }
        if (preg_match("/ionCube Loader Version\s+(\S+)/",$loader_strs,$loader_version)) {
            $loader_system['loader_version'] = $loader_version[1];
		} elseif (preg_match("/ioncube_loader_(\d{1,2}\.\d\.\d{1,2})\./",$loader_strs,$loader_version)){
			$loader_system['loader_version'] = $loader_version[1];
        } else {
            $loader_system['loader_version'] = 'UNKNOWN';
        }
        if (isset($loader_system['php_version_major'])) {
            $loader_system['php_version'] = $loader_system['php_version_major'] . '.' . $loader_system['php_version_minor'];
        }
    }
    return $loader_system;
}

function loader_compatibility_test($loader_location)
{
    $errors = array();

    $sysinfo = get_sysinfo();
    if (LOADER_NAME_CHECK) {
        $installed_loader_name = basename($loader_location);
        $expected_loader_name = get_loader_name();
        if ($installed_loader_name != $expected_loader_name) {
            $errors[ERROR_LOADER_UNEXPECTED_NAME] = "The installed loader (<code>$installed_loader_name</code>) does not have the name expected (<code>$expected_loader_name</code>) for your system. Please check that you have the correct loader for your system.";
        }
    }
    if (empty($errors) && !is_readable($loader_location)) {
        $execute_error = "The loader at $loader_location does not appear to be readable.";
        $execute_error .= "<br>Please check that it exists and is readable.";
        $execute_error .= "<br>Please also check the permissions of the containing ";
        $execute_error .= (is_ms_windows()?'folder':'directory') . '.';
		if ($sysinfo['SS'] == 'PHP-FPM') {
			$execute_error .= "<br>Please also check that PHP-FPM has been restarted.";
        } elseif (($sysinfo['SS'] == 'IIS') || !($sysinfo['IS_CGI'] || $sysinfo['IS_CLI'])) {
            $execute_error .= "<br>Please also check that the web server has been restarted.";
        }
        $execute_error .= ".";
        $errors[ERROR_LOADER_NOT_READABLE] = $execute_error;
    }
    $loader_strs = get_loader_strings($loader_location);
    $phpv = php_version(); 
    if (preg_match("/php version:\s*(.)\.(.)\.(..?)(-ts)?/i",$loader_strs,$version_matches)) {
        if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
            $loader_php = $version_matches[1] . "." . $version_matches[2];
            $server_php =  $phpv['major'] . "." .  $phpv['minor'];
            $errors[ERROR_LOADER_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
        }
        if (is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'] && !is_ms_windows() && !(isset($version_matches[4]) && $version_matches[4] == '-ts')) {
            $errors[ERROR_LOADER_NONTS_PHP_TS] = "Your server is running a thread-safe version of PHP but the loader is not a thread-safe version.";
        } elseif (isset($version_matches[4]) && $version_matches[4] == '-ts' && !(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE'])) {
            $errors[ERROR_LOADER_TS_PHP_NONTS] = "Your server is running a non-thread-safe version of PHP but the loader is a thread-safe version.";
        }
    } elseif (preg_match("/ioncube_loader_..?\.._(.)\.(.)\.(..?)(_nonts)?(_amd64)?\.dll/i",$loader_strs,$version_matches)) {
        if (!is_ms_windows()) {
            $errors[ERROR_LOADER_WIN_SERVER_NONWIN] = "You have a Windows loader but your server does not appear to be running Windows.";
        } else {
            if (isset($version_matches[4]) && $version_matches[4] == '_nonts' && is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) {
                $errors[ERROR_LOADER_WIN_NONTS_PHP_TS] = "You have the non-thread-safe version of the Windows loader but you need the thread-safe one.";
            } elseif (!(is_bool($sysinfo['THREAD_SAFE']) &&  $sysinfo['THREAD_SAFE']) && !(isset($version_matches[4]) && $version_matches[4] == '_nonts')) {
                $errors[ERROR_LOADER_WIN_TS_PHP_NONTS] = "You have the thread-safe version of the Windows loader but you need the non-thread-safe one."; 
            }
            if ($version_matches[1] != $phpv['major'] || $version_matches[2]  != $phpv['minor']) {
                $loader_php = $version_matches[1] . "." . $version_matches[2];
                $server_php =  $phpv['major'] . "." .  $phpv['minor'];
                $errors[ERROR_LOADER_WIN_PHP_MISMATCH] = "The installed loader is for PHP $loader_php but your server is running PHP $server_php.";
            }
                        
            if ($version_matches[1] == 8 && $version_matches[2] >= 1) {
                $loader_compiler = 'VC16';
            } elseif ($version_matches[1] == 7 && $version_matches[2] >= 2) {
                $loader_compiler = 'VC15'; 
            } elseif ($version_matches[1] == 7) {
                $loader_compiler = 'VC14'; 
            } elseif ($version_matches[1] == 5 && $version_matches[2] >= 5) {
                $loader_compiler = 'VC11'; 
            } elseif (preg_match("/assemblyIdentity.*version=\"([^.]+)\./",$loader_strs,$compiler_matches)) {
                $loader_compiler = "VC" . strtoupper($compiler_matches[1]);
            } else {
                $loader_compiler = 'VC6';
            }
            if ($loader_compiler != $sysinfo['PHP_COMPILER']) {
                $errors[ERROR_LOADER_WIN_COMPILER_MISMATCH] = "Your loader was built using $loader_compiler but you need the loader built using ${sysinfo['PHP_COMPILER']}.";
            }
        }
    } else {
            $errors[ERROR_LOADER_PHP_VERSION_UNKNOWN] = "The PHP version for the loader cannot be determined - please check that you have a valid ionCube Loader.";
    } 
    $errors += os_arch_string_check($loader_strs);

    return $errors;
}


function shared_server()
{
    if (!$rtl_path = runtime_loading()) {
        if (empty($_SESSION['use_ini_method']) && runtime_loading_is_possible()) {
            runtime_loading_instructions();
        } else {
            php_ini_install_shared();
        }
    } else {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        echo "<p>The ionCube Loader $lv for PHP $phpv has been successfully installed.</p>";
        $is_legacy_loader = loader_major_version_instructions($mv);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,$newer_version);
        }
        successful_install_end_instructions($rtl_path);
    }
}

function dedicated_server()
{
    php_ini_install('dedicated or VPS', SERVER_DEDICATED, true);
}

function local_install()
{
    php_ini_install('local',SERVER_LOCAL, true);
}


function unregister_globals()
{
    if (!ini_get('register_globals')) {
        return;
    }

    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

function clear_session($persist = array())
{
    $persist['not_go_daddy'] = empty($_SESSION['not_go_daddy'])?0:1;
    $persist['use_ini_method'] = empty($_SESSION['use_ini_method'])?0:1;
    $persist['server_type'] = empty($_SESSION['server_type'])?SERVER_UNKNOWN:$_SESSION['server_type'];
    @session_destroy();
    $_SESSION = array();
    $_SESSION['CREATED'] = time();
    $_SESSION = $persist;
}

function can_archive()
{
	return (extension_loaded('zip') || (extension_loaded('zlib') && !is_ms_windows()));
}

function is_ioncube()
{
        return (($_SERVER["REMOTE_ADDR"] == IONCUBE_IP_ADDRESS) || ($_SERVER["REMOTE_ADDR"] == gethostbyname(IONCUBE_ACCESS_ADDRESS)));
}

function can_reach_ioncube()
{
	return (isset($_SESSION['remote_access_successful']));
}

function info_should_be_disabled($only_allow_ioncube = false)
{
    $elapsed = time() - max(filemtime(__FILE__),filectime(__FILE__));
	
	if (is_ioncube()) {
		$cutoff_time = IONCUBE_WIZARD_EXPIRY_MINUTES * 60;
	} else {
		if (!$only_allow_ioncube && !extension_loaded(LOADER_EXTENSION_NAME)) {
			$cutoff_time = WIZARD_EXPIRY_MINUTES * 60;
		} else {
			return true;
		}
	}
	
    return ($elapsed > $cutoff_time);
}

function info_disabled_text()
{
    return "The information you have tried to access has been disabled for security reasons. Please re-install this Loader Wizard script and try again.";
}

function info_disabled_check()
{
    if (info_should_be_disabled()) {
        heading();
        echo info_disabled_text();
        footer(true);
        exit;
    }
}

function run()
{

	$user_agent = $_SERVER['HTTP_USER_AGENT'];
	if (preg_match('/googlebot/i',$user_agent)) {
		exit;
	}
    unregister_globals();
    if (is_php_version_or_greater(4,3,0)) {
        ini_set('session.use_only_cookies',1);
    }
    $session_ok = @session_start();

    if (!defined('PHP_EOL')) {
        if (is_ms_windows()) {
            define('PHP_EOL',"\r\n");
        } else {
            define('PHP_EOL',"\n");
        }
    }

    if (!isset($_SESSION['CREATED'])) {
        $_SESSION['CREATED'] = time();
    } elseif (time() - $_SESSION['CREATED'] > SESSION_LIFETIME_MINUTES * 60 ) {
        clear_session(); 
    }
    if (!isset($_SERVER)) $_SERVER =& $HTTP_SERVER_VARS;

    (php_sapi_name() == 'cli') && die("This script should only be run by a web server.\n");

    $page = get_request_parameter('page');
    $host = get_request_parameter('host');
    $clear = get_request_parameter('clear');
    $ini = get_request_parameter('ini');
    $timeout = get_request_parameter('timeout');

    if ($timeout) {
        $_SESSION['timing_out'] = 1;
        $_SESSION['initial_run'] = 0;
    }

    if (!empty($host)) {
        if ($host == 'ngd') {
            $_SESSION['not_go_daddy'] = 1;
        }
    }
    if (!empty($ini)) {
        $_SESSION['use_ini_method'] = 1;
    }

    if (!empty($clear)) {
        clear_session();
        unset($_SESSION['not_go_daddy']);
        unset($_SESSION['use_ini_method']);
        unset($_SESSION['server_type']);
    } else {
        $stype = get_request_parameter('stype');
        $hostprovider = get_request_parameter('hostprovider');
        $hosturl = get_request_parameter('hosturl');
        if (!empty($hostprovider)) {
            $_SESSION['hostprovider'] = $hostprovider;
            $_SESSION['hosturl'] = $hosturl;
        }
        $server_type = find_server_type($stype,false,true);
    }
    if ($session_ok && !$timeout && !isset($_SESSION['initial_run']) && empty($page)) {
        $_SESSION['initial_run'] = 1;
        initial_page();
        @session_write_close();
        exit;
    } else {
        $_SESSION['initial_run'] = 0;
    }

    if (empty($_SESSION['server_type'])) {
        $_SESSION['server_type'] = SERVER_UNKNOWN;
    }

    if (empty($page) || !function_exists($page . "_page")) {
        $page = get_default_page();
    } 

    $fn = "{$page}_page";
    $fn();

    @session_write_close();
    exit(0);
}

function wizardversion_page()
{
    $start_time = time();
    $wizard_version_only = get_request_parameter('wizard_only');
    $clear_session_info = get_request_parameter('clear_info');
    if ($clear_session_info) {
        unset($_SESSION['timing_out']);
        unset($_SESSION['latest_wizard_version']);
    }
    $wizard_version = latest_wizard_version();
    $message = '';
    if (false === $wizard_version) {
        $message = "0";
    } elseif (update_is_available($wizard_version)) {
        $message = "$wizard_version";
    } else {
        $message = "1";
    }
    echo $message;
    @session_write_close();
    exit(0);
}

function platforminfo_page()
{
    $message = '';
    $platforms = get_loader_platforms();
    $message = empty($platforms)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function loaderversion_page()
{
    $message = '';
    $loader_versions = get_loader_version_info();
    $message = empty($loader_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function compilerversion_page()
{
    $message = '';
    $compiler_versions = find_win_compilers();
    $message = empty($compiler_versions)?0:1;
    echo $message;
    @session_write_close();
    exit(0);
}

function initial_page()
{
    $self = get_self();
    $start_page = get_default_address(false);
    $stage_timeout = 7000;
    $step_lag = 500;

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <style type="text/css">
        body {
            height: 100%;
            width: 100%;
        }
        </style>
        <script type="text/javascript">
        var timingOut = 0;
        var xmlHttpTimeout;
        var ajax;
        var statusPar;
        var stage_timeout = $stage_timeout;
        var step_lag = $step_lag;

        function checkNextStep(ajax,expected,continuation) {
            if (ajax.readyState==4 && ajax.status==200)
            {
                clearTimeout(xmlHttpTimeout);
                if (ajax.responseText == expected) {
                   setTimeout('',step_lag);
                   continuation();
                } else {
                   statusPar.innerHTML = 'Unable to check for update<br>script continuing';
                   setTimeout("window.location.href = '$start_page&timeout=1'",1000);
                }
            }
        }

        function getXmlHttp() {
            if (window.XMLHttpRequest) {
                xmlhttp=new XMLHttpRequest();
            } else {
                xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xmlhttp;
        }
        var startMainLoaderWizard = function() {
            window.location.href = '$start_page';
        }
        var loaderVersionCheck = function() {
            statusPar.innerHTML = 'Stage 4/4: Getting latest loader versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",startMainLoaderWizard);
            }
            xmlHttp.open("GET","$self?page=loaderversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var platformCheck = function() {
            statusPar.innerHTML = 'Stage 3/4: Getting platform information';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",loaderVersionCheck);
            }
            xmlHttp.open("GET","$self?page=platforminfo",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var compilerVersionCheck = function() {
            statusPar.innerHTML = 'Stage 2/4: Getting compiler versions';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",platformCheck);
            }
            xmlHttp.open("GET","$self?page=compilerversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        var startChecks = function() {
            statusPar = document.getElementById('status');
            statusPar.innerHTML = 'Stage 1/4: Getting Loader Wizard version';
            var xmlHttp = getXmlHttp();
            xmlHttp.onreadystatechange=function() {
                checkNextStep(xmlHttp,"1",compilerVersionCheck);
            }
            xmlHttp.open("GET","$self?page=wizardversion",true);
            xmlHttp.send("");
            ajax = xmlHttp;
            xmlHttpTimeout=setTimeout('ajaxTimeout()',stage_timeout);
        }
        function ajaxTimeout(){
           ajax.abort();
           statusPar.innerHTML = 'Cannot reach server<br>script continuing';
           setTimeout("window.location.href = '$start_page&timeout=1'",1000);
        }
        </script>
    </head>
    <body>

    <div id="loading"><script type="text/javascript">document.write('<p>Initialising<br>ionCube Loader Wizard<br><span id="status"></span></p>');</script><p id="noscript">Your browser does not support JavaScript so the ionCube Loader Wizard initialisation cannot be made now. This script can get the latest loader version information from the ionCube server when you go to the next page.<br>Please choose one of the following. <br>If the script appears to hang please restart the script and choose the "NO" option.<br><br><br><a href="$start_page">YES - my server DOES have internet access</a><br><br><a href="$start_page&timeout=1">NO - my server does NOT have internet access</a></p></div>
    <script type="text/javascript">
        document.getElementById('noscript').style.display = 'none';
        window.onload = startChecks;
    </script>
    </body>
    </html>
EOT;
}

function default_page($loader_extension = LOADER_EXTENSION_NAME)
{
    $self = get_self();
    foreach (array('self') as $vn) {
        if (empty($$vn)) {
			$server_data = print_r($_SERVER,true);
            error("Unable to initialise ($vn)". ' $_SERVER is: ' . $server_data);
        }
    }

    heading();

    $wizard_update = check_for_wizard_update(true);

    $rtl = try_runtime_loading_if_applicable();

    $server_type = find_server_type();

    if (extension_loaded($loader_extension) && $server_type != SERVER_UNKNOWN) {
        loader_already_installed($rtl);
    } else {
        loader_not_installed();
    }
    send_stats('default');

    footer($wizard_update);
}

function uninstall_wizard_instructions()
{
    echo '<p><strong>For security reasons we advise that you remove this Wizard script from your server now that the ionCube Loader is installed.</strong></p>';
}

function contact_script_provider_instructions()
{
    echo '<p>Please contact the script provider if you do experience any problems running encoded files.</p>';
}

function may_need_to_copy_ini()
{
    $sys = get_sysinfo();
    if (ini_same_dir_as_wizard() && $sys['IS_CGI']) {
        $dirphrase = is_ms_windows()?'folder':'directory';
        $ini = ini_file_name();
        echo "<p>Please note that if encoded files in a different $dirphrase from the Wizard fail then you should attempt to copy the $ini file to each $dirphrase in which you have encoded files.</p>";
    }
}

function ioncube_24_is_available()
{
	$loaderinfo = get_loaderinfo();
	$php_ver = php_version();
   
	return ($loaderinfo['oscode'] == 'lin' && (($php_ver['major'] == 5 && $php_ver['minor'] >= 3) || $php_ver['major'] > 5) );
}

function ioncube_24_is_enabled()
{
	$ic24_enabled = ini_get(IC24_ENABLED_INI_PROPERTY);
	return $ic24_enabled;
}

function ioncube_24_information()
{
    if (ioncube_24_is_available() && !ioncube_24_is_enabled()) {
        $self = get_self();
        echo '<div class="ic24">';
        echo '<div class="ic24graphic">';
        echo '<a target="_blank" href="' . IONCUBE24_URL . '"><img id="ic24logo" src="' . $self . '?page=ic24logo" alt="ionCube24 logo"></a>';
        echo '</div>';
        echo '<div id="ic24info">';
        echo '<p><strong>Bonus Features!</strong> The ionCube Loader can also give ';
        echo '<strong>real-time intrusion protection</strong> to protect against malware and <strong>PHP error reporting</strong> ';
        echo 'to alert when things go wrong on your website.</p>';
        echo '<p>These features are disabled by default but easily activated. ';
        echo '<strong><a target="_blank" href="' . IONCUBE24_URL . '">visit ioncube24.com</a></strong> to find out more.</p>';
        echo '</div>';
        echo '</div>';
    }
}

function cli_install_instructions()
{

	if (is_php_version_or_greater(5,3)) {
		$cli_loader_installed = shell_exec('php -r "echo extension_loaded(\"' . LOADER_EXTENSION_NAME . '\");"');
		
		if (!$cli_loader_installed) {
			$cli_php_ini_output = shell_exec("php --ini");
			
			$ini_loader_loc = scan_inis_for_loader();
		
			if (!is_null($cli_php_ini_output)) {
				echo '<div class="panel">';
				echo '<h4>Loader Installation for Command-Line (CLI) PHP</h4>';
				echo "<p>At present it does not look like the ionCube Loader is installed for command-line (CLI) PHP.</p>";
				echo "<p>Please note that if you need to run the CLI PHP, such as for <strong>cron jobs</strong>, then please ensure the zend_extension line for the ionCube Loader is included in your CLI PHP configuration.</p>";
				
				if (!empty($ini_loader_loc['location'])) {
					echo "<p>The zend_extension line that needs to be copied is:</p>";
					echo "<p><kbd>zend_extension = " . $ini_loader_loc['location'] . "</kbd></p>";
				}
				
				echo "<p>Your CLI PHP Configuration is:</p>";
				echo '<div class="terminal">';
				echo "<pre>";
				echo $cli_php_ini_output;
				echo "</pre>";
				echo '</div>';
				echo '</div>';
			}
		}
	}
}

function successful_install_end_instructions($rtl_path = null)
{
    if (empty($rtl_path)) {
        may_need_to_copy_ini();
    } elseif (is_string($rtl_path)) {
        echo "<p>The runtime loading method of installation was used with path <code>$rtl_path</code></p>";
    }
    contact_script_provider_instructions();
    if (is_legacy_platform()) {
        legacy_platform_instructions();
    }
	
	if (!is_ms_windows() && is_php_version_or_greater(5,3)) {
		cli_install_instructions();
	}
	
    uninstall_wizard_instructions();
	
	ioncube_24_information();
}

function loader_major_version_instructions($mv)
{
    if ($mv < LATEST_LOADER_MAJOR_VERSION) {
        echo "<p><strong>The installed version of the Loader cannot run files produced by the most recent ionCube Encoder.</strong>";
        echo " You will need a version " . LATEST_LOADER_MAJOR_VERSION . " ionCube Loader to run such files.</p>";
    }
    return ($mv < LATEST_LOADER_MAJOR_VERSION);
}

function loader_already_installed($rtl = null)
{
    list($lv,$mv,$newer_version) = ioncube_loader_version_information();
    $phpv = php_version_maj_min();
    $php_str = ' for PHP ' . $phpv;
    echo '<div class="success">';
    echo '<h4>Loader Installed</h4>';
    if ($newer_version) {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is <strong>already installed</strong> but it is an old version.';
        echo ' It is recommended that the Loader be upgraded to the latest version if possible.</p>';
        $know_latest_version = is_string($newer_version);
        $is_legacy_loader = loader_major_version_instructions($mv);
        echo '</div>';
        loader_upgrade_instructions($lv,$newer_version);
    } else {
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' is already installed and encoded files should run without problems.</p>'; 
        echo '</div>';
        $is_legacy_loader = loader_major_version_instructions($mv,true);
        if ($is_legacy_loader) {
            loader_upgrade_instructions($lv,true);
        }
    }

    successful_install_end_instructions($rtl);
}

function loader_upgrade_instructions($installed_version,$newer_version)
{
    if ($newer_version) {
        echo '<div class="panel">';
        echo '<h4>Loader Upgrade Instructions</h4>';
        $restart_needed = true;
        $server_type = find_server_type();
        if ($server_type == SERVER_SHARED || $server_type == SERVER_UNKNOWN) {
            $loader_path = find_loader(true);
            if (!is_string($loader_path) || false === user_ini_space_path($loader_path)) {
                $verb_case = ($server_type == SERVER_UNKNOWN)?"may":"will";
                echo "<p>Please note that you $verb_case need your system administrator to do the following to upgrade. The web server will need to be restarted after the loader file is changed.</p>";
            }
            $restart_needed = false;
        }
        if (is_string($newer_version)) {
            $version_str = "version $newer_version";
        } else {
            $version_str = "a newer version";
        }
        $loader_name =  get_loader_name();
        echo "<p>To upgrade from version $installed_version to $version_str of the ionCube Loader, please replace your existing loader file, $loader_name, with
            the file of the same name from one of the following packages:</p>";
        if (is_ms_windows()) {
            $basename = windows_package_name();
        } else {
            list($basename,$multiple_os_versions) = unix_package_name();
        }
        echo make_archive_list($basename,array('zip','tar.gz'));
        if ($restart_needed) {
            echo "<p>Once you have replaced the loader file please restart your web server.</p>";
        }
        echo '</div>';
    }
}

function legacy_platform_warning()
{
    $leg_warn = '<p><strong>You are on a platform on which ionCube Loaders are no longer being developed. ';
    $leg_warn .= 'Loaders on your platform may not be able to run files produced by the latest ionCube Encoder. ';
    $leg_warn .= 'Please switch, if possible, to a platform on which loaders are currently supported. ';
    $leg_warn .= 'A list of currently supported platforms is shown on our <a href="' . LOADERS_PAGE . '" target="loaders">loaders page</a>.</strong></p>';

    return $leg_warn;
}

function legacy_platform_instructions()
{
    echo legacy_platform_warning();
}

function loader_not_installed()
{
    $loader = get_loaderinfo();
    $sysinfo = get_sysinfo();

    $stype = get_request_parameter('stype');
    $manual_select = get_request_parameter('manual');
    $host_type = find_server_type($stype,$manual_select,true);

    if ($host_type != SERVER_UNKNOWN && is_array($loader) && !$sysinfo['DEBUG_BUILD']) {
        $warnings = server_restriction_warnings();
        if (is_legacy_platform()) {
            $warnings[] = legacy_platform_warning();
        }
        if (empty($_SESSION['use_ini_method']) && $host_type == SERVER_SHARED && runtime_loading_is_possible()) {
            $errors = runtime_loading_errors();
        } else {
            $errors = ini_loader_errors();
            $warnings = array_merge($warnings,ini_loader_warnings());
        }
        if (!empty($errors)) {
            if (count($errors) > 1) {
                $problem_str = "Please note that the following problems currently exist";
            } else {
                $problem_str = "Please note that the following problem currently exists";
            }
            echo '<div class="alert">' .$problem_str . ' with the ionCube Loader installation:';
            echo make_list($errors,"ul"); 
            echo '</div>';
        }
        if (!empty($warnings)) {
            $addword = empty($errors)?'':'also';
            $plural = (count($warnings)>1)?'s':'';
            echo '<div class="warning">';
            echo "Please note $addword the following issue$plural:";
            echo make_list($warnings,"ul"); 
            echo '</div>';
        }
    }
    if (!isset($stype)) {
        echo '<p>To use files that have been protected by the <a href="' . ENCODER_URL . '" target=encoder>ionCube PHP Encoder</a>, a component called the ionCube Loader must be installed.</p>';
    }

    if (!is_supported_php_version()) {
        echo '<p>Your server is running PHP version ' . PHP_VERSION . ' and is
                unsupported by ionCube Loaders.  Recommended PHP 4 versions are PHP 4.2 or higher, 
                PHP 5.1 or higher for PHP 5, PHP 7.1 or higher for PHP 7 and PHP 8.1 or higher for PHP 8. Please note that there is not an ionCube Loader for PHP 8.0.</p>';
	} elseif ($latest_supported_php_version = is_after_max_php_version_supported()) {
		echo '<strong>Your server is running PHP version ' . PHP_VERSION . ' and is
                currently unsupported by any ionCube Loaders. <br/>This may change in the future if a Loader is produced for your PHP platform.<br/>In the meantime please downgrade PHP to version ' . $latest_supported_php_version . '.</strong>';
    } elseif ($sysinfo['DEBUG_BUILD']) {
         echo '<p>Your server is currently running a debug build of PHP. The Loader cannot be installed with a debug build of PHP. Please ensure that PHP is reconfigured with debug disabled. Note that debug builds of PHP cannot help in debugging PHP scripts.</p>'; 
    } elseif (!is_array($loader)) {
        if ($loader == ERROR_WINDOWS_64_BIT) {
            echo '<p>Loaders for 64-bit PHP on Windows are not currently available. However, if you <b>install and run 32-bit PHP</b> the corresponding 32-bit loader for Windows should work.</p>';
            if ($sysinfo['THREAD_SAFE']) {
                echo '<li>Download one of the following archives of 32-bit Windows x86 loaders:';
            } else {
                echo '<li>Download one of the following archives of 32-bit Windows non-TS x86 loaders:';
            }
            echo make_archive_list(windows_package_name());
        } else {
            echo '<p>There may not be an ionCube Loader available for your type of system at the moment. However, if you create a <a href="'  . SUPPORT_SITE . '">support ticket</a> more advice and information may be available to assist. Please include the URL for this Wizard in your ticket.</p>';
        }
    } elseif (!$sysinfo['SUPPORTED_COMPILER']) {
        $supported_compilers = supported_win_compilers();
        $supported_compiler_string = join('/',$supported_compilers);
        echo '<p>At the current time the ionCube Loader requires PHP to be built with ' . $supported_compiler_string . '. Your PHP software has been built using ' . $sysinfo['PHP_COMPILER'] . '. Supported builds of PHP are available from <a href="https://windows.php.net/download/">PHP.net</a>.';
    } else {
        switch ($host_type) {
            case SERVER_SHARED:
                shared_server();
                break;
            case SERVER_DEDICATED:
                dedicated_server();
                break;
            case SERVER_LOCAL:
                local_install();
                break;
            default:
                echo server_selection_form();
                break;
        }
    }
}

function server_selection_form()
{
    $self = get_self();
    $timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?1:0;
    $hostprovider = (!empty($_SESSION['hostprovider']))?$_SESSION['hostprovider']:'';
    $hostprovider = htmlspecialchars($hostprovider, ENT_QUOTES, 'UTF-8');
    $hosturl = (!empty($_SESSION['hosturl']))?$_SESSION['hosturl']:'';
    $hosturl =  htmlspecialchars($hosturl, ENT_QUOTES, 'UTF-8');
    $form = <<<EOT
    <p>This Wizard will give you information on how to install the ionCube Loader.</p>
    <p>Please select the type of web server that you have and then click Next.</p>
    <script type=text/javascript>
        function trim(s) {
            return s.replace(/^\s+|\s+$/g,"");
        }
        function input_ok() {
            var l = document.getElementById('local');
            if (l.checked) {
                return true;
            } 

            var s = document.getElementById('shared');
            var d = document.getElementById('dedi');

            if (!s.checked && !d.checked) {
                alert("Please select one of the server types.");
                return false;
            } else {
                var hn = document.getElementById('hostprovider');
                var hu = document.getElementById('hosturl');
                var hostprovider = trim(hn.value);
                var hosturl = trim(hu.value);

                if (!hostprovider || !hosturl) {
                    alert("Please enter both a hosting provider name and their URL.");
                    return false;
                }
                if (hostprovider.length < 1) {
                    alert("The hosting provider name should be at least 1 character in length.");
                    return false;
                }
                if (!hosturl.match(/[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/.=]+/)) {
                    alert("The hosting provider URL is invalid.");
                    return false;
                }
                if (hosturl.length < 4) {
                    alert("The hosting provider URL should be at least 4 characters in length.");
                    return false;
                }
            }
            return true;
        }
    </script>
    <form method=GET action=$self>
        <input type="hidden" name="page" value="default">
        <input type="hidden" name="timeout" value="$timeout">
        <input type=radio id=shared name=stype value=s onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=shared>Shared <small>(for example, server with FTP access only and no access to php.ini)</small></label><br>
        <input type=radio id=dedi name=stype value=d onclick="document.getElementById('hostinginfo').style.display = 'block';"><label for=dedi>Dedicated or VPS <small>(server with full root ssh access)</small></label><br>
        <div id="hostinginfo" style="display: none">If you are on a shared or dedicated server, please give your hosting provider and their URL:
            <table>
                <tr><td><label for=hostprovider>Name of your hosting provider</label></td><td><input type=text id="hostprovider" name=hostprovider value="$hostprovider"></td></tr>
                <tr><td><label for=hosturl>URL of your hosting provider</label></td><td><input type=text id="hosturl" name=hosturl value="$hosturl"></td></tr>
            </table>
        </div>
        <input type=radio id=local name=stype value=l onclick="document.getElementById('hostinginfo').style.display = 'none';"><label for=local>Local install</label>
        <p><input type=submit value=Next onclick="return (input_ok(this) && showOverlay());"></p>
    </form>
EOT;
    return $form;
}

function phpinfo_page()
{
    info_disabled_check();
    if (function_is_disabled('phpinfo')) {
        echo "phpinfo is disabled on this server";
    } else {
        @phpinfo();
    }
}

function loader_check_page($ext_name = LOADER_EXTENSION_NAME)
{
    heading();

    $rtl_path = try_runtime_loading_if_applicable();
	
    if (extension_loaded($ext_name)) {
        list($lv,$mv,$newer_version) = ioncube_loader_version_information();
        $phpv = php_version_maj_min();
        $php_str = ' for PHP ' . $phpv;
        echo '<div class="success">';
        echo '<h4>Loader Installed Successfully</h4>';
        echo '<p>The ionCube Loader version ' . $lv . $php_str . ' <strong>is installed</strong> and encoded files should run successfully.';
        if ($newer_version) {
            echo ' Please note though that you have an old version of the ionCube Loader.</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            loader_upgrade_instructions($lv,$newer_version);
        } else {
            echo '</p>';
            $is_legacy_loader = loader_major_version_instructions($mv);
            echo '</div>';
            if ($is_legacy_loader) {
                loader_upgrade_instructions($lv,true);
            }
        }
        successful_install_end_instructions($rtl_path);
    } else {
        echo '<div class="failure">';
        echo '<h4>Loader Not Installed</h4>';
        echo '<p>The ionCube Loader is <b>not</b> currently installed successfully.</p>';
	
        if (!is_null($rtl_path)) {
            echo '<p>Runtime loading was attempted but has failed.</p>';
            echo '</div>';
            $rt_errors = runtime_loading_errors();
            if (!empty($rt_errors)) {
                list_loader_errors($rt_errors);
            } 
            link_to_php_ini_instructions();
        } else {
            echo '</div>';
            list_loader_errors();
        }
    }
	
    send_stats('check');
    footer(true);
}

function ini_loader_errors()
{
    $errors = array();
    if (SERVER_SHARED == find_server_type() && !own_php_ini_possible(true)) {
        $errors[ERROR_INI_USER_CANNOT_CREATE] = "It appears that you are not be able to create your own ini files on your shared server. <br><strong>You will need to ask your server administrator to install the ionCube Loader for you.</strong>";
    }
    $loader_loc = find_loader(false);
    if (is_string($loader_loc)) {
        if (!shared_and_runtime_loading()) {
            $sys = get_sysinfo();
            if (empty($sys['PHP_INI'])) {
                $errors[ERROR_INI_NO_PATH] = 'No file path found for the PHP configuration file (php.ini).';
            } elseif (!@file_exists($sys['PHP_INI'])) {
                $errors[ERROR_INI_NOT_FOUND] = 'The PHP configuration file (' . $sys['PHP_INI'] .') cannot be found.';
            }
        }
        $errors = $errors + loader_compatibility_test($loader_loc);
    } else {
        $errors = $errors + $loader_loc;
        $fs_location = find_loader_filesystem();
        if (!empty($fs_location)) {
            $fs_loader_errors = loader_compatibility_test($fs_location);
            if (!empty($fs_loader_errors)) {
                $errors[ERROR_LOADER_WRONG_GENERAL] = "The loader file found at $fs_location is not the correct one for your system.";
            }
            $errors = $errors + $fs_loader_errors;
        }
    } 
    return $errors;
}

function unix_path_dir($dir = '')
{
    if (empty($dir)) {
        $dir = dirname(__FILE__);
    }
    if (is_ms_windows()) {
        $dir = str_replace('\\','/',substr($dir,2));
    }
    return $dir;
}

function unrecognised_inis_webspace($startdir)
{
    $ini_list = array();

    $ini_name = ini_file_name();
    $sys = get_sysinfo();
    $depth = substr_count($startdir,'/');

    $rel_path = '';
    $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
    for ($seps = 0; $seps < $depth; $seps++) {
        $full_ini_loc = @realpath($startdir . '/' . $rel_path) . DIRECTORY_SEPARATOR . $ini_name;
        if (@file_exists($full_ini_loc) && $sys['PHP_INI'] != $full_ini_loc) {
            $ini_list[] = @realpath($full_ini_loc);
        }

        if (dirname($full_ini_loc) == $rootpath) {
            break;
        }
        $rel_path .= '../';
    }
    return $ini_list;
}

function correct_loader_wrong_location()
{
    $loader_location_pair = array();
    $loader_location = find_loader_filesystem();
    if (is_string($loader_location) && !empty($loader_location)) {
        $loader_errors = loader_compatibility_test($loader_location);
        if (empty($loader_errors)) {
            $ini_loader = scan_inis_for_loader();
            if (!empty($ini_loader['location'])) {
                $ini_loader_errors = loader_compatibility_test($ini_loader['location']);
                if (!empty($ini_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = dirname($ini_loader['location']);
                }
            } else {
                $std_dir = loader_install_dir(find_server_type());
                $std_ld_path = $std_dir . DIRECTORY_SEPARATOR . get_loader_name();
                if (@file_exists($std_ld_path)) {
                    $stdloc_loader_errors = loader_compatibility_test($std_ld_path);
                } else {
                    $stdloc_loader_errors = array("Loader file does not exist.");
                }
                if (!empty($stdloc_loader_errors)) {
                    $loader_location_pair['loader'] = $loader_location;
                    $loader_location_pair['newloc'] = $std_dir;
                }
            }
        }
    }
    return $loader_location_pair;
}

function ini_loader_warnings()
{
    $warnings = array();
    if (find_server_type() == SERVER_SHARED)
    {
        if (own_php_ini_possible()) {
            $sys = get_sysinfo();
            $ini_name = ini_file_name();
            $rootpath = realpath($_SERVER['DOCUMENT_ROOT']);
            $root_ini_file = $rootpath . DIRECTORY_SEPARATOR . $ini_name;
            $cgibinpath = @realpath($_SERVER['DOCUMENT_ROOT'] . "/cgi-bin");
            $cgibin_ini_file = (empty($cgibinpath))?'':$cgibinpath . DIRECTORY_SEPARATOR . $ini_name;
            $here = unix_path_dir();
            $ini_files = unrecognised_inis_webspace($here);
            $shared_ini_loc = shared_ini_location();
            $shared_ini_file = $shared_ini_loc . DIRECTORY_SEPARATOR . $ini_name;
            $ini_dir = dirname($sys['PHP_INI']);
            $all_ini_locations_used = !empty($ini_files);
            foreach ($ini_files as $full_ini_loc) {
                $advice = "The file $full_ini_loc is not being recognised by PHP.";
                $advice .= " Please check that the name and location of the file are correct.";
                if (!ini_same_dir_as_wizard()) {
                    $ini_loc_dir = dirname($full_ini_loc);
                    if (!@file_exists($shared_ini_file) && !empty($shared_ini_loc) && $ini_loc_dir != $shared_ini_loc && $ini_dir != $shared_ini_loc) {
                        $all_ini_locations_used = false;
                        $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $shared_ini_loc . "</code>.";
                    } else {
                        if (!@file_exists($root_ini_file) && $rootpath != $shared_ini_loc && $full_ini_loc != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= " Please try copying the <code>$full_ini_loc</code> file to <code>" . $rootpath . "</code>.";
                        } 
                        if (!empty($cgibin_ini_file) && !@file_exists($cgibin_ini_file) && $cgibinpath != $shared_ini_loc && $full_ini_loc != $cgibinpath && $cgibinpath != $rootpath) {
                            $all_ini_locations_used = false;
                            $advice .= "  Please try copying the <code>$full_ini_loc</code> file to <code>" . $cgibinpath . "</code>.";
                        }
                        $herepath = realpath($here);
                        $here_ini_file = $herepath . DIRECTORY_SEPARATOR . $ini_name;
                        if (!@file_exists($here_ini_file) && $herepath != $rootpath && $herepath != $cgibinpath) {
                            $all_ini_locations_used = false;
                            $advice .= " It may be necessary to copy the <code>$full_ini_loc</code> file to <code>$herepath</code> and to all " . (is_ms_windows()?'folders':'directories') . ' in which you have encoded files';
                        }
                    }
                } else {
                    $all_ini_locations_used = false;
                }
                $warnings[] = $advice;
            }
            if ($all_ini_locations_used) {
                $warnings[] = "<strong>It looks as if ini files are not being recognised in any of the standard locations in your webspace. Please contact your hosting provider to check whether you can create your own PHP ini file and where it should go.</strong>";
            }
        } else {
            if (own_php_ini_possible(true)) {
                $warnings[] = "You may not be able to create your own ini files on your shared server. <br><strong>You might need to ask your server administrator to install the ionCube Loader for you.</strong>";
            }
        }
    } else {
        $loader_dir_pair = correct_loader_wrong_location();
        if (!empty($loader_dir_pair)) {
            $advice = "The correct loader for your system has been found at <code>${loader_dir_pair['loader']}</code>."; 
            if ($loader_dir_pair['loader'] != $loader_dir_pair['newloc']) {
                $advice .= " Please copy the loader from <code>${loader_dir_pair['loader']}</code> to <code>${loader_dir_pair['newloc']}</code>.";
            }
            $warnings[] = $advice;
        }
    }
    return $warnings;
}

function list_loader_errors($errors = array(),$warnings = array(),$suggest_restart = true)
{
    $default = get_default_address();
    $retry_message = '';

    
    if (empty($errors)) {
        $errors = ini_loader_errors();
        if (empty($warnings)) {
            $warnings = ini_loader_warnings();
        }
    }
	
    if (!empty($errors)) {
        $try_again = '<a href="#" onClick="window.location.href=window.location.href">try again</a>';
	
        echo '<div class="alert">';
        if (count($errors) > 1) {
            echo 'The following problems have been found with the ionCube Loader installation:';
            $retry_message = "Please correct those errors and $try_again.";
        } else {
            echo 'The following problem has been found with the ionCube Loader installation:';
            $retry_message = "Please correct that error and $try_again.";
        }
        if (array_key_exists(ERROR_INI_USER_CANNOT_CREATE,$errors)) {
            $retry_message = '';
        }
        echo make_list($errors,"ul");
        echo '</div>';
        if (!empty($warnings)) {
            echo '<div class="warning">';
            echo 'Please also note the following:';
            echo make_list($warnings,"ul");
            echo '</div>';
        }
    } elseif (!empty($warnings)) {
        echo '<div class="warning">';
        echo 'There are the following potential problems:';
        echo make_list($warnings,"ul");
        echo '</div>';
    } elseif ($suggest_restart) {
        if (SERVER_SHARED == find_server_type()) {
            echo "<p>Please contact your server administrator about installing the ionCube Loader.</p>";
        } else {
            if (selinux_is_enabled()) {
                echo "<p>It appears that SELinux is enabled on your server. This might be solved by running the command <code>restorecon [full path to loader file]</code> as root.</p>";
            } elseif (grsecurity_is_enabled()) {
                echo "<p>It appears that grsecurity is enabled on your server. Please run the command, <code>execstack -c [full path to loader file]</code> and then restart your web server.</p>";
            } else {
                $sysinfo = get_sysinfo();
                $ss = $sysinfo['SS'];
				if ($ss == 'PHP-FPM') {
					echo "<p>Please check that PHP-FPM has been restarted.</p>";
                } elseif (!$sysinfo['CGI_CLI'] || is_ms_windows()) {
                    echo "<p>Please check that the $ss web server software has been restarted.</p>";
                } 
            }
        }
    }
    echo '<div>';
    echo $retry_message;
    echo " You may wish to view the following for further help:";
    echo make_list(help_resources($errors),"ul");
    echo '<a href="' . $default . '">Click here to go back to the start of the Loader Wizard</a>.</div>';
}

function phpconfig_page()
{
    info_disabled_check();
    $sys = get_sysinfo();
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        } else {
			if (!preg_match('`^.*\.ini$`',$ini_file_name) || preg_match('`/`',$ini_file_name) || preg_match('`\\\`',$ini_file_name)) {
				die("Illegal file name $ini_file_name");
			}
		}
        header('Content-Type: text/plain');
        header('Content-Disposition: attachment; filename=' . $ini_file_name);
    } else {
        header('Content-Type: text/plain');
    }
    $exclude_original = get_request_parameter('newlinesonly');
    $prepend = get_request_parameter('prepend');
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    if (!empty($exclude_original) || !empty($prepend)) {
        $loader_dir = loader_install_dir($server_type);
        $zend_lines = zend_extension_lines($loader_dir);
        echo join(PHP_EOL,$zend_lines);
        echo PHP_EOL;
    }
    if (empty($ini_file_name) || empty($sys['PHP_INI_DIR']) || ($sys['PHP_INI_BASENAME'] == $ini_file_name)) {
        $original_ini_file = isset($sys['PHP_INI'])?$sys['PHP_INI']:'';
    } else {
        $original_ini_file = $sys['PHP_INI_DIR'] . DIRECTORY_SEPARATOR . $ini_file_name;
    }
    if (empty($exclude_original) && !empty($original_ini_file) && @file_exists($original_ini_file)) {
        if (!empty($download)) {
            @readfile($original_ini_file);
        } else {
            echo all_ini_contents();
        } 
    }
}

function extra_page($check_access_to_info = true)
{
    if ($check_access_to_info) {
		info_disabled_check();
	}
    heading();
    $sys = get_sysinfo();
    $ini_loader = scan_inis_for_loader();
    $ini_loader_path = $ini_loader['location'];
    $loader_path = find_loader(true);
    $ldinf = get_loaderinfo();
    $self = get_self();
    echo "<h4>Additional Information</h4>";
    echo "<table>";
    $lines = array();
    if (is_string($loader_path)) {
        $lines['Loader is at'] = $loader_path;
        $loader_system = loader_system($loader_path);
        if (!empty($loader_system)) {
            $lines['Loader OS code'] = $loader_system['oscode'];
            $lines['Loader architecture'] = $loader_system['arch'];
            $lines['Loader word size'] = $loader_system['wordsize'];
            $lines['Loader PHP version'] = $loader_system['php_version'];
            $lines['Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Loader compiler'] = $loader_system['compiler'];
            $lines['Loader version'] = $loader_system['loader_version'];
            $lines['File size is'] = filesize($loader_path) . " bytes.";
            $lines['MD5 sum is'] = md5_file($loader_path);
        }
        $lines['Loader file'] = "<a href=\"$self?page=loaderbin\">Download loader file</a>";
    } else {
        $lines['Loader file'] = "Loader cannot be found.";
    }
    $lines['Loader found in ini file'] = empty($ini_loader_path)?"No":"Yes";
    if (!empty($ini_loader_path) && (!is_string($loader_path) || $ini_loader_path != $loader_path)) {
        $lines['Loader location found in ini file'] =  $ini_loader_path;
        $loader_system = loader_system($ini_loader_path);
        if (!empty($loader_system)) {
            $lines['Ini Loader OS code'] = $loader_system['oscode'];
            $lines['Ini Loader architecture'] = $loader_system['arch'];
            $lines['Ini Loader word size'] = $loader_system['wordsize'];
            $lines['Ini Loader PHP version'] = $loader_system['php_version'];
            $lines['Ini Loader thread safety'] = $loader_system['thread_safe']?'Yes':'No';
            $lines['Ini Loader compiler'] = $loader_system['compiler'];
            $lines['Ini Loader version'] = $loader_system['loader_version'];
        }
    }
    $lines["OS extra security"] = (selinux_is_enabled() || possibly_selinux())?"SELinux":(grsecurity_is_enabled()?"Grsecurity":"None");
    $lines['PHPRC is'] = $sys['PHPRC'];
    $lines['INI DIR is'] = $sys['PHP_INI_DIR'];
    $lines['Additional INI files'] = $sys['PHP_INI_ADDITIONAL'];
    $stype = get_request_parameter('stype');
    $server_type = find_server_type($stype);
    $lines['Server type is'] = server_type_string();
    $lines["PHP uname"] = $ldinf['uname'];
    $lines['Server word size is'] = $ldinf['wordsize'];
    $lines['Disabled functions'] = ini_get('disable_functions');
    $writeable_dirs = writeable_directories();
    $lines['Writeable loader locations'] = (empty($writeable_dirs))?"<em>None</em>":join(", ",$writeable_dirs);
    if (!empty($_SESSION['hostprovider'])) {
        $lines['Hosting provider'] = $_SESSION['hostprovider'];
        $lines['Provider URL'] = $_SESSION['hosturl'];
    }
    foreach ($lines as $h => $i) {
        $v = (empty($i))?'<em>EMPTY</em>':$i;
        echo '<tr><th>'. $h . ':</th>' . '<td>' . $v . '</td></tr>';
    }
    echo "</table>";
    footer(true);
}

function loaderbin_page()
{
    info_disabled_check();
    $loader_path = find_loader(true);
    if (is_string($loader_path)) {
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='. basename($loader_path));
        @readfile($loader_path);
    }
}



function GoDaddy_root($html_root = '')
{
    if (empty($_SESSION['not_go_daddy']) && empty($_SESSION['godaddy_root'])) {
        $godaddy_pattern = "[\\/]home[\\/]content[\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z][\\/][0-9a-z]+[\\/]html";

        if (empty($html_root)) {
            $html_root =  $_SERVER['DOCUMENT_ROOT'];
        }
        if (preg_match("@$godaddy_pattern@i",$html_root,$matches)) {
            $_SESSION['godaddy_root'] = $matches[0];
        } else {
            $_SESSION['not_go_daddy'] = 1;
            $_SESSION['godaddy_root'] = '';
        } 
    } elseif (!empty($_SESSION['not_go_daddy'])) {
        $_SESSION['godaddy_root'] = '';
    }
    if (!empty($_SESSION['godaddy_root'])) {
        $_SESSION['hostprovider'] = 'GoDaddy';
        $_SESSION['hosturl'] = 'www.godaddy.com';
    }
    return $_SESSION['godaddy_root'];
}

function GoDaddy_windows_instructions()
{
    $instr = "It appears that you are hosted on a Windows server at GoDaddy.<br/>";
    $instr .= "Please change to a Linux hosting plan at GoDaddy.<br />";
    $instr .=  "If you <a href=\"https://help.godaddy.com/\">contact their support team</a> they should be able to switch you to a Linux server.";

    echo $instr;
}

function GoDaddy_linux_instructions($html_dir)
{
    $base = get_base_address();
    $loader_name = get_loader_name();
    $zend_extension_line="<code>zend_extension = $html_dir/ioncube/$loader_name</code>";
    $php_ini_name = is_php_version_or_greater(5,0)?'php5.ini':'php.ini';
    $ini_path = $html_dir . '/' . $php_ini_name;

    $instr = array();
    $instr[] = 'In your html directory, ' . $html_dir . ', create a sub-directory called <b>ioncube</b>.';
    if (@file_exists($ini_path)) {
       $instr[] = "Edit the $php_ini_name in your  $html_dir and add the following line to the <b>top</b> of the file:<br>" . $zend_extension_line ;
    } else {
        $instr[] = "<a href=\"$base&amp;page=phpconfig&amp;ininame=$php_ini_name&amp;stype=s&amp;download=1&amp;prepend=1\">Save this $php_ini_name file</a> and upload it to your html directory, $html_dir";
    }
    $instr[] = 'Download the <a target="_blank" href="' . IONCUBE_DOWNLOADS_SERVER . '"/ioncube_loaders_lin_x86.zip">Linux ionCube Loaders</a>.';
    $instr[] = 'Unzip the loaders and upload them into the ioncube directory you created previously.';
    $instr[] = 'The encoded files should now be working.';

    echo '<div class=panel>';
    echo (make_list($instr));
    echo '</div>';
}

function GoDaddy_page()
{
    $base = get_base_address();

    heading();

        $inst_str = '<h4>GoDaddy Installation Instructions</h4>';
        $inst_str .= '<p>It appears that you are hosted with GoDaddy (<a target="_blank" href="https://www.godaddy.com/">www.godaddy.com</a>). ';
        $inst_str .= "If that is <b>not</b> the case then please <a href=\"$base&amp;page=default&amp;host=ngd\">click here to go to the main page of this installation wizard</a>.</p>";
        $inst_str .= "<p>If you have already installed the loader then please <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">click here to test the loader</a>.</p>";

        echo $inst_str;

        if (is_ms_windows()) {
            GoDaddy_windows_instructions();
        } else {
            GoDaddy_linux_instructions($_SESSION['godaddy_root']);
        }

    send_stats('gd_default');

    footer(true);
}



function get_request_parameter($param_name)
{
    static $request_array;

    if (!isset($request_array)) {
        if (isset($_GET)) {
            $request_array = $_GET;
        } elseif (isset($HTTP_GET_VARS)) {
            $request_array = $HTTP_GET_VARS;
        }
    }

    if (isset($request_array[$param_name])) {
        $return_value = strip_tags($request_array[$param_name]);
    } else {
        $return_value = null;
    }
    return $return_value;
}

function make_list($list_items,$list_type='ol')
{
    $html = '';
    if (!empty($list_items)) {
        $html .= "<$list_type>";
        $html .= '<li>';
        $html .= join('</li><li>',$list_items);
        $html .= '</li>';
        $html .= "</$list_type>";
    }
    return $html;
} 

function make_archive_list($basename,$archives_list = array(),$download_server = IONCUBE_DOWNLOADS_SERVER)
{
    if (empty($archives_list)) {
        $archives_list = array('tar.gz','zip');
    }

    foreach ($archives_list as $a) {
        $link_text = $a;
        $ext_sep = '.';
        $archive_list[] = "<a href=\"$download_server/$basename$ext_sep$a\">$link_text</a>";
    }

    return make_list($archive_list,"ul");
}

function error($m)
{
    die("<b>ERROR:</b> <span class=\"error\">$m</span><p>Please help us improve this script by <a href=\"". SUPPORT_SITE . "\">reporting this error</a> and including the URL to the script so that we can test it.");
}


function filter_server_input($server_var)
{
	$res = htmlspecialchars($_SERVER[$server_var], ENT_QUOTES, "UTF-8");
	return $res;
}

function failsafe_get_self()
{
    $result = '';
    $sfn = filter_server_input('SCRIPT_FILENAME');
    $dr = $_SERVER['DOCUMENT_ROOT'];
    if (!empty($sfn) && !empty($dr)) {
        if ($dr == '/' || $dr == '\\') {
            $result = $sfn;
        } else {
            $drpos = strpos($sfn,$dr);
            if ($drpos === 0) {
                $drlen = strlen($dr);
                $result = substr($sfn,$drlen);
            }
        }
        $result = str_replace('\\','/',$result);
    }
    if (empty($result)) {
        $result = DEFAULT_SELF;
    }
    return $result;
}

function get_self()
{ 
	$page = '';
    if (empty($_SERVER['PHP_SELF'])) {
        if (empty($_SERVER['SCRIPT_NAME'])) {
            if (empty($_SERVER['REQUEST_URI'])) {
                $page = failsafe_get_self();
            } else {
                $page = filter_server_input('REQUEST_URI');
            }
        } else {
            $page = filter_server_input('SCRIPT_NAME');
        }
    } else {
        $page = filter_server_input('PHP_SELF');
    }
	return $page;
}

function get_default_page()
{
    $godaddy_root = GoDaddy_root();
    if (empty($godaddy_root)) {
         $page = 'default';
    } else {
         $page = 'GoDaddy';
    }
    return $page;
}

function get_base_address()
{
    $self = get_self();
    $remote_timeout = (isset($_SESSION['timing_out']) && $_SESSION['timing_out'])?'timeout=1':'timeout=0';
    $using_ini = (isset($_SESSION['use_ini_method']) && $_SESSION['use_ini_method'])?'ini=1':'ini=0';
    return $self . '?' . $remote_timeout . '&' . $using_ini;
}

function get_default_address($include_timeout = true)
{
    if ($include_timeout) {
        $base =  get_base_address();
        $base .= "&amp;";
    } else {
        $base = get_self();
        $base .= "?";
    }
    $page = get_default_page();

    return $base . 'page=' . $page;
}

function heading()
{
    $self = get_self();

    echo <<<EOT
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <meta name="robots" content="noindex, nofollow">
    <head>
        <title>ionCube Loader Wizard</title>
        <link rel="stylesheet" type="text/css" href="$self?page=css">
        <script type="text/javascript">
            function showOverlay()
            {
                document.getElementById('overlay').style.display = 'block';
                return true;
            }

            function hideOverlay()
            {
                document.getElementById('overlay').style.display = 'none';
                return true;
            }
        </script>
    </head>
    <body onload="hideOverlay()">
    <div id="overlay">
        <div id="inner_overlay">Checking server configuration<br>Please wait</div>
    </div>
    <div id="header">
        <img src="?page=logo" alt="ionCube logo">
    </div>
	<div id="important">
	<h3 class="important">IMPORTANT: Ensure that This Script Is Removed When No Longer Required</h3>
	</div>
    <div id="main">
    <h2>ionCube Loader Wizard</h2>
EOT;
}

function footer($update_info = null)
{
    $self = get_self();
    $base = get_base_address();
    $default = get_default_address(false);
    $year = gmdate("Y");

    echo "</div>";
    echo "<div id=\"footer\">" .
    "Copyright ionCube Ltd. 2002-$year | " .
    "Loader Wizard version " . script_version() . " ";

    if ($update_info === true) {
        $update_info = check_for_wizard_update(false);  
    }
    $loader_wizard_loc = LOADER_WIZARD_URL;
    $wizard_version_string =<<<EOT
    <script type="text/javascript">
    var xmlhttp;
    function version_check()
    { 
        var body = document.getElementsByTagName('body')[0];
        var ldel = document.getElementById('loading');
        if (!ldel) {
            body.innerHTML += '<div id="loading"></div>';
            ldel = document.getElementById('loading');
        }
        ldel.innerHTML = '<p>Retrieving Wizard version information<br>Please wait</p>';
        ldel.style.display = 'block';
        ldel.style.height = '300px';
        ldel.style.left = '200px';
        ldel.style.border = '4px #660000 solid';
        if (window.XMLHttpRequest) {
            xmlhttp=new XMLHttpRequest();
        } else {
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            var loadedOkay = 0;
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                var wizardversion = xmlhttp.responseText;
                var msg;
                clearTimeout(xmlHttpTimeout);
                buttons = '';
                if (wizardversion == '1') {
                    msg = 'You have the current version of the<br>ionCube Loader Wizard'; 
                } else if (wizardversion != '0') {
                    msg = 'A new version, ' + wizardversion + ', of the loader wizard is available';
                    buttons = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; window.open(\'$loader_wizard_loc\'); return false">Get new version</button> &nbsp;'; 
                } else {
                    msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
                }
                buttons += '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>'; 
                ldel.innerHTML = '<p>' + msg +  '<br>' + buttons + '</p>';
            }
        }
        xmlhttp.open("GET",'$self?page=wizardversion&wizard_only=1&clear_info=1',true);
        xmlhttp.send();
        var xmlHttpTimeout=setTimeout(ajaxTimeout,7000);
    }
    function ajaxTimeout(){
       xmlhttp.abort();
       msg = 'Wizard version information cannot be obtained from the<br>ionCube server';
       button = '<button onclick="document.getElementById(\'loading\').style.display=\'none\'; return false">Close this box</button>';
       var ldel = document.getElementById('loading');
       ldel.innerHTML = '<p>' + msg +  '<br>' + button + '</p>';
    }
    </script>
EOT;

    $wizard_version_string .= '('; 
    if ($update_info === null) {
        $wizard_version_string .= '<a target="_blank" href="' . $loader_wizard_loc . '" onclick="version_check();return false;">check for new version</a>';
    } else if ($update_info !== false) {
        $wizard_version_string .= '<a href="' . LOADERS_PAGE .'" target="_blank">download version ' . $update_info . '</a>';
    } else {
        $wizard_version_string .=  "current";
    }
    $wizard_version_string .= ')'; 
    echo $wizard_version_string;

    $server_type_code = server_type_code();
	
	if (!info_should_be_disabled(true)) {
		echo " | <a href=\"$base&amp;page=phpinfo\" target=\"phpinfo\">phpinfo</a>";
		echo " | <a href=\"$base&amp;page=phpconfig\" target=\"phpconfig\">config</a>";
		echo " | <a href=\"$base&amp;page=extra&amp;stype=$server_type_code\" target=\"extra\">additional</a>";
	}

    echo " | <a href=\"$default\" onclick=\"showOverlay();\">wizard start</a>";
    echo " | <a href=\"$base&amp;page=loader_check\" onclick=\"showOverlay();\">loader test</a>";
    echo ' | <a href="' . LOADERS_PAGE . '" target="loaders">loaders</a>';

    echo "</div>\n";
    echo "\n</body></html>\n";
}

function css_page()
{
    header('Content-Type: text/css');
    echo <<<EOT
    body {
        font-family: verdana, helvetica, arial, sans-serif;
        font-size: 10pt;
        line-height: 150%;
        margin: 0px;
        min-height: 400px;
        position: relative;
    }

    code {
        color: #c00080;
    }

    li {
        margin-top: 10px;
    }
    #overlay {
        display: block;
        z-index: 100;
        position: absolute;
        top: 0;
        left: 0;
        padding: 0;
        margin: 0;
        width: 100%;
        height: 100%;
        background-color: white;
    }
    #inner_overlay {
        display: block;
        z-index: 100;
        position: absolute;
        font-size: 200%;
        color: #660000;
        top: 50%;
        left: 25%;
        width: 460px;
        height: 460px;
        line-height: 200%;
        text-align: center;
        vertical-align: middle;
    }

    #loading {
        display: block;
        position: absolute;
        top: 33%;
        left: 25%;
        margin: auto;
        height: 320px;
        width: 460px;
        padding: 4px;
        color: #660000;
        background-color: white;
        z-index: 100;
    }

    #loading p {
        position: absolute;
        margin-top: 10px;
        text-align: center;
        vertical-align: middle;
        padding-left: 40px;
        padding-right: 30px;
        font-size: 200%;
        line-height: 200%;
    }

    #loading p span#status{
        font-size: 60%;
        line-height: 120%;
    }
    #loading p#noscript {
        font-size: 120%;
        line-height: 120%;
        position: absolute;
        text-align: left;
        padding-top: 10px;
        bottom: 0;
    }
    #loading p#noscript a {
        text-align: center;
    }

    #loading button {
        margin-top: 20px;
        line-height: 100%;
        padding-top: 4px;
        padding-bottom: 4px;
    }


    h4 {
        margin-bottom: 0;
        padding-bottom: 4px;
    }

    p,#main div {
        max-width: 1000px;
        width: 75%;
    }

    #hostinginfo {
        margin-top: 10px;
        margin-left: 20px;
    }
    #hostinginfo table {
        font-size: 1.00em;
    }
    #hostinginfo table td {
        padding-right: 4px;
    }
    #hostinginfo input {
        margin-top: 6px;
    }

    #hostinginfo label {
        margin-left: 6px;
    }

    th {
        text-align: left;
    }
	
	#important {
		margin-top: 12px;
	} 
	h3.important {
		margin: 0;
		border: 0;
        border-top: 1px solid #660000;
		border-bottom: 1px solid #660000;
        padding: 1ex 0 1ex 0;
        background-color: #CB2430;
		text-align: center;
        color: #ffffff; 
        width: 100%;
	}

    .alert {
        margin: 2ex 0;
        border: 1px solid #660000;
        padding: 1ex 1em;
        background-color: #ffeeee;
        color: #660000; 
        width: 75%;
    }

    .warning {
        margin: 2ex 0;
        border: 1px solid #FFBF00;
        padding: 1ex 1em;
        background-color: #FDF5E6;
        color: #000000; 
        width: 75%;
    }

    .success {
        margin: 2ex 0;
        border: 1px solid #006600;
        padding: 1ex 1em;
        background-color: #EEFFEE;
        color: #000000; 
        width: 75%;
    }

    .error {
        color: #FF0000;
    }

    .panel {
        border: 1px solid #c0c0c0;
        background-color: #f0f0f0;
        width: 75%;
        padding: 1ex 1em;
    }
	
	.terminal {
		border: none;
		background-color: #000000;
		color: #ffffff;
		width: 50%;
		padding: 1ex 1em;
	}

    #header {
        background: #fff;
    }

    #footer {
        border-top: 1px solid #404040;
        margin-top: 20px;
        padding-top: 10px;
        padding-left: 20px;
        font-size: 75%;
        text-align: left;
    }

    #main {
        margin: 20px;
    }
	
	
	#main .ic24 {
		position: relative;
		width: 75%;
		height: auto;
		border-width: 1px 1px 1px 1px;
		border-style: solid;
		border-color: #4B8DF8;   
		background-color: #EFEFFF;
		padding: 12px;
		padding-top: 16px;
		padding-bottom: 8px;
		margin-top: 20px;
		overflow: hidden;
	}
	
	#main .ic24 p {
		width: 100%;
	}
	
	
	#main .ic24graphic {
		position: relative;
		width: auto;
		height: auto;
		border: none;
		padding: 0px;
		padding-right: 16px;
		margin: 0px;
		float: left;
		
	}
	
	#main #ic24info {
		position: relative;
		width: auto;
		height: auto;
		float: left;
	}
	
	#main #ic24info a {
		color: #0B4DB8;
		text-decoration: none;
	}
	
	#main #ic24logo {
		max-width: 132px;
		max-height: 132px;
	}
	
EOT;
}

function logo_page()
{
$img_encoded = 'iVBORw0KGgoAAAANSUhEUgAAAakAAACABAMAAABD1osiAAAAKlBMVEUAAAAAAADnHCwAAAAAAAAAAAAAAAAAAABMCQ4AAADnHCznHCznHCwAAAAjcBE1AAAADHRSTlMAeDRHwSqg4BJl/PLTJLuIAAAF1UlEQVR42u2by4vTQBzHp3TTzR6EBtfXYS/+BZW6Pg6FFavgoRDBBx4KFd+HQgWFvQQqiuJhoeL7sP+LR0EPlj6yPfz+F5NMZ77TmmJjM3ZT5nNpOzvNzGcev5lMusxgMBgMBoPBYDAYDAaDwWDQwel5YRnC/jkvbZYdjFV2MFbZwVhlB2OVIVZyb2HIED/n5AfLEj/nhWUJY5UdjFV2MFbZwVgdMqzNZydXz2qrf59Kq2a1NmTsRnfVrLZOfj3VrrkrZuVb/dpBvZEJqzOOc5TNQ75rjXKDtV+ZsNoi6rJ52OhZwxONwiGwsi46zqnt1Kx8r7N8q/wmRfhP3BSsrK7VW/u13krDysGwT8o5kvilxa2YZ/U2eulEC0KhCTlLCo0UrPYff7Tfe+2lWt0glTT6qjB02e0eW6ZVjiZYaF4hq+eXlmll1yik75TL5eMeDVOxsj89hNQyrN5QyDFRm9GCVmCZVrYXBr4OE9w8ZFbBCNr+x646ycAhs/o3moFUj62Y1UY4/txVs9oLrAZs1azCAVhaNSsLgXNpVt/+dlNXZAplx4mLiXecU5hHhcBqN6lV/p3znk1xEYUltfr+t0J/4dN1jwKGWIg+VKuBdL5JAQ9EYj34ILOAjWq12lG+eE2xsk9EF/7CFN7WKOCpq9kK2/CTyp93mFUbpyKRZmwNi2oX4Y0dfgULd8QL4vRdvVavJ+6XYLVPIQjmHq9xAqvbJBTa8paTBCOtVpZHY1DrSmCF7flABotBIiuLJM+RQdJJO1qoVnUKqfLh1pBWrX10YVu0ciuRVXjlfpUiXGSmp85xdFaaT7thZUV95I5DRldaDYJPT8oXmyQqnYP0nFZetL23tgjtsT/e8uc9mKa3XsFqL3Rpy3YsCSufhwmrJgbeGmo/jxUCjd2UzWWFg1EuEzv6rJoY4ftyQapghBRElda5cxKrEfaPvGPWw+Esyx1ps8pHhaP0LqxK8p7KZwFHklt1kEqNcbsNcFfT12a1zgtEv7WFVZehB93xUGVJrPg7MXgPxotDUWlCV5dVhYtgjhV5KuLd+jixktjqYHoHmVcLw9fSt2ry8lDBlrAqKomN5FZI5aX0+Rztqmk7uqywtGKhRQ+KmbeT3AoDDN89gsJQBQ1WWFrFpmgkIruq2kpuhWCASFNBYXxN1GGFKk1XqqLWiXjeOvpv3n2gpBDm4dtL1aqnyaqAcA2bGCu0d3Ir5GkSPasKsFlO3WpNGf68P3wdVhs84tRIRZ/VEUwWfIyxwo4puRUiDh0+q2jntnJWOf6aplVv+VZ5VGMBq3tlhQuarNYnw3V9Zgzkr8PFYiByAi0xcM7ILva+7kJWNeyktVoV5l2FeSI1kluh8UKrlnar6dv2qNhejBVG6yDeaifOajg5X9tR4sH/sLIIBeFTjJV4JMImmd5KNmGFvHxfyV9Guq2mDvnQc9NWyIuOBWrD2BSzZ4fsHi6rzUq26cRdY2e2VSU+ChJ6IDdh1Zi+wylAVa9VfWqu+2y2VYFiO6uGzHsTVj01WOxgsOq3KqB0nMbMsLK96fNxKVASgrDCSogcHjpbq5WNg1WcVsRY4Zi3i1Xblqm7OLFXrHbRWn2GxUG/FduX0yIHwRlWFomD3ojrT+Vxje+KE3tYiQ6ym3JJKKidnW9rscJkuSwOiUdsphXO5P2724y9PPOI+njMMSyxOzWiTViF7/0v4kS6gzEcZA0545X0WbFmVClnk1B4vJXsDYArcPzXitUxCnhW5f070SyXHGfTw1jUYVUgMGKzrTBKQQk/LonYzSlWxToyFuOapaXRim2hqd2/WbFbJEBlLTx8k1a1QNmaai0eUMBAp5XVFFIdNtMqVqs/nhmvpGQuSJRWUmHoMsl5klzRacWsE4Sn3TOswMtH9Mfvbj+L36JNWrFzUgqcE6ofdf8X9PXN6qWjbF5eOverV51ye/ICd+NCWv549er0ha3o69vMYDAYDAaDwWAwGAwGg8FgSJffF2mwYDNbStYAAAAASUVORK5CYII=';

    header('Content-Type: image/png');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}

function ic24logo_page()
{
	$img_encoded = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6b3NiPSJodHRwOi8vd3d3Lm9wZW5zd2F0Y2hib29rLm9yZy91cmkvMjAwOS9vc2IiCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB2ZXJzaW9uPSIxLjAiCiAgIHdpZHRoPSI2OTAiCiAgIGhlaWdodD0iNjkxLjI1IgogICB2aWV3Qm94PSIwIDAgNTUyIDU1MyIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgaWQ9InN2ZzMwMzUiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNSByMTAwNDAiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImlvbkN1YmUyNF9jdWJlLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMwODMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzQ5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTM1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUzMzkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzMxIgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTMzMyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzMjUiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A1MzI3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NSIKICAgICAgIG9zYjpwYWludD0ic29saWQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMTI3M2I4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4ODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgb3NiOnBhaW50PSJzb2xpZCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMxMjczYjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg4MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NzMiCiAgICAgICBvc2I6cGFpbnQ9InNvbGlkIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzEyNzNiODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODc1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTMzNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUzNDEiCiAgICAgICB4MT0iNDQzNS40NDI0IgogICAgICAgeTE9IjI5NDkuMDQyIgogICAgICAgeDI9IjQ4MzQuMzkyMSIKICAgICAgIHkyPSIyOTQ5LjA0MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNDYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNDgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNTgiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjAiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjIiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNjYiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNjgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzAiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogICAgPGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDMxNzQiPgogICAgICA8cGF0aAogICAgICAgICBkPSJtIDE2MDM0LDIyMzYgYyAtMywtOCAtMywtMzQwIC0xLC03MzggNSwtNzg5IDQsLTc4NiA2NiwtOTc3IDQyLC0xMzAgOTIsLTIxNCAxODUsLTMwNyAxMjgsLTEyOCAyNTcsLTE4MSA0NjcsLTE5MSAyNDYsLTEyIDQ2Miw2OSA2MjksMjM3IDM2LDM2IDgwLDg3IDk4LDExNCAxNywyNyAzMyw0OCAzMyw0NSAxLC0yIDcsLTgwIDEzLC0xNzQgbCAxMSwtMTcwIDE3OSwtMyAxNzgsLTIgLTYsNDIgYyAtNCwyNCAtOSw1MTQgLTEyLDEwOTEgbCAtNiwxMDQ3IC0xOTYsLTIgLTE5NywtMyAtNSwtNzMwIGMgLTQsLTUwOCAtOSwtNzQwIC0xNywtNzYyIC0xMDIsLTI4NCAtMzY2LC00NDUgLTY0NCwtMzkzIC0xNzgsMzQgLTI5OSwxNzIgLTM1MSw0MDAgLTIxLDkxIC0yMiwxMjMgLTI1LDc5MyBsIC00LDY5NyAtMTk1LDAgYyAtMTU4LDAgLTE5NiwtMyAtMjAwLC0xNCB6IgogICAgICAgICBpZD0icGF0aDMxNzYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2NsaXBQYXRoPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxOCIKICAgICBpZD0ibmFtZWR2aWV3MzA4MSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC45NjUzODc0IgogICAgIGlua3NjYXBlOmN4PSI3MjQuNTI3MjIiCiAgICAgaW5rc2NhcGU6Y3k9IjMzMy4xMTQ1MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMzAzNSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMCIKICAgICBmaXQtbWFyZ2luLWxlZnQ9IjAiCiAgICAgZml0LW1hcmdpbi1yaWdodD0iMCIKICAgICBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEzMDM3Ij4KQ3JlYXRlZCBieSBwb3RyYWNlIDEuMTEsIHdyaXR0ZW4gYnkgUGV0ZXIgU2VsaW5nZXIgMjAwMS0yMDEzCjxyZGY6UkRGPgogIDxjYzpXb3JrCiAgICAgcmRmOmFib3V0PSIiPgogICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICA8ZGM6dHlwZQogICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICA8L2NjOldvcms+CjwvcmRmOlJERj4KPC9tZXRhZGF0YT4KICA8ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMSwwLDAsLTAuMSwtNCw1NTcpIgogICAgIGlkPSJnMzAzOSIKICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO3N0cm9rZTpub25lIj4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIC0yLDg2OCAtMyw4NjcgLTg2NywzIC04NjgsMiAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA0MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDQ3MDAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDMiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDM4MjcsNTU2MyBjIC00LC0zIC03LC0zOTUgLTcsLTg3MCBsIDAsLTg2MyA4NzAsMCA4NzAsMCAwLDg3MCAwLDg3MCAtODYzLDAgYyAtNDc1LDAgLTg2NywtMyAtODcwLC03IHoiCiAgICAgICBpZD0icGF0aDMwNDUiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDQwLDI4MDAgMCwtODcwIDg2OCwyIDg2NywzIDMsODY4IDIsODY3IC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNDciCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDE5MzAsMjgwMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiBtIDEwMzUsNjMwIGMgODAsLTMxIDE1NCwtMTAyIDE5MSwtMTgzIDI1LC01NCAyOCwtNzQgMjksLTE1NyAwLC0xOTAgLTc0LC0zMTggLTM0NCwtNTkyIGwgLTE3NCwtMTc4IDI3NiwwIDI3NywwIDAsLTgwIDAsLTgwIC00MDcsMiAtNDA4LDMgLTMsNTYgLTMsNTUgMTgxLDE3NCBjIDM1NSwzMzkgNDUyLDQ5MyA0MjMsNjY3IC0xOSwxMDYgLTcxLDE2MiAtMTcyLDE4NCAtOTIsMjAgLTIwMiwtNiAtMjkzLC02OSBsIC00NiwtMzEgLTI2LDU4IGMgLTE0LDMyIC0yNiw2MiAtMjYsNjYgMCwyMiAxNDcsOTkgMjI4LDEyMCA4MiwyMSAyMjEsMTQgMjk3LC0xNSB6IgogICAgICAgaWQ9InBhdGgzMDQ5IgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAzODIyLDI4MDMgMywtODY4IDg2OCwtMyA4NjcsLTIgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAyLC04NjcgeiBtIDExNzgsMjQyIDAsLTM5NSA5MCwwIDkwLDAgMCwtNzAgMCwtNzAgLTkwLDAgLTkwLDAgMCwtMTcwIDAsLTE3MCAtODUsMCAtODUsMCAwLDE3MCAwLDE3MCAtMjkwLDAgLTI5MCwwIDAsNjMgMCw2NCAyODEsNDAxIDI4MSw0MDIgOTQsMCA5NCwwIDAsLTM5NSB6IgogICAgICAgaWQ9InBhdGgzMDUxIgogICAgICAgc3R5bGU9ImZpbGw6IzEyNzNiODtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA0NzkwLDMxNzMgYyAtMjQsLTQzIC0xMTEsLTE3MiAtMTk1LC0yODggLTgzLC0xMTUgLTE1NSwtMjE2IC0xNTksLTIyMiAtNiwtMTAgMzUsLTEzIDE5MywtMTMgbCAxOTksMCA0LDI5OCBjIDIsMTYzIDMsMjk4IDIsMzAwIC0xLDIgLTIxLC0zMiAtNDQsLTc1IHoiCiAgICAgICBpZD0icGF0aDMwNTMiCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NTM0MSk7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTg1MTYsMTc0MyBjIC0zLC04MzUgLTksLTE1NTMgLTEyLC0xNTk1IGwgLTYsLTc4IDE3MCwwIDE3MCwwIDcsODggYyAzLDQ4IDksMTI3IDEzLDE3NiBsIDcsODkgNDAsLTU5IGMgNTMsLTc3IDE2MCwtMTgxIDIyOSwtMjIzIDEyOCwtNzcgMjQ4LC0xMTEgNDIxLC0xMTggMjEwLC05IDM4NywzOCA1NTIsMTQ3IDI3NiwxODEgNDM4LDQ4MiA0NzQsODc5IDM5LDQzMyAtMTA1LDgzOSAtMzc1LDEwNTYgLTE1NSwxMjUgLTMzMCwxODUgLTU0MSwxODUgLTE5OSwwIC0zNTcsLTQwIC00OTMsLTEyNiAtNzEsLTQ1IC0xODMsLTE1MyAtMjI1LC0yMTkgbCAtMzIsLTUwIC0zLDY4MyAtMiw2ODIgLTE5NCwwIC0xOTQsMCAtNiwtMTUxNyB6IG0gMTE1NSwyMjMgYyAxNDksLTMyIDMwNSwtMTQ4IDM4OCwtMjg5IDc5LC0xMzUgMTIxLC0zMTMgMTIxLC01MTIgMCwtMTk2IC0zNSwtMzU2IC0xMDgsLTUwMCAtNDMsLTg0IC0xNzEsLTIxNyAtMjQ5LC0yNTggLTc3LC00MSAtMTkyLC02NyAtMjk0LC02NyAtMTE2LDAgLTE3NywxMyAtMjc4LDYyIC0xNDYsNjkgLTI1OCwyMDMgLTMxNywzNzggLTE3LDQ5IC0xOSw4OCAtMTksMzYwIDAsMzA1IDAsMzA1IDI3LDM4NSAzNywxMDkgOTEsMTk2IDE2OSwyNzUgNzQsNzQgMTkwLDE0MSAyODYsMTY0IDc2LDE5IDE5MSwxOSAyNzQsMiB6IgogICAgICAgaWQ9InBhdGgzMDU1IgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE3NCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTQ2MTAsMzEzOSBjIC01MTgsLTY1IC05NDQsLTM1NyAtMTE2NCwtNzk3IC0xNDEsLTI4MCAtMjAxLC02MzYgLTE2NiwtOTgzIDcyLC03MTEgNDgwLC0xMTc3IDExNDcsLTEzMTAgMjExLC00MiA1NTcsLTM2IDgxMywxMiAxMTksMjMgMzIwLDg2IDMyNiwxMDMgNiwxNyAtNzIsMzExIC04MiwzMDkgLTUsLTEgLTQ5LC0xNiAtOTcsLTMzIC0xNDcsLTUyIC0yNjIsLTcxIC00NzAsLTc3IC0yMTAsLTYgLTMyMCw0IC00NTcsNDQgLTQzNywxMjYgLTcwNSw0NzIgLTc2MSw5NzkgLTE1LDE0MCAtNSwzODggMjAsNTE0IDYwLDI5OSAxOTgsNTM2IDQwMyw2OTAgMjIzLDE2OSA0NzIsMjM4IDgwOCwyMjcgMTg0LC02IDMwNywtMjggNDQyLC03OCA0NiwtMTYgODksLTMxIDk2LC0zMiA5LC0xIDMwLDQ5IDYyLDE1MyAyNyw4NSA0OCwxNTUgNDcsMTU2IC01Miw0MCAtMjc2LDEwMSAtNDU3LDEyMyAtOTcsMTMgLTQxNCwxMiAtNTEwLDAgeiIKICAgICAgIGlkPSJwYXRoMzA1NyIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNzApIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczNzAsMjg1NSAwLC0xOTUgMjEwLDAgMjEwLDAgMCwxOTUgMCwxOTUgLTIxMCwwIC0yMTAsMCAwLC0xOTUgeiIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNjYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIzODg2LDMwMjQgYyAtOTksLTE4IC0yNjQsLTczIC0zNDgsLTExNSAtNzEsLTM1IC0yMTgsLTEzMCAtMjM3LC0xNTMgLTEwLC0xMiAwLC00MCA1MCwtMTUwIDM0LC03NSA2MywtMTM2IDY1LC0xMzYgMSwwIDM2LDI0IDc3LDUzIDE2NiwxMTkgMzI0LDE3NiA1MTMsMTg0IDMwOCwxNCA1MDMsLTEwOCA1ODAsLTM2MiAxNCwtNDYgMTksLTkzIDE5LC0yMDAgLTEsLTE3MSAtMTksLTI0NyAtMTAwLC00MTAgLTEzMCwtMjYxIC0zODAsLTU0MyAtMTA0NCwtMTE4MCBsIC0yNTAsLTI0MCAtMSwtMTIyIDAsLTEyMyA5MzUsMCA5MzUsMCAwLDE2NSAwLDE2NSAtNjU3LDAgLTY1NywwIDEwOSwxMDEgYyA2MSw1NiAyMTgsMjEwIDM1MCwzNDMgMzQyLDM0NSA1MTgsNTYzIDYzNCw3ODYgMTc5LDM0NSAxOTgsNjc4IDU3LDk2NSAtODEsMTYzIC0xODgsMjcwIC0zNTEsMzUxIC0xNDEsNzAgLTIxOSw4NiAtNDI1LDkwIC0xMjUsMiAtMTk4LC0xIC0yNTQsLTEyIHoiCiAgICAgICBpZD0icGF0aDMwNjEiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE2MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMjY2ODEsMjk3NyBjIC02LC04IC0yOTksLTQyNSAtNjUxLC05MjggbCAtNjQwLC05MTQgMCwtMTMyIDAsLTEzMyA2ODAsMCA2ODAsMCAwLC00MDAgMCwtNDAwIDE4NSwwIDE4NSwwIDAsNDAwIDAsNDAwIDIwNSwwIDIwNSwwIDAsMTU1IDAsMTU1IC0yMDUsMCAtMjA1LDAgMCw5MDUgMCw5MDUgLTIxNCwwIGMgLTE2NiwwIC0yMTYsLTMgLTIyNSwtMTMgeiBtIDcxLC0xMDg0IC0zLC03MTMgLTQ4MCwwIGMgLTM4MiwwIC00NzksMyAtNDczLDEzIDUsNiAxNjYsMjMwIDM1OCw0OTcgMzQ3LDQ4MSAzOTksNTYwIDUzMCw3OTggMzgsNjggNjksMTIyIDcwLDEyMCAwLC0yIDAsLTMyNCAtMiwtNzE1IHoiCiAgICAgICBpZD0icGF0aDMwNjMiCiAgICAgICBzdHlsZT0iZmlsbDojMTI3M2I4O2ZpbGwtb3BhY2l0eToxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE1OCkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMTE5MjcsMjI4OCBjIC0xMDgsLTEwIC0yNDgsLTU1IC0zNDEsLTExMCAtODIsLTQ4IC0yMDMsLTE2MCAtMjQ3LC0yMjkgLTE3LC0yNyAtMzQsLTQ3IC0zOCwtNDQgLTMsNCAtMTAsODIgLTE2LDE3MyBsIC0xMCwxNjcgLTE3OSwzIC0xNzgsMiA2LC00NyBjIDQsLTI3IDksLTUxNyAxMiwtMTA5MCBsIDYsLTEwNDMgMTk5LDAgMTk4LDAgMyw3MjcgMyw3MjggMzEsNzIgYyAxMTMsMjYwIDM0MSwzOTggNTk4LDM2MiAxNjQsLTIyIDI3NiwtMTAzIDM0NiwtMjUxIDczLC0xNTQgNzIsLTE0OCA3NywtOTM1IGwgNSwtNzAzIDE5NCwwIDE5NCwwIDAsNzIzIGMgMCw3OTYgLTIsODI0IC02Miw5OTcgLTEyMSwzNDcgLTQyMCw1MzMgLTgwMSw0OTggeiIKICAgICAgIGlkPSJwYXRoMzA2NSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNTQpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDczOTAsMTE4MCAwLC0xMTEwIDE5MCwwIDE5MCwwIDAsMTExMCAwLDExMTAgLTE5MCwwIC0xOTAsMCAwLC0xMTEwIHoiCiAgICAgICBpZD0icGF0aDMwNjciCiAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMTUwKSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSA5MTk5LDIyODAgYyAtMjIwLC0zNyAtNDE4LC0xMzggLTU3MCwtMjg5IC0xNTAsLTE1MSAtMjQyLC0zMjkgLTI5NSwtNTcxIC0yNiwtMTE5IC0yNywtNDI5IC0xLC01NDcgNTIsLTI0NCAxNDksLTQyNiAzMDUsLTU3NSAxODcsLTE3OCAzOTYsLTI2NCA2NjgsLTI3NSA1MDAsLTIxIDkxMiwyNTEgMTA2NSw3MDQgNTQsMTYxIDY0LDIzMCA2Myw0NDggMCwxNjcgLTMsMjE1IC0yMSwyOTEgLTEwMyw0NDEgLTM5MCw3MzAgLTgwMyw4MDggLTg3LDE3IC0zMjYsMjAgLTQxMSw2IHogbSAzMzQsLTMwNSBjIDI1NSwtNjYgNDM4LC0zMDggNDg3LC02NDQgMTcsLTExNiA4LC0zNDMgLTE4LC00NDIgLTY0LC0yNDMgLTE5NywtNDIzIC0zNzQsLTUwOCAtMTA1LC01MCAtMTg0LC02NiAtMjk2LC01OCAtMjIxLDE1IC0zOTMsMTM2IC01MDgsMzU5IC02NiwxMjkgLTk1LDI1MCAtMTAxLDQyNSAtMTEsMzA4IDY3LDU0NSAyMzYsNzE0IDgxLDgxIDE1OCwxMjYgMjYxLDE1MyA3MywxOSAyNDEsMjAgMzEzLDEgeiIKICAgICAgIGlkPSJwYXRoMzA2OSIKICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMxNDYpIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBkPSJtIDIxNzUwLDIyNzUgYyAtMzUyLC03MCAtNjExLC0zMDUgLTczOSwtNjY4IC01OCwtMTY1IC03NSwtMjcxIC03NSwtNDc3IC0xLC0yMDQgMTAsLTI3OSA2NiwtNDQ3IDExOSwtMzYwIDQyMCwtNTk4IDgyNiwtNjUzIDEyNywtMTggMzkyLC04IDU0MiwyMCAxMjIsMjIgMzYwLDk2IDM2MCwxMTEgMCwxOCAtNjMsMjY0IC02OSwyNzEgLTMsNCAtNTEsLTggLTEwNiwtMjcgLTE1NCwtNTEgLTI3MiwtNjggLTQ3NSwtNjggLTIwMywwIC0yNzgsMTUgLTQwOSw4MyAtMjE0LDExMSAtMzI4LDMwMiAtMzU2LDU5OCBsIC03LDcyIDc2NSwwIGMgNjg4LDAgNzY1LDIgNzcxLDE2IDEyLDMyIDYsMzAzIC05LDM5MCAtNDMsMjQ0IC0xMzQsNDMzIC0yNzcsNTcwIC0xMTUsMTEyIC0yMzUsMTc0IC00MDAsMjA4IC05NCwxOSAtMzE0LDIwIC00MDgsMSB6IG0gMzUzLC0yOTUgYyAyMDcsLTY0IDMzOCwtMjU3IDM2MywtNTM1IGwgNywtNzUgLTU3NywwIC01NzYsMCAwLDIzIGMgMCw1MiA0MiwxODcgODYsMjc1IDgyLDE2OCAyMjcsMjkyIDM3NCwzMjEgMzAsNiA2NCwxMyA3NSwxNSA0MSwxMCAxODUsLTUgMjQ4LC0yNCB6IgogICAgICAgaWQ9InBhdGgzMDcxIgogICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzE0MikiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gNDAsOTEwIDAsLTg3MCA4NjgsMiA4NjcsMyAzLDg2OCAyLDg2NyAtODcwLDAgLTg3MCwwIDAsLTg3MCB6IgogICAgICAgaWQ9InBhdGgzMDc1IgogICAgICAgc3R5bGU9ImZpbGw6I2MwMWQyZTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgZD0ibSAxOTMwLDkxMCAwLC04NzAgODcwLDAgODcwLDAgMCw4NzAgMCw4NzAgLTg3MCwwIC04NzAsMCAwLC04NzAgeiIKICAgICAgIGlkPSJwYXRoMzA3NyIKICAgICAgIHN0eWxlPSJmaWxsOiNjMDFkMmU7ZmlsbC1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGQ9Im0gMzgyMCw5MTAgMCwtODcwIDg3MCwwIDg3MCwwIDAsODcwIDAsODcwIC04NzAsMCAtODcwLDAgMCwtODcwIHoiCiAgICAgICBpZD0icGF0aDMwNzkiCiAgICAgICBzdHlsZT0iZmlsbDojYzAxZDJlO2ZpbGwtb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICA8L2c+Cjwvc3ZnPgo=';
	header('Content-Type: image/svg+xml');
    header('Cache-Control: public');
    echo base64_decode($img_encoded);
}
alt-php84-ioncube-loader/README.txt000064400000007751150536261270012672 0ustar00                            The ionCube Loader 
                            ------------------

This package contains:

* ionCube Loaders

* a Loader Wizard script to assist with Loader installation (loader-wizard.php)

* the License document for use of the Loader and encoded files (LICENSE.txt)

* User Guide describing options that can be configured through a php.ini file.  
  There are options that may improve performance, particularly with files on
  a network drive. Options for the ionCube24 intrusion protection and PHP error
  reporting service (ioncube24.com) are also described.


INSTALLATION
============

Quick Guide for experienced system admins
-----------------------------------------

The Loader is a PHP engine extension, so should be referenced with 
a zend_extension line in a php.ini file. It must be the first engine
extension to be installed. 

The Loader must be for the correct operating system, match the 
PHP version, and for whether PHP is built as thread-safe (TS) or not. 
All information required for installing is available on a phpinfo page. 

For example, if your web server is 64 bit Linux, thread safety is disabled,
PHP is version 8.1.8, the main php.ini file is /etc/php.ini and you
have unpacked Loaders to /usr/local/ioncube, you would:

1) edit /etc/php.ini
2) at the top of the php.ini file add

zend_extension = /usr/local/ioncube/ioncube_loader_lin_8.1.so

3) restart the PHP environment (i.e. Apache, php-fpm, etc.)

4) Check a phpinfo page and the Loader should show up in the Zend Engine box.


Assisted Installation with the Loader Wizard
--------------------------------------------

1. Upload the contents of this package to a directory/folder called ioncube
   within the top level of your web scripts area. This is sometimes called the
   "web root" or "document root". Common names for this location are "www",
   "public_html", and "htdocs", but it may be different on your server.

2. Launch the Loader Wizard script in your browser. For example:
     https://yourdomain/ioncube/loader-wizard.php

   If the wizard is not found, check carefully the location on your server
   where you uploaded the Loaders and the wizard script. 

3. Follow the steps given by the Loader Wizard. If you have full access to the 
   server then installation should be easy. If your hosting plan is more limited, 
   you may need to ask your hosting provider for assistance. 

4. The Loader Wizard can automatically create a ticket in our support system
   if installation is unsuccessful, and we are happy to assist in that case.

   YouTube with a search for "ioncube loader wizard" also gives some helpful 
   examples of installation.


WHERE TO INSTALL THE LOADERS
============================

The Loader Wizard should be used to guide the installation process but the
following are the standard locations for the Loader files. Loader file
packages can be obtained from https://www.ioncube.com/loaders.php

Please check that you have the correct package of Loaders for your system.

Installing to a remote SHARED server
------------------------------------

* Upload the Loader files to a directory/folder called ioncube within your
  main web scripts area.  (This will probably be where you placed the
  loader-wizard.php script.)


Installing to a remote UNIX/LINUX DEDICATED or VPS server
---------------------------------------------------------

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, /usr/local/ioncube


** Installing to a remote WINDOWS DEDICATED or VPS server

* Upload the Loader files to the PHP extensions directory or, if that is
  not set, C:\windows\system32


64-BIT LOADERS FOR WINDOWS
--------------------------

64-bit Loaders for Windows are available for PHP 5.5 upwards.
The Loader Wizard will not give directions for installing 64-bit Loaders for
any earlier version of PHP 5.

Copyright (c) 2002-2025 ionCube Ltd.           Last revised January 2025
alt-php84-snuffleupagus/README.md000064400000014667150536261270012456 0ustar00<h1 align="center">
  <br>
  <a href="https://snuffleupagus.readthedocs.io/">
    <img src="https://github.com/jvoisin/snuffleupagus/raw/master/doc/source/_static/sp.png" alt="Snuffleupagus' logo" width="200"></a>
  <br>
  Snuffleupagus
  <br>
</h1>

<h4 align="center">Security module for php7 and php8 - Killing bugclasses and virtual-patching the rest!</h4>

<p align="center">
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php7.yml/badge.svg"
         alt="Testing PHP7 on various Linux distributions" />
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/distributions_php8.yml/badge.svg"
         alt="Testing PHP8 on various Linux distributions" />
  </a>
  <a href="https://scan.coverity.com/projects/jvoisin-snuffleupagus">
    <img src="https://scan.coverity.com/projects/13821/badge.svg?flat=1"
         alt="Coverity">
  </a>
  <a href="https://bestpractices.coreinfrastructure.org/projects/1267">
      <img src="https://bestpractices.coreinfrastructure.org/projects/1267/badge"
           alt="CII Best Practises">
  </a>
  <a href="http://snuffleupagus.readthedocs.io/?badge=latest">
    <img src="https://readthedocs.org/projects/snuffleupagus/badge/?version=latest"
         alt="readthedocs.org">
  </a>
  <a href="https://coveralls.io/github/jvoisin/snuffleupagus?branch=master">
    <img src="https://coveralls.io/repos/github/jvoisin/snuffleupagus/badge.svg?branch=master"
         alt="coveralls">
  </a>
  <a href="https://twitter.com/dustriorg">
    <img src="https://img.shields.io/badge/twitter-follow-blue.svg"
         alt="twitter">
  </a>
  <a href="https://repology.org/project/php:snuffleupagus/versions">
    <img src="https://repology.org/badge/tiny-repos/php:snuffleupagus.svg"
         alt="Packaging status">
  </a>
  <a href="https://github.com/jvoisin/snuffleupagus">
    <img src="https://github.com/jvoisin/snuffleupagus/actions/workflows/codeql-analysis.yml/badge.svg"
         alt="CodeQL">
  </a>
</p>

<p align="center">
  <a href="#key-features">Key Features</a> •
  <a href="#download">Download</a> •
  <a href="#examples">Examples</a> •
  <a href="https://snuffleupagus.readthedocs.io/">Documentation</a> •
  <a href="https://github.com/jvoisin/snuffleupagus/blob/master/LICENSE">License</a> •
  <a href="#thanks">Thanks</a>
</p>

Snuffleupagus is a [PHP 7+ and 8+](https://secure.php.net/) module designed to
drastically raise the cost of attacks against websites, by killing entire bug
classes. It also provides a powerful virtual-patching system, allowing
administrator to fix specific vulnerabilities and audit suspicious behaviours
without having to touch the PHP code.

## Key Features

* No [noticeable performance impact](https://dustri.org/b/snuffleupagus-030-dentalium-elephantinum.html)
* Powerful yet simple to write virtual-patching rules
* Killing several classes of vulnerabilities
  * [Unserialize-based](https://www.owasp.org/images/9/9e/Utilizing-Code-Reuse-Or-Return-Oriented-Programming-In-PHP-Application-Exploits.pdf) code execution
  * [`mail`-based]( https://blog.ripstech.com/2016/roundcube-command-execution-via-email/ ) code execution
  * Cookie-stealing [XSS]( https://en.wikipedia.org/wiki/Cross-site_scripting )
  * File-upload based code execution
  * Weak PRNG
  * [XXE]( https://en.wikipedia.org/wiki/XML_external_entity_attack )
  * Filter based remote code execution and assorted shenanigans
* Several hardening features
  * Automatic `secure` and `samesite` flag for cookies
  * Bundled set of rules to detect post-compromissions behaviours
  * Global [strict mode]( https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.scalar-type-declarations) and type-juggling prevention
  * Whitelisting of [stream wrappers](https://secure.php.net/manual/en/intro.stream.php)
  * Preventing writeable files execution
  * Whitelist/blacklist for `eval`
  * Enforcing TLS certificate validation when using [curl](https://secure.php.net/manual/en/book.curl.php)
  * Request dumping capability
* A relatively sane code base:
  * A [comprehensive](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master) test suite close to 100% coverage
  * Every commit is tested on [several distributions](https://gitlab.com/jvoisin/snuffleupagus/pipelines)
  * An `clang-format`-enforced code style
  * A [comprehensive documentation](https://snuffleupagus.rtfd.io)
  * Usage of [coverity](https://scan.coverity.com/projects/jvoisin-snuffleupagus), codeql, [scan-build](https://clang-analyzer.llvm.org/scan-build.html), …

## Download

We've got a [download
page](https://snuffleupagus.readthedocs.io/download.html), where you can find
packages for your distribution, but you can of course just `git clone` this
repo, or check the releases on [github](https://github.com/jvoisin/snuffleupagus/releases).

## Examples

We're providing [various example rules](https://github.com/jvoisin/snuffleupagus/tree/master/config),
that are looking like this:

```python
# Harden the `chmod` function
sp.disable_function.function("chmod").param("mode").value_r("^[0-9]{2}[67]$").drop();

# Mitigate command injection in `system`
sp.disable_function.function("system").param("command").value_r("[$|;&`\\n]").drop();
```

Upon violation of a rule, you should see lines like this in your logs:

```python
[snuffleupagus][0.0.0.0][disabled_function][drop] The execution has been aborted in /var/www/index.php:2, because the return value (0) of the function 'strpos' matched a rule.
```

## Documentation

We've got a [comprehensive website](https://snuffleupagus.readthedocs.io/) with
all the documentation that you could possibly wish for. You can of course
[build it yourself](https://github.com/jvoisin/snuffleupagus/tree/master/doc).

## Thanks

Many thanks to:

- The [Suhosin project](https://suhosin.org) for being a __huge__ source of inspiration
- [NBS System](https://www.nbs-system.com) for initially sponsoring the development
- [Suhosin-ng](https://github.com/sektioneins/suhosin-ng) for their
  [experimentations](https://github.com/sektioneins/suhosin-ng/wiki/News)
  and [contributions](https://github.com/jvoisin/snuffleupagus/commits?author=bef),
  as well as [NLNet](https://nlnet.nl/project/Suhosin-NG/) for sponsoring it
- All [our contributors](https://github.com/jvoisin/snuffleupagus/graphs/contributors)

alt-php84-snuffleupagus/CONTRIBUTING.md000064400000013046150536261270013416 0ustar00## Contributing

First off, thank you for considering contributing to snuffleupagus.

### 1. Where do I go from here?

If you've noticed a bug or have a question,
look at the [faq](https://snuffleupagus.readthedocs.io/faq.html) and
[search the issue tracker](https://github.com/jvoisin/snuffleupagus/issues)
to see if someone else has already created a ticket. If not, go ahead and
[make one](https://github.com/jvoisin/snuffleupagus/issues/new)!

### 2. Fork & create a branch

If this is something you think you can fix,
then [fork snuffleupagus](https://help.github.com/articles/fork-a-repo) and
create a branch with a descriptive name.

A good branch name would be (where issue #325 is the ticket you're working on):

```sh
git checkout -b 325-kill-sql-injections
```

### 3. Get the test suite running

Just type `make coverage` or `make debug`, the testsuite should be run
automatically.

Please add tests if you're fixing a bug or adding a new feature: we do have a
[high coverage](https://coveralls.io/github/jvoisin/snuffleupagus?branch=master)
(functions, lines and branches), and intend to keep it that way.

#### 3.3 Debugging failures in the test suite

If your changes have introduced run-time failures in the test-suite, you can
easily troubleshoot them by inspecting the files that
[php has generated](https://qa.php.net/write-test.php#analyzing-failing-tests)
for this purpose.

A nice trick is to edit the `.sh` file to prepend `gdb --args` to it before
launching it, in order to run the failing test inside GDB.


### 4. Did you find a bug?

* **Ensure the bug was not already reported** by
  [searching all issues](https://github.com/jvoisin/snuffleupagus/issues?q=).
* If you're unable to find an open issue addressing the problem,
  [open a new one](https://github.com/jvoisin/snuffleupagus/issues/new).
  Be sure to include a **title and clear description**,
  as much relevant information as possible, and a **code sample**
  or an **executable test case** demonstrating the expected behavior that is not
  occurring.


### 5. Get the style right

Your patch should follow the same conventions & pass the same code quality
checks as the rest of the project. We're using [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to
ensure a consistent code-style. Please run it with `clang-format --style="{BasedOnStyle: google, SortIncludes: false}"`
before committing, or even better, use a [pre-commit hook](https://github.com/andrewseidl/githook-clang-format).

### 6. Make a Pull Request

At this point, you should switch back to your master branch and make sure it's
up to date with our upstream master branch:

```sh
git remote add upstream git@github.com:jvoisin/snuffleupagus.git
git checkout master
git pull upstream master
```

Then update your feature branch from your local copy of master, and push it!

```sh
git checkout 325-kill-sql-injections
git rebase master
git push --set-upstream origin 325-kill-sql-injections
```

Finally, go to GitHub and [make a Pull Request](https://help.github.com/articles/creating-a-pull-request) :D

Travis CI will [run our test suite](https://travis-ci.org/jvoisin/snuffleupagus)
against all supported PHP versions. We care about quality, so your PR won't be
merged until all tests pass. It's unlikely, but it's possible that your changes
pass tests in one PHP version but fail in another. In that case, you'll have to
setup your development environment to use the problematic PHP version, and
investigate what's going on!

### 7. Keeping your Pull Request updated

If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
has changed, and that you need to update your branch so it's easier to merge.

To learn more about rebasing in Git, there are a lot of [good](http://git-scm.com/book/en/Git-Branching-Rebasing)
[resources](https://help.github.com/articles/interactive-rebase) but here's the suggested workflow:

```sh
git checkout 325-kill-sql-injections
git pull --rebase upstream master
git push --force-with-lease 325-kill-sql-injections
```

### 8. Merging a PR (maintainers only)

A PR can only be merged into master by a maintainer if:

1. It is passing CI.
2. It has been approved by at least one maintainer. If it was a maintainer who
   opened the PR, only one extra approval is needed.
3. It has no requested changes.
4. It is up to date with current master.

Any maintainer is allowed to merge a PR if all of these conditions are met.

### 9. Shipping a release (maintainers only)

Maintainers need to do the following to push out a release:

1. Make sure that all pending and mergeable pull requests are in
2. Close the corresponding
	 [milestone](https://github.com/jvoisin/snuffleupagus/milestones)
2. Run `valgrind` (by adding a `-m` after the `-q` in the Makefile) and check that everything is ok.
   Don't mind the python-related issues.
2. Run `cd src; phpize; ./configure --enable-snuffleupagus --enable-debug; scan-build make`
   and fix the possible issues.
3. Update the `src/php_snuffleupagus.h` according to [semantic versioning](https://semver.org/)
4. Update the changelog page in the documentation
5. Update the Debian changelog in `./debian/changelog` with `cd debian; dch`
6. Commit the result
7. Clean up the folder `make clean; git clean -xdf`
8. Create a tag for the release:

  ```sh
  git tag -s v$MAJOR.$MINOR.$PATCH -m "v$MAJOR.$MINOR.$PATCH"
  git push --tags
	git push origin master
  ```

9. Wait for the CI on the new tag branch to finish
10. Create the [release on github](https://github.com/jvoisin/snuffleupagus/releases)
11. Add the freshly built Debian packages from the CI to the release
12. Do the *secret release dance*
alt-ruby31-libs/README.md000064400000015641150556332170010673 0ustar00[![Actions Status: MinGW](https://github.com/ruby/ruby/workflows/MinGW/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MinGW")
[![Actions Status: MJIT](https://github.com/ruby/ruby/workflows/MJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MJIT")
[![Actions Status: Ubuntu](https://github.com/ruby/ruby/workflows/Ubuntu/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Ubuntu")
[![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows")
[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0sy8rrxut4o0k960/branch/master?svg=true)](https://ci.appveyor.com/project/ruby/ruby/branch/master)
[![Travis Status](https://app.travis-ci.com/ruby/ruby.svg?branch=master)](https://app.travis-ci.com/ruby/ruby)
[![Cirrus Status](https://api.cirrus-ci.com/github/ruby/ruby.svg)](https://cirrus-ci.com/github/ruby/ruby/master)

# What's Ruby

Ruby is an interpreted object-oriented programming language often
used for web development. It also offers many scripting features
to process plain text and serialized files, or manage system tasks.
It is simple, straightforward, and extensible.

## Features of Ruby

*   Simple Syntax
*   **Normal** Object-oriented Features (e.g. class, method calls)
*   **Advanced** Object-oriented Features (e.g. mix-in, singleton-method)
*   Operator Overloading
*   Exception Handling
*   Iterators and Closures
*   Garbage Collection
*   Dynamic Loading of Object Files (on some architectures)
*   Highly Portable (works on many Unix-like/POSIX compatible platforms as
    well as Windows, macOS, etc.) cf.
    https://github.com/ruby/ruby/blob/master/doc/maintainers.rdoc#label-Platform+Maintainers


## How to get Ruby

For a complete list of ways to install Ruby, including using third-party tools
like rvm, see:

https://www.ruby-lang.org/en/downloads/

### Git

The mirror of the Ruby source tree can be checked out with the following command:

    $ git clone https://github.com/ruby/ruby.git

There are some other branches under development. Try the following command
to see the list of branches:

    $ git ls-remote https://github.com/ruby/ruby.git

You may also want to use https://git.ruby-lang.org/ruby.git (actual master of Ruby source)
if you are a committer.

### Subversion

Stable branches for older Ruby versions can be checked out with also the
following command:

    $ svn co https://svn.ruby-lang.org/repos/ruby/branches/ruby_2_6/ ruby

Try the following command to see the list of branches:

    $ svn ls https://svn.ruby-lang.org/repos/ruby/branches/


## Ruby home page

https://www.ruby-lang.org/

## Mailing list

There is a mailing list to discuss Ruby. To subscribe to this list, please
send the following phrase:

    subscribe

in the mail body (not subject) to the address [ruby-talk-request@ruby-lang.org].

[ruby-talk-request@ruby-lang.org]: mailto:ruby-talk-request@ruby-lang.org?subject=Join%20Ruby%20Mailing%20List&body=subscribe

## Requirements to build from repository

1. GNU or BSD make
2. C99 compiler
3. autoconf 2.67 or higher
4. automake 1.15 or higher
5. bison 2.3 or higher
6. Ruby 2.2 or higher

When building from a released version, only a C99 compiler and GNU or BSD make
is required.

## How to compile and install

1.  If you want to use Microsoft Visual C++ to compile Ruby, read
    [win32/README.win32](rdoc-ref:win32/README.win32) instead of this document.

2.  Run `./autogen.sh` to generate configure, when you build the source checked
    out from the Git repository.

3.  Run `./configure`, which will generate `config.h` and `Makefile`.

    Some C compiler flags may be added by default depending on your
    environment. Specify `optflags=..` and `warnflags=..` as necessary to
    override them.

4.  Edit `include/ruby/defines.h` if you need. Usually this step will not be needed.

5.  Optional: Remove comment mark(`#`) before the module names from `ext/Setup`.

    This step is only necessary if you want to link modules statically.

    If you don't want to compile dynamic extensions (probably on architectures
    which do not allow dynamic loading), remove comment mark from the line
    "`#option nodynamic`" in `ext/Setup`.

    Usually this step will not be needed.

6.  Run `make`.

    * On Mac, set RUBY\_CODESIGN environment variable with a signing identity.
      It uses the identity to sign `ruby` binary. See also codesign(1).

7.  Optionally, run '`make check`' to check whether the compiled Ruby
    interpreter works well. If you see the message "`check succeeded`", your
    Ruby works as it should (hopefully).

8.  Run '`make install`'.

    This command will create the following directories and install files into
    them.

    *   `${DESTDIR}${prefix}/bin`
    *   `${DESTDIR}${prefix}/include/ruby-${MAJOR}.${MINOR}.${TEENY}`
    *   `${DESTDIR}${prefix}/include/ruby-${MAJOR}.${MINOR}.${TEENY}/${PLATFORM}`
    *   `${DESTDIR}${prefix}/lib`
    *   `${DESTDIR}${prefix}/lib/ruby`
    *   `${DESTDIR}${prefix}/lib/ruby/${MAJOR}.${MINOR}.${TEENY}`
    *   `${DESTDIR}${prefix}/lib/ruby/${MAJOR}.${MINOR}.${TEENY}/${PLATFORM}`
    *   `${DESTDIR}${prefix}/lib/ruby/site_ruby`
    *   `${DESTDIR}${prefix}/lib/ruby/site_ruby/${MAJOR}.${MINOR}.${TEENY}`
    *   `${DESTDIR}${prefix}/lib/ruby/site_ruby/${MAJOR}.${MINOR}.${TEENY}/${PLATFORM}`
    *   `${DESTDIR}${prefix}/lib/ruby/vendor_ruby`
    *   `${DESTDIR}${prefix}/lib/ruby/vendor_ruby/${MAJOR}.${MINOR}.${TEENY}`
    *   `${DESTDIR}${prefix}/lib/ruby/vendor_ruby/${MAJOR}.${MINOR}.${TEENY}/${PLATFORM}`
    *   `${DESTDIR}${prefix}/lib/ruby/gems/${MAJOR}.${MINOR}.${TEENY}`
    *   `${DESTDIR}${prefix}/share/man/man1`
    *   `${DESTDIR}${prefix}/share/ri/${MAJOR}.${MINOR}.${TEENY}/system`


    If Ruby's API version is '*x.y.z*', the `${MAJOR}` is '*x*', the
    `${MINOR}` is '*y*', and the `${TEENY}` is '*z*'.

    **NOTE**: teeny of the API version may be different from one of Ruby's
    program version

    You may have to be a super user to install Ruby.

If you fail to compile Ruby, please send the detailed error report with the
error log and machine/OS type, to help others.

Some extension libraries may not get compiled because of lack of necessary
external libraries and/or headers, then you will need to run '`make distclean-ext`'
to remove old configuration after installing them in such case.

## Copying

See the file [COPYING](rdoc-ref:COPYING).

## Feedback

Questions about the Ruby language can be asked on the [Ruby-Talk] mailing list
or on websites like https://stackoverflow.com.

Bugs should be reported at https://bugs.ruby-lang.org. Read [HowToReport] for more information.

[Ruby-Talk]: https://www.ruby-lang.org/en/community/mailing-lists
[HowToReport]: https://bugs.ruby-lang.org/projects/ruby/wiki/HowToReport

## Contributing

See the file [CONTRIBUTING.md](rdoc-ref:CONTRIBUTING)

## The Author

Ruby was originally designed and developed by Yukihiro Matsumoto (Matz) in 1995.

<matz@ruby-lang.org>
alt-ruby31-libs/NEWS.md000064400000050447150556332240010513 0ustar00# NEWS for Ruby 3.1.0

This document is a list of user-visible feature changes
since the **3.0.0** release, except for bug fixes.

Note that each entry is kept to a minimum, see links for details.

## Language changes

*   The block argument can now be anonymous if the block will
    only be passed to another method. [[Feature #11256]]

    ```ruby
    def foo(&)
      bar(&)
    end
    ```

*   Pin operator now takes an expression. [[Feature #17411]]

    ```ruby
    Prime.each_cons(2).lazy.find_all{_1 in [n, ^(n + 2)]}.take(3).to_a
    #=> [[3, 5], [5, 7], [11, 13]]
    ```

*   Pin operator now supports instance, class, and global variables.
    [[Feature #17724]]

    ```ruby
    @n = 5
    Prime.each_cons(2).lazy.find{_1 in [n, ^@n]}
    #=> [3, 5]
    ```

*   One-line pattern matching is no longer experimental.

*   Parentheses can be omitted in one-line pattern matching.
    [[Feature #16182]]

    ```ruby
    [0, 1] => _, x
    {y: 2} => y:
    x #=> 1
    y #=> 2
    ```

*   Multiple assignment evaluation order has been made consistent with
    single assignment evaluation order.  With single assignment, Ruby
    uses a left-to-right evaluation order.  With this code:

    ```ruby
    foo[0] = bar
    ```

    The following evaluation order is used:

    1. `foo`
    2. `bar`
    3. `[]=` called on the result of `foo`

    In Ruby before 3.1.0, multiple assignment did not follow this
    evaluation order.  With this code:

    ```ruby
    foo[0], bar.baz = a, b
    ```

    Versions of Ruby before 3.1.0 would evaluate in the following
    order

    1. `a`
    2. `b`
    3. `foo`
    4. `[]=` called on the result of `foo`
    5. `bar`
    6. `baz=` called on the result of `bar`

    Starting in Ruby 3.1.0, the evaluation order is now consistent with
    single assignment, with the left-hand side being evaluated before
    the right-hand side:

    1. `foo`
    2. `bar`
    3. `a`
    4. `b`
    5. `[]=` called on the result of `foo`
    6. `baz=` called on the result of `bar`

    [[Bug #4443]]

*   Values in Hash literals and keyword arguments can be omitted.
    [[Feature #14579]]

    For example,

    * `{x:, y:}` is a syntax sugar of `{x: x, y: y}`.
    * `foo(x:, y:)` is a syntax sugar of `foo(x: x, y: y)`.

    Constant names, local variable names, and method names are allowed as
    key names.  Note that a reserved word is considered as a local
    variable or method name even if it's a pseudo variable name such as
    `self`.

*   Non main-Ractors can get instance variables (ivars) of classes/modules
    if ivars refer to shareable objects.
    [[Feature #17592]]

*   A command syntax is allowed in endless method definitions, i.e.,
    you can now write `def foo = puts "Hello"`.
    Note that `private def foo = puts "Hello"` does not parse.
    [[Feature #17398]]

## Command line options

* `--disable-gems` is now explicitly declared as "just for debugging".
  Never use it in any real-world codebase.
  [[Feature #17684]]

## Core classes updates

Note: We're only listing outstanding class updates.

* Array

    * Array#intersect? is added. [[Feature #15198]]

* Class

    *   Class#subclasses, which returns an array of classes
        directly inheriting from the receiver, not
        including singleton classes.
        [[Feature #18273]]

        ```ruby
        class A; end
        class B < A; end
        class C < B; end
        class D < A; end
        A.subclasses    #=> [D, B]
        B.subclasses    #=> [C]
        C.subclasses    #=> []
        ```

* Enumerable

    *   Enumerable#compact is added. [[Feature #17312]]

    *   Enumerable#tally now accepts an optional hash to count. [[Feature #17744]]

    *   Enumerable#each_cons and each_slice to return a receiver. [[GH-1509]]

        ```ruby
        [1, 2, 3].each_cons(2){}
        # 3.0 => nil
        # 3.1 => [1, 2, 3]

        [1, 2, 3].each_slice(2){}
        # 3.0 => nil
        # 3.1 => [1, 2, 3]
        ```

* Enumerator::Lazy

    *   Enumerator::Lazy#compact is added. [[Feature #17312]]

* File

    *   File.dirname now accepts an optional argument for the level to
        strip path components. [[Feature #12194]]

* GC

    *   "GC.measure_total_time = true" enables the measurement of GC.
        Measurement can introduce overhead. It is enabled by default.
        GC.measure_total_time returns the current setting.
        GC.stat[:time] or GC.stat(:time) returns measured time
        in milli-seconds. [[[Feature #10917]]]

    *   GC.total_time returns measured time in nano-seconds. [[[Feature #10917]]]

* Integer

    *   Integer.try_convert is added. [[Feature #15211]]

* Kernel


    *   Kernel#load now accepts a module as the second argument,
        and will load the file using the given module as the
        top-level module. [[Feature #6210]]

* Marshal

    *   Marshal.load now accepts a `freeze: true` option.
        All returned objects are frozen except for `Class` and
        `Module` instances. Strings are deduplicated. [[Feature #18148]]

* MatchData

    *   MatchData#match is added [[Feature #18172]]

    *   MatchData#match_length is added [[Feature #18172]]

* Method / UnboundMethod

    *   Method#public?, Method#private?, Method#protected?,
        UnboundMethod#public?, UnboundMethod#private?,
        UnboundMethod#protected? have been added. [[Feature #11689]]

* Module

    *   Module#prepend now modifies the ancestor chain if the receiver
        already includes the argument. Module#prepend still does not
        modify the ancestor chain if the receiver has already prepended
        the argument. [[Bug #17423]]

    *   Module#private, #public, #protected, and #module_function will
        now return their arguments.  If a single argument is given, it
        is returned. If no arguments are given, nil is returned.  If
        multiple arguments are given, they are returned as an array.
        [[Feature #12495]]

* Process

    *   Process.\_fork is added. This is a core method for fork(2).
        Do not call this method directly; it is called by existing
        fork methods: Kernel.#fork, Process.fork, and IO.popen("-").
        Application monitoring libraries can overwrite this method to
        hook fork events. [[Feature #17795]]

* Struct

    *   Passing only keyword arguments to Struct#initialize is warned.
        You need to use a Hash literal to set a Hash to a first member.
        [[Feature #16806]]

    *   StructClass#keyword_init? is added [[Feature #18008]]

* String

    *   Update Unicode version to 13.0.0 [[Feature #17750]]
        and Emoji version to 13.0 [[Feature #18029]]

    *   String#unpack and String#unpack1 now accept an `offset:` keyword
        argument to start the unpacking after an arbitrary number of bytes
        have been skipped. If `offset` is outside of the string bounds
        `ArgumentError` is raised. [[Feature #18254]]

* Thread

    *   Thread#native_thread_id is added. [[Feature #17853]]

* Thread::Backtrace

    *   Thread::Backtrace.limit, which returns the value to limit backtrace
        length set by `--backtrace-limit` command line option, is added.
        [[Feature #17479]]

* Thread::Queue

    *   Thread::Queue.new now accepts an Enumerable of initial values.
        [[Feature #17327]]

* Time

    *   Time.new now accepts optional `in:` keyword argument for the
        timezone, as well as `Time.at` and `Time.now`, so that is now
        you can omit minor arguments to `Time.new`. [[Feature #17485]]

        ```ruby
        Time.new(2021, 12, 25, in: "+07:00")
        #=> 2021-12-25 00:00:00 +0700
        ```

        At the same time, time component strings are converted to
        integers more strictly now.

        ```ruby
        Time.new(2021, 12, 25, "+07:30")
        #=> invalid value for Integer(): "+07:30" (ArgumentError)
        ```

        Ruby 3.0 or earlier returned probably unexpected result
        `2021-12-25 07:00:00`, not `2021-12-25 07:30:00` nor
        `2021-12-25 00:00:00 +07:30`.

    *   Time#strftime supports RFC 3339 UTC for unknown offset local
        time, `-0000`, as `%-z`. [[Feature #17544]]

* TracePoint

    *   TracePoint.allow_reentry is added to allow reenter while TracePoint
        callback.
        [[Feature #15912]]

* $LOAD_PATH

    *   $LOAD_PATH.resolve_feature_path does not raise. [[Feature #16043]]

* Fiber Scheduler

    *   Add support for `Addrinfo.getaddrinfo` using `address_resolve` hook.
        [[Feature #17370]]

    *   Introduce non-blocking `Timeout.timeout` using `timeout_after` hook.
        [[Feature #17470]]

    *   Introduce new scheduler hooks `io_read` and `io_write` along with a
        low level `IO::Buffer` for zero-copy read/write. [[Feature #18020]]

    *   IO hooks `io_wait`, `io_read`, `io_write`, receive the original IO object
        where possible. [[Bug #18003]]

    *   Make `Monitor` fiber-safe. [[Bug #17827]]

    *   Replace copy coroutine with pthread implementation. [[Feature #18015]]

* Refinement

    *   New class which represents a module created by Module#refine.
        `include` and `prepend` are deprecated, and `import_methods` is added
        instead. [[Bug #17429]]

## Stdlib updates

*   The following default gem are updated.
    * RubyGems 3.3.3
    * base64 0.1.1
    * benchmark 0.2.0
    * bigdecimal 3.1.1
    * bundler 2.3.3
    * cgi 0.3.1
    * csv 3.2.2
    * date 3.2.2
    * did_you_mean 1.6.1
    * digest 3.1.0
    * drb 2.1.0
    * erb 2.2.3
    * error_highlight 0.3.0
    * etc 1.3.0
    * fcntl 1.0.1
    * fiddle 1.1.0
    * fileutils 1.6.0
    * find 0.1.1
    * io-console 0.5.10
    * io-wait 0.2.1
    * ipaddr 1.2.3
    * irb 1.4.1
    * json 2.6.1
    * logger 1.5.0
    * net-http 0.2.0
    * net-protocol 0.1.2
    * nkf 0.1.1
    * open-uri 0.2.0
    * openssl 3.0.0
    * optparse 0.2.0
    * ostruct 0.5.2
    * pathname 0.2.0
    * pp 0.3.0
    * prettyprint 0.1.1
    * psych 4.0.3
    * racc 1.6.0
    * rdoc 6.4.0
    * readline 0.0.3
    * readline-ext 0.1.4
    * reline 0.3.0
    * resolv 0.2.1
    * rinda 0.1.1
    * ruby2_keywords 0.0.5
    * securerandom 0.1.1
    * set 1.0.2
    * stringio 3.0.1
    * strscan 3.0.1
    * tempfile 0.1.2
    * time 0.2.0
    * timeout 0.2.0
    * tmpdir 0.1.2
    * un 0.2.0
    * uri 0.11.0
    * yaml 0.2.0
    * zlib 2.1.1
*   The following bundled gems are updated.
    * minitest 5.15.0
    * power_assert 2.0.1
    * rake 13.0.6
    * test-unit 3.5.3
    * rexml 3.2.5
    * rbs 2.1.0
    * typeprof 0.21.2
*   The following default gems are now bundled gems.
    * net-ftp 0.1.3
    * net-imap 0.2.3
    * net-pop 0.1.1
    * net-smtp 0.3.1
    * matrix 0.4.2
    * prime 0.1.2
    * debug 1.4.0

* Coverage measurement now supports suspension. You can use `Coverage.suspend`
  to stop the measurement temporarily, and `Coverage.resume` to restart it.
  See [[Feature #18176]] in detail.

* Random::Formatter is moved to random/formatter.rb, so that you can
  use `Random#hex`, `Random#base64`, and so on without SecureRandom.
  [[Feature #18190]]

## Compatibility issues

Note: Excluding feature bug fixes.

* `rb_io_wait_readable`, `rb_io_wait_writable` and `rb_wait_for_single_fd` are
  deprecated in favour of `rb_io_maybe_wait_readable`,
  `rb_io_maybe_wait_writable` and `rb_io_maybe_wait` respectively.
  `rb_thread_wait_fd` and `rb_thread_fd_writable` are deprecated. [[Bug #18003]]

## Stdlib compatibility issues

* `ERB#initialize` warns `safe_level` and later arguments even without -w.
  [[Feature #14256]]

* `lib/debug.rb` is replaced with `debug.gem`

* `Kernel#pp` in `lib/pp.rb` uses the width of `IO#winsize` by default.
  This means that the output width is automatically changed depending on
  your terminal size. [[Feature #12913]]

* Psych 4.0 changes `Psych.load` as `safe_load` by the default.
  You may need to use Psych 3.3.2 for migrating to this behavior.
  [[Bug #17866]]

## C API updates

* Documented. [[GH-4815]]

* `rb_gc_force_recycle` is deprecated and has been changed to a no-op.
  [[Feature #18290]]

## Implementation improvements

* Inline cache mechanism is introduced for reading class variables.
  [[Feature #17763]]

* `instance_eval` and `instance_exec` now only allocate a singleton class when
  required, avoiding extra objects and improving performance. [[GH-5146]]

* The performance of `Struct` accessors is improved. [[GH-5131]]

* `mandatory_only?` builtin special form to improve performance on
  builtin methods. [[GH-5112]]

* Experimental feature Variable Width Allocation in the garbage collector.
  This feature is turned off by default and can be enabled by compiling Ruby
  with flag `USE_RVARGC=1` set. [[Feature #18045]] [[Feature #18239]]

## JIT

* Rename Ruby 3.0's `--jit` to `--mjit`, and alias `--jit` to `--yjit`
  on non-Windows x86-64 platforms and to `--mjit` on others.

### MJIT

* The default `--mjit-max-cache` is changed from 100 to 10000.

* JIT-ed code is no longer cancelled when a TracePoint for class events
  is enabled.

* The JIT compiler no longer skips compilation of methods longer than
  1000 instructions.

* `--mjit-verbose` and `--mjit-warning` output "JIT cancel" when JIT-ed
  code is disabled because TracePoint or GC.compact is used.

### YJIT: New experimental in-process JIT compiler

New JIT compiler available as an experimental feature. [[Feature #18229]]

See [this blog post](https://shopify.engineering/yjit-just-in-time-compiler-cruby
) introducing the project.

* Disabled by default, use `--yjit` command-line option to enable YJIT.

* Performance improvements on benchmarks based on real-world software,
  up to 22% on railsbench, 39% on liquid-render.

* Fast warm-up times.

* Limited to Unix-like x86-64 platforms for now.

## Static analysis

### RBS

*   Generics type parameters can be bounded ([PR](https://github.com/ruby/rbs/pull/844)).

    ```rbs
    # `T` must be compatible with the `_Output` interface.
    # `PrettyPrint[String]` is ok, but `PrettyPrint[Integer]` is a type error.
    class PrettyPrint[T < _Output]
      interface _Output
        def <<: (String) -> void
      end

      attr_reader output: T

      def initialize: (T output) -> void
    end
    ```

*   Type aliases can be generic. ([PR](https://github.com/ruby/rbs/pull/823))

    ```rbs
    # Defines a generic type `list`.
    type list[T] = [ T, list[T] ]
                 | nil

    type str_list = list[String]
    type int_list = list[Integer]
    ```

* [rbs collection](https://github.com/ruby/rbs/blob/master/docs/collection.md) has been introduced to manage gems’ RBSs.

* Many signatures for built-in and standard libraries have been added/updated.

* It includes many bug fixes and performance improvements too.

See the [CHANGELOG.md](https://github.com/ruby/rbs/blob/master/CHANGELOG.md) for more information.

### TypeProf

* [Experimental IDE support](https://github.com/ruby/typeprof/blob/master/doc/ide.md) has been implemented.
* Many bug fixes and performance improvements since Ruby 3.0.0.

## Debugger

* A new debugger [debug.gem](https://github.com/ruby/debug) is bundled.
  debug.gem is a fast debugger implementation, and it provides many features
  like remote debugging, colorful REPL, IDE (VSCode) integration, and more.
  It replaces `lib/debug.rb` standard library.

* `rdbg` command is also installed into `bin/` directory to start and control
  debugging execution.

## error_highlight

A built-in gem called error_highlight has been introduced.
It shows fine-grained error locations in the backtrace.

Example: `title = json[:article][:title]`

If `json` is nil, it shows:

```
$ ruby test.rb
test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)

title = json[:article][:title]
            ^^^^^^^^^^
```

If `json[:article]` returns nil, it shows:

```
$ ruby test.rb
test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)

title = json[:article][:title]
                      ^^^^^^^^
```

This feature is enabled by default.
You can disable it by using a command-line option `--disable-error_highlight`.
See [the repository](https://github.com/ruby/error_highlight) in detail.

## IRB Autocomplete and Document Display

The IRB now has an autocomplete feature, where you can just type in the code, and the completion candidates dialog will appear. You can use Tab and Shift+Tab to move up and down.

If documents are installed when you select a completion candidate, the documentation dialog will appear next to the completion candidates dialog, showing part of the content. You can read the full document by pressing Alt+d.

## Miscellaneous changes

* lib/objspace/trace.rb is added, which is a tool for tracing the object
  allocation. Just by requiring this file, tracing is started *immediately*.
  Just by `Kernel#p`, you can investigate where an object was created.
  Note that just requiring this file brings a large performance overhead.
  This is only for debugging purposes. Do not use this in production.
  [[Feature #17762]]

* Now exceptions raised in finalizers will be printed to `STDERR`, unless
  `$VERBOSE` is `nil`.  [[Feature #17798]]

* `ruby -run -e httpd` displays URLs to access.  [[Feature #17847]]

* Add `ruby -run -e colorize` to colorize Ruby code using
  `IRB::Color.colorize_code`.

[Bug #4443]:      https://bugs.ruby-lang.org/issues/4443
[Feature #6210]:  https://bugs.ruby-lang.org/issues/6210
[Feature #10917]: https://bugs.ruby-lang.org/issues/10917
[Feature #11256]: https://bugs.ruby-lang.org/issues/11256
[Feature #11689]: https://bugs.ruby-lang.org/issues/11689
[Feature #12194]: https://bugs.ruby-lang.org/issues/12194
[Feature #12495]: https://bugs.ruby-lang.org/issues/12495
[Feature #12913]: https://bugs.ruby-lang.org/issues/12913
[Feature #14256]: https://bugs.ruby-lang.org/issues/14256
[Feature #14579]: https://bugs.ruby-lang.org/issues/14579
[Feature #15198]: https://bugs.ruby-lang.org/issues/15198
[Feature #15211]: https://bugs.ruby-lang.org/issues/15211
[Feature #15912]: https://bugs.ruby-lang.org/issues/15912
[Feature #16043]: https://bugs.ruby-lang.org/issues/16043
[Feature #16182]: https://bugs.ruby-lang.org/issues/16182
[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
[Feature #17312]: https://bugs.ruby-lang.org/issues/17312
[Feature #17327]: https://bugs.ruby-lang.org/issues/17327
[Feature #17370]: https://bugs.ruby-lang.org/issues/17370
[Feature #17398]: https://bugs.ruby-lang.org/issues/17398
[Feature #17411]: https://bugs.ruby-lang.org/issues/17411
[Bug #17423]:     https://bugs.ruby-lang.org/issues/17423
[Bug #17429]:     https://bugs.ruby-lang.org/issues/17429
[Feature #17470]: https://bugs.ruby-lang.org/issues/17470
[Feature #17479]: https://bugs.ruby-lang.org/issues/17479
[Feature #17485]: https://bugs.ruby-lang.org/issues/17485
[Feature #17544]: https://bugs.ruby-lang.org/issues/17544
[Feature #17592]: https://bugs.ruby-lang.org/issues/17592
[Feature #17684]: https://bugs.ruby-lang.org/issues/17684
[Feature #17724]: https://bugs.ruby-lang.org/issues/17724
[Feature #17744]: https://bugs.ruby-lang.org/issues/17744
[Feature #17750]: https://bugs.ruby-lang.org/issues/17750
[Feature #17762]: https://bugs.ruby-lang.org/issues/17762
[Feature #17763]: https://bugs.ruby-lang.org/issues/17763
[Feature #17795]: https://bugs.ruby-lang.org/issues/17795
[Feature #17798]: https://bugs.ruby-lang.org/issues/17798
[Bug #17827]:     https://bugs.ruby-lang.org/issues/17827
[Feature #17847]: https://bugs.ruby-lang.org/issues/17847
[Feature #17853]: https://bugs.ruby-lang.org/issues/17853
[Bug #17866]:     https://bugs.ruby-lang.org/issues/17866
[Bug #18003]:     https://bugs.ruby-lang.org/issues/18003
[Feature #18008]: https://bugs.ruby-lang.org/issues/18008
[Feature #18015]: https://bugs.ruby-lang.org/issues/18015
[Feature #18020]: https://bugs.ruby-lang.org/issues/18020
[Feature #18029]: https://bugs.ruby-lang.org/issues/18029
[Feature #18045]: https://bugs.ruby-lang.org/issues/18045
[Feature #18148]: https://bugs.ruby-lang.org/issues/18148
[Feature #18172]: https://bugs.ruby-lang.org/issues/18172
[Feature #18176]: https://bugs.ruby-lang.org/issues/18176
[Feature #18190]: https://bugs.ruby-lang.org/issues/18190
[Feature #18229]: https://bugs.ruby-lang.org/issues/18229
[Feature #18239]: https://bugs.ruby-lang.org/issues/18239
[Feature #18254]: https://bugs.ruby-lang.org/issues/18254
[Feature #18273]: https://bugs.ruby-lang.org/issues/18273
[Feature #18290]: https://bugs.ruby-lang.org/issues/18290

[GH-1509]: https://github.com/ruby/ruby/pull/1509
[GH-4815]: https://github.com/ruby/ruby/pull/4815
[GH-5112]: https://github.com/ruby/ruby/pull/5112
[GH-5131]: https://github.com/ruby/ruby/pull/5131
[GH-5146]: https://github.com/ruby/ruby/pull/5146